Commit Graph
99 Commits
Author SHA1 Message Date
can1357 e58c9f4d52 fix(packages/agent): patched steering checks to avoid consuming messages
- Added `hasSteeringMessages` to `executeToolCalls` polling so queued steering is detected without dequeuing.
- Retained fallback to `getSteeringMessages` by consuming messages when no peek callback exists.
2026-06-12 03:50:05 +02:00
can1357 51208e5de1 feat(coding-agent): added boundary-aware steering and idle steer-queue handling
- Added optional `hasSteeringMessages` config hook and limited steering checks to boundaries.
- Fixed interrupted tool-batch steering by keeping queued messages until boundary handling.
- Added idle text and image submissions to steer queueing when no input waiter exists.
- Auto-continued resumable sessions after queued steering and preserved submit metadata.
2026-06-12 03:30:51 +02:00
can1357 a82d68ef49 feat(coding-agent): added experimental snapcompact inline imaging for system prompt and tool results
- Added `renderSnapcompactFrames()` and `snapcompactFrameCount()` to @oh-my-pi/snapcompact for paging arbitrary text into PNG image blocks without dim-marker bookkeeping.
- Widened the agent loop's `transformProviderContext` hook to `(context, model) => Context` so per-request transforms can gate on the dispatch model's capabilities.
- Added `SnapcompactInlineTransformer` rendering the system prompt and large historical tool results as snapcompact frames on vision models: vision gate, per-provider image budgets, 3k-token floor, savings-margin gate, skip-last rule, and hash-keyed render caches swept to live tool calls.
- Added default-off `snapcompact.systemPrompt` and `snapcompact.toolResults` settings under a new Context → Experimental group, composed after secret obfuscation in `sdk.ts` so frames are built per-request and never persisted to session.jsonl.
- Added prompt stubs (`snapcompact-system-stub.md`, `snapcompact-system-frames-note.md`, `snapcompact-toolresult-note.md`) and unit tests covering frame paging, no-mutate guarantees, budget caps, gates, and render caching.
2026-06-12 03:27:50 +02:00
can1357 eb966cc6dc fix: handled non-terminal pause_turn stops by resampling interrupted turns
- Mapped Codex `end_turn:false` terminal events to `pause_turn` stop details in response stream parsing.
- Updated `agent-loop` to re-sample `pause_turn` turns, reset on tool calls, and cap continuations at 8.
- Added coverage for pause-turn mapping and continuation-capping in agent and AI stream tests.
2026-06-12 02:33:45 +02:00
can1357 ce4ebad726 feat(agent): added per-call tool concurrency resolver and parallel bash execution
- Extended `AgentTool.concurrency` to accept per-call resolver functions and resolved concurrency mode from each tool call, falling back to exclusive on resolver errors.
- Updated BashTool to schedule non-PTY calls as shared and PTY calls as exclusive so non-interactive bash calls can run in parallel within one message.
- Tracked in-use persistent shell sessions in the bash executor and routed overlapping calls on the same session key to isolated one-shot shells while preserving owner session availability.
2026-06-11 18:13:07 +02:00
Can BölükandGitHub 38c44faef8 Merge branch 'main' into fix/anthropic-empty-error-tool-result 2026-06-11 17:43:27 +02:00
can1357 84175ce4b2 fix(agent): preserved queued steering across externally aborted runs
Interrupting mid-tool execution (e.g. Enter with a pending steer) drained the steering queue into the dying run — it landed in history without a response and the post-abort resume saw an empty queue, so the agent stopped instead of continuing. Steering/follow-up/aside queue polls in runLoopBody and the post-tool-call check in executeToolCalls are now skipped once the run's abort signal fires, leaving the queue intact for Agent.continue().
2026-06-10 17:43:51 +02:00
Theo Mathieu e13ecc60f9 fix: prevent Anthropic 400 on empty error tool results
Anthropic rejects tool_result blocks when is_error is true and content is
empty after trimming whitespace. Fill a placeholder at encode time and in
coerceToolResult so wedged sessions recover on the next request.
2026-06-10 11:05:46 +02:00
can1357 c939aff883 feat(agent): add transformProviderContext hook before telemetry and provider send 2026-06-10 09:51:44 +02:00
roboomp 6abc72d4c7 fix(agent): re-resolved disableReasoning per loop iteration
Added AgentLoopConfig.getDisableReasoning so the agent loop refreshes disableReasoning on every model call, matching getReasoning. Mid-run thinking-level transitions in and out of off now propagate to the next request instead of sticking on the value captured at prompt start.\n\nFixes #2239
2026-06-10 07:47:25 +00:00
can1357 9cfb63fd07 fix(agent): retained mid-stream tool calls on deliberate aborts
- Kept committed tool-call blocks on TTSR/user-interrupt aborts, pairing them with a labeled placeholder result.
- Dropped incomplete tool calls only on anonymous `abort()` where partial args are unsafe to replay.
2026-06-08 18:31:20 +02:00
can1357 d18539a320 fix(agent): fixed stalled abort handling and Anthropic stream gaps
- Stopped aborted runs from waiting on provider iterator cleanup.
- Ran afterToolCall for completed executions after a run aborts.
- Ignored unknown Anthropic content blocks while preserving known ones.
- Kept sampling params and tool-result caching for disabled thinking.
2026-06-08 15:26:40 +02:00
can1357 3d5572a0fc test(natives): documented AST conditions and expanded astMatch tests
- Updated `docs/ttsr-injection-lifecycle.md` to document `astCondition` behavior, including registration rules and tool-stream matching.
- Extended `packages/natives/test/native.test.ts` with new `astMatch` coverage for Smart matching, metavariable consistency, parse errors, and empty-language rejection.
2026-06-08 15:00:28 +02:00
can1357 16cb096eed fix(ai): fixed Anthropic CCH anchoring and agent tool interruption handling
- Deferred non-interrupting asides to the outer drain when a turn was finishing, preventing an extra model turn from firing before queued follow-ups.
- Coerced post-hook tool results before emission and only marked interrupted tool calls as skipped when execution failed, preserving completed call outcomes.
- Reworked Anthropic CCH patching with native `Buffer.indexOf`, and logged a warning while sending the body unchanged when the billing placeholder could not be anchored.
2026-06-08 14:58:09 +02:00
can1357 0890b2be61 fix: fixed tool-call recovery, stream parsing, and image normalization flows
- Fixed tool result validation to reject invalid blocks and append explicit error diagnostics.
- Handled aborted and leaked tool calls by returning abort results and dropping partial leaked output.
- Fixed Anthropic streaming by enforcing strict SSE parsing and content-block lifecycle checks.
- Fixed image handling by normalizing model-context inputs and preserving images on resize failure.
2026-06-08 14:40:18 +02:00
can1357 462c2b749c fix(coding-agent/task): show agent type in task result header
Append the dispatched agent type to the task result frame header so it reads `Task 16 agents: Reviewer` instead of just `Task 16 agents`.
2026-06-08 14:22:49 +02:00
can1357 0753a7a433 feat(agent): removed max tool-call caps from agent loop and session flow
- Removed `maxToolCallsPerTurn` from `AgentOptions`, `AgentLoopConfig`, and config serialization.
- Removed stream-loop cap enforcement, including the `toolcall_end` abort path and capped assistant messages.
- Removed Anthropic Opus 4.8 batch-cap resolver and agent-session sync logic from coding-agent.
- Updated tests and changelogs to align with uncapped tool-call behavior and dropped cap-specific cases.
2026-06-08 14:15:46 +02:00
can1357 641a6ec205 fix(agent): excluded buffered tool call after capped batch
- Sliced cloned content through the capping tool call's index.
- Prevented executing a started-but-unfinished call beyond the cap.
2026-06-08 14:13:50 +02:00
can1357 28dade85c3 fix(agent): resolved deferred asides at injection to drop stale messages
- Introduced `AsideMessage` as a message-or-thunk union so aside providers can defer injection decisions.
- Updated agent loop handling to resolve aside thunks at injection time and skip entries that returned `null`, then switched the session yield queue to `drainLazy` for deferred message building.
- Added tests validating lazy aside evaluation and staleness-aware dropping when everything becomes stale after dequeueing.
2026-06-08 06:46:41 +02:00
can1357 de03d7f3d1 feat(agent): added non-interrupting aside message support
- Added a new aside-message source on `Agent` and exposed it in `AgentLoopConfig` as `getAsideMessages`.
- Updated the agent loop to poll aside messages after tool batches and before yielding, merging them with follow-up messages before continuing.
- Changed coding-agent session and yield queue handling to pull queued background messages via `drainMessages` at step boundaries instead of streaming-only injection.
2026-06-08 06:08:43 +02:00
can1357 31309d6212 fix(agent): removed tool-level abort-signal bypasses for read/write/edit tool execution
- Updated `executeToolCalls` to always pass the active `toolSignal` into `tool.execute` rather than bypassing it for non-abortable tools.
- Removed the `nonAbortable` option from `AgentTool` and from the read, write, and edit tools so they can no longer opt out of abort handling.
- Documented the cancellation behavior change in the affected tool docs and package changelogs.
2026-06-08 05:27:00 +02:00
can1357 a78f4c6766 feat(coding-agent): enabled abort reasons to propagate and surface through streaming messages
- Added optional `reason` parameters to `Agent.abort` and `AgentSession.abort` APIs.
- Passed abort reasons through interrupt flows into underlying agent cancellation.
- Replaced hard-coded abort text with `resolveAbortLabel` for streaming and replayed messages.
- Fell back to generic `Request was aborted` text when no abort reason was provided.
2026-06-07 06:19:55 +02:00
can1357 cba6641299 feat: enabled resolver-based API key retries with refresh and rotation
- Added `ApiKeyResolver`/`ApiKey` types and exported auth-retry helpers.
- Changed stream and gateway auth retry handling to use resolver steps.
- Added initial-key, force-refresh, and rotate credential retries for auth failures.
- Updated agent and coding-agent integrations to use context-aware API-key resolvers.
2026-06-07 04:20:48 +02:00
roboomp e4a31b22bf fix(agent): surfaced max_tokens truncation cause to the model on skipped tool calls
When a tool call (most visibly `write` with >~1000 lines of content) is

truncated by `stop_reason: length` — e.g. OpenCode Zen's claude-3-5-haiku

with its 8192 `max_tokens` cap — the agent loop correctly refuses to

execute the call (its streamed arguments are mid-string) but used to

attach the same generic placeholder result it uses for non-runnable

non-tool turns: "Tool call was not executed because the assistant ended

its turn." The auto-continue loop re-prompted, the model re-emitted the

same oversized payload, and the user saw the file write fail again and

again — perceived as a "write tool crash" with the target file lost.

`createAbortedToolResult` now takes a `length` reason that names

`stop_reason: length` and tells the model to split the work into multiple

smaller tool calls (write the first chunk, append the rest with `edit`

insert ops, or break the file into multiple `write` targets). The skip

path in agentLoop forwards the real stop reason so the hint reaches the

model on the very next continuation. Tool execution is still guarded —

the truncated args never run.

Regression test in packages/agent/test/agent-loop.test.ts verifies the

synthetic `write` call is skipped AND the resulting tool-result message

carries the length-specific guidance.

Fixes #1785
2026-06-03 09:40:22 +00:00
DarkPhilosophy ad2568cbb4 fix(agent): pop leaked partial before retry in trailing path 2026-06-01 23:49:46 +03:00
DarkPhilosophy 26b3300c76 fix(agent): engage harmony leak detection on the committed assistant message 2026-06-01 23:44:45 +03:00
can1357 ae905fb3cf feat(agent): added agent tool-call cap enforcement to stream loop
- Added `maxToolCallsPerTurn` support to `AgentOptions` and `AgentLoopConfig`, with Agent getter/setter and serialized state wiring.
- Implemented stream-loop cap handling by normalizing bad values and halting after `toolcall_end` reaches the limit.
- Added `ANTHROPIC_TOOL_CALL_BATCH_CAP`=8 and wired session cap sync on init, model changes, and restore.
- Added tests that truncated a 10-call stream to 8 tool calls, and verified non-Claude models resolve no cap.
2026-05-30 04:47:58 +02:00
can1357 445fe99fbc fix(agent): executed tool calls emitted under end_turn stop reason
- Fixed agent loop abandoning tool_use blocks on `stop`/`end_turn` turns; only `length` (truncation) now skips execution.
- Verified against live Anthropic API: stop_reason is never replayed on wire and doesn't gate continuation validity.
- Added tests pinning the wire-safety contract: thinking blocks with stale/missing signatures are downgraded to text before replay.
2026-05-30 00:27:03 +02:00
can1357 1fe843de2e fix(agent): handled skipped tool calls for non-toolUse assistant turns
- Updated the agent loop to execute tool calls only when the assistant stop reason was `toolUse`.
- Added skipped placeholder `tool_result` messages for leftover `toolCall` blocks when a turn ended without `toolUse`.
- Promoted OpenAI/Ollama `stop` tool-call turns to `toolUse` and stripped thinking signatures on abandoned tool-use turns during message transforms.
2026-05-29 13:31:37 +02:00
can1357 3078d31a4c chore: reformat 2026-05-26 20:44:09 +02:00
hezhiyang2000 afe574b351 fix: prevent busy-wait in agent loop and bash executor
- yieldIfDue() uses compensated sleep (sleepAtLeast): retries Bun.sleep()
  until the requested wall-clock duration has elapsed. This is necessary
  because napi callbacks (uv_async_send) can wake the event loop
  prematurely, causing Bun.sleep(N) to return after only ~1-2ms.
- ExponentialYield for bash-executor: starts at 20ms, doubles to 10s.

Closes #1384
2026-05-26 17:35:00 +08:00
can1357 80186e341c feat(agent): threaded intentTracing option through append-only context
- Exported `normalizeTools` so `AppendOnlyContext` uses the same tool normalization as the agent loop.
- Added `BuildOptions.intentTracing` to `build()`/`reset()`/`takeSnapshot()` so intent injection is consistent and included in the prefix fingerprint.
- Improved `#computeDigest` to cover tool_calls, tool_call_id, name, and id fields to catch in-place mutations.
- Fixed `#unsubscribeAppendOnly` leak and added no-op guard in `#syncAppendOnlyContext`.
2026-05-25 14:06:44 +02:00
Brit 648bbdc163 fix(agent): passed AbortSignal to transformContext and re-evaluated append-only on model switch 2026-05-24 22:28:38 +02:00
Brit 2a86049f0f feat(agent): add append-only context mode for DeepSeek prefix-cache stability
ImmutablePrefix caches system prompt + tool specs after first build()
so subsequent turns reuse identical byte sequences. AppendOnlyLog
converts messages once via syncMessages() and only appends deltas
on further turns — prior-turn bytes stay stable.

- New module: packages/agent/src/append-only-context.ts
  StablePrefix, AppendOnlyLog, AppendOnlyContextManager
- AppendOnlyContextManager added to AgentLoopConfig
- Wired into streamAssistantResponse in agent-loop.ts
- Toggleable via provider.appendOnlyContext setting (auto/on/off)
- Default auto enables for deepseek provider
- 38 tests covering prefix, log, sync, compaction handling
- /session info surfaces current active state
2026-05-24 22:08:53 +02:00
can1357andCan Bölük 796f963da9 feat(coding-agent): added coding-agent follow-up queue with onBeforeYield
- Added optional `onBeforeYield` configuration and `setOnBeforeYield` in Agent, executed before follow-up checks.
- Added `YieldQueue` to `AgentSession`, with setup/teardown and streaming/idle flush via `setOnBeforeYield`.
- Replaced immediate async-result follow-up dispatch with queued batch entries, including stale-state suppression.
- Added MCP follow-up queueing in SDK, deduplicating updates by `serverName` and `uri`.
- Added changelog entries for `onBeforeYield`, async-result batching, MCP dedupe, and `display.shimmer` modes.
- Added yield queue unit tests for streaming emission, debounced idle batches, stale filtering, and error isolation.
2026-05-22 13:08:51 +09:00
can1357 39f34ada70 feat: added pure-JS sanitizeText
- Migrated sanitizeText from pi-natives to pi-utils as a pure-JS implementation, removing the native dependency across all call sites.
2026-05-16 20:12:26 +02:00
can1357 feb6c74c84 feat(agent): implemented header-based gateway detection in agent telemetry
- Added MockResponse metadata fields and invoked onResponse pre-stream with lowercased headers, status fallback, and requestId.
- Wrapped request onResponse in agent-loop, captured response headers, and forwarded them with baseUrl to finish/fail span handling.
- Added detectGatewayFromHeaders export and pi.gen_ai.gateway.* span attributes via header-based gateway detection.
- Extended telemetry event/span payloads with responseHeaders and validated detection-priority and onResponse forwarding in tests.
2026-05-15 23:46:23 +02:00
can1357 3c6d2346ad fix(agent): corrected run telemetry counters, cached input tokens, and span hook safety
- Skipped tool double-count: runTool's interrupt early-return no longer records the skipped tool inline; the post-batch tail sweep now handles accounting once per record so a single queued steering cancellation no longer logs N+1 skips.
- Aborted/errored assistant messages with embedded tool calls now record a collector orphan with status 'aborted' or 'error', so coverage.toolsInvoked and tools counters reflect them.
- run-collector chat record now stores inputTokens = input + cacheRead + cacheWrite, matching ChatUsageEvent and the public AgentRunSummary contract.
- onSpanStart and onSpanEnd hook invocations are wrapped in safeOnSpanStart/safeOnSpanEnd; thrown user callbacks surface via onTelemetryWarning (on_span_start_failed / on_span_end_failed) instead of leaking through finishChatSpan/finishExecuteToolSpan/finishInvokeAgentSpan/recordHandoff.
- summarizeTelemetryValue gained a depth+ancestor guard for arrays (matching the existing object recursion guard); cycles return '[Circular]' and over-depth returns the bounded {kind:'array',length} sentinel.
2026-05-15 17:48:02 +02:00
can1357 2867e1f4e3 feat(deps): added pi.zod exports and removed TypeBox package exports
- Added canonical `pi.zod` schema API exports and removed TypeBox package exports/imports.
- Migrated Tool schema typing from TypeBox to shared `TSchema`/Zod flow with legacy TypeBox compatibility.
- Updated AI provider adapters and MCP/agent builders to convert tool params through `toolWireSchema()`.
- Reworked schema validation from AJV to Zod-safe parsing with `fromTypeBox`, `toolWireSchema`, and meta schema checks.
2026-05-15 14:46:54 +02:00
can1357 80103f383d feat(agent): added OpenAI/PiGenAI OTEL constants and run summaries
- Swapped deprecated telemetry keys for OpenAIAttr/PiGenAIAttr constants, including tool intent keys.
- Normalized provider names via mapProviderNameToOtel and emitted OTEL pi.gen_ai fields on chat/request/response spans.
- Revised usage and aggregate telemetry to include cache-token totals plus failed and skipped step counts in run summaries.
- Updated OTEL and run-summary tests to use z.object schemas and renamed GenAI/PiGenAI attribute assertions.
2026-05-15 14:46:54 +02:00
can1357 7cb7c8313d feat(agent): added onChatUsage hook for chat usage telemetry
- Added `onChatUsage` telemetry configuration and `ChatUsageEvent` payload so each chat step with usage now emits a usage event without requiring a cost estimator.
- Updated chat span completion paths to await async chat usage emission, and emitted `on_chat_usage_failed` warnings when callbacks or hooks reject.
- Awaited `finishChatSpan` in assistant-stream completion and abort flows so telemetry callbacks run before returning from chat completion.
2026-05-15 14:46:54 +02:00
can1357 716b6c8234 feat(agent): added run-end tracking to emit telemetry.onRunEnd only once
- Added `runEnded`/`markRunEnded()` tracking and only fired `telemetry.onRunEnd` once per run.
- Added `agent_end` telemetry support for per-run `telemetry`/`coverage` and `agentLoopDetailed()` with `detailed()`.
- Added `aggregateAgentRunSummaries`/`aggregateAgentRunCoverage` and mapped `execute_tool` outcomes to `blocked` and `skipped`.
- Updated `finishInvokeAgentSpan` to derive failure `error.type`/status text from run status and exception state.
- Added run-summary test helpers covering `agent_end`, aggregation, and `onRunEnd` warning/compatibility scenarios.
2026-05-15 14:46:54 +02:00
can1357 14cc9d6bdc feat(agent): added run-collector exports and agent loop detailed spans
- Added `run-collector` exports, `agentLoopDetailed`, and `agentLoopContinueDetailed` APIs.
- Expanded `agent_end` event payloads with optional `telemetry` and `coverage` fields.
- Added `AgentRunCollector` span tracking with typed chat/tool records and summary/coverage builders.
- Fixed telemetry totals to include interrupted, skipped, and failed tool/chat paths via `failChatSpan` and skip recording.
2026-05-15 14:46:54 +02:00
can1357 4679789cf1 feat(agent): added OTEL spans for agent invoke/chat/tool flows
- Added opt-in telemetry configuration to Agent and session APIs, including Agent#setTelemetry mutator.
- Implemented OpenTelemetry spans for invoke_agent, chat, execute_tool, and handoff paths with metadata and step tracking.
- Added a telemetry helper module, OpenTelemetry request/usage types, and dependency wiring with no-op behavior when tracer SDK is absent.
- Added OTEL end-to-end tests and fixed coding-agent OutputSink realignment and artifact-link newline output issues.
2026-05-15 14:46:53 +02:00
can1357 c29fe28dbb feat(agent): add beforeToolCall and afterToolCall hooks
Mirrors the pi-mono API surface so apps can preflight tool execution
(block or mutate validated args) and post-process tool results
(override content/details/isError) without wrapping tools.

- `AgentLoopConfig.beforeToolCall` runs after argument validation. Return
  `{ block: true, reason }` to short-circuit with a tool-error result.
  Mutations to `context.args` are forwarded to `tool.execute` without
  revalidation, matching pi-mono semantics.
- `AgentLoopConfig.afterToolCall` runs after execution and before
  `tool_execution_end` / tool-result message emission. Returned fields
  override the executed result; omitted fields fall through. Hook
  exceptions surface as tool errors and do not abort the batch.
- `Agent` exposes both hooks as public, reassignable fields so extension
  reloads can swap implementations mid-session.

Compatibility: fully additive. Both hooks default to undefined and the
loop behaves identically when neither is set. The internal
`executeToolCalls` signature was collapsed to `(context, message,
signal, stream, config)` -- it is not exported, so this is not a public
API change. Pi-mono's `terminate` field on `AfterToolCallResult` is
omitted because our `AgentToolResult` has no batch-level early-stop
contract.
2026-05-15 09:16:44 +02:00
can1357 f1f6516056 refactor: reorganized exports and removed obsolete helper branches
- Removed export leakage by demoting many helper and const symbols to module-local scope.
- Renamed underscore-prefixed internals and cache fields, then updated related references and `satisfies never` checks.
- Deleted obsolete logic branches and helpers, including harmony-stream interruption flow and unused benchmark runtime helpers.
- Updated Biome config and manifests by broadening lint coverage and removing an unused `@napi-rs/cli` dev dependency.
- Adjusted tests and utilities to use renamed test helpers and remove redundant private test-only helpers/locals.
2026-05-14 04:36:19 +02:00
can1357 4623e7d3ea fix(coding-agent): marked streaming edit aggregates as errors when per-path edits fail
- Stored a failure counter during single-path edit execution and set isError on aggregate results when any entry edit failed.
- Set streaming-edit handling to always evaluate auto-generated-file checks, but only primed the file cache when edit.streamingAbort was enabled.
2026-05-12 04:44:38 +02:00
can1357 8b92ec937e feat: gpt-5 harmony errata fixes
- Replaced `===== ... =====` eval cell headers with `*** Begin ` / `*** End ` markers; legacy format remains renderable in HTML exports.
- Replaced hashline patch grammar with `*** Begin Patch` / `*** End Patch` envelope; old inputs without the envelope are still accepted.
- Extracted `sniffEvalLanguage` into a shared `sniff.ts` module reused by the parser and tool.
- Added `docs/ERRATA-GPT5-HARMONY.md` and `scripts/session-stats/harmony_backtest.py` documenting and backtesting the GPT-5 Harmony-header leak defect.
2026-05-10 19:52:44 +02:00
Miroslav Drbal fc70a45c46 fix(ai): stable metadata.user_id per session for Anthropic OAuth
Anthropic counts sessions by metadata.user_id. Without this fix, OMP
generated fresh random entropy on every API request, inflating the
session count and preventing backend attribution to the authenticated
account.

Changes:

packages/ai:
- resolveAnthropicMetadataUserId() now accepts JSON-format user_id
  matching real Claude Code's getAPIMetadata shape
  ({ session_id, account_uuid, ... }). Previously only the legacy
  cloaking format was accepted on OAuth, causing stable caller-supplied
  values to be silently discarded.
- AnthropicOAuthFlow.exchangeToken() and refreshAnthropicToken() now
  populate OAuthCredentials.{accountId, email} from the token response
  account block, removing the need for a separate /api/oauth/profile
  round-trip.
- AuthStorage.getOAuthAccountId(provider, sessionId) returns the OAuth
  accountId for the session-sticky credential, used to build
  account_uuid in metadata.user_id. Guards against misattribution for
  API-key, runtime-override, env-key, and fallback-resolver paths that
  do not record a session credential.

packages/agent:
- Agent.metadataForProvider(provider) resolves request metadata for
  the given provider via the installed resolver, or returns the static
  metadata value. The plain metadata getter now returns only the static
  value; provider-aware resolution is explicit.
- Agent.setMetadataResolver(fn) installs a (provider: string) resolver
  evaluated per LLM request in agent-loop, after getApiKey records the
  session-sticky credential, so account_uuid reflects the credential
  actually used.
- AgentLoopConfig.metadataResolver is called with config.model.provider
  after getApiKey, overriding the static metadata field.

packages/coding-agent:
- AgentSession.#syncAgentSessionId installs a metadata resolver that
  builds { user_id: JSON.stringify({ session_id, account_uuid? }) },
  matching the Anthropic session attribution format. account_uuid is
  only included for provider="anthropic" to avoid leaking the OAuth
  identity to third-party Anthropic-format-compatible providers.
- sessionId getter prefers providerSessionId when supplied via
  AgentSessionConfig so all API paths (getApiKey, direct calls,
  metadata resolver) share the same provider-facing session ID.
- prepareSimpleStreamOptions stamps session metadata on direct calls
  (runEphemeralTurn, compaction, branch summary, title generation) so
  they share the same session bucket as Agent.prompt requests.
- generateBranchSummary and generateSessionTitle accept a
  (provider: string) metadata resolver evaluated after their own
  getApiKey call for correct credential attribution.
2026-05-09 09:48:10 +02:00
can1357 1a2869444e fix(agent): coerced malformed tool results before downstream agent processing
- Added a boundary normalizer that validated tool output shape and replaced malformed responses with a fallback text-only result.
- Updated tool execution to coerce both streaming partial updates and final tool results through that normalizer.
- Set the tool call error state when a malformed result was detected by the coercer.
2026-05-07 04:36:40 +02:00