Commit Graph
10553 Commits
Author SHA1 Message Date
can1357 cf4da4d786 Merge #3437 + reconcile with #3439: unified cross-API reasoning preservation
#3437 (preserve cross-api reasoning replay) and #3439 (preserve 3p thinking blocks across cross-API switches) both rewrite the thinking-block path of transform-messages.ts and the encoder in openai-completions.ts to fix issues #3433/#3434, and overlap structurally. Reconciled into one resolved-compat design:

- transform-messages.ts threads the request-time resolved compat (from #3437) into the predicate, replacing #3439's base+whenThinking union traversal. resolveOpenAICompatPolicy already swaps in whenThinking for thinking-on requests, so the predicate and encoder stay in lockstep (closes both Codex 'use resolved compat' reviews and keeps the #1071/#1484 OpenCode paths correct).

- The predicate keeps #3439's broad coverage: preserve a native, signature-stripped thinking block when the resolved openai-completions target is reasoning-capable, not requiresThinkingAsText, and either requiresReasoningContentForToolCalls or thinkingFormat==='zai'. Other cross-API targets text-demote.

- openai-completions.ts keeps #3439's Z.AI-format encoder branch and #3437's compat threading, but drops #3439's text-fold fallback and isSameModelHistory: under threading they are unreachable (any preserved cross-model block is consumed by the requiresReasoningContentForToolCalls or zai branch; thinking-off targets text-demote in transform). Markup-healed same-model thinking still falls through unemitted, as before.

Regression tests from both PRs retained. Fixes #3433, #3434.
2026-06-25 06:31:22 +02:00
can1357 df1a88248e Merge #3439: preserve 3p thinking blocks across cross-API switches 2026-06-25 06:23:32 +02:00
roboomp 57882ac307 fix(ai): skip text-fold fallback for same-model unsigned thinking
Markup-healed streams (MiniMax M3 \`<think>…</think>\`, Kimi K2 healed
reasoning, every \`getStreamMarkupHealingPattern === "thinking"\` host)
reconstruct thinking blocks from raw text deltas, so the resulting
\`ThinkingContent\` lands with \`thinkingSignature: undefined\`. On a
same-model continuation those blocks are PRIVATE reasoning the source
emitted, not cross-API preserved reasoning — promoting them into the next
request's visible \`content\` would leak hidden chain-of-thought.

The text-fold fallback added in 8f7fb1d for cross-API preserved blocks now
gates on \`!isSameModelHistory\` before firing. Same-model history keeps the
legacy behavior of silently dropping unsigned thinking when no per-compat
branch consumes it, matching pre-#3434 semantics. Cross-API replays
(different api, provider, or model id) still fold to content so the
reasoning chain at least survives as conversation context.

Tests: \`issue-3434-repro.test.ts\` adds a pin for same-model unsigned
thinking on \`opencode-go\`/Kimi — visible content stays exactly the model's
visible answer, no reasoning_content / reasoning / reasoning_text on the
wire.

\`bun test packages/ai\`: 2297 pass / 1 fail (the same \`proxy.test.ts\`
\`Bun.env\` leak that fails on \`main\`). \`bun check\` passes.

Addresses chatgpt-codex-connector P2 review on #3439.
2026-06-25 04:20:06 +00:00
roboomp 8f7fb1d074 fix(ai): consult compat.whenThinking when gating cross-API thinking replay
The cross-API preservation predicate added in the parent commit read only
\`model.compat\`, so it missed the resolved \`compat.whenThinking\` view that
OpenCode-hosted reasoning models (Kimi/GLM/DeepSeek/Qwen/MiMo via \`opencode-go\`
/ \`opencode-zen\`) require:

- Base compat keeps \`requiresReasoningContentForToolCalls: false\` so
  thinking-disabled requests dodge \`Extra inputs are not permitted\` (#1071).
- \`compat.whenThinking\` reactivates the flag for thinking-engaged requests
  so they dodge \`thinking is enabled but reasoning_content is missing\` (#1484).

The old predicate read the base compat, so a cross-API switch into an
OpenCode reasoning model still demoted the prior thinking to text and the
next thinking-on request re-triggered #1484. The predicate now folds both
views (base + \`whenThinking\`) through a shared \`acceptsReasoningContentReplay\`
helper; if either view permits replay, the block is preserved.

Encoder companion fix in \`openai-completions.ts\`: when preserved cross-API
thinking reaches a request whose resolved compat can't surface
\`reasoning_content\` (most often OpenCode in thinking-disabled mode), fold
the reasoning into the visible content. Same shape as
\`requiresThinkingAsText\`, but gated on signature-stripped blocks only, so
same-model replays (which keep the streaming signature) are untouched. This
preserves the pre-#3434 text-demotion semantics for that branch without
silently dropping the reasoning chain.

Tests: \`packages/ai/test/issue-3434-repro.test.ts\` now also pins:
- OpenCode \`whenThinking\` compat surfaces \`reasoning_content\` from the
  preserved block (guards against re-opening #1484 on cross-API switch).
- OpenCode base compat (thinking off) folds the preserved block into
  content (guards against silently dropping the reasoning chain).

\`bun test packages/ai\`: 2296 pass / 1 fail; the lone failure
(\`proxy.test.ts > normalizes hyphenated provider ids to underscores\`)
is the same pre-existing \`Bun.env\` leak from a sibling test that fails on
\`main\`. \`bun check\` passes.

Addresses chatgpt-codex-connector review on #3439.
2026-06-25 04:11:30 +00:00
roboomp 57f2c646c6 fix(ai): used resolved compat for reasoning replay
Threaded the resolved OpenAI completions compat into transformMessages so thinking-enabled request policy controls cross-API reasoning preservation.

Added coverage for Kimi/OpenCode replay where base compat is false but the thinking-enabled policy requires reasoning_content.

Fixes #3433
2026-06-25 03:57:32 +00:00
roboomp c30e647ec5 fix(ai): preserve 3p thinking blocks across cross-API switches
On a mid-session switch between an Anthropic-compatible 3p endpoint and an
OpenAI-compatible 3p endpoint on the same vendor (Z.AI Anthropic → Z.AI OpenAI,
Kimi Anthropic → Kimi OpenAI, custom \`models.yaml\` switches that cross API
types), \`transformMessages\` demoted every prior \`thinking\` block to plain
text on the cross-API path. The next request shipped the reasoning chain as
conversation text instead of structured \`reasoning_content\`, so the target
model lost the prior reasoning context and the source-side reasoning tokens
were paid for twice.

Two-half fix:

1. \`packages/ai/src/providers/transform-messages.ts\` — the cross-API thinking
   path now preserves the prior reasoning as a native, signature-stripped
   \`thinking\` block whenever the \`openai-completions\` target can re-emit it
   on the wire (\`requiresReasoningContentForToolCalls\` or
   \`thinkingFormat: "zai"\`). The source wire-format signature is always
   stripped because it is bound to the source API (Anthropic crypto sig /
   OpenAI Responses encrypted blob) and useless to the target.
2. \`packages/ai/src/providers/openai-completions.ts\` — the encoder now
   surfaces preserved thinking blocks via \`reasoningContentField\` for
   Z.AI-format hosts that don't strictly require the field, so a preserved
   block with a stripped/opaque signature still ships as
   \`reasoning_content\` on the wire.

Other cross-API targets (openai-responses encrypted blobs, google signed
thought parts, anthropic-from-foreign-source) keep the existing text-demotion
fallback so reasoning still survives as visible conversation context.

Tests:
- New \`packages/ai/test/issue-3434-repro.test.ts\` pins the Z.AI → Z.AI,
  Anthropic 3p → DeepSeek, and Anthropic 3p → official-OpenAI-non-reasoning
  wire shapes; all 4 tests fail on \`main\` and pass after the fix.
- \`bun test packages/ai\`: 2294 pass / 1 fail; the one failure
  (\`proxy.test.ts > normalizes hyphenated provider ids to underscores\`) also
  fails on \`main\` from a \`Bun.env.PI_PROXY_*\` leak in a sibling test and is
  unrelated to this diff.

Fixes #3434
2026-06-25 03:57:17 +00:00
roboomp 256631bbf5 fix(ai): preserved cross-api reasoning replay
Preserved cross-API thinking blocks for OpenAI-compatible reasoning targets so the completions encoder can write them to the configured reasoning_content field after signatures are stripped.

Added regression coverage for Anthropic-message history replayed through DeepSeek-compatible chat completions.

Fixes #3433
2026-06-25 03:48:07 +00:00
can1357 1a89d784e7 chore: bump version to 16.1.18 2026-06-25 05:17:47 +02:00
can1357 366313df33 test(coding-agent): improved stdout geometry stubs in tests
- Added no-op setters to process.stdout properties in test geometry stubs.
- Prevented potential errors when code under test attempts to reassign stdout dimensions.
2026-06-25 05:15:40 +02:00
can1357 72f121ee2c chore: update changelogs 2026-06-25 05:13:23 +02:00
can1357 fb43fbe9a7 refactor(coding-agent): drop dead legacy-pi bundled test seams
Remove `__getLegacyPiBundledRegistry` and `__synthesizeLegacyPiBundledSource`:
both reject outside compiled-binary mode, so no unit test can call them — they
were untested test seams. Real coverage runs through the pure
`__synthesizeLegacyPiBundledSourceWithRegistry` + `__getLegacyPiBundledRegistryGlobal`.

Also document why the synthesized virtual module must bridge back to the host
registry through `globalThis` (separate ES module, no shared closure scope,
live non-serializable exports) so the indirection isn't mistaken for cruft.
2026-06-25 05:12:14 +02:00
can1357 0cd852053e Merge branch 'farm/6a62fa2b/fix-bunfs-override-validation-fallback'
Serve bundled pi-* and TypeBox through an in-process virtual namespace
on Bun 1.3.14+ where `--compile` extras are unreachable via any
filesystem API (issue #3423).

Merge resolution:
- Reconciled `TYPEBOX_SHIM_PATH` with main's #3414 fall-through:
  `__resolveTypeBoxShimPath(isCompiled, sourcePath, exists)` returns the
  `omp-legacy-pi-bundled:` virtual specifier in compiled mode (no FS
  probe) and the on-disk source path otherwise, dropping to null when
  the shim file is missing so bare typebox imports fall through to native
  resolution.
- Removed the now-dead `--compile` extras path: dropped
  `LEGACY_COMPAT_BUILD_ENTRYPOINTS` usage from both build-binary.ts and
  ci-release-build-binaries.ts and deleted scripts/binary-entrypoints.ts;
  the bundler reaches every surface via legacy-pi-bundled-registry.ts.
- Deleted obsolete tests for the removed bunfs machinery
  (legacy-pi-compat-entrypoints, legacy-pi-typebox-shim-validation) and
  added regression coverage for __resolveTypeBoxShimPath.
- Dropped the binary-compiling smoke driver per maintainer request.

Verified: bun check clean; 77 extensibility tests pass; instrumented
compiled-binary run confirmed onLoad fires for all bundled specifiers.
2026-06-25 05:08:36 +02:00
can1357 3e1d5fce12 feat(coding-agent): filtered out non-reportable accounts in usage CLI
- Add `usageProviderFor` helper to `AuthStorage` to distinguish between providers without usage endpoints and missing data.
- Implement account filtering in the usage CLI to exclude providers that do not support usage reporting unless explicitly requested.
- Improve CLI diagnostic messages when no usage data is retrieved by differentiating between missing credentials and unsupported providers.
2026-06-25 04:44:36 +02:00
roboomp 294d41bd3b fix(coding-agent): served bundled pi-* through virtual ns on bun 1.3.14
Bun 1.3.14 stopped exposing `--compile` extras through every filesystem-style API: `fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, and `await import()` on `/$bunfs/...` or `file:///$bunfs/...` all fail; only `/$bunfs/root/<binary-name>` itself answers. The pre-existing legacy-pi rewrite emitted `file:///$bunfs/...` URLs that Bun then could not load, so every legacy extension that imported `@oh-my-pi/pi-*` or `@sinclair/typebox` failed on the `omp-darwin-arm64` release binary.

`legacy-pi-compat.ts` now keeps a JS-heap reference to every bundled pi-* surface in a lazy-loaded sibling `legacy-pi-bundled-registry.ts` and serves them through an `omp-legacy-pi-bundled:` virtual namespace whose `Bun.plugin().onLoad` synthesizes a re-export module — no bunfs path ever leaves the module in compiled mode. Dev / source-link / installed-package modes keep the historical `file://` rewrite (source files exist on disk). The matching `--compile` extras in `scripts/build-binary.ts` are gone; `BUNFS_PACKAGE_ROOT`, `bunfsPath`, `__computeBunfsPackageRoot`, and `__joinBunfsPath` are deleted as dead code. `scripts/smoke-3423.ts` compiles a tiny binary that loads a fixture extension end-to-end through the new path.

Fixes #3423
2026-06-25 02:35:50 +00:00
can1357 591f1c5765 feat(ai): implemented idempotent credential refresh with CAS logic
- Added id-based credential persistence and CAS-based invalidation to prevent cross-process race conditions.
- Categorized OAuth failure responses into transient and definitive types for more resilient refresh orchestration.
- Enabled stable credential lookups during refresh to ensure integrity during peer rotation or index shifts.
- Validated new persistence and error handling logic through comprehensive concurrency and failure-mode tests.
2026-06-25 04:31:58 +02:00
can1357 61b430da9d feat(ai): added focused oauth account selection and listing
- Added listOAuthAccounts and getOAuthAccessAt to permit targeted credential retrieval without impacting sibling accounts.
- Implemented sameOAuthIdentity helper to ensure resolution consistency when manually selecting accounts.
- Added --list and --account CLI flags to token command for inspecting and choosing specific credentials.
2026-06-25 04:18:10 +02:00
can1357 08a9f837e9 Merge remote-tracking branch 'origin/farm/ecbccfbb/fix-codex-image-input' 2026-06-25 04:03:17 +02:00
can1357 b54cb1f58e Merge remote-tracking branch 'origin/farm/73774d66/typebox-shim-missing-on-bunfs' 2026-06-25 04:02:55 +02:00
can1357 e2c85d9d21 Merge remote-tracking branch 'origin/farm/c748dce5/fix-append-only-context-log-rewrite' 2026-06-25 04:02:51 +02:00
can1357 27ed9f7af7 feat(coding-agent): enabled mouse navigation and fullscreen mode for extension dashboard
- Implemented SGR mouse event routing for dashboard interaction, including tab selection and pane scrolling.
- Added mouse-driven list manipulation in the extension viewer with selection highlighting, click toggling, and wheel navigation.
- Enabled fullscreen alternate-screen behavior and host terminal mouse tracking for the dashboard overlay.
- Integrated hit-testing and row selection logic into the extension list to support unified mouse and keyboard inputs.
2026-06-25 04:02:34 +02:00
roboomp 46c1410c27 style: bun run fix 2026-06-25 01:34:23 +00:00
roboomp 04bfce62c6 fix(ai): disabled codex lite for image prompts
Codex Responses Lite only accepts text input, so GPT image prompts with input_image failed before reaching the full multimodal transport.

The request transformer and Codex headers now fall back to full Responses whenever a request body contains input_image, with regression coverage for the lite header.

Fixes #3421
2026-06-25 01:34:07 +00:00
roboomp 08977b226d fix(release): restored legacy pi-compat --compile entrypoints in release builds
- Extracted the legacy `--compile` entrypoint list to `scripts/binary-entrypoints.ts` and consumed it from both the release CI script and the local dev `build-binary.ts`, so the two cannot drift apart.
- `scripts/ci-release-build-binaries.ts` no longer ships release binaries without the typebox shim, legacy pi shims, and `@oh-my-pi/{agent,natives,tui,utils}` package barrels in bunfs. Commit dc5c93462f removed worker entrypoints and false-comment-claimed the legacy entrypoints were "still" listed, so every published `omp-<platform>-<arch>` since shipped without them and the resolver emitted bunfs URLs to missing files.
- Validated TYPEBOX_SHIM_PATH at module init via __resolveTypeBoxShimPath, mirroring __validateLegacyPiPackageRootOverrides (#2168). When the shim is absent the rewriter leaves bare typebox / @sinclair/typebox imports alone so Bun falls through to native node_modules resolution.
- Pinned both halves of the contract with tests: release+dev scripts must source from the shared constant, every shim path computed in legacy-pi-compat.ts must appear in it, and __resolveTypeBoxShimPath drops missing candidates.

Fixes #3414
2026-06-25 00:14:41 +00:00
roboomp 2b68785e82 fix(agent): include provider payloads in append-only digests
Responses-style providers serialize providerPayload history items instead of the
visible message blocks when replaying native history. Include providerPayload in
the append-only per-message digest so payload-only history rewrites stop the
stable-prefix walk and re-sync the changed message before any later divergent
tail.

Add a regression where an assistant message keeps identical visible content and
id but changes its openaiResponsesHistory providerPayload while a later message
also diverges; syncMessages must preserve the prefix before the assistant and
refresh the assistant payload.

Fixes #3406
2026-06-24 23:11:12 +00:00
roboomp 5b9e009a8b fix(agent): bound append-only stable prefix by log length
Direct callers can clear AppendOnlyContextManager.log without resetting the
private sync cursor. The advisor reset path does this when recycling its helper
agent, leaving lastSyncCount and messageDigests describing the old transcript
while the physical log is empty.

Clamp the stable-prefix reuse count to the current log length before truncating
and appending. A direct log clear now forces the next sync to replay from index 0
instead of starting from a stale private cursor and dropping prefix messages from
the provider context.

Add a regression that clears the public log after syncing two messages, then
resyncs a context with the same first message and a rewritten second; both
messages must be present in the rebuilt append-only log.

Fixes #3406
2026-06-24 23:07:11 +00:00
roboomp a2471339a7 test(coding-agent): cover subagent append-only context rewrites
Add a createAgentSession-based subagent regression for issue #3406. The test
runs a taskDepth=1 session against a loopback llama.cpp-style model so
provider.appendOnlyContext auto-enables through the SDK path used by task
subagents.

A real context extension rewrites the prior assistant turn on the second
subagent request. The captured provider contexts assert the first request's user
message object is reused in the second request, proving the append-only log kept
the stable prefix instead of clearing and re-rendering it for subagents.

Fixes #3406
2026-06-24 23:00:19 +00:00
roboomp cce627ee4b fix(agent): include tool result metadata in append-only digests
Track internal tool-result metadata in append-only per-message digests so
metadata-only rewrites of toolCallId, toolName, or isError stop the stable-prefix
walk and re-sync the changed tool result before any later divergent tail.

This prevents stale tool-result pairing or error state from being preserved when
the text content stays unchanged but provider-serialized metadata changes.

Fixes #3406
2026-06-24 22:42:51 +00:00
roboomp c803a3e30d style: bun run fix 2026-06-24 22:35:03 +00:00
roboomp 65a974aa90 fix(agent): preserve append-only log prefix on in-place message rewrites
`AppendOnlyContextManager.syncMessages` hashed a single rolling digest
over the entire synced prefix, so any in-place rewrite of an already-
synced message — per-turn `pruneSupersededToolResults` / `pruneToolOutputs`
collapsing a tool result, image stripping, or a `transformContext` re-render
— triggered `log.clear()` and re-appended the full conversation from
the current (mutated) view. The provider's cached bytes still matched
the prefix, but every position past the divergence had to be re-prefilled.
On llama.cpp / Ollama / LM Studio this re-prefilled tens of thousands
of tokens every few turns (`n_past \u2248 end-of-system-prompt` collapse,
~40k-token full re-prefill, GPU pinned >400W).

Replace the rolling digest with per-message digests in `#messageDigests`,
walk the new sync against them to find the longest byte-stable prefix,
truncate the log down to that prefix via a new `AppendOnlyLog.truncate(count)`,
and only re-append the diverged tail. Genuine compaction (`length <
lastSyncCount`) still clears the log.

- Tail-only rewrite: prefix stays byte-stable; only the trailing message
  re-syncs.
- Deep rewrite: prefix up to the divergence stays byte-stable; the
  provider re-prefills from the divergent message onward (architectural
  minimum).
- True compaction: unchanged, full replay.

Replace the now-misleading `detects in-place rewrite of already-synced
messages` / `detects in-place rewrite via digest mismatch` tests with
`preserves the byte-stable prefix when a deep message is rewritten (#3406)`,
`preserves the prefix when the tail is rewritten (#3406)`, `appended
new messages keep the prefix stable even when the prior tail also
diverged (#3406)`, and `rewriting the first message still re-syncs
from scratch` so each invariant is asserted directly.

Fixes #3406
2026-06-24 22:33:22 +00:00
can1357 8d60776a6f chore: bump version to 16.1.17 2026-06-24 21:11:31 +02:00
roboompandcan1357 8739a78d69 fix(ai): honored long cache retention for openrouter anthropic responses
Mapped cacheRetention="long" to cache_control.ttl="1h" on OpenRouter Anthropic Responses requests; guarded against overwriting a caller-supplied cache_control.\n\nRefs #3397
2026-06-24 21:08:46 +02:00
can1357 90c8f8251a Merge remote-tracking branch 'origin/farm/3d137ac8/openrouter-anthropic-reasoning-replay' 2026-06-24 21:07:21 +02:00
can1357 23838ba80b chore: update changelogs 2026-06-24 21:03:29 +02:00
can1357 9ad17a2b49 ux(coding-agent/modes): removed hotkeys tip from welcome component
- Removed the hotkeys tip from the welcome screen UI.
2026-06-24 21:01:55 +02:00
can1357 0eb21efa1a Merge remote-tracking branch 'origin/farm/7ef98714/snapcompact-copilot-vision-gate' 2026-06-24 21:00:37 +02:00
can1357 79193e8e78 Merge remote-tracking branch 'origin/farm/e725242d/fix-openrouter-anthropic-cache' 2026-06-24 21:00:23 +02:00
can1357 45ade3ef9d Merge remote-tracking branch 'origin/farm/d5c3021f/tmux-notification-bell-passthrough' 2026-06-24 21:00:19 +02:00
can1357 4c4fb21caa Merge remote-tracking branch 'origin/farm/cf20a2c7/clamp-ollama-cloud-max-output-tokens' 2026-06-24 21:00:03 +02:00
can1357 e59cfececf Merge remote-tracking branch 'origin/farm/f9a71625/anthropic-headers-override' 2026-06-24 20:59:59 +02:00
can1357 0f2737f16e Merge remote-tracking branch 'origin/farm/e322f828/eval-agent-yield-terminal' 2026-06-24 20:59:54 +02:00
roboomp ebdce456dc fix(providers): stripped openrouter anthropic reasoning replay
Fixes #3399
2026-06-24 18:57:33 +00:00
roboomp c4ce8a8b31 fix(ai): enabled openrouter anthropic responses caching
Added OpenRouter Anthropic Responses cache_control wiring and request-capture coverage.\n\nFixes #3397
2026-06-24 18:24:46 +00:00
roboomp d8d037e8ac style: bun run fix 2026-06-24 18:07:25 +00:00
roboomp 28e1caec69 fix(tui): deliver notifications under tmux via DCS passthrough + BEL fallback
When the inner-terminal env markers (KITTY_WINDOW_ID, GHOSTTY_RESOURCES_DIR,
WEZTERM_PANE, ITERM_SESSION_ID) leak into a tmux session, TERMINAL_ID
resolves to the inner terminal and notifyProtocol becomes OSC 9 / OSC 99.
sendNotification() wrote that raw OSC straight to stdout, but tmux does not
forward bare OSC 9/99 to the outer terminal and the bare sequence does not
flag tmux's own monitor-bell / monitor-activity — so a backgrounded omp pane
under the common tmux + kitty/ghostty/wezterm/iTerm2 stack had no signal at
all for completion or 'ask' blockage.

Under TMUX, OSC-protocol notifications are now wrapped in tmux's
\x1bPtmux;…\x1b\\ DCS passthrough envelope (so users with
allow-passthrough on still get the real desktop toast) and followed by a
\x07 BEL (so monitor-bell flags the window otherwise — the standard
'needs attention' workflow). The OSC 99 capability probe is wrapped the
same way so rich notifications keep working across tmux. Bell-protocol
paths are unchanged.

Fixes #3395
2026-06-24 18:07:14 +00:00
roboomp 0edb3d32b8 fix(ai/ollama): clamped num_predict at the 65536 Ollama Cloud cap
Ollama Cloud rejects any chat request whose options.num_predict exceeds
65536 with HTTP 400, but the existing safety relied on the load-time
omitMaxOutputTokens policy in model-registry.ts. Stale models.db rows
predating that policy (and custom modelOverrides re-enabling output
caps) carried maxTokens: 1048576 forward to the wire layer untouched,
so every request to deepseek-v4-pro / deepseek-v4-flash 400'd with:

  max_tokens (1048576) exceeds model's maximum output tokens (65536)
  for model deepseek-v4-pro

createChatBody now resolves num_predict through resolveNumPredict,
which clamps every ollama-cloud request at the documented cap before
serialization — independent of the cached spec, on top of the existing
omitMaxOutputTokens path. Self-hosted ollama traffic is unaffected.

Fixes #3392
2026-06-24 17:29:28 +00:00
roboomp d2e06fc9d0 fix(ai/anthropic): honored caller-supplied Authorization/X-Api-Key for custom proxies
`buildAnthropicHeaders` filtered `Authorization` and `X-Api-Key` out of
`model.headers` (and `ANTHROPIC_CUSTOM_HEADERS`) via `enforcedHeaderKeys`,
then re-attached the auto-built `Bearer <apiKey>` / `X-Api-Key: <apiKey>`,
so custom-proxy users could never override anthropic-messages auth — unlike
`openai-responses` (`headers.Authorization ??= Bearer apiKey`) and the
GitHub Copilot anthropic branch (`mergeHeaders(..., model.headers, ...)`).

Non-OAuth, non-Cloudflare branches now honor the caller's `Authorization` /
`X-Api-Key`; case-insensitive capture keeps the spread free of duplicate
keys. OAuth still forces `Authorization: Bearer <oauth-token>` (the OAuth
credential itself) and Cloudflare AI Gateway still owns
`cf-aig-authorization` — both drop + log caller overrides.

`buildAnthropicClientOptions` no longer requires the surviving
`Authorization` to start with `Bearer ` before suppressing the
client-level `X-Api-Key`; any custom Authorization on a non-official
endpoint suppresses it so the proxy gets a single credential.

Fixes #3391
2026-06-24 17:21:25 +00:00
roboomp 997b2b24ff fix(session): suppressed empty-stop retry after successful yield
Trailing empty assistant 'stop' arriving after a successful 'yield'
revived the already-yielded subagent. AgentSession.agent_end maintenance
compared #assistantEndedWithSuccessfulYield(msg) against the trailing
empty-stop message — not the yield-bearing one — so the empty-stop
recovery path appended a retry reminder and scheduled agent.continue().

Track a sticky #yieldTerminationPending flag set when the yield tool
finishes without error and cleared on the next #promptWithMessage. The
agent_end routing extends the existing successful-yield branch: when the
flag is set, or the current message ended with yield, short-circuit
empty-stop / unexpected-stop / compaction continuations for the rest of
the run, so a successful yield is terminal regardless of trailing stops.

Fixes #3389
2026-06-24 17:08:49 +00:00
can1357 a4dbe6396c style: biome organize-imports on merged test files (#3193, #3312) 2026-06-24 19:03:32 +02:00
can1357 ff2280e6ee chore(changelog): normalize [Unreleased] after merge sweep (fix-changelogs --since baseline; dedup #3258) 2026-06-24 18:46:00 +02:00
can1357 7b619400fd Merge PR #1800: fix(tui): runtime Hangul Compatibility Jamo width override + Ghostty detection (@ZergRocks) 2026-06-24 18:43:01 +02:00