Skip to main content
Connic
Build

Runtime Controls

Bound execution, coordinate concurrent runs, retain session history, and share configuration across agent families.

Last updated

Execution limits and retries

agents/agent.yaml
max_concurrent_runs: 10
max_iterations: 50
timeout: 120

retry_options:
  attempts: 5
  initial_delay: 10
  max_delay: 60
  # Tool and sequential agents only:
  rerun_middleware: true
  • max_concurrent_runs caps simultaneous runs, subject to your subscription limit.
  • max_iterations limits the LLM loop so repeated tool calls cannot run indefinitely.
  • timeout sets the maximum execution time in seconds, with a minimum of five seconds and a plan-level cap.
  • retry_options retries the failing operation. LLM agents retry an individual model request and reflect failed tool calls without replaying the agent. Tool and sequential agents retain operation-level retries. attempts includes the first attempt and is limited to 10.
  • Model requests use capped exponential backoff with jitter unless the provider supplies Retry-After. A value above max_delay fails without sleeping.
  • rerun_middleware only affects operation-level retries on tool and sequential agents; LLM agents are never replayed.

Concurrency rules

Concurrency rules ensure that only one run per unique key is active at a time. Use them when an agent processes events for a specific support process, customer, or order and parallel processing would conflict.

Queue mode (default)

When another event arrives for an active key, it waits until the first run finishes and then starts automatically.

agents/support-processor.yaml
version: "1.0"

name: support-processor
type: llm
model: gemini/gemini-2.5-pro
description: "Processes support tickets one at a time per process"
system_prompt: "You are a support agent. Process the incoming ticket."

# Only one run per process_id at a time. Additional runs wait in queue.
concurrency:
  key: "process_id"
  on_conflict: queue

Drop mode

When another event arrives for an active key, the new run is cancelled immediately. Use this when duplicate work would be wasteful.

agents/notification-handler.yaml
version: "1.0"

name: notification-handler
type: tool
description: "Handles notifications, skipping duplicates"
tool_name: notifications.handle

# Drop duplicate runs for the same customer while one is active.
concurrency:
  key: "data.customer_id"
  on_conflict: drop

Key extraction

The key uses dot notation to read the trigger payload. If a Kafka payload is {"data": {"customer_id": "abc"}}, use data.customer_id. If the path does not exist, concurrency enforcement is skipped for that run.

Interaction with max_concurrent_runs

Both constraints apply. With max_concurrent_runs: 5 and concurrency.key: "process_id", five process IDs can run in parallel, but only one run per process ID can be active.

Limitations

Concurrency rules are not supported on sequential agents. The key comes from the raw trigger payload, so it applies uniformly to all trigger types, including Kafka, HTTP, Cron, API, and trigger_agent.

Persistent sessions

By default, every request creates an isolated session. Persistent sessions maintain conversation history across requests, restarts, and redeployments.

agents/support-bot.yaml
version: "1.0"

name: support-bot
type: llm
model: gemini/gemini-2.5-pro
description: "A support chatbot that remembers conversation history"
system_prompt: |
  You are a helpful support agent. Use the conversation history
  to provide contextual responses.

# Maintain persistent sessions keyed by chat ID from middleware
session:
  key: context.chat_id
  ttl: 86400  # Sessions expire after 24 hours of inactivity

# Keep long conversations within the model context window
context_compression:
  enabled: true
  # Optional model for compression summaries; defaults to the agent model
  model: gemini/gemini-2.5-flash
  keep_recent_messages: 12
  # Optional early compression based on model-reported prompt usage
  max_prompt_tokens: 100000

Session key

The key identifies the session and must use one of two prefixes:

  • context.<path> resolves from the middleware context. This is recommended because middleware can derive a stable key from any part of the request.
  • input.<path> resolves from the raw connector payload before middleware. It requires valid JSON and supports nested paths.

Set the key in middleware

middleware/support-bot.py
async def before(content: dict, context: dict) -> dict:
    # Extract a stable identifier for this conversation from the connector payload.
    payload = context.get("payload", {})
    context["chat_id"] = payload.get("chat_id")
    return content

Use an input key

agents/agent.yaml
# When the connector payload is JSON like {"user_id": "u123", "message": "..."}
session:
  key: input.user_id

TTL and session management

The optional ttlexpires sessions after that many inactive seconds. The minimum is 60 seconds; without a TTL, sessions never expire. View and delete active sessions in the dashboard under Storage > Sessions. Sessions are scoped per environment.

Context compression

Add context_compression to keep long-running LLM sessions inside the model context window. Once configured, provider context-window errors trigger compression and an automatic retry. Set context_compression.model to use a separate summary model; normal agent calls and their retry still use the agent model. Set max_prompt_tokens to compress earlier using reported prompt usage. Use session_history.interval only when stored history should also be compacted between runs.

Session keys are required at runtime

If the session key resolves to an empty or missing value, the run fails. Ensure the middleware or payload always provides it.

Cascading defaults with _defaults.yaml

Add _defaults.yaml to any directory under agents/ to share configuration with agents at that level and below. Use it for a common model, guardrails, tools, or database.collections.

agents/ layout
agents/
_defaults.yamlapplies to every agent in the project
process/
_defaults.yamladds/overrides for everything under process/
ingest/
foo.yamlinherits root + process defaults
enrich/
_defaults.yamladds/overrides for process/enrich/*
bar.yamlinherits root + process + enrich defaults
support-assistant.yamlinherits only root defaults

The loader merges defaults shallowest-first, then applies the agent file last so the agent wins on conflict.

What can live in a defaults file

Defaults accept the same fields as agent YAML and may be partial, with two exceptions:

  • name and description are forbidden because they identify a specific agent.
  • version is allowed so you can pin the schema version project-wide. The agent file must still set it together with name and description.

Merge rules

  • Scalars such as model, temperature, system_prompt, and timeout are replaced by the deeper layer.
  • Objects such as database, knowledge, retry_options, approval, session, and guardrails merge recursively by key.
  • Lists concatenate with deduplication:
    • tools, discoverable_tools, and approval.tools deduplicate by tool reference; a deeper declaration overrides the inherited entry.
    • mcp_servers deduplicates by server name; a deeper full server configuration replaces the inherited one.
    • guardrails.input and guardrails.output deduplicate by rule name when present and otherwise append.
    • Sequential agents deduplicate by string.

Example

agents/_defaults.yaml
version: "1.0"
type: llm
model: anthropic/claude-sonnet-4-6
temperature: 0
guardrails:
  input:
    - type: prompt_injection
      mode: block
  output:
    - type: system_prompt_leakage
      mode: block
tools:
  - audit.log_event
agents/billing/refund-agent.yaml
version: "1.0"
name: refund-agent
description: "Issues refunds against the billing system."
system_prompt: "Refund only valid charges. Use the tools."
tools:
  - billing.lookup_charge
  - billing.issue_refund
approval:
  tools:
    - billing.issue_refund: param.amount > 50
  timeout: 3600

The effective refund-agent inherits the model, temperature, and both guardrails. Its tools become [audit.log_event, billing.lookup_charge, billing.issue_refund].

Run connic lint to validate the merged configuration. A/B test variants named <base>-test-<name>.yaml inherit the same defaults as their base.

Iterate faster with the dev server

Use connic dev for a cloud dev runner with hot reload. Pair it with tests before shipping.