Skip to content

DeepAgentExecutor runs in-process agents via LangGraph's createReactAgent. This is the default runtime for all agents defined in workspace/agents/*.yaml.

Type string: deep-agentPackage: @langchain/langgraph + @langchain/openaiRegistered by: AgentRuntimePlugin — one executor per agent YAML file at install() time.

How it works

  1. AgentRuntimePlugin scans workspace/agents/ on startup and creates one DeepAgentExecutor per YAML file
  2. Each executor is registered in ExecutorRegistry for the skills listed in the agent's YAML
  3. When SkillDispatcherPlugin routes a SkillRequest to this executor, it:
    • Creates a LangGraph ReAct agent with ChatOpenAI pointed at the LiteLLM gateway
    • Resolves the system prompt: if the matched skill has systemPromptOverride, uses that; otherwise uses the agent's systemPrompt
    • Replays recent conversation history when per-agent memory is enabled (this.memory.history(...)), so the agent sees the conversation rather than only the latest message
    • Provides LangChain tools matching the tools whitelist from the agent YAML
    • Runs the agent loop with recursionLimit derived from maxTurns
    • Returns the final AI message as SkillResult.text

Agent YAML definition

yaml
# workspace/agents/ava.yaml
name: ava
role: general
model: claude-opus-4-6

systemPrompt: |
  You are Ava, the chief-of-staff protoAgent...

tools:
  # Orchestration
  - chat_with_agent
  - delegate_task
  - publish_event
  - manage_cron
  - run_ceremony
  - list_agents
  # Observation
  - get_projects
  - get_ci_health
  - get_pr_pipeline
  - get_branch_drift
  - get_incidents
  - get_ceremonies
  - searxng_search
  # Write / Act
  - create_github_issue
  - report_incident
  - pr_inspector
  # Conversation
  - react
  - send_update

maxTurns: 25

discordBotTokenEnvKey: DISCORD_BOT_TOKEN_AVA

skills:
  - name: chat
    description: Operational helm — the user's single control interface.
    keywords: []

  - name: debug_ci_failures
    description: Investigate CI failures, delegate to Quinn, file issues.
    keywords: [ci, failure, build, pipeline]

Skill-level systemPromptOverride

When a skill declares systemPromptOverride, the executor uses it instead of the agent's main systemPrompt for that specific invocation. This allows structured-output skills (like diagnose_pr_stuck) to use narrow, format-enforcing prompts while operational skills use the full conversational prompt.

See Agent Skills Reference for the full YAML schema and available tools.

Streaming & live tool narration

The executor streams the LangGraph run rather than calling invoke(). It iterates agent.stream({ messages }, { streamMode: "values" }), which yields the full accumulated state after each node; the final yield is exactly what invoke() would have returned, so all downstream extraction (final text, memory, structured output) is unchanged.

Streaming exists so progress reaches the caller live — the moment each turn streams in — instead of being replayed in a tight loop after the whole run settles. The executor fires three hooks during the run, all wired by AgentRuntimePlugin onto the bus:

HookWhenBus topicPayload
onProgressAn initial "thinking" frame, emitted before the first LLM turn (which can take 15–20s) so the stream is not byte-silentagent.skill.progress.{correlationId}Humanized progress text
onToolCallEach tool-call turn as it streams in, before its tools executeagent.skill.progress.{correlationId}Humanized tool-call narration (toolNames, toolCalls)
onToolFrameA structured tool-call-v1 lifecycle frame (startedcompleted/failed) per tool call as the graph streamsagent.skill.toolframe.{correlationId}Structured ToolCallArtifactData frame

The progress topics carry humanized narration for plain clients; the toolframe topic carries structured frames that the a2a-server emits as streamed artifact-update DataParts for rich clients. All three hooks are best-effort — a throwing callback is logged and never aborts the run.

Available tools

Tools are defined as LangChain tools with zod schemas in DeepAgentExecutor. Each wraps an HTTP call to workstacean's own API. Agents only get the tools listed in their tools: array — unlisted tools are not available.

The tables below are a representative selection. The canonical, complete tool list is the set of name: entries in src/executor/executors/deep-agent-executor.ts.

Orchestration

ToolAPI endpointPurpose
chat_with_agentPOST /api/a2a/chatMulti-turn A2A conversation with another agent
delegate_taskPOST /api/a2a/delegateFire-and-forget dispatch to an agent
publish_eventPOST /publishInject a raw bus event
manage_cronPOST /api/ceremonies/*CRUD scheduled ceremonies
run_ceremonyPOST /api/ceremonies/:id/runManually trigger a ceremony

Observation

ToolAPI endpointPurpose
get_projectsGET /api/projectsList registered projects
get_ci_healthGET /api/ci-healthCI pass rates across repos
get_pr_pipelineGET /api/pr-pipelineOpen PRs: total, conflicts, stale, failing CI
get_branch_driftGET /api/branch-driftDev vs main divergence per project
get_incidentsGET /api/incidentsOpen security/operational incidents
get_ceremoniesGET /api/ceremoniesList ceremony definitions
searxng_searchSearXNG /searchQuick web search (5 results)

Write / Act

ToolAPI endpointPurpose
create_github_issuePOST /api/github/issuesFile GitHub issues on managed repos
report_incidentPOST /api/incidentsFile a security/operational incident

Conversation feedback

ToolAPI endpointPurpose
reactPOST /api/discord/reactAdd emoji reaction to triggering message
send_updatePOST /api/discord/progressSend progress update during long work

Discord operations (protoBot agent)

ToolAPI endpointPurpose
discord_server_statsGET /api/discord/server-statsServer stats: members, channels, roles
discord_list_channelsGET /api/discord/channelsList all channels
discord_create_channelPOST /api/discord/channels/createCreate a channel
discord_sendPOST /api/discord/sendSend a message to a channel
discord_list_membersGET /api/discord/membersList server members

LLM gateway

All LLM calls route through LiteLLM at LLM_GATEWAY_URL (or OPENAI_BASE_URL). The executor creates a ChatOpenAI instance with the gateway as baseURL and OPENAI_API_KEY for auth. Model aliases (e.g. protolabs/reasoning, claude-sonnet-4-6) are resolved by the gateway.

Observability

correlationId from the bus message is propagated through the LangGraph invocation. When LANGFUSE_* env vars are set, the LangChain callback handler traces every LLM call and tool invocation to Langfuse.

When to use

Use DeepAgentExecutor for any agent that should run inside the workstacean process with direct access to bus tools. This is the right choice for most agents.

Use A2A instead when the agent lives in a separate service (protopen, protoContent) or needs its own resource isolation.

protoWorkstacean — a switchboard, not an agent.