Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Effectful-Tech/clanka/llms.txt

Use this file to discover all available pages before exploring further.

The Agent.send() method returns a Stream<Output, AgentFinished | AiError>. Each element of the stream is a tagged class that describes one moment in the agent’s execution — from startup through script runs, reasoning traces, sub-agent delegation, and token usage reporting.

Output union

export type Output =
  | AgentStart
  | ContentPart
  | SubagentStart
  | SubagentComplete
  | SubagentPart

export type ContentPart =
  | ReasoningStart
  | ReasoningDelta
  | ReasoningEnd
  | ScriptStart
  | ScriptDelta
  | ScriptEnd
  | ScriptOutput
  | Usage
  | ErrorRetry
Output is the top-level discriminated union. Every event has a _tag string discriminant matching the class name.

Agent lifecycle events

AgentStart

Emitted once at the beginning of each agent run, before any model output is produced.
export class AgentStart extends Schema.TaggedClass<AgentStart>()("AgentStart", {
  id: Schema.Number,
  prompt: Prompt.Prompt,
  provider: Schema.String,
  model: Schema.String,
}) {}
id
number
required
Monotonically increasing identifier for this agent invocation. Sub-agents receive their own unique id.
prompt
Prompt.Prompt
required
The full structured prompt sent to the model for this turn.
provider
string
required
The model provider name (e.g. "anthropic", "openai"), sourced from Model.ProviderName in context.
model
string
required
The model identifier (e.g. "claude-opus-4-5"), sourced from Model.ModelName in context.

AgentFinished

A tagged error class — the stream fails with this value when the agent completes. It is not emitted as a regular stream element; catch it with Stream.catchTag("AgentFinished", ...) or Effect.catchTag("AgentFinished", ...).
export class AgentFinished extends Schema.TaggedErrorClass<AgentFinished>()(
  "AgentFinished",
  {
    summary: Schema.String,
  },
) {}
summary
string
required
The final summary text produced by the agent when it called taskComplete. Empty string when the agent is in conversation mode.
AgentFinished is a normal, expected termination signal — not an unhandled failure. Always handle it explicitly to retrieve the agent’s summary.

Reasoning events

These three events bracket a block of extended thinking / chain-of-thought output. They arrive in order: ReasoningStart → one or more ReasoningDeltaReasoningEnd.

ReasoningStart

Signals that the model has begun a reasoning block.
export class ReasoningStart extends Schema.TaggedClass<ReasoningStart>()(
  "ReasoningStart",
  {},
) {}

ReasoningDelta

A chunk of reasoning text.
export class ReasoningDelta extends Schema.TaggedClass<ReasoningDelta>()(
  "ReasoningDelta",
  {
    delta: Schema.String,
  },
) {}
delta
string
required
Incremental reasoning text. Concatenate all ReasoningDelta.delta values between a ReasoningStart / ReasoningEnd pair to reconstruct the full reasoning block.

ReasoningEnd

Signals that the current reasoning block is complete.
export class ReasoningEnd extends Schema.TaggedClass<ReasoningEnd>()(
  "ReasoningEnd",
  {},
) {}

Script execution events

The agent writes and executes JavaScript scripts through the execute tool. These events track the full lifecycle of each script.

ScriptStart

Emitted when the model begins writing a script to the execute tool.
export class ScriptStart extends Schema.TaggedClass<ScriptStart>()(
  "ScriptStart",
  {},
) {}

ScriptDelta

A chunk of script content as the model streams it.
export class ScriptDelta extends Schema.TaggedClass<ScriptDelta>()(
  "ScriptDelta",
  {
    delta: Schema.String,
  },
) {}
delta
string
required
Incremental script text. Concatenate all ScriptDelta.delta values between ScriptStart and ScriptEnd to reconstruct the full script source.

ScriptEnd

Emitted when the complete script has been received and submitted to the executor sandbox.
export class ScriptEnd extends Schema.TaggedClass<ScriptEnd>()(
  "ScriptEnd",
  {},
) {}

ScriptOutput

The result of running the script — all console output produced by the sandbox.
export class ScriptOutput extends Schema.TaggedClass<ScriptOutput>()(
  "ScriptOutput",
  {
    output: Schema.String,
  },
) {}
output
string
required
The full console output string from the script execution. This is what the model sees as the tool result and uses to decide next steps.

Sub-agent events

When a script calls a sub-agent, three events are emitted to track that nested invocation.

SubagentStart

Emitted when a sub-agent is about to start executing.
export class SubagentStart extends Schema.TaggedClass<SubagentStart>()(
  "SubagentStart",
  {
    id: Schema.Number,
    prompt: Schema.String,
    model: Schema.String,
    provider: Schema.String,
  },
) {}
id
number
required
Unique identifier for this sub-agent invocation. Correlates SubagentStart, SubagentPart, and SubagentComplete events.
prompt
string
required
The plain-text prompt passed to the sub-agent.
model
string
required
The model identifier the sub-agent is using.
provider
string
required
The model provider the sub-agent is using.

SubagentPart

Wraps an output event emitted by the sub-agent, tagged with the sub-agent’s id.
export class SubagentPart extends Schema.TaggedClass<SubagentPart>()(
  "SubagentPart",
  {
    id: Schema.Number,
    part: ContentPart,
  },
) {}
id
number
required
The sub-agent id from the corresponding SubagentStart.
part
ContentPart
required
A nested output event from the sub-agent’s own stream. Can be any ContentPart variant (ReasoningDelta, ScriptOutput, etc.).

SubagentComplete

Emitted when the sub-agent’s stream has finished.
export class SubagentComplete extends Schema.TaggedClass<SubagentComplete>()(
  "SubagentComplete",
  {
    id: Schema.Number,
    summary: Schema.String,
  },
) {}
id
number
required
The sub-agent id from the corresponding SubagentStart.
summary
string
required
The final summary from the sub-agent’s AgentFinished error.

Token usage

Usage

Emitted once per model response, after the finish part arrives from the streaming API.
export class Usage extends Schema.TaggedClass<Usage>()("Usage", {
  contextTokens: Schema.Number,
  inputTokens: Schema.Number,
  outputTokens: Schema.Number,
}) {}
contextTokens
number
required
The number of input tokens for the current request (i.e. the context window used this turn).
inputTokens
number
required
Cumulative input tokens consumed across all turns in this agent session.
outputTokens
number
required
Cumulative output tokens produced across all turns in this agent session.

Error events

ErrorRetry

Emitted when the agent encounters a retryable error and is about to retry the current turn. The stream continues — this is an informational event, not a failure.
export class ErrorRetry extends Schema.TaggedClass<ErrorRetry>()("ErrorRetry", {
  error: AiError.AiError,
}) {}
error
AiError.AiError
required
The retryable error that triggered the retry. Common causes include rate-limit responses (AiError.isRetryable === true) and turn timeout (TurnTimeout expiry, which generates an UnknownError with description "TurnTimeout was reached").
ErrorRetry does not terminate the stream. The agent automatically backs off and retries using an exponential schedule. To abort on error, race the stream against a timeout or interrupt the fiber.

Consuming the stream

Pattern matching on events

import { Agent, AgentOutput } from "clanka"
import { Effect, Stream } from "effect"

const program = Effect.gen(function* () {
  const agent = yield* Agent.Agent

  const stream = yield* agent.send({
    prompt: "Summarize the README.",
  })

  yield* stream.pipe(
    Stream.runForEach((event) =>
      Effect.sync(() => {
        switch (event._tag) {
          case "AgentStart":
            console.log(`[${event.provider}/${event.model}] Agent started`)
            break
          case "ReasoningStart":
            process.stdout.write("<thinking>")
            break
          case "ReasoningDelta":
            process.stdout.write(event.delta)
            break
          case "ReasoningEnd":
            process.stdout.write("</thinking>\n")
            break
          case "ScriptStart":
            process.stdout.write("```javascript\n")
            break
          case "ScriptDelta":
            process.stdout.write(event.delta)
            break
          case "ScriptEnd":
            process.stdout.write("\n```\n")
            break
          case "ScriptOutput":
            console.log("Output:", event.output)
            break
          case "SubagentStart":
            console.log(`Sub-agent #${event.id} started: ${event.prompt}`)
            break
          case "SubagentPart":
            // Nested event — recurse or handle selectively
            break
          case "SubagentComplete":
            console.log(`Sub-agent #${event.id} done: ${event.summary}`)
            break
          case "Usage":
            console.log(`Tokens — in: ${event.inputTokens}, out: ${event.outputTokens}`)
            break
          case "ErrorRetry":
            console.warn("Retrying after error:", event.error.message)
            break
        }
      })
    ),
    Effect.catchTag("AgentFinished", (finished) =>
      Effect.sync(() => console.log("Summary:", finished.summary))
    )
  )
})

Collecting reasoning text

import { Stream, Effect } from "effect"

const collectReasoning = (
  stream: Stream.Stream<AgentOutput.Output, AgentOutput.AgentFinished>
) =>
  stream.pipe(
    Stream.filterMap((event) =>
      event._tag === "ReasoningDelta"
        ? { _tag: "Some" as const, value: event.delta }
        : { _tag: "None" as const }
    ),
    Stream.mkString,
  )

Separating top-level and sub-agent events

import { Stream } from "effect"
import type { Output, SubagentPart } from "clanka/AgentOutput"

const topLevelOnly = (stream: Stream.Stream<Output>) =>
  stream.pipe(
    Stream.filter((event): event is Exclude<Output, SubagentPart> =>
      event._tag !== "SubagentPart"
    )
  )

Build docs developers (and LLMs) love