Commit Graph
428 Commits
Author SHA1 Message Date
can1357 e28197c694 Revert "merged PR #5602: fix(agent-loop): reclassify empty toolUse stop as retryable error"
This reverts commit 2baaea8782, reversing
changes made to 6783c3a473.
2026-07-16 04:09:44 +02:00
can1357 1df790a5d2 Revert "fix(agent-loop): discard incomplete sibling tool calls"
This reverts commit 7a2e34988b.
2026-07-16 04:08:59 +02:00
can1357 93cc1fed1c merged PR #5417: fix(openai): render native response images
# Conflicts:
#	packages/coding-agent/src/modes/components/chat-transcript-builder.ts
#	packages/coding-agent/test/agent-session-skill-keywords.test.ts
2026-07-16 03:48:21 +02:00
can1357 7a2e34988b fix(agent-loop): discard incomplete sibling tool calls 2026-07-16 03:31:57 +02:00
roboomp 4200dec047 fix(agent-loop): strip incomplete tool calls on empty toolUse stop
A dropped stream that emitted toolcall_start/delta but never toolcall_end
leaves an incomplete toolCall block in content. The prior guard bailed on
any toolCall block, so the outer loop dispatched empty or partially
parsed arguments instead of retrying the transport failure.

Track streamed tool-call ids (toolcall_start/delta) alongside completed
ones (toolcall_end): a call streamed but never completed is incomplete.
reclassifyEmptyToolUseStop now reclassifies unless a usable (atomic or
completed) tool call remains, stripping incomplete blocks first. Atomic
deliveries (single done/end(result) message, e.g. Cursor) emit no
granular events and stay usable.

Fixes #5600
2026-07-15 18:06:13 +00:00
roboomp 94fc54859f fix(agent-loop): reclassify empty toolUse in result-only completion
Streams finalized via end(result) with no terminal done/error event fall
through to the trailing-result branch, which returned response.result()
unchanged. An empty toolUse turn completing that way stayed a silent
success and never retried. Apply the same
retainCompletedToolCalls/recoverTransientErrorToolTurn/
reclassifyEmptyToolUseStop chain to the trailing branch.

Fixes #5600
2026-07-15 17:52:25 +00:00
roboomp f64a17c529 fix(agent-loop): reclassified empty toolUse stop as retryable error
A provider stream that closes after the thinking block but before the
tool call JSON is emitted finalizes with stopReason=toolUse and zero
toolCall content blocks. The loop treated this as a successful turn:
dispatched no tools, rendered an empty tool widget, and never retried.

reclassifyEmptyToolUseStop stamps such a turn as stopReason=error with
the Transient classifier bit set explicitly, so AgentSession's standard
retry-with-backoff path fires regardless of message-text matching.

Fixes #5600
2026-07-15 17:44:53 +00:00
can1357 5ff277349c refactor(coding-agent): consolidated tool surface onto xd:// devices and hub
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
2026-07-15 15:16:29 +02:00
can1357 b58fa6e1d3 Merge PR #5513: fix(agent): keep completed tool results from false "skipped" placeholder (@roboomp) 2026-07-14 23:11:08 +02:00
can1357 6b381eb765 Merge PR #5451: fix(eval): honor timeout zero and classify session deadlines (@roboomp) 2026-07-14 22:58:49 +02:00
roboomp b591f3d054 fix(agent): kept completed tool results from false skipped placeholder
The interrupt-clobber branch in executeToolCalls replaced a tool's real
result with the "Skipped due to queued user message" placeholder whenever
an interrupt fired, the tool's own signal aborted, and the result was an
error. It ignored whether tool.execute() actually completed, so steering
while a tool was in flight could discard a genuine error result (e.g. a
command exiting non-zero) that the tool had already produced.

Gate the clobber on !completedToolExecution so a tool that ran to
completion keeps its real result; only tools cut off before returning are
reported as skipped. Align the aborted telemetry status the same way.

Fixes #4752
2026-07-14 19:57:38 +00:00
roboomp 8e6d26b1e8 fix(eval): honored unlimited cell timeouts
- Disabled the eval watchdog when timeout is explicitly zero.
- Classified session deadline aborts as TimeoutError while preserving their message.
- Documented and tested both timeout contracts.

Fixes #5250
2026-07-14 17:33:56 +00:00
can1357 3239b4e7d3 Merge PR #5190: fix(agent): escape Harmony compaction markers (@roboomp) 2026-07-14 18:34:14 +02:00
roboomp b6b947bdbe fix(openai): rendered native response images
- Normalized completed image_generation_call results into assistant image blocks.
- Persisted image bytes through the session blob store and rendered them in live, replay, ACP, proxy, telemetry, and HTML paths.
- Added response normalization, persistence, and TUI rendering regressions.

Fixes #4768
2026-07-14 16:15:53 +00:00
can1357 4903a13511 feat(session): implemented automated recovery and status reporting
- Added `warning` field to `CompactionEntry` and `CompactionSummaryMessage` to persist dead-end status in session history.
- Introduced a multi-tier rescue mechanism in `AgentSession` that automatically performs `elide` and `dropImages` passes when maintenance fails to recover sufficient headroom.
- Integrated visual indicators for dead-ends into the `CompactionSummaryMessageComponent`, surfacing warnings directly on the compaction divider and detail block.
- Updated `AgentSession` logic to re-evaluate progress after each rescue tier and emit recovery notices, ensuring transparent reporting of automated history rewrites.
2026-07-13 01:40:14 +02:00
can1357 9a868d2e7a feat: introduced agent suspension mechanism with pause command and ui
- Introduced an `AgentPauseGate` mechanism to suspend and resume agent loops and tool executions safely.
- Added a `/pause` slash command to trigger a new fullscreen UI that manages agent suspension and lifecycle.
- Integrated pause checks into the core agent loop and tool execution pipeline to ensure responsive state handling.
- Provided a new pause screen component to facilitate user interaction and resume control during suspension.
2026-07-11 17:15:00 +02:00
roboomp 9831386deb fix(agent): escaped harmony compaction markers
Escaped Harmony control-token markers when compaction serializes transcripts into plain summary prompts so Copilot gpt-5.6 models do not reject analysis-channel text.

Added regression coverage for summary-bound Harmony serialization while keeping native transcript rendering unchanged.

Fixes #5184
2026-07-11 13:36:32 +00:00
can1357 0f8fed88e1 Merge remote-tracking branch 'origin/farm/6d5a35ab/advisor-steering-skip-message' 2026-07-11 07:39:30 +02:00
can1357 531880c620 feat: improved json serialization for bigint values
- Introduced `stringifyJson` helper to preserve bigint precision by serializing them as decimal strings.
- Replaced native `JSON.stringify` across compaction and session management modules to prevent serialization errors when handling bigint values in tool arguments.
- Added regression tests in `agent` and `coding-agent` packages to ensure bigint tool arguments remain intact through compaction and persistence flows.
2026-07-11 00:12:29 +02:00
can1357 c30bdc54ce feat(ai): enforced all_turns reasoning context for responses lite
- Force `reasoning.context` to `all_turns` in OpenAI Codex requests when `responsesLite` is enabled.
- Include `reasoning.encrypted_content` in the `include` header for lite responses.
- Update request transformation logic to ensure these fields are populated even when reasoning effort is not explicitly set.
2026-07-10 20:09:31 +02:00
roboomp 74c63fa6c5 fix(agent): labeled system steering skips accurately
- Carried steering queue origin through mid-batch interrupt polling.
- Preserved queued-user skip wording while labeling advisor/system steering as system advisory skips.
- Added regression coverage for advisor steering skip wording.

Fixes #5074
2026-07-10 14:00:59 +00:00
can1357 d435385ab1 feat: introduced max reasoning effort tier across model and rpc systems
- Introduced `Max` as a first-class reasoning effort tier across all packages, including AI providers, coding agent configurations, and RPC protocols.
- Refactored model effort ladders to use wire-exact mappings and removed legacy effort aliasing (e.g., `max-to-xhigh` mapping).
- Updated model registry and provider configurations to support `Max` tier routing, color themes, and UI icon associations.
- Expanded test suites to provide end-to-end coverage for the new reasoning tier, including updated compatibility and fallback scenarios.
2026-07-10 13:39:42 +02:00
can1357 17c7c6d0f8 fix(agent): preserve external abort boundaries 2026-07-10 12:37:46 +02:00
can1357 a3c0d536cc Merge PR #4971: fix(agent): stop terminal yield loops after IRC wake 2026-07-10 12:37:38 +02:00
can1357 2dafa7ac79 feat: further codex metadata 2026-07-10 11:35:09 +02:00
can1357 29deeef876 feat: enabled codex responses lite for gpt-5.6 models and remote compaction
- Enabled Codex Responses Lite for GPT-5.6 models by integrating model discovery flags and wire contract updates.
- Implemented request transformations for streaming and remote compaction, including header injection and image detail stripping.
- Introduced sequential-cutoff logic and atomic reasoning summary events for concurrent stream processing.
- Added comprehensive test suites to validate remote compaction, image handling, and reasoning summary delivery.
2026-07-10 09:46:27 +02:00
roboomp 2c838e9622 Merge remote-tracking branch 'origin/main' into farm/8134d5cd/fix-revived-yield-loop 2026-07-10 03:38:00 +00:00
can1357 fde4a19c62 feat: added prompt-cache affinity support for grok models
- Introduced `getOpenAIPromptCacheKey` to provide a unified identity resolution for both cache keys and affinity headers.
- Enabled `x-grok-conv-id` header support in the OpenAI completions provider for models configured with cache affinity.
- Added comprehensive tests to verify cache affinity header behavior across varied session and cache configuration states.
2026-07-09 22:28:58 +02:00
roboomp 0f3cf73a85 fix(agent): stopped terminal yield wake loops
- Aborted the active agent loop synchronously when a terminal yield tool result finishes, so IRC-wake turns stop before another provider call.
- Added a regression covering idle IRC wake handling after a terminal yield.

Fixes #4963
2026-07-09 19:13:29 +00:00
can1357 53df3c82b7 style: applied biome formatting to merged sources 2026-07-08 15:37:43 +02:00
can1357 1bb29873ea fix(agent): adapted scoped TTSR abort labels to completed-call retention
- derive per-tool abort labels from a tool-scoped abort signal for provider-built aborted messages
- restore main's single-call TTSR label test dropped by the merge
- complete the innocent read in the sibling-label test; incomplete matched calls mint no placeholder under the retention policy
2026-07-08 15:34:37 +02:00
can1357 32158b74ea merge PR #4542: fix(coding-agent): scoped TTSR abort reason to matching tool call 2026-07-08 15:27:25 +02:00
can1357 9547ff6f55 merge PR #4633: fix(agent): support chat completions remote compaction endpoints 2026-07-08 15:19:35 +02:00
roboomp 389515baad fix(agent): retried handoff auto-only tool choice errors
Retried handoff generation with toolChoice auto when a provider rejects the cache-preserving toolChoice none request as auto-only.
Kept unrelated provider 400s terminal so bad request failures still surface without masking the cause.

Fixes #4715
2026-07-06 14:13:02 +00:00
roboomp da6f0ebc38 fix(agent): used wire model id for chat compaction
- Sent remoteCompaction.model or requestModelId in chat-completions remote compaction requests instead of the local catalog id.
- Covered both direct requestRemoteCompaction formatting and end-to-end openai-completions compaction with wire model ids.

Fixes #4630
2026-07-05 21:12:08 +00:00
roboomp 241beb9b3d fix(agent): supported chat completions remote compaction
- Sent OpenAI-compatible chat messages when compaction.remoteEndpoint targets /chat/completions while preserving the existing custom summarizer payload elsewhere.
- Added regressions for direct wire formatting and end-to-end openai-completions compaction against a configured chat endpoint.

Fixes #4630
2026-07-05 20:53:06 +00:00
roboomp 8b17f0d3a1 fix(coding-agent): scoped TTSR abort reason to matching tool call
TTSR stream-interrupt aborts now carry a per-tool reason so the placeholder
loop labels only the tool call whose stream matched the rule with the rule
name and gives sibling committed tool calls a neutral "TTSR interrupt on
another tool call" reason. Previously the single `message.errorMessage`
was stamped onto every retained tool-call block, so unrelated read/edit
calls read as violating a rule they never matched and misled the model's
own reasoning about which call fired.

Threads the matched `toolcall:<id>` extracted from the TTSR match context
through `agent.abort(...)` as a `ToolScopedAbortReason` object; the agent
loop unwraps it in `emitAbortedAssistantMessage` into a
`toolCallAbortMessages` map on the aborted `AssistantMessage`, and the
`stopReason === "aborted"` fanout in `runAgentLoop` prefers the per-tool
message when one exists.

Fixes #2783
2026-07-04 17:38:51 +00:00
roboomp 38454d3321 fix(agent): excluded orchestration tokens from context sizing
calculateContextTokens returned usage.totalTokens which, with the new
Usage.orchestration sidecar, folds provider-side orchestration back into the
context size used by auto-compaction/context promotion thresholds. Subtract
the orchestration sidecar so context sizing stays conversation-only while
cost and totalTokens keep the orchestration spend visible.

Refs #4469
2026-07-03 16:53:11 +00:00
can1357 82f3706410 Merge remote-tracking branch 'origin/farm/6f26b11c/distinguish-synthetic-tool-failure' 2026-07-02 23:42:38 +02:00
can1357 cc1990a2ad Merge remote-tracking branch 'origin/farm/c1eb4f67/cursor-persist-tool-calls' 2026-07-02 23:32:21 +02:00
can1357 03821843a5 Merge remote-tracking branch 'origin/farm/c1eb4f67/cursor-persist-tool-calls' 2026-07-02 23:27:22 +02:00
roboomp eb64e7e5d1 fix(agent-loop): skip cursor exec-resolved toolCall blocks to avoid double-execution
Codex review on PR #4351: synthesizing toolCall content blocks for
Cursor's exec-channel native tools made the shared agent loop treat the
finalized assistant message as a fresh runnable tool turn. Because
executeToolCalls filters message.content for any toolCall block on
stop/toolUse, bash/write/delete/etc. ran a second time after Cursor
already executed them server-side via the bridge, duplicating side
effects and appending conflicting toolResults.

- packages/ai/src/utils/block-symbols.ts: add `kCursorExecResolved`
  symbol and `CursorExecResolvedCarrier` carrier type. Symbol-keyed so
  the marker never leaks into JSONL; rebuild pairs blocks with toolResult
  messages by id.
- packages/ai/src/providers/cursor.ts: stamp the marker onto every
  block `synthesizeCursorExecToolCall` emits and extend `ToolCallState`.
- packages/agent/src/agent-loop.ts: filter marked blocks out of the
  runnable-toolCall extraction in both the main runnable path and the
  error/aborted placeholder path, plus defense-in-depth inside
  `executeToolCalls`. Marked blocks stay in `assistantMessage.content`
  for persistence + rebuild rendering; they just never re-execute.
- packages/agent/test/agent-loop.test.ts: two regression tests — one
  proves a marked block yields zero `tool.execute` calls and no
  `tool_execution_*` events from the loop, the other verifies mixed
  batches still run the unmarked blocks unchanged.

Fixes #4348
2026-07-02 21:26:37 +00:00
roboomp cfedc0efd0 fix(cursor): synthesize toolCall blocks for exec-channel native tools
Cursor's provider only pushed toolCall content blocks for MCP and todo
in processInteractionUpdate.toolCallStarted. Native tools (bash, read,
write, grep, ls, delete, lsp) execute via the exec channel and produced
no toolCall blocks, so persisted assistant messages contained only text.

On replay, renderSessionContext could not pair the subsequent toolResult
messages with any toolCall block and fell through to addMessageToChat
(a no-op for toolResult), causing header-less \`\\u23ce\` output beneath the
last assistant text.

- packages/ai/src/providers/cursor.ts: add synthesizeCursorExecToolCall
  and inject it at the top of each native exec case in
  handleExecServerMessage, using the coding-agent bridge's mapped tool
  name and args so live event and rebuild render identically. Normalize
  args.toolCallId before invoking the handler so provider block id and
  bridge result id always match.
- packages/agent/src/agent.ts: drop the text-length split in
  #emitCursorSplitAssistantMessage. With toolCall blocks now at their
  correct positions in content, emit the assistant message as-is
  followed by buffered toolResults; the split's preambleText-per-text
  copy also silently duplicated text on multi-block turns.
- packages/ai/test/cursor-streaming-args.test.ts + new
  packages/coding-agent/test/issue-4348-repro.test.ts: guard block
  ordering, event sequence, and rebuild pairing behavior.

Fixes #4348
2026-07-02 21:02:33 +00:00
can1357 d82b9bdc5f feat(agent): allowed dynamic model resolution per LLM call
- Added `getModel` to `AgentLoopConfig` to allow runtime model resolution.
- Updated `streamAssistantResponse` to resolve the model dynamically per provider call instead of using the stale configuration snapshot.
- Enabled mid-run model switches to take effect immediately for context promotion and retry fallbacks.
2026-07-02 22:43:11 +02:00
roboomp 211e3d71b7 style: bun run fix 2026-07-02 15:19:47 +00:00
roboomp 3d86935a5e fix(agent): distinguish synthetic placeholder tool results from real tool failures
When an assistant turn ends with stopReason="error" after a tool call
was already streamed, agent-loop synthesizes a placeholder tool result
via createAbortedToolResult() to preserve the tool_use / tool_result
pairing the provider API requires. The previous wording ("Tool
execution failed due to an error: <upstream>") and event shape
(normal tool_execution_start / tool_execution_end with empty details)
were indistinguishable from a real local tool failure — a Codex
websocket close mid-turn showed up in the CLI as a broken Edit panel,
misattributing provider-transport faults to the local tool.

Reword the "error" placeholder to state explicitly that the tool
never ran ("Tool call was not executed because the provider stream
ended with an error before the tool could run: <upstream>") and thread
a SyntheticToolResultDetails discriminator ({ __synthetic: true,
source: "assistant_stop_error" | "assistant_stop_aborted" |
"assistant_stop_skipped" | "assistant_stop_length", executed: false,
upstreamError }) through both the ToolResultMessage.details and the
tool_execution_end event's result.details, so downstream UI/telemetry/
ACP consumers can render "provider transport failed, tool not
executed" without string-matching content.

Fixes #4321
2026-07-02 15:19:30 +00:00
can1357 0d96c2b6ec Merge remote-tracking branch 'origin/farm/bf21f607/frame-rewind-completion'
# Conflicts:
#	packages/coding-agent/src/session/agent-session.ts
#	packages/coding-agent/test/agent-session-checkpoint-rewind-branch.test.ts
2026-07-02 03:56:59 +02:00
can1357 21f5728ef8 fix(agent): prevented consuming legacy steering queue during mid-batch interrupts
- Stopped calling the consuming `getSteeringMessages` getter during mid-batch interrupt polls to prevent stranding or dropping messages before they reach the injection boundary.
- Skip subsequent steering checks in the poll loop once an interrupt has already triggered.
- Added a regression test to ensure legacy steering remains queued until the injection boundary when no non-consuming peek exists.
2026-07-02 03:34:14 +02:00
roboomp 1bbd0c92f6 feat(anthropic): opt-in server-side fallback beta chain
Added AnthropicOptions.fallbacks + wire types + response parsing gated on the opt-in — server-side fallback stays fully inert on every request that does not set the option.

Coding-agent surfaces the feature via providers.anthropic.serverSideFallback (default off). When enabled, Fable/Mythos requests inject fallbacks: [{ model: claude-opus-4-8 }]; caller-supplied fallbacks always win.

transformMessages centrally strips persisted fallback blocks on cross-provider hops and non-official Anthropic replays so a stored fallback turn never wedges downstream converters. Retry resets restore output.model to the requested id.

Fixes #4177
2026-07-01 23:34:48 +00:00
can1357 fc91aadccd fix(agent): honored explicit compaction reserve equal to default
- Made CompactionSettings.reserveTokens optional so field presence carries provenance; the proportional small-window fallback only applies to genuinely defaulted reserves.
- Clamped the fallback reserve to >= 1 and the derived threshold strictly below the context window.
- Changed the coding-agent settings-schema default from 16384 to unset so Settings.get() no longer materializes a default that masks provenance.
2026-07-02 00:32:48 +02:00