Commit Graph
1437 Commits
Author SHA1 Message Date
can1357 b8e4da23d0 ci(ci): refactored CI setup and test-state isolation for coding-agent workflows
- Added a setup-system-deps action with preloaded-runner guards and apt fallbacks.
- Updated CI workflows to download Linux x64 native artifacts and gate on native job success.
- Renamed coding-agent fast mode to singleton in scripts and test partitioning logic.
- Added settings test-state begin/restore helpers with recursive cleanup in affected tests.
2026-06-14 22:37:05 +02:00
Can BölükandGitHub be90624863 Merge pull request #2570 from usr-bin-roygbiv/fix/openai-responses-error-nesting
fix: handle nested error object in openai responses stream
2026-06-14 17:17:54 +02:00
can1357 b883283673 Merge remote-tracking branch 'origin/farm/3a98e2ea/duplicate-reasoning-message' 2026-06-14 17:10:19 +02:00
can1357 53b20e3ec6 Merge remote-tracking branch 'origin/farm/2a0f0068/fix-gitlab-duo-oauth-redirect-uri' 2026-06-14 17:10:18 +02:00
can1357 3efebf8805 fix: harden merged provider, agent-loop, eager, and autolearn paths
- agent-loop: raise repetition-detection floor to 180 chars and clear thinking
  replay anchors when collapsing a detected loop.
- providers/google: ignore empty text parts, retain terminal thoughtSignatures,
  and stop function-call signatures clobbering the prior block.
- autolearn: capture goal-mode at the turn boundary; harden managed-skill writes
  against hard-links/symlinks (O_NOFOLLOW + nlink); refuse minting managed skills
  whose name an authored skill already claims.
- eager tasks: thread agentKind through the session so a custom top-level agentId
  still gets always-mode delegation; split Eager Tasks prompt into hard vs soft.
- title-generator: race the online title model against a local tiny-model fallback.
- eager-todo: keep the soft reminder aligned with the todo init schema.
- mcp/stdio: keep close() detaching the read loop instead of awaiting it.
- stream loop: fix collapsing and tool-call thought-signature handling.
2026-06-14 17:09:59 +02:00
can1357 2b94fa8c71 Merge PR #2549: fix(agent-loop): detect repetition loops during assistant stream and abort gracefully 2026-06-14 17:09:41 +02:00
can1357 1b436b775b Merge PR #2543: fix(providers/google): avoid outputting system rules and preambles in Antigravity 2026-06-14 17:09:41 +02:00
can1357 fca6409cf6 Merge PR #2538: fix(providers/google): avoid creating empty text blocks on stream ending 2026-06-14 17:09:41 +02:00
usr_bin_roygbiv b837c9b304 fix: handle nested error object in openai responses stream 2026-06-14 09:55:25 -05:00
can1357 760de18d23 Merge remote-tracking branch 'origin/farm/a1b8f17d/disable-bun-fetch-timeout' 2026-06-14 16:13:38 +02:00
roboomp 67a5cf454f fix(anthropic): drop eager_input_streaming on github-copilot transport
GitHub Copilot's Anthropic-compatible proxy (api.githubcopilot.com/v1/messages) validates tool definitions with additionalProperties: false and rejected every tool-bearing turn with `400 tools.0.custom.eager_input_streaming: Extra inputs are not permitted`. The catalog's Anthropic compat builder defaulted supportsEagerToolInputStreaming to true for all hosts, so convertTools added the flag to every tool sent to Copilot.

Gate the flag on host in buildAnthropicCompat (false for github-copilot, matching the existing supportsLongCacheRetention: official pattern), and stop pushing the legacy fine-grained-tool-streaming-2025-05-14 beta header on the Copilot transport — the proxy doesn't whitelist Anthropic beta features either, so the fallback path would 400 too.

Fixes #2558
2026-06-14 11:00:01 +00:00
roboomp 6855bec715 fix(ai): added pre-response watchdog to direct-use streaming providers
Direct callers of ./providers/{amazon-bedrock,google-gemini-cli,ollama,openai-codex-responses} bypass register-builtins' iterator-level first-event watchdog. With Bun's native ~300s fetch ceiling disabled in #2422, a stalled upstream that accepts the POST and never sends headers would hang forever.

Combine the caller's signal with AbortSignal.timeout(firstEventTimeoutMs) at each fetchWithRetry site so pre-response stalls fail within the configured budget. Bedrock/Gemini use getStreamFirstEventTimeoutMs (Gemini floors at 5min to match its register-builtins limits); Ollama uses getOpenAIStreamFirstEventTimeoutMs floored by getOpenAIStreamIdleTimeoutMs; Codex SSE threads firstEventTimeoutMs through CodexRequestSetup -> openCodexSseTransport -> openCodexSseEventStream.

Verified with an out-of-tree smoke that aborts a stalling Bedrock fetch via streamFirstEventTimeoutMs: 2_000ms — elapsed 2005ms, stopReason error, errorMessage 'Request was aborted'. Smoke discarded per directive.

Refs #2422
2026-06-14 07:30:34 +00:00
roboomp 3a05c41195 fix(ai): persisted minimax cumulative reasoning dedup across block transitions
Cumulative reasoning_content dedup keyed on currentBlock.thinking failed
once </think> and visible text arrived: currentBlock flipped to text, the
guard missed, and the next chunk's cumulative snapshot was re-emitted as
a fresh thinking block after the answer had started.

Replaced the block-scoped check with lastCumulativeReasoningBySignature,
a closure-scoped Map keyed by signature (the reasoning field name) that
holds the last full snapshot regardless of currentBlock state. Cumulative
chunks now slice against this tracker, so post-answer snapshots resolve
to an empty delta and never reinstate a phantom thinking block.

Added a regression test covering the post-text cumulative case.

Fixes #2433
2026-06-14 07:14:10 +00:00
roboomp 041f59d078 fix(ai): disabled bun native fetch timeout in streaming providers
Bun's fetch enforces a hard ~300s pre-response timeout that the caller's AbortSignal cannot lengthen. Every streaming provider's first-event/idle/SDK watchdog was silently capped by it, so cold large-context streams (multi-hundred-K prompts against slow-prefill backends) died at exactly 300s with TimeoutError.

- Added FetchWithRetryOptions.timeout (forwarded to fetch) so fetchWithRetry callers can pass Bun's timeout: false / numeric override directly.
- Passed timeout: false in openai-http, openai-codex-responses, amazon-bedrock, google-gemini-cli, ollama where each provider already constructs the fetch init.
- Added timeout to AnthropicFetchOptions and threaded timeout: false through buildAnthropicClientOptions's fetchOptions; anthropic-client already spreads fetchOptions into every fetch call.
- Allowed compat.streamIdleTimeoutMs: 0 in models.yml so the documented per-model disable knob matches the env-var escape hatch.

Verified with an out-of-tree smoke that stalls a local server 305s before responding: pre-fix the streaming provider died at ~300003ms with the Bun TimeoutError; post-fix the request completes (SUCCESS elapsed=305006ms). The smoke is discarded per directive.

Fixes #2422
2026-06-14 07:13:56 +00:00
roboomp 7251d851de fix(ai): rejected https gitlab duo loopback redirects
GitLab Duo OAuth callback handling now rejects HTTPS loopback redirect URIs before browser auth because the embedded callback server only serves plaintext HTTP.

Fixes #2424
2026-06-14 07:13:07 +00:00
usr_bin_roygbiv 0e59977dd0 fix(providers/google): remove incorrect user role from Antigravity systemInstruction 2026-06-13 23:41:28 -05:00
usr-bin-roygbiv 521b325697 fix(providers/google): stop Gemini/Claude rule leaks under Antigravity 2026-06-13 22:42:57 -05:00
roboomp f5d54e4acd fix(providers): downgraded forced tool choice for kimi
Added OpenAI-compatible compat metadata for endpoints that allow tools but reject forced tool_choice. OpenCode Go kimi-k2.7-code now downgrades resolve-gate forcing to auto tool selection while preserving thinking-mode request state.\n\nFixes #2546
2026-06-14 03:41:00 +00:00
usr-bin-roygbiv 2926fb2ab3 fix(providers/google): avoid creating empty text blocks on stream ending 2026-06-13 20:25:28 -05:00
can1357 9a26a945a7 fix: dropped unavailable forced toolChoice and added runtime fallback recovery
- Validated queued toolChoice against active tools in agent and coding-agent sessions.
- Rejected queued forced choices with reason "unavailable" when selected tools were inactive.
- Dropped provider toolChoice payloads when requested function tools were not offered.
- Probed Tokio worker-thread support and fell back to current-thread runtime creation.
2026-06-14 01:32:47 +02:00
usr_bin_roygbiv 1d7361de00 fix(providers/google): normalize tool schemas for non-CCA Google models 2026-06-13 17:49:11 -05:00
oldschoola 3bff0720b7 feat(catalog): add Z.AI GLM-5.2 with 1M context
Seed glm-5.2 and glm-5.2[1m] on the zai (GLM Coding Plan) provider
as selectable catalog entries with 1M context, pin the context at
catalog generation so discovery cannot regress to 200k, and use
glm-5.2 for Z.AI API key validation. Default model stays glm-5.1
(bumping requires maintainer sign-off).
2026-06-13 13:00:57 -07:00
can1357 6d534a3c54 fix(agent): corrected agent event listener errors to structured warnings
- Replaced `Agent` listener error reporting with structured `logger.warn` calls.
2026-06-13 18:03:39 +02:00
can1357 60a46f37db fix(ai): fixed SSE cancellation to stop upstream requests on client stream cancel
- Extended gateway stream control to pass abort signals and onCancel into encodeStream.
- Added optional cancellation control parameters to provider encodeStream handlers.
- Stopped provider stream loops on cancellation and suppressed SSE completion/error output after abort.
- Added a regression test verifying reader.cancel triggers onCancel and aborts upstream request.
2026-06-13 17:53:53 +02:00
can1357 3def4a6979 feat(coding-agent-logout/auth-ux): enabled selective OAuth account logout
- Added a credential-picker `/logout` flow for selecting one OAuth account.
- Added optional `/logout` provider argument and unknown-provider error handling.
- Changed logout handling to delete only the chosen credential and keep others.
- Added AuthStorage APIs to list and remove credentials by id, with remote deletion hook.
2026-06-13 17:31:18 +02:00
can1357 ef126fd0f6 fix(ai): fixed Google empty STOP retries to emit a single stream start event
- Added shared Google empty-stream retry constants and reused them in CLI.
- Replaced local content checks with hasMeaningfulGoogleContent for retry gating.
- Refactored streamGoogleGenAI to bound empty STOP retries with state reset and reopen.
- Moved stream start emission before retry loops to avoid duplicate start events.
2026-06-13 16:58:04 +02:00
can1357 69051241f1 fix(ai): added finite output-token fallback when model maxTokens is unknown
- Applied a finite 64,000-token fallback for OpenAI completion requests when model maxTokens is unavailable.
- Refactored stream max-token computation to use a shared helper and preserve a finite cap when caller and model limits are null.
- Added regression coverage for null maxTokens flows and bumped the model-cache schema to invalidate entries using retired unknown-limit sentinels.
2026-06-13 15:52:06 +02:00
can1357 f0c6a54f51 fix: handled unknown model limits as null to avoid artificial token caps
- Replaced unknown model contextWindow/maxTokens sentinels with nullable values across types and catalog data.
- Mapped request token calculations to treat null maxTokens as unlimited output caps.
- Updated remote compaction and context checks to ignore unknown limits by using Infinity/0 fallbacks.
- Adjusted CLI/model registry flows to skip cap enforcement for null limits and render unknown values as '-'.
2026-06-13 15:35:40 +02:00
roboomp a8829420d7 fix(ai): deduplicated minimax reasoning stream
MiniMax-M3 OpenAI-compatible streams can carry the same reasoning in visible <think> content and structured reasoning_content. The stream parser now treats the structured reasoning field as authoritative for that chunk and collapses cumulative MiniMax reasoning snapshots to deltas.\n\nFixes #2433
2026-06-13 02:44:25 +00:00
can1357 7732c9b158 feat(ai/providers): enhanced SSE parsing and propagated timeout headers
- Augmented streaming SSE observers to infer event names from payload fields when the event field is missing.
- Added `X-Stainless-Timeout` request headers derived from `requestTimeoutMs` for OpenAI and Azure response/completions streaming calls.
2026-06-13 00:59:34 +02:00
can1357 6e8a56e24e fix(deps): migrated OpenAI providers to wire-based streaming and removed SDK dependency
- Replaced Azure and OpenAI provider calls with `postOpenAIStream` flow.
- Fixed stream error handling by retaining status, headers, and body on failures.
- Fixed stream parsing by handling raw JSON SSE frames and `[DONE]` events.
- Added `OpenAIHttpError` with parsed messages and timeout-aware retry behavior.
- Added remote-compaction tests for timeout, abort, and 500-fallback behavior.
2026-06-13 00:43:24 +02:00
can1357 f34610b1ee Merge remote-tracking branch 'origin/farm/428ce54a/sqlite-busy-recovery-during-concurrent-s' 2026-06-13 00:05:51 +02:00
can1357 64aa558e62 chore: consistency 2026-06-13 00:03:27 +02:00
can1357 bbca89d0ff Merge remote-tracking branch 'origin/farm/2a0f0068/fix-gitlab-duo-oauth-redirect-uri' 2026-06-12 23:04:16 +02:00
roboomp 6189afe022 fix(ai): added GITLAB_CLIENT_ID and GITLAB_REDIRECT_URI overrides for gitlab-duo OAuth
The bundled GitLab Duo `client_id` had its registered redirect URI list
drift away from `http://localhost:8080/callback`, so every browser
authorize request landed on GitLab's "The redirect URI included is not
valid" error page. The random-port fallback in `callback-server.ts` was
guaranteed to break for the same reason (strict OAuth redirect URI
matching).

- Honour `GITLAB_CLIENT_ID` / `GITLAB_REDIRECT_URI` env vars in both the
  authorize URL and the token-exchange / refresh POSTs so users running
  with their own GitLab OAuth application can replace the bundled
  credentials end-to-end.
- When `GITLAB_REDIRECT_URI` is set, advertise the exact string to
  GitLab, bind the local callback server to the URI's loopback host/port
  (random port for non-loopback URIs that only complete via paste-code),
  and pass `OAuthCallbackFlowOptions.redirectUri` so the silent random
  port fallback is disabled — a mismatched URI now surfaces the bind
  error rather than producing a token GitLab refuses to redeem.
- Surface the new env vars (and the existing `GITLAB_TOKEN` PAT path) in
  the browser instructions text when GitLab rejects the URI.
- Thread `ctrl.fetch` through the login flow to match the xiaomi /
  anthropic patterns.

Fixes #2424
2026-06-12 20:37:26 +00:00
can1357 2f8718188f fix(ai): mapped bare finish_reason error to retryable error message
- Mapped OpenAI completions streams ending with `finish_reason: "error"` to `stopReason: "error"` with the message `Provider returned error finish_reason`.
- Added regression tests for bare `finish_reason: "error"` streams, including tool-call payloads, to verify the error remains retryable.
2026-06-12 22:27:04 +02:00
roboomp 03bead1eac fix(auth): retried SQLITE_BUSY family and hoisted busy_timeout
Concurrent omp --session restores after an unclean shutdown crashed
in SqliteAuthCredentialStore.#initializeSchema() with
SQLITE_BUSY_RECOVERY because the multi-statement schema run installed
PRAGMA busy_timeout=5000 AFTER PRAGMA journal_mode=WAL, the first
lock-taking statement during WAL recovery. Bun's default busy_timeout
is 0, so the lock conflict surfaces immediately.

- packages/ai/src/auth-storage.ts: hoisted PRAGMA busy_timeout to a
  standalone first statement, dropped it from the multi-statement
  schema run, wrapped SqliteAuthCredentialStore.open() in a 4-attempt
  exponential-backoff retry loop on the SQLITE_BUSY family, and the
  exhausted-retry error now includes the DB path. Exported
  isSqliteBusyError(err) (matches code prefix 'SQLITE_BUSY').
- packages/coding-agent/src/session/agent-storage.ts: same hoist and
  the existing retry loop now uses isSqliteBusyError so
  SQLITE_BUSY_RECOVERY / _SNAPSHOT / _TIMEOUT also trigger backoff.
- Hoisted busy_timeout before journal_mode=WAL in every other shared
  SQLite open path: history-storage, autoresearch/storage,
  memories/storage, github-cache, report-tool-issue (auto-QA),
  catalog/model-cache; stats/db.ts now sets busy_timeout at all.
- packages/ai/test/auth-storage-sqlite-busy.test.ts pins the contract:
  isSqliteBusyError matches every BUSY extended code (rejects
  SQLITE_LOCKED, non-errors, strings); open() leaves the connection in
  WAL mode (proves busy_timeout ran before journal_mode); open() retries
  through synthetic SQLITE_BUSY_RECOVERY; non-BUSY errors (SQLITE_CORRUPT)
  short-circuit; exhausted retries throw an error mentioning the DB path
  with exactly 3 sleeps for a 4-attempt budget.

Fixes #2421
2026-06-12 20:17:12 +00:00
can1357 28df38ed37 feat(agent): added useless-result tagging and compaction dropping of tool outputs
- Added optional `useless` flags to tool result types and payload builders.
- Added `pruneUseless` and `dropUeless` options to control uneventful result pruning.
- Changed compaction and shake passes to prune or ignore non-error useless tool results.
- Changed conversation serialization to omit useless toolCall/toolResult pairs from output.
- Added coverage for useless tagging, pruning, and serialization behavior.
2026-06-12 16:26:38 +02:00
can1357 5fa3ae3982 fix(ai): sanitized Anthropic payloads with toWellFormed before SDK serialization
- Applied `toWellFormedDeep` to Anthropic stream payloads after optional replacement before request serialization.
- Added a regression test that injects a surrogate-escaping tool-call payload and verifies the serialized request body is sanitized to `\ufffd`.
- Documented the payload-sanitization fix in the `ai` package changelog.
2026-06-12 15:42:43 +02:00
can1357 4e144be484 fix(ai): sanitized Anthropic tool-use arguments with
- Sanitized Anthropic tool-use arguments with toWellFormedDeep on every replay path.
- Updated unsigned-thinking replay tests to assert same-API tool arguments are sanitized.
- Documented the lone-surrogate replay fix in the ai package changelog.
2026-06-12 15:32:55 +02:00
can1357 7119153077 fix(ai): removed Codex SSE stateful chaining and enforced turn-scoped state
- Removed stateful SSE chain controls from Codex provider options.
- Changed SSE transport to send full request bodies without `previous_response_id` deltas.
- Updated stale-chain recovery to treat `unsupported` as stale and recover via websocket.
- Scoped `x-codex-turn-state` to in-turn follow-ups and cleared turn state otherwise.
2026-06-12 11:12:27 +02:00
can1357 e28ae2fd88 fix(ai): hoisted images out of error Anthropic tool results
- Adjusted Anthropic tool-result conversion to keep error results text-only while collecting any image blocks separately.
- Reattached collected images after the tool-result run in the same user message with a separator note for Anthropic compatibility.
- Added tests covering image-only error tool_results, image hoisting order, and successful tool_result image preservation.
2026-06-12 11:07:35 +02:00
can1357 1308f654a0 feat(ai): ensure Anthropic requests use correct thinking model ID
- Previously, `anthropic-messages` requests using `resolveWireModelId` would always derive the non-thinking variant for `requestModelId`, even when reasoning was explicitly enabled.
- This change ensures the `reasoning` state is correctly passed to `resolveWireModelId`, allowing the API request to include the appropriate `X-thinking` model variant when thinking is active, standardizing behavior across providers.
2026-06-12 08:27:41 +02:00
can1357 e5f8f7ed67 feat(ai): clamped omitted and disabled reasoning on requiresEffort models
- Added `normalizeMandatoryReasoningOptions` to `stream.ts`: models baked with `thinking.requiresEffort` floor omitted or disabled reasoning to `minimumSupportedEffort` instead of sending an explicit disable, fixing "Reasoning is mandatory for this endpoint and cannot be disabled" 400s on OpenRouter Gemini 3.x.
- Skipped the clamp for `suppressWhenOff` models, which handle off provider-side via an explicit wire config.
- Added `requires-effort.test.ts` covering omitted-reasoning clamping, `disableReasoning` suppression, untouched explicit efforts, flag-free pair routing, and flagged collapsed pairs.
- Added the pi-ai changelog entry.
2026-06-12 08:21:06 +02:00
can1357 17c4edda0d feat(ai): routed openai-completions and anthropic wire ids through resolveWireModelId
- Added a `requestModelId` option to `AnthropicOptions`, serialized as `requestModelId ?? model.requestModelId ?? model.id` in `buildParams`.
- Replaced `resolveOpenAICompletionsModelId`'s pinned-id short-circuit with `resolveWireModelId`-based resolution ahead of the provider-specific id transforms.
- Passed `requestModelId: resolveWireModelId(model, reasoning)` from every `mapOptionsForApi` case in `stream.ts`, so collapsed `X`/`X-thinking` pairs on aggregators and custom providers switch to the thinking SKU when reasoning is enabled.
- Added the pi-ai changelog entry.
2026-06-12 08:20:48 +02:00
can1357 048aef12ac feat(ai): routed collapsed effort-tier variants to per-effort wire ids in google-gemini-cli
- Mapped `google-gemini-cli` request model ids through `resolveWireModelId` in `stream.ts`: the session effort picks the backing variant id (collapsed `gemini-3.5-flash` at high → `gemini-3.5-flash-low`; claude pairs route off → bare id, efforts → `-thinking`) while `AssistantMessage.model` and usage attribution stay on the logical id; a thinking budget clamped to zero now falls through to the thinking-off path instead of only disabling thinking.
- Added `requestModelId` and `thinking.suppress` request options to the `google-gemini-cli` provider, fixing `Model.requestModelId` being ignored at serialization and sending an explicit `thinkingConfig` (`includeThoughts: false` with `thinkingLevel: "MINIMAL"` or `thinkingBudget: 0`) for thinking-off requests on models with `thinking.suppressWhenOff` — Cloud Code Assist re-applies the baked server default when the config is omitted.
- Added `google-gemini-cli-variant-routing.test.ts` covering collapsed-variant effort routing, pair off-routing, and off-suppression serialization.
- Recorded the ai changelog entries.
2026-06-12 07:37:16 +02:00
can1357 35d3afc929 feat(coding-agent): refactored usage command into show/reset subcommands
- Added `handleUsageResetCommand` support to list and redeem usage reset credits.
- Refactored `/usage` into `show` and `reset` subcommands and removed `/reset-usage`.
- Handled ACP/TUI `/usage` flows so `show` reports usage and `reset` redeems credits.
- Kept selected theme setting values dirty-colored while selected in the UI list.
2026-06-12 06:18:44 +02:00
can1357 a15ac433f2 Merge remote-tracking branch 'origin/farm/8573d9d3/v15-11-4-openai-responses-400-previous-r' 2026-06-12 05:55:14 +02:00
can1357 34345fee5a feat(coding-agent): added automatic Codex reset redemption and retry handling
- Added configurable Codex auto-redeem settings with default behavior toggles.
- Added auto-redeem evaluation in usage-limit flow before model fallback.
- Added Codex auto-redeem coordinator with cooldowns and in-flight dedupe retries.
- Cleared temporary credential backoff blocks after successful redeemResetCredit.
2026-06-12 05:52:48 +02:00
can1357 f2099fcc00 feat(todo): removed todo note fields and note operation behavior
- Removed the `note` operation from `TodoOp` validation and the `text` field from todo operation payloads.
- Deleted `TodoItem` note storage and stripped note-aware logic from execution, markdown round-trip helpers, summaries, and rendering.
- Updated todo docs and prompt schema text to remove `note` usage and keep the public operation set aligned.
2026-06-12 05:38:40 +02:00