* feat(telemetry): report per-run stall signals Add task.run_health (one per agent run, every exit path) and task.run_idle (at most once per run, after 60s with no runtime event) so harness stalls can be measured from telemetry instead of transcripts. run_health carries the longest gap between runtime events and what preceded it, finish reason, final message shape and a text signature of a final text-only turn. session.input_sent gains agentBusy, msSinceTurnEnd and a bumpKind label (probe/nudge/greeting) so the user's reaction to a run can be paired with it; task.cancelled gains msSinceLastEvent. No message text is sent. * refactor(telemetry): move run stall signals into a core observer Stall diagnostics now come from a core RunHealthObserver that watches runtime events, instead of living in the agent loop. Its fields are added to agent.run-finished / agent.run-failed through a runEndTelemetryProperties hook, replacing task.run_health and the task.cancelled additions. Also fixes measurement gaps: tool-argument streaming now emits a tool-call-delta progress event, the silence before a run ends is counted, and a turn rejected before reaching history is labelled empty. * fix(telemetry): tighten run stall signals Clear finishReason per turn, skip textSignature for media-only replies, keep stall fields off replayed queued prompts, and document the run health observer. * fix(telemetry): identify the run on its run-end stall fields agent.run-finished / agent.run-failed carry no session, model or provider of their own, so the stall fields could not be grouped by model or provider, paired with the user's next message (session.input_sent), or filtered to root agents. RunHealthObserver now adds sessionId, isSubagent, providerId and modelId to the run-end properties; undefined values are omitted. * fix(telemetry): keep stall labels on prompts sent during a queued run A queued prompt replayed by the drain starts its run unlabelled, but the session-wide drain flag also stripped the stall fields from new prompts the user sent while that queued run was busy. Only the replay itself (the input that starts the run) is unlabelled now. Tool-argument chunks now report progress at most once a second: each event copies the whole conversation, and a large file write streams thousands of chunks. * fix(telemetry): mark only the replayed queued prompt as a replay The queue drain now marks the one input it replays, and runTurn consumes that marker, instead of inferring a replay from the session-wide drain flag. Fresh user input during a queued run keeps its stall fields whether the run is busy or just finishing. --------- Co-authored-by: Max Paulus 🥪 <max@cline.bot>
29 KiB
Plugin slash commands
Use core.pluginCommands on an existing ClineCore (local or hub-backed), or
client.pluginCommands on an existing HubSessionClient. Hosts with a
NodeHubClient can use createHubPluginCommandsApi(client) from @cline/core.
These APIs reuse the runtime and connection; clients do not load plugins or own
a separate command sandbox. Pass the active sessionId so a command runs in
that session's plugin instance and retains the state and context shared with
its hooks.
If a connection closes after a command is dispatched, execution rejects without automatically resending it: the command may already have changed external state.
const target = { workspacePath: workspaceRoot, sessionId };
const catalog = await core.pluginCommands.list(target);
const result = await core.pluginCommands.run({ ...target, prompt: "/upload-history" });
// Display result?.reply; submit only result?.submitPrompt to the agent.
// undefined means no registered command handled the input.
Omit sessionId, or pass one the runtime does not have, to use the workspace
catalog. Every call checks the enabled plugins and their sources and reloads the
catalog when they change, so call list again whenever the command menu needs to be
current. A failed load lists healthy commands with status: "error" and is
retried after 30 seconds. Workspace catalogs idle for 10 minutes release their
plugin workers.
For a resident session, listing and execution use its initialized contribution registry and existing plugin sandbox. Workspace file changes apply to new sessions, not an active session's commands. Built-in command precedence and rendering remain host responsibilities. Preserve the original arguments when dispatching.
Model request retries and Langfuse
AI SDK text requests allow three retries after the initial request (four total attempts) for retryable request-start failures. Provider errors received after streaming starts have a separate budget of three stream retries. Exhausting either budget does not trigger another whole-turn retry.
When Langfuse tracing is enabled, each failed request-start or stream attempt records its error on its model-call span, including attempts followed by a successful retry. Request-start failures close their attempt spans before retry backoff begins. A recovered request keeps a successful overall trace; exhausted retries mark the overall operation as failed. Span export follows the configured telemetry processor's flushing policy.
Caller cancellation closes model-call spans without recording an exception or marking a provider failure, including cancellation before the response opens. Timeout cancellations remain failures.
Oversized tool result recovery
Cached text excludes native image data. Cache admission uses the persisted JSON/string model-preview size for the truncation threshold; YAML size controls only cache capacity. Plain strings stay unchanged; structured cached text is serialized as YAML, preserving multiline payloads as literal blocks without automatic wrapping. Original history and tool events keep their existing format. Recovery uses the existing read_files output and per-line limits; disabling that tool does not disable caching or remove recovery notices.
Tools created with createTool may set resultPolicy: "cache-oversized". Core enables this for MCP and Composio tools. Original output remains in history and events; synchronous model preparation sends a bounded preview with a cline://cache/<encoded-session-id>/<result-id>.result.txt URI for cached oversized responses. Use read_files with start_line/end_line to read omitted content. Shell and filesystem search tools do not support these URIs. The stateless agent runtime does not own a cache.
Entries expire after five further model iterations without a cache read, across follow-up turns. Explicit reads refresh expiry; model requests do not. A 16 MiB UTF-8 text limit per session evicts least recently read entries; individually larger results have no recovery URI. Shutdown, history reset, and restore clear the cache, and resume does not regenerate entries. Missing reads instruct the agent to refetch with an appropriate read/query tool without repeating side-effecting actions. Evicting cached text does not remove original conversation output or change earlier recovery notices; URI references remain until the cache is cleared. Cache-miss feedback appears only when an agent attempts to read missing content.
Shared agent review UI
@cline/ui exports presentation-only components for showing a session's changed
files and pull-request status. Configure Tailwind v4 and a token entry point before
importing @cline/ui/components.css, following the
complete styling setup.
Then import the components from the package root:
import {
AgentChangedFile,
AgentChangesPanel,
AgentPullRequestBar,
} from "@cline/ui";
AgentChangesPanel owns the Changes header, count, close action, empty state,
and scroll region. Compose AgentChangedFile children to show collapsible paths,
copy feedback, additions/deletions, host-provided actions, and rendered diff
content. The host retains change collection, clipboard and editor integration,
and conversation focus.
AgentPullRequestBar accepts normalized AgentPullRequestData plus loading and
error state. The host owns refresh, polling, navigation, and telemetry, and
provides its accessible checks popover through renderChecks. Native hosts can
intercept links with onNavigate; web hosts can omit it to render external
anchors. getAgentPullRequestMergeStatus and
summarizeAgentPullRequestChecks expose the same status normalization for other
host presentation.
Fork metadata
createForkSessionMetadata from @cline/core copies metadata, replaces fork ancestry, and removes inherited handoff markers. Callers supply the source ID, timestamp, source, and optional beforeRunCount; titles and session creation remain caller-owned.
Cloud sessions (experimental)
summarizeConversation({ messages, config, signal? }) from @cline/core returns
a continuation note without changing session history or compaction state.
Top-level credentials in config override those in providerConfig.
The request retains the prior summary, latest instruction, and its most recent
response. It shortens older context to fit the model's input limit and rejects
requests if the retained context cannot fit. It also rejects
empty, incomplete, failed, or cancelled output. Claude Code, Codex CLI, OpenCode,
and Dify are unsupported because they may execute their own tools.
CloudSessionApi and CloudSessionController are exported from @cline/core/cloud.
The API handles REST requests; the controller handles remote Hub connections,
session lifecycle, transcript reconciliation, and approvals. Hosts provide API
URLs and a fresh-token callback; feature gating and account selection stay in the
host. Importing this subpath does not start a local agent.
For ordinary creation, CloudCreationUnconfirmedError means a dispatched request
could not be reconciled. It remains a CloudSessionError with code request_failed;
hosts should direct users to their session list instead of offering a blind retry.
Use subscribe for immutable snapshots and live events, attach/readMessages
to open a session, and send for a follow-up. Attaching a provisioning or failed
session returns its receipt without connecting. detach closes this viewer, not
the remote task. Call dispose when the host shuts down.
The optional sixth argument to send accepts a beforeDispatch callback.
The callback runs before submission and can throw to prevent it. A successful
return without recoveredAfterDisconnect confirms acknowledgement.
The callback does not confirm acceptance.
Viewers hydrating active runs with readMessages reconcile canonical history at
completion even when they missed the run-start event and earlier content deltas.
create accepts sandboxType: "standard" | "resumable" (default: "standard").
The controller resumes suspended sessions when opened and restores their saved tasks.
Hosts replacing controllers during credential refresh can share the
pendingInitialTasks: Map<string, CloudCreationOptions> constructor option.
It retains first-task approval/thinking/reasoning preferences, including updates
through restoreCreationOptions, until the inner task is found or created (or
the outer session is deleted). dispose preserves an injected map; without one,
the controller owns and clears its pending state. Restoring options alone never
authorizes recreation of a missing established task.
Experimental cloud handoff
loadCloudModels and CloudSessionController.listModels() provide eligible cloud
models. Handoff requires the selected model; it never substitutes another.
Use create({ handoff, ... }) to provision and seed, or seedHandoff(id, seed) for
an existing target. Persist target IDs and dispatch markers through the callbacks;
use recoverOnly after uncertain dispatch to avoid duplicate conversations.
Handoff creation requires onCreating: durably save intent before returning, and reject a previously unconfirmed intent after restart.
Callback errors preserve their original type; they do not prove an earlier POST was rejected or permit clearing its intent.
CloudHandoffSeedRejectedError means no seed was dispatched; clear only the seed marker before retrying the saved target.
verifyHandoffTranscript checks the seeded history; waitUntilReady(id) waits for provisioning.
Voice input models
getLocalTranscriptionModels(providerId, config?) from @cline/core returns the
voice models supported by a provider's transcription transport. Use it to build
voice pickers rather than filtering the bundled chat catalog. Vercel uses its live
model list and advertised streaming tags; unavailable or malformed responses fail
discovery rather than restoring stale bundled models. Voice selection saves and
both batch and streaming execution revalidate through the same service.
isTranscriptionModel from @cline/shared (also exported for browsers) accepts
exact audio-only input and text-only output modalities. An explicit transcription
label does not override additional input or output modalities. Multimodal live
models are classified as realtime, which currently has no built-in transport
support and is excluded from voice and chat pickers. Dedicated transcription can
still use either batch or streaming mode. Classification alone does not prove
that a provider implements the required transport.
createStreamingAudioTranscriptionSession mints short-lived Vercel or single-use
ElevenLabs credentials. Its shared response includes transport and sampleRate;
browser clients must capture PCM at that rate (Google live routes require 16 kHz).
ElevenLabs exposes batch scribe_v2 and live scribe_v2_realtime separately.
SSH remote environments
RemoteEnvironmentService (exported by @cline/core and @cline/sdk) owns SSH
profiles, connection testing, helper installation, authenticated loopback tunnels,
remote commands, status changes, and cleanup. It runs in the client's Node host;
browser clients expose this API through their host transport. No desktop code is
required. OpenSSH config aliases, identity files, and ssh-agent authentication are
supported. Connections use batch mode and require an already-trusted host key in
OpenSSH known_hosts (or knownHostsPath). Before first use, verify the server
fingerprint through a trusted channel and enroll it using your SSH client. Unknown
or changed keys are rejected before inspection, upload, or execution.
import { ClineCore, RemoteEnvironmentService } from "@cline/core";
const environments = new RemoteEnvironmentService({
helperBinaryDirectory: "/opt/my-client/remote-helpers",
onStatusChange: (status) => console.log(status),
});
const profile = await environments.upsert({ name: "Build host", host: "builder" });
const connection = await environments.connect(profile.id);
const core = await ClineCore.create({
clientName: "my-client",
backendMode: "remote",
remote: {
endpoint: connection.endpoint,
authToken: connection.authToken,
workspaceRoot: connection.workspaceRoot,
},
});
try {
// The ordinary session, tools, approvals, and event APIs execute on this host.
// Supply provider credentials in the session config, as for other remote hubs.
console.log(await core.list());
} finally {
await core.dispose();
await environments.dispose();
}
The service also exposes list, upsert, delete, test, disconnect, run,
getConnection, getActive, activateConnection, and getStatuses.
onConnectionLost lets clients retire runtime bindings after a tunnel fails.
Each service instance has a unique remote Hub discovery record, so another
client connecting to the same host cannot stop its Hub.
Connect/disconnect/profile mutations are serialized; concurrent connects reuse
one tunnel. Dispose the ClineCore runtime before disconnecting its environment.
Do not expose the connection's authentication token to a browser or logs.
Profiles default to ~/.cline/data/settings/remote-environments.json, written
atomically with mode 0600. They contain identity-file paths, never private keys.
Options include profilesPath, sshPath, knownHostsPath, process timeouts,
helperBinaryPath, and helperBinaryDirectory. The corresponding helper/SSH
configuration variables are CLINE_REMOTE_HELPER_BINARY,
CLINE_REMOTE_HELPER_DIRECTORY, CLINE_SSH_PATH, and
CLINE_SSH_KNOWN_HOSTS_FILE.
Remote Hubs are CLI-managed. Clients package the self-contained Cline CLI
binary (apps/cli, compiled with Bun) for each remote OS and architecture; the
service stages it on the host and runs cline hub ensure --json --discovery-path <path> ... to start or reuse a loopback Hub, and cline hub stop --discovery-path <path> to stop it. Use remoteHelperBinaryFilename({ platform, arch }) for the bundled filename (cline-<target-triple>). Linux and macOS on
x64/arm64 are supported. The CLI must be built from the same SDK build as the
client; missing binaries produce an explicit error, without installing a
runtime from the network. Agent tools and persistence run remotely; the host
only manages SSH and forwards the authenticated hub connection.
Clients whose own process cannot host the Hub daemon can call
setHubDaemonLauncher({ command: "/path/to/cline" }) so detached Hubs they
start are launched through the Cline CLI.
The hub /health endpoint includes hubId, the instance identity also returned by authenticated /status and discovery. Restart callers can compare it before and after shutdown to distinguish a replacement at the same address from the original hub.
Provider authentication metadata for host UIs
@cline/shared (including its browser entry point) exports ProviderAuthInfo,
ProviderLocalCli, resolveProviderLocalCli(provider), and
resolveProviderApiKeyOptional(provider). The resolvers accept provider data
(metadata.localCliCommand with optional docsUrl, and metadata.apiKeyOptional);
they perform no registry lookup. Hosts resolve providers through @cline/llms and
then pass that data to the shared helpers. listLocalProviders includes the
resulting facts in each ProviderListItem.auth (localCli, and apiKeyOptional
for local inference servers and cloud-credential providers that run without a
key), allowing browser clients to render authentication guidance and gate sessions
without importing the LLM catalog. ProviderListItem.modelTools likewise
carries provider-level native tool availability for settings indicators.
Concurrent subagent tool calls
spawn_agent and configured subagent_* tools declare
executionMode: "parallel". Consecutive calls to these tools in one model
response run concurrently even when the parent runtime uses its default
sequential mode. Each call still returns its child's completed answer, and tool
results remain in the model's original call order.
A tool's optional executionMode overrides the runtime's toolExecution setting.
Unmarked tools inherit the runtime setting. Sequential calls form ordering
boundaries: read_file → [spawn A, spawn B] → edit_file executes the read first,
then both child runs together, then the edit after both finish. This does not
change the execution mode of tools inside the child agents.
Preparation remains serial for the whole response, before any tool executes.
All before-tool hooks and required approvals therefore complete before the
parallel group starts. A before-tool skip blocks its own call; a before-tool
stop prevents the entire response's execution, as before. Pending approvals
can delay sibling execution. No background-run handles or new concurrency
limit are introduced.
Configured subagent approvals
Configured agents do not expose a tool approval policy setting. The parent’s
subagent_<name> call follows the parent session’s approval policy; the child
executes its available tools without inheriting that policy or approval callback.
Its configured tools allowlist and disabled-tool filtering still apply. Runtime
hooks remain inherited and can block tool execution.
Saving provider credentials
saveLocalProviderSettings is asynchronous; callers must await it before
reloading provider catalogs or continuing onboarding. When a saved
provider has a modelsSourceUrl, credential, header, and base URL updates refresh
its model list before saving the new settings. updateLocalProvider follows the
same rule even when the request omits models and modelsSourceUrl. Endpoint
changes relocate same-origin model sources; separate catalog origins remain
unchanged. Model refresh in saveLocalProviderSettings is best-effort: if it
fails during discovery, the new settings are still saved and the last known
catalog is retained. Settings and catalog persistence errors still reject the save.
Provider-service mutations are serialized per catalog file within the process,
including across manager instances and different providers. Discovery prepares
the update before the complete settings patch is persisted once. If the catalog
write fails, the prior provider settings are restored only while the failed
operation still owns the current settings entry; newer saves and removals are
preserved. A rollback failure is reported alongside the original error.
Explicit updateLocalProvider calls still reject failed model fetches and retain
the prior settings and catalog.
Catalog refreshes replace discovery-owned model IDs while retaining manually
added models, their default selection, and overrides on retained model entries.
models.json records discovery-only IDs in discoveredModelIds; IDs also supplied
explicitly are user-managed. An explicit models update replaces the manual list.
An existing model selection in provider settings does not count as a manual
addition when initializing a source-backed catalog.
Provider capabilities are inherited when registering models, so stored per-model
capability overrides continue to take precedence after refreshes.
Shared UI session rows
@cline/ui exports AgentSessionRow, AgentSessionRowEditor, and
AgentSessionOverview, together with their public props types. These are
presentation primitives for session navigation, rename, and metadata content;
the host retains session data, routing, menus, permissions, formatting, and
interaction policy. Import the shared component stylesheet with the host theme.
AgentSessionRow owns the row geometry, selected/hover appearance, timestamp
placement, and pending/provisioning/running/unread status-dot precedence. Hosts
provide the already-formatted label and timestamp, optional leading and
pinnedIndicator content, and a sibling action. Root DOM props and refs pass
through to the row wrapper for host-owned context-menu or hover-card triggers.
The default control is the desktop native button; its disabled and
onSelect props apply only in that mode. URL or router navigation uses the
mutually exclusive renderControl mode, which receives the shared navigation
className and row children for the host's link or router control. The host
control owns its href, accessibility, disabled behavior, and event handling.
The control union prevents combining renderControl with disabled or
onSelect, and keeps optional actions as siblings so interactive elements are
not nested.
AgentSessionRowEditor supplies the matching edit frame while the host owns
the rename input, focus, Enter/Escape/blur handling, and saving state.
AgentSessionOverview renders a title and [label, value, fullValue?]
metadata rows; the host owns the hover-card lifecycle, positioning, and
metadata formatting. See the session-row adoption guide
for the import, slot, and trigger/ref examples.
Shared context usage presentation (@cline/ui)
AgentContextUsage exposes desktop's context ring and token breakdown through
its children render callback. It adds no wrapper: the host receives
AgentContextUsagePresentation (triggerLabel, ring, and details) and keeps
its own accessible trigger, popover, positioning, focus, and keyboard behavior.
AgentContextUsageProps accepts usage: AgentContextUsageData, optional
costLabel: ReactNode, and the required render callback. Usage contains
tokensIn, tokensOut, cacheReadTokens, and optional contextWindow.
Supply current-request metrics and the model's authoritative context capacity,
not accumulated session token traffic. The component renders nothing when
usage is empty or context capacity is unavailable or nonpositive. Cached tokens
are part of input usage, not additional context consumption.
costLabel is a separate host-formatted cost. Numeric zero is displayed;
previously hidden falsy values remain omitted. Desktop retains its existing
cost formatter and usage source. Import the component and all three public
types from @cline/ui; see UI adoption guidance for
theme setup, styling, and composition examples.
Shared command output and image presentation (@cline/ui)
AgentCommandOutput renders output with a running cursor controlled by
isRunning. Optional children let the host retain ANSI rendering or normalize
control characters. It follows new output initially, pauses when the user
scrolls away, and resumes within 24px of the bottom. Hosts own output collection,
limits, and session identity; remount it when switching commands. tabIndex and
classNames.viewport / classNames.cursor allow host-specific accessibility styling.
AgentImageLightboxContent renders an image and two close controls calling
onClose. The host owns the dialog, positioning, Escape handling, focus management,
and image navigation. backdropTabIndex can exclude the backdrop from a managed
dialog's tab order. Image source validation and resolution remain host-owned;
provider-generated URLs must go through an explicit host trust policy before
rendering. This presentation primitive does not replace GeneratedMediaContent
or its inline-byte validation.
Shell executor errors
The executor returned by createShellExecutor rejects on execution failure.
The following error classes are exported from @cline/core so hosts can
distinguish process outcomes without parsing messages. They are not an exhaustive
list of rejections: cancellation, timeout, and stdin-write failures can reject
with other errors.
CommandExitError— the shell started and exited non-zero.exitCodeis the numeric process exit code andoutputcontains a completion notice and the captured output (subject to the configured truncation limit).CommandTerminationError— the process terminated without a numeric exit code.signalis the terminating signal, ornullif none was reported;outputcontains a termination notice and the captured output. This error has noexitCodefield.CommandSpawnError— the shell process could not be started, so there is no exit code. The message keeps the pre-existingFailed to execute command: …form.codeis the operating system error libuv reported (ENOENT,EACCES,EFTYPEfor a file that is not a valid executable). Because spawn reportsENOENTwith the same message when the executable is not found and when the working directory no longer exists,missingrecords which path was absent at failure time:"executable"or"cwd". It isundefinedfor every other code.codeitself isundefinedif the underlying error has no code.
The public run_commands tool catches executor failures and resolves with
per-command results containing success: false, rather than propagating these
errors as rejected tool calls. For CommandExitError and
CommandTerminationError, the failed result retains output in its result
field. For CommandSpawnError, result is empty and error includes the spawn
failure message. Hosts that need the structured error fields must observe the
executor rejection before this conversion.
Hosts that record command telemetry should label a CommandSpawnError by its
code (and missing) rather than inventing an exit code. The VS Code and
standalone adapters do this in the errorCode dimension, and use the bounded
labels signal and no_exit_code for CommandTerminationError. Only an actual
numeric exit is reported as exitCode.
Symlinked instruction files
Rules and workflows can be symbolic links to regular files. Source paths and fallback names use the link's name and location, not the target's. Broken, circular, and non-file targets are skipped.
UnifiedConfigFileWatcher watches only the directory containing the link, not
the link's target. Edits to a symlink's target are picked up on the next
refresh or new session.
Unknown model completion recovery
The AI SDK adapter maps unified length to max-tokens and missing or unrecognized reasons (including other) to unknown. Explicit stop, tool-calls, content-filter, and error retain their meanings. The agent also treats a stream without a finish event as unknown.
Without tool activity, an unknown response is preserved in history and continued once, with the model-visible user message “Previous turn ended unexpectedly. Continue from where you left off.” The message uses displayRole: "system" and userRunSpan: 0, matching injected hook context so it stays out of live and replayed chat transcripts. The system prompt is unchanged. A second unknown completion fails the run. Queued user instructions are consumed before the continuation, including in the first iteration. Tool calls receive their results through the normal loop; provider-executed actions are not replayed.
Host connector transport
Pass connectorsRequest: (path, init) => Promise<Response> to LocalRuntimeHost
and createLocalHubScheduleRuntimeHandlers to supply connector authentication.
Paths start with /api/v1/connectors; the host supplies the API origin and
authentication. Omit it to retain local account authentication and rollout checks.
MCP Apps (experimental)
MCP Apps support is off by default.
createDefaultMcpServerClientFactory({ mcpApps: true }) turns it on by
advertising the io.modelcontextprotocol/ui extension (MCP_APPS_EXTENSION_ID)
with the text/html;profile=mcp-app MIME type during initialize, for stdio
and URL servers alike.
createMcpTools always leaves out tools whose _meta.ui.visibility does not
include "model", whether or not the client advertised the extension.
Tool descriptors keep the server's _meta. getMcpAppToolMeta reads
_meta.ui: resourceUri is kept only for ui:// URIs, and visibility
defaults to ["model", "app"] when it is not an array. An explicit array is
used as given after dropping unknown entries, so [] makes the tool visible to
neither. isMcpToolVisibleToModel and isMcpToolVisibleToApp check those
lists; a host must reject app-initiated tool calls when
isMcpToolVisibleToApp is false.
McpManager.readResource({ serverName, uri, context }) sends resources/read
and returns { contents, _meta? }, validated against the MCP SDK schema;
malformed replies throw. It is optional on McpManager and
McpServerClient. InMemoryMcpManager reads without waiting for in-flight
tool calls on an already connected server. A read that starts while the server
is being disconnected or re-registered can fail with a disconnect error; retry
it.
Run stall telemetry
@cline/core measures stalls with a RunHealthObserver
(packages/core/src/services/telemetry/run-health.ts). SessionRuntime
creates one per run, for root agents and subagents, when telemetry is
configured. It watches only the run's runtime events and is disposed when the
run returns.
task.run_idlefires at most once per run, while it is still running and has emitted no runtime event for 60s.- When the run ends,
AgentRuntimecalls the optionalAgentRuntimeConfig.runEndTelemetryProperties()once, while capturingagent.run-finishedoragent.run-failed, and merges the result into that event. Core uses it to addmaxIdleMs,maxIdleAfter,msSinceLastEvent,lastEventType,finishReason,idleReported,endedOnandtextSignature. The observer stops its idle check at that point. tool-call-deltais a runtime event emitted for each streamed tool-call argument chunk. It carries no arguments and exists so that a slow tool-call stream is not mistaken for a silent one. It is not mirrored to telemetry and is not forwarded as hub hook traffic.
No message text leaves the client: textSignature and session.input_sent's
bumpKind are enums computed locally
(packages/core/src/services/telemetry/stall-signals.ts).