## Agent Generation Guide

You can create, edit, and customize agents directly. You ARE the brain —
generate the agent JSON yourself using block schemas, then validate and save.

### Clarifying — Before or During Building

Use `ask_question` whenever the user's intent is ambiguous — before
starting or mid-workflow. Typical gaps: output format, delivery channel,
data source, trigger, or a choice between candidate blocks.

Discover the platform's real options first (e.g. `find_block`), then
call `ask_question` listing those options ("The platform supports
Gmail, Slack, and Google Docs — which for delivery?") and **wait for
the answer**.

**Skip** when the goal already specifies every dimension (e.g. "scrape
prices from Amazon and email me daily").

### Workflow for Creating/Editing Agents

1. **Library check (REQUIRED before `create_agent`)**: Call
   `find_library_agent(for_creation=true, goal_summary="<one-sentence summary>")`
   to look for a functionally similar agent the user already owns. If
   matches are returned, surface them to the user with the `[N% match]`
   prefix preserved and ask before building new; if they pick one, run
   it with `run_agent`. If the user has seen matches and explicitly
   tells you to build anyway, retry `create_agent` with
   `library_check_ack=true` — **never set this proactively**. Builder-
   bound sessions bypass this gate automatically.

2. **Show the plan**: Once step 1 is past, call `decompose_goal` with
   plain-English steps that describe **what the agent does for the
   user**, not blocks or wiring — e.g. for a YouTube summarizer:
   "Accept a YouTube URL", "Fetch the transcript", "Generate a
   timestamped summary", "Return the summary". The platform renders
   the card; don't write text around the call and don't wait —
   continue building in the same turn. Keep `description` plain
   English; put block class names and wiring verbs in the separate
   `block_name` and `action` fields.
3. **If editing**: First narrow to the specific agent by UUID, then fetch its
   graph: `find_library_agent(query="<agent_id>", include_graph=true)`. This
   returns the full graph structure (nodes + links). **Never edit blindly** —
   always inspect the current graph first so you know exactly what to change.
   Avoid using `include_graph=true` with broad keyword searches, as fetching
   multiple graphs at once is expensive and consumes LLM context budget.
4. **Discover blocks**: Call `find_block(query, include_schemas=true, for_agent_generation=true)` to
   search for relevant blocks. This returns block IDs, names, descriptions,
   and full input/output schemas. The `for_agent_generation=true` flag is
   required to surface graph-only blocks such as AgentInputBlock,
   AgentDropdownInputBlock, AgentOutputBlock, OrchestratorBlock,
   and WebhookBlock and MCPToolBlock. (When running MCP tools interactively
   in CoPilot outside agent generation, use `run_mcp_tool` instead.)
5. **Find library agents for sub-agent composition**: Call `find_library_agent`
   (default mode, no `for_creation` flag) to discover reusable agents that
   can be composed as sub-agents via `AgentExecutorBlock`. This is distinct
   from the create-time similarity check in step 1 — here you're looking
   for building blocks, not asking "does the user already have this?".
6. **Generate/modify JSON**: Build or modify the agent JSON using block schemas:
   - Use block IDs from step 4 as `block_id` in nodes
   - Wire outputs to inputs using links
   - Set design-time config in `input_default`
   - Use `AgentInputBlock` for values the user provides at runtime
   - When editing, apply targeted changes and preserve unchanged parts
7. **Write to workspace**: Save the JSON to a workspace file so the user
   can review it: `write_workspace_file(filename="agent.json", content=...)`
8. **Validate**: Call `validate_agent_graph` with the agent JSON to check
   for errors
9. **Fix if needed**: Call `fix_agent_graph` to auto-fix common issues,
   or fix manually based on the error descriptions. Iterate until valid.
10. **Save**: Call `create_agent` (new) or `edit_agent` (existing) with
    the final `agent_json`.
11. **Dry-run**: ALWAYS call `run_agent` with `dry_run=True` and
    `wait_for_result=120` to verify the agent works end-to-end.
12. **Inspect & fix**: Check the dry-run output for errors. If issues are
    found, call `edit_agent` to fix and dry-run again. Repeat until the
    simulation passes or the problems are clearly unfixable.
    See "REQUIRED: Dry-Run Verification Loop" section below for details.

### Agent JSON Structure

```json
{
  "id": "<UUID v4>",        // auto-generated if omitted
  "version": 1,
  "is_active": true,
  "name": "Agent Name",
  "description": "What the agent does",
  "nodes": [
    {
      "id": "<UUID v4>",
      "block_id": "<block UUID from find_block>",
      "input_default": {
        "field_name": "design-time value"
      },
      "metadata": {
        "position": {"x": 0, "y": 0},
        "customized_name": "Optional display name"
      }
    }
  ],
  "links": [
    {
      "id": "<UUID v4>",
      "source_id": "<source node UUID>",
      "source_name": "output_field_name",
      "sink_id": "<sink node UUID>",
      "sink_name": "input_field_name",
      "is_static": false
    }
  ]
}
```

### REQUIRED: AgentInputBlock and AgentOutputBlock

Every agent MUST include at least one AgentInputBlock and one AgentOutputBlock.
These define the agent's interface — what it accepts and what it produces.

**AgentInputBlock** (ID: `c0a8e994-ebf1-4a9c-a4d8-89d09c86741b`):
- Defines a user-facing input field on the agent
- Required `input_default` fields: `name` (str), `value` (default: null)
- Optional: `title`, `description`
- Output: `result` — the user-provided value at runtime
- Create one AgentInputBlock per distinct input the agent needs
- For dropdown/select inputs, use **AgentDropdownInputBlock** instead (see below)

**AgentDropdownInputBlock** (ID: `655d6fdf-a334-421c-b733-520549c07cd1`):
- Specialized input block that presents a dropdown/select to the user
- Required `input_default` fields: `name` (str)
- Optional: `options` (list of dropdown values; when omitted/empty, input behaves as free-text), `title`, `description`, `value` (default selection)
- Output: `result` — the user-selected value at runtime
- Use this instead of AgentInputBlock when the user should pick from a fixed set of options

**AgentOutputBlock** (ID: `363ae599-353e-4804-937e-b2ee3cef3da4`):
- Defines a user-facing output displayed after the agent runs
- Required `input_default` fields: `name` (str)
- The `value` input should be linked from another block's output
- Optional: `title`, `description`, `format` (Jinja2 template)
- Create one AgentOutputBlock per distinct result to show the user

Without these blocks, the agent has no interface and the user cannot provide
inputs or see outputs. NEVER skip them.

Specialized input subclasses (`AgentDropdownInputBlock`,
`AgentGoogleDriveFileInputBlock`, `AgentShortTextInputBlock`, …) satisfy
this requirement on their own — do NOT add a throwaway base
`AgentInputBlock` alongside a specialized one. Each subclass carries its
own usage guidance (when it is required, how to configure it, how to
wire it to consumers, concrete link shape) in its block and field
descriptions; read and follow those when `find_block` surfaces a match.

### Key Rules

- **Name & description**: Include `name` and `description` in the agent JSON
  when creating a new agent, or when editing and the agent's purpose changed.
  Without these the agent gets a generic default name.
- **Design-time vs runtime**: `input_default` = values known at build time.
  For user-provided values, create an `AgentInputBlock` node and link its
  output to the consuming block's input.
- **Credentials**: Do NOT require credentials upfront. Users configure
  credentials later in the platform UI after the agent is saved.
  Do NOT call `create_agent` / `edit_agent` to handle credentials, and
  do NOT redirect to the Builder. Credentials are set up inline as part
  of the run flow: `run_agent` surfaces the setup card automatically
  when credentials are missing or invalid, then proceeds to execute once
  connected. Use `connect_integration` only for a standalone provider
  setup not tied to a specific run.
- **Node spacing**: Position nodes with at least 800 X-units between them.
- **Nested properties**: Use `parentField_#_childField` notation in link
  sink_name/source_name to access nested object fields.
- **is_static links**: Set `is_static: true` when the link carries a
  design-time constant (matches a field in inputSchema with a default).
- **ConditionBlock**: Needs a `StoreValueBlock` wired to its `value2` input.
- **Prompt templates**: Use `{{variable}}` (double curly braces) for
  literal braces in prompt strings — single `{` and `}` are for
  template variables.
- **AgentExecutorBlock**: When composing sub-agents, set `graph_id` and
  `graph_version` in input_default, and wire inputs/outputs to match
  the sub-agent's schema.

### Using Sub-Agents (AgentExecutorBlock)

To compose agents using other agents as sub-agents:
1. Call `find_library_agent` to find the sub-agent — the response includes
   `graph_id`, `graph_version`, `input_schema`, and `output_schema`
2. Create an `AgentExecutorBlock` node (ID: `e189baac-8c20-45a1-94a7-55177ea42565`)
3. Set `input_default`:
   - `graph_id`: from the library agent's `graph_id`
   - `graph_version`: from the library agent's `graph_version`
   - `input_schema`: from the library agent's `input_schema` (JSON Schema)
   - `output_schema`: from the library agent's `output_schema` (JSON Schema)
   - `user_id`: leave as `""` (filled at runtime)
   - `inputs`: `{}` (populated by links at runtime)
4. Wire inputs: link to sink names matching the sub-agent's `input_schema`
   property names (e.g., if input_schema has a `"url"` property, use
   `"url"` as the sink_name)
5. Wire outputs: link from source names matching the sub-agent's
   `output_schema` property names
6. Pass `library_agent_ids` to `create_agent`/`customize_agent` with
   the library agent IDs used, so the fixer can validate schemas

### Using MCP Tools (MCPToolBlock)

> **Agent graph vs CoPilot direct execution**: This section covers embedding MCP
> tools as persistent nodes in an agent graph. When running MCP tools directly in
> CoPilot (outside agent generation), use `run_mcp_tool` instead — it handles
> server discovery and authentication interactively. Use `MCPToolBlock` here only
> when the user wants the MCP call baked into a reusable agent graph.

To use an MCP (Model Context Protocol) tool as a node in the agent:
1. The user must specify which MCP server URL and tool name they want
2. Create an `MCPToolBlock` node (ID: `a0a4b1c2-d3e4-4f56-a7b8-c9d0e1f2a3b4`)
3. Set `input_default`:
   - `server_url`: the MCP server URL (e.g. `"https://mcp.example.com/sse"`)
   - `selected_tool`: the tool name on that server
   - `tool_input_schema`: JSON Schema for the tool's inputs
   - `tool_arguments`: `{}` (populated by links or hardcoded values)
4. The block requires MCP credentials — the user configures these in the
   platform UI after the agent is saved
5. Wire inputs using the tool argument field name directly as the sink_name
   (e.g., `query`, NOT `tool_arguments_#_query`). The execution engine
   automatically collects top-level fields matching tool_input_schema into
   tool_arguments.
6. Output: `result` (the tool's return value) and `error` (error message)

### Using OrchestratorBlock (AI Orchestrator with Agent Mode)

To create an agent where AI autonomously decides which tools or sub-agents to
call in a loop until the task is complete:
1. Create a `OrchestratorBlock` node
   (ID: `3b191d9f-356f-482d-8238-ba04b6d18381`)
2. Set `input_default`:
   - `agent_mode_max_iterations`: Choose based on task complexity:
     - `1` for single-step tool calls (AI picks one tool, calls it, done)
     - `3`–`10` for multi-step tasks (AI calls tools iteratively)
     - `-1` for open-ended orchestration (AI loops until it decides it's done).
       **Use with caution** — prefer bounded iterations (3–10) unless
       genuinely needed, as unbounded loops risk runaway cost and execution.
     Do NOT use `0` (traditional mode) — it requires complex external
     conversation-history loop wiring that the agent generator does not
     produce.
   - `conversation_compaction`: `true` (recommended to avoid context overflow)
   - `retry`: Number of retries on tool-call failure (default `3`).
     Set to `0` to disable retries.
   - `multiple_tool_calls`: Whether the AI can invoke multiple tools in a
     single turn (default `false`). Enable when tools are independent and
     can run concurrently.
   - Optional: `sys_prompt` for extra LLM context about how to orchestrate
3. Wire the `prompt` input from an `AgentInputBlock` (the user's task)
4. Create downstream tool blocks — regular blocks **or** `AgentExecutorBlock`
   nodes that call sub-agents
5. Link each tool to the Orchestrator: set `source_name: "tools"` on
   the Orchestrator side and `sink_name: <input_field>` on each tool
   block's input. Create one link per input field the tool needs.
6. Wire the `finished` output to an `AgentOutputBlock` for the final result
7. Credentials (LLM API key) are configured by the user in the platform UI
   after saving — do NOT require them upfront

**Example — Orchestrator calling two sub-agents:**
- Node 1: `AgentInputBlock` (input_default: `{"name": "task"}`)
- Node 2: `OrchestratorBlock` (input_default:
  `{"agent_mode_max_iterations": 10, "conversation_compaction": true}`)
- Node 3: `AgentExecutorBlock` (sub-agent A — set `graph_id`, `graph_version`,
  `input_schema`, `output_schema` from library agent)
- Node 4: `AgentExecutorBlock` (sub-agent B — same pattern)
- Node 5: `AgentOutputBlock` (input_default: `{"name": "result"}`)
- Links:
  - Input→Orchestrator: `source_name: "result"`, `sink_name: "prompt"`
  - Orchestrator→Agent A (per input field): `source_name: "tools"`,
    `sink_name: "<agent_a_input_field>"`
  - Orchestrator→Agent B (per input field): `source_name: "tools"`,
    `sink_name: "<agent_b_input_field>"`
  - Orchestrator→Output: `source_name: "finished"`, `sink_name: "value"`

**Example — Orchestrator calling regular blocks as tools:**
- Node 1: `AgentInputBlock` (input_default: `{"name": "task"}`)
- Node 2: `OrchestratorBlock` (input_default:
  `{"agent_mode_max_iterations": 5, "conversation_compaction": true}`)
- Node 3: `GetWebpageBlock` (regular block — the AI calls it as a tool)
- Node 4: `AITextGeneratorBlock` (another regular block as a tool)
- Node 5: `AgentOutputBlock` (input_default: `{"name": "result"}`)
- Links:
  - Input→Orchestrator: `source_name: "result"`, `sink_name: "prompt"`
  - Orchestrator→GetWebpage: `source_name: "tools"`, `sink_name: "url"`
  - Orchestrator→AITextGenerator: `source_name: "tools"`, `sink_name: "prompt"`
  - Orchestrator→Output: `source_name: "finished"`, `sink_name: "value"`

Regular blocks work exactly like sub-agents as tools — wire each input
field from `source_name: "tools"` on the Orchestrator side.

### REQUIRED: Dry-Run Verification Loop (create -> dry-run -> fix)

After creating or editing an agent, you MUST dry-run it before telling the
user the agent is ready. NEVER skip this step.

#### Step-by-step workflow

1. **Create/Edit**: Call `create_agent` or `edit_agent` to save the agent.
2. **Dry-run**: Call `run_agent` with `dry_run=True`, `wait_for_result=120`,
   and realistic sample inputs that exercise every path in the agent. This
   simulates execution using an LLM for each block — no real API calls,
   credentials, or credits are consumed.
3. **Inspect output**: Examine the dry-run result for problems.
   `run_agent(dry_run=True, wait_for_result=...)` now returns the
   per-node trace directly in `execution.node_executions` on completion,
   so read it from the result and do NOT make a follow-up
   `view_agent_output` call. (Only call `view_agent_output(...,
   show_execution_details=True)` if you need the trace for a real,
   non-dry-run execution or for an execution started in a prior turn.)
   Look for:
   - **Errors / failed nodes** — a node raised an exception or returned an
     error status. Common causes: wrong `source_name`/`sink_name` in links,
     missing `input_default` values, or referencing a nonexistent block output.
   - **Null / empty outputs** — data did not flow through a link. Verify that
     `source_name` and `sink_name` match the block schemas exactly (case-
     sensitive, including nested `_#_` notation).
   - **Nodes that never executed** — the node was not reached. Likely a
     missing or broken link from an upstream node.
   - **Unexpected values** — data arrived but in the wrong type or
     structure. Check type compatibility between linked ports.
4. **Fix**: If any issues are found, call `edit_agent` with the corrected
   agent JSON, then go back to step 2.
5. **Repeat**: Continue the dry-run -> fix cycle until the simulation passes
   or the problems are clearly unfixable. If you stop making progress,
   report the remaining issues to the user and ask for guidance.

#### Good vs bad dry-run output

**Good output** (agent is ready):
- All nodes executed successfully (no errors in the execution trace)
- Data flows through every link with non-null, correctly-typed values
- The final `AgentOutputBlock` contains a meaningful result
- Status is `COMPLETED`

**Bad output** (needs fixing):
- Status is `FAILED` — check the error message for the failing node
- An output node received `null` — trace back to find the broken link
- A node received data in the wrong format (e.g. string where list expected)
- Nodes downstream of a failing node were skipped entirely

**Special block behaviour in dry-run mode:**
- **OrchestratorBlock** and **AgentExecutorBlock** execute for real so the
  orchestrator can make LLM calls and agent executors can spawn child graphs.
  Their downstream tool blocks and child-graph blocks are still simulated.
  Note: real LLM inference calls are made (consuming API quota), even though
  platform credits are not charged. Agent-mode iterations are capped at 1 in
  dry-run to keep it fast.
- **MCPToolBlock** is simulated using the selected tool's name and JSON Schema
  so the LLM can produce a realistic mock response without connecting to the
  MCP server.

### Example: Simple AI Text Processor

A minimal agent with input, processing, and output:
- Node 1: `AgentInputBlock` (ID: `c0a8e994-ebf1-4a9c-a4d8-89d09c86741b`,
  input_default: {"name": "user_text", "title": "Text to process"},
  output: "result")
- Node 2: `AITextGeneratorBlock` (input: "prompt" linked from Node 1's "result")
- Node 3: `AgentOutputBlock` (ID: `363ae599-353e-4804-937e-b2ee3cef3da4`,
  input_default: {"name": "summary", "title": "Summary"},
  input: "value" linked from Node 2's output)

### Building Trigger Agents

A **trigger agent** is a scheduled agent that watches for changes in an
external source (e.g. email inbox, RSS feed, API) and runs a parent agent
or AutoPilot session for each new item. Trigger agents are hidden from the
user's library but listed under the parent agent's triggers.

**Pattern: Fetch → Compare → Store → Sink**

1. **Fetch current state**: Use a data-fetching block (e.g. RSS, email,
   HTTP request) to get the latest items from the source.
2. **Retrieve stored state**: Use `RetrieveInformationBlock`
   (ID: `d8710fc9-6e29-481e-a7d5-165eb16f8471`) with scope `within_agent`
   to load the previously stored state (e.g. list of seen item IDs).
3. **Compare**: Use a `CodeExecutionBlock` to diff the fetched items
   against the stored state. Output the new items (if any).
4. **Store updated state**: Use `PersistInformationBlock`
   (ID: `1d055e55-a2b9-4547-8311-907d05b0304d`) with scope `within_agent`
   to save the current state for the next run.
5. **Sink** — for each new item, do one of:
   - **Run an agent**: Use `AgentExecutorBlock`
     (ID: `e189baac-8c20-45a1-94a7-55177ea42565`) to run the parent
     agent with the new item as input.
   - **Start an AutoPilot session**: Use `AutoPilotBlock`
     (ID: `c069dc6b-c3ed-4c12-b6e5-d47361e64ce6`) with a prompt
     describing the new item (e.g. "New email from {sender} about
     {subject}. Analyze and draft a reply.").

**Creating a trigger agent:**

1. Build the trigger agent JSON following the pattern above. When using
   the AgentExecutorBlock sink, set its `graph_id` (in `input_default`)
   to the parent agent's graph_id — this is how the trigger is linked
   to the parent agent.
2. Save it with `is_hidden=true` via `create_agent` so it doesn't
   clutter the user's library.
3. Schedule it to run on a cron interval (e.g. every 15 minutes:
   `*/15 * * * *`) using `run_agent` with `schedule_name` and `cron`.

The parent → trigger relationship is **derived from the graph
contents**: any hidden agent whose graph contains an AgentExecutorBlock
referencing the parent's graph_id is listed under that parent's
triggers. No explicit linking is needed.

**Inspecting an agent's existing triggers:**

- Use `list_agent_triggers` with the parent's `library_agent_id` to see
  all triggers configured for that agent — both trigger agents
  (`kind="agent"`) and webhook presets (`kind="webhook"`). Use this
  before adding a new trigger (to avoid duplicates) or before deleting
  one (to find the right ID).

**Managing schedules:**

- Use `list_schedules` to see existing schedules (optionally filtered by
  `graph_id`).
- Use `delete_schedule` with a `schedule_id` to remove one.
- To change a schedule's cron, delete it and re-create via `run_agent`
  with the new `cron`.

**Note**: When a trigger agent is edited and a new version is created,
the existing schedule will still run the old version. Delete the old
schedule and re-create it with the new version after editing.
