Skip to main content
An Agent is a logical actor that issues governed calls — a customer support bot, an internal coding assistant, a sub-routine of a larger orchestrator. Every governed call is attributed to exactly one Agent on the dashboard so you can review activity, scope policies, and report on usage.

The default attribution

When you call egisai.init(app="customer-support-bot"), that name becomes the default Agent for the process. Unless overridden, every governed call is attributed to it. Agents are auto-created in your organization on first sight — if no Agent with that name exists, the SDK registers one for you and the dashboard’s Agents page updates live. There is no manual onboarding step.
This produces an Agent visible at Dashboard → Agents named customer-support-bot.

Sub-agents and per-call identity

Real applications often have several distinct flows running inside the same process — a triage agent, a billing agent, a coding agent. There are three ways to pin a sub-agent identity, in order of preference:

1. with egisai.agent("name"): (block-scoped)

Best when you want one block of code attributed to a single agent name and the previous identity restored on exit. Safe to nest.

2. egisai.set_context(agent="…") (handler-scoped)

Best when one handler runs several downstream calls and they should all inherit the same identity. Writes to a ContextVar, so async tasks and threads inherit cleanly without leaking across requests.

3. Auto-detection (no code change)

If you don’t set an identity explicitly, the SDK derives one for each call through a multi-tier resolver (described below). Two calls that share a system prompt and tools resolve to the same Agent row; distinct prompts resolve to distinct Agent rows. The first time the SDK sees a new agent — explicit or auto-detected — it registers it with the platform; subsequent calls are a cache hit. If you’d rather have the Agent row exist on the dashboard before any traffic flows (e.g. at process startup), call egisai.register_agent(name). See the set_context reference for every parameter and Multi-agent context for end-to-end patterns.

Resolution precedence

When attributing a call, the SDK walks a multi-tier resolver and uses the first identity it finds:
  1. Explicit overrideswith egisai.agent(name): or set_context(agent_id=…) / set_context(agent=…).
  2. Server-issued stable IDs — provider-supplied identifiers such as an OpenAI prompt_id, a Gemini cached_content, or a Bedrock managed-agent ID.
  3. Framework signal — when one of the patched agent frameworks (OpenAI Agents, Claude Agent SDK, CrewAI, LangGraph, …) tells us the agent name directly. The declared name is the identity: editing a named agent’s instructions or tools is a revision of the same agent, never a new dashboard row.
  4. Framework bundle hash — a stable hash of the framework’s per-call bundle (canonical system prompt + tool list) when no explicit name is available.
  5. System-prompt fingerprint — for direct provider calls, the SDK hashes the system prompt + tool list so two calls with the same prompt resolve to the same Agent row.
  6. Process-level default — the app= you passed to egisai.init().
Explicit agent() and set_context calls always win over auto-detection — you never lose the ability to override.
Identity is model-invariant. The model id is never part of any identity bundle, and prompt fingerprints are computed over a canonical form of the prompt with model-name tokens masked — so switching models (your choice or Smart Model Routing) keeps the same agent, even when the calling tool embeds the model name in its system prompt. The engines an agent actually runs on are recorded as observed metadata on its Provenance card instead. Incremental prompt edits reconcile to the existing agent automatically; heavy rewrites can be re-stamped explicitly via POST /v1/agents/{agent_id}/identity/restamp.
Only non-reversible digests of the structural data (canonical system prompt, tool list, prompt SimHash) ever leave the process boundary, never the raw prompt itself. identity_source is a controlled-vocabulary token. Neither field can carry PII.

Why the system prompt matters

When two calls share a system prompt, they almost certainly come from the same logical agent. The SDK fingerprints the system prompt of each call and uses that to keep distinct agents distinct on the dashboard, even when the operator hasn’t set an explicit set_context(agent=...) for them. This means:
  • Two helpers in the same process with different system prompts show up as two Agents.
  • Restarting your process keeps the same fingerprints, so historical activity joins up correctly.
You can opt out of fingerprinting on a per-call basis by setting set_context(agent=...) to a friendly name; the explicit value wins.

Multi-tenant attribution

If you serve multiple end-customers from a single deployment, attach the end-customer identity per request using set_context(user_id=..., session_id=..., end_user_id=...). Those fields land on each audit event for the lifetime of the context and do not affect agent attribution.
user_id is typically the operator or session principal. end_user_id is the downstream customer the agent is serving — used by the dashboard’s Agent Identity view to roll up per-end-user behavior. We recommend hashing the raw customer identifier on the SDK side so the unhashed value never leaves your process.

The Access tab

Each agent’s modal includes an Access tab: the live inventory of what the agent can reach — tools, MCP servers and their tools — with per-item category, risk tier, governance status, and usage counters, plus actionable insights (e.g. one-click policy creation for ungoverned or never-used capabilities). It populates automatically from two capture layers; there is nothing to configure:
  • Declared access — capabilities the agent’s configuration grants. For direct provider calls (OpenAI, Anthropic, Gemini, Bedrock) this is the tools array on each request; for the Claude Agent SDK it is mcp_servers plus allowed_tools; for Gateway traffic the gateway inspects the same request payloads. Declared items removed from a later configuration are tombstoned (“no longer declared”) rather than deleted, preserving the audit trail.
  • Observed access — any tool the agent actually invokes that was never declared is added from the audit stream and labeled “observed on live traffic”. Usage is evidence of access, so nothing the agent does stays invisible — and an invocation of a tombstoned item revives it.
Only metadata ships: tool names, parameter names, a schema hash, and PII-sanitized descriptions. Full JSON schemas, parameter values, and MCP connection material (commands, URLs, credentials) never leave the process. For the Claude Agent SDK, allowed_tools is the grant boundary — permission-gated CLI built-ins are not declared (see the Claude Agent SDK page).

Governance assessment

“Ungoverned” is not automatically a finding. The platform resolves, per capability, whether any enabled policy already reaches it — a governed row shows the covering policy names on hover — and then the access judge assesses each ungoverned capability against the agent’s role, the tool’s nature, and its live traffic:
  • Policy recommended — a specific guardrail is warranted now. The insight card carries the exact prefilled policy (type, config, priority, agent-only scope), built server-side from vetted templates — one click creates it. Recommendations prefer the least disruptive shape: a payments agent gets an amount cap on its payment tool, not a block; a database tool gets a dangerous-SQL guard, not a block.
  • Monitoring — no policy needed at this time on current evidence. The judge re-assesses automatically as traffic accumulates (traffic crossing an order of magnitude re-arms the assessment), so a tool that looks benign today gets a fresh verdict after a few days of real usage.
  • No policy needed — reachable by design and consistent with the agent’s role (typically read-only capabilities).
Two invariants hold regardless of the assessment layer: an ungoverned destructive tool is always flagged (the deterministic floor cannot be suppressed), and the LLM never authors policy config — it only selects among deterministic candidates. When no LLM is configured, a conservative deterministic fallback produces the verdicts instead. Recommended-policy counts surface as a badge on the Access tab, on the agent’s row in the Agents table (summed with open anomalies), and in the sidebar’s Agents badge — the operator’s “things to act on” number. A recommendation is a suggestion, not a mandate: each card carries a Dismiss action (“no policy needed”) next to Create policy. Dismissing clears the flag everywhere immediately and the decision sticks — Egis re-flags the capability only if its evidence actually changes (coverage, risk classification, an order-of-magnitude traffic move, or a blocked call appearing), never on the mere passage of time. The row’s governance chip shows Dismissed with the date on hover. The one exception is the destructive floor: recommendations for ungoverned destructive tools cannot be dismissed — the fix is creating the blocking policy or removing the tool from the agent’s toolset.

What’s next

Multi-agent context

Patterns for distinguishing several agents in one process.

set_context reference

Every accepted parameter and what it sets.