Commit Graph
460 Commits
Author SHA1 Message Date
can1357 6be1b41d3b Merge PR #7821: fix(ai): preserve Copilot integrator entitlement errors (@roboomp) 2026-08-07 13:37:53 +02:00
roboomp 1bcf08c27f fix(ai): preserved Copilot integrator entitlement errors
- Classified model_not_available_for_integrator as a permanent entitlement denial instead of transient fleet skew.

- Preserved the provider response and Available models list while retaining model_not_supported fleet retries.

Fixes #7819
2026-08-06 09:50:32 +00:00
can1357 e9888367d1 refactor: migrated packages to internal utility modules and removed external dependencies
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
2026-08-05 13:39:09 +02:00
Magicien f3ad5ede6b fix(ai): scope the Copilot 8-attempt retry budget to model flaps
The 3 -> 8 bump in callWithCopilotModelRetry was shared by the generic
retryable branch, so a persistent status-less transport blip on Copilot
would ramp across 8 attempts (~11.2s of dead time) instead of the 3 it
took before, and a repeated Retry-After 429 could stretch the same way
on top of the transport's own fetchWithRetry budget.

Derive the budget from the failure kind: model-availability 400s keep the
8-attempt reroll, everything else caps at the previous 3.

Also read COPILOT_TRANSIENT_MODEL_CODES with Object.hasOwn — `code` is
provider-controlled, so a 400 body whose code was `__proto__` or
`toString` classified as transient through the prototype chain.
2026-08-04 21:51:35 +01:00
Magicien d33f2a1658 fix(ai): retry GitHub Copilot fleet-skew model 400s
Any Copilot model in the middle of a rollout (claude-sonnet-4.6,
claude-opus-4.6, gpt-5.4, gpt-5.3-codex, ...) returned a raw HTTP 400 on
roughly half of all turns. GET /models on api.githubcopilot.com returns
two different catalogs across repeated calls: part of the fleet serves
those ids, part rejects them with

  400 {"error":{"message":"The requested model is not available for
  integrator \"copilot-language-server\". ...",
  "code":"model_not_available_for_integrator", ...}}

The absorb machinery already existed and was correct
(isCopilotTransientModelError -> isProviderRetryableError -> the
Anthropic transport's PROVIDER_MAX_RETRIES). Only the classifier missed:
it matched the older model_not_supported code and probed err.code /
err.error.code, while the real code is model_not_available_for_integrator
sitting at err.error.error.code (the SDK stores the parsed body on
.error, and Copilot's body is itself {error:{code}}). So
isProviderRetryableError fell through to "4xx => terminal".

Fix the classifier: providerErrorCode() walks the error envelope up to
depth 3 instead of hardcoding a shape, both Copilot model-availability
codes are accepted, and a wire-body text match backs it up because SDK
envelope shapes drift between provider families while the stringified
message does not. This alone restores the retry path, because
isProviderRetryableError consults the provider hook before its
4xx short-circuit.

Retry shape, since a rejection is a per-request replica reroll rather
than upstream backpressure:

- both transports wait a flat delay between model-flap attempts instead
  of the growing backoff; generic retryable failures (429/5xx/transport)
  keep their linear ramp and Retry-After handling
- the OpenAI-transport budget goes 3 -> 8 attempts, because a measured
  ~70% flap window produced a turn that needed 6 wire attempts and
  exhausting the budget escalates to the agent-level retry, which
  restarts the whole turn

Absorbed attempts cost no tokens: rejections are gateway-side, carry no
usage block, and return in ~208ms median versus ~1884ms for a served
request.

Also refresh the exhausted-retry guidance text, which cited a
nonexistent model id and described the cause as a per-client rollout gap
rather than fleet skew.
2026-08-04 21:45:44 +01:00
can1357 bc39ffa265 feat: introduced omptype validation package and migrated workspace dependencies
- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
2026-08-03 21:56:48 +02:00
can1357 e06ccbd907 Merge PR #7080: fix(ai): add authenticated Bedrock Mantle routing (@anatoli-tsinovoy)
# Conflicts:
#	packages/ai/src/registry/registry.ts
#	packages/catalog/scripts/generated-policies.ts
#	packages/catalog/src/models.json
2026-08-03 14:36:52 +02:00
can1357 a58584ff3c feat: implemented shared serialization utilities and standardized inventories
- Added shared Python call and literal serialization utilities with multiline verbatim support.
- Standardized tool inventories to format as an OpenAI-Harmony functions namespace using TypeScript declarations.
- Updated tool normalization and rendering functions to accept options objects and default to Python-syntax examples.
- Refactored Gemini dialect rendering to leverage shared serialization functions directly.
2026-08-03 05:06:49 +02:00
can1357 cc2265f681 feat: use simple form replace when replace is the edit mode 2026-08-03 01:00:51 +02:00
Anatoli Tsinovoy e5541a577a fix(ai): address Bedrock Mantle review feedback 2026-08-01 12:29:07 +03:00
can1357 642892ae5c feat(ai/providers): implemented custom cowork transport for anthropic requests
- Added custom `coworkFetch` transport for ordered headers and decompression support in Anthropic requests.
- Updated Anthropic and Claude runtime versions along with request headers to replicate Cowork desktop profiles.
- Configured default Anthropic message stream fetches to use the new cowork fetch transport and TLS profiles.
- Updated alignment tests and documentation to reflect the new Cowork request configurations and header rules.
2026-07-30 17:02:26 +02:00
Anatoli Tsinovoy 7aa772beee fix(ai): validate AWS credential sources 2026-07-30 16:02:26 +03:00
can1357 00fedcf6ac feat(ai): extended codex and stream timeout defaults to 300 seconds
- Increased codex websocket first event timeout default to 300 seconds.
- Increased default stream idle and first event timeout thresholds to 300 seconds.
- Updated stream timeout test expectations to match new 300s global default.
2026-07-30 05:33:06 +02:00
Diogo Soares Rodriguesandcan1357 b6e01c8a3c feat(ai): handle Cursor's modern exec wire protocol
Current Cursor CLI builds emit exec frames this client did not model. A
frame whose oneof number is absent from `agent.proto` decodes with
`message.case` unset, so the dispatcher found no handler, ran no tool and
sent no result — the server was left waiting on an execution that never
happened.

Every recognised frame now gets a typed answer:

- The seven Pi tools (45-51) run their local equivalents. They are a
  separate wire family from the legacy args, not aliases: `pi_grep`'s
  `ignore_case` is the inverse of the local `case` flag, `pi_find`
  searches filenames (so it routes to `glob`, not `grep`), and
  `pi_edit`'s replacements are renamed to snake_case pairs.
- Hooks, subagents, prechecks, MCP state, smart-mode, canvas,
  conversation search and agent-store answer with the error, not-found or
  empty-but-valid variant that is true of this client.
- Unnameable frames raise `ExecClientControlMessage.throw`
  (`unknown_exec_variant`); recognised frames with no truthful answer —
  `git_diff_request`, whose `GetDiffResponse` has no error variant —
  raise `exec_variant_unsupported`.

Four frames previously answered `create(XSchema, {})`. In proto3 that is
not an empty result: the oneof is unset and the server reads it as "the
tool ran and produced nothing", indistinguishable from success. They now
send real variants.

`connect_scm` lost its repository (the target rides in a oneof, so the
flat property was always undefined) and settled on a fixed failure at the
announcement, before the server's `success`/`error`/`rejected` verdict
arrived on the completion frame.

The stream decoder tracked a single "current" tool-call block and settled
it on any `toolCallCompleted`, ignoring the envelope `call_id`: an
unrelated completion paired the wrong block, and `start A, start B`
orphaned A so nothing ever paired it — which strips the whole interaction
from every rebuilt transcript. Blocks are now retained per envelope id.

`lsp` is advertised as MCP again; the native `diagnostics` frame covers
one of ~10 actions.

(cherry picked from commit 4d269724a3a448886d13b4323ac02aadbfe38de3)
2026-07-30 01:41:55 +02:00
usr-bin-roygbivandcan1357 47ac33aa1f fix(ai): inspect snake-case schema children
(cherry picked from commit 41590a873ca838f9ac3b54e1008fd7c97424c3d3)
2026-07-30 01:27:35 +02:00
usr-bin-roygbivandcan1357 6dcd28c302 fix(ai): preserve negated enum semantics
(cherry picked from commit c96aa0d61445de12597abf76c397ce5f9707bcb8)
2026-07-30 01:27:35 +02:00
usr-bin-roygbivandcan1357 b8c5f1544e style(ai): format schema traversal fix
(cherry picked from commit ffa704ed0abdd6f27d0ce56d8c97ccd64d025010)
2026-07-30 01:27:35 +02:00
usr-bin-roygbivandcan1357 2ee5a10923 fix(ai): preserve CCA literal payloads
(cherry picked from commit b026a96326e3d7df89771f3224476dc37eeeaa9c)
2026-07-30 01:27:35 +02:00
usr-bin-roygbivandcan1357 05d5b8c12d style(ai): format schema normalization
(cherry picked from commit aee3d7e5e26c3a5cb3e950266a2561ece4b1d20c)
2026-07-30 01:27:35 +02:00
usr-bin-roygbivandcan1357 34069920a6 fix(ai): normalize map value schemas
(cherry picked from commit 836951121076394b775771b29070f1022d7591c7)
2026-07-30 01:27:34 +02:00
usr-bin-roygbivandcan1357 2f579e1ac1 fix(ai): preserve literal schema payloads
(cherry picked from commit 3631bc5bd0a27eabb774bf800e0144523d25a55b)
2026-07-30 01:27:34 +02:00
usr-bin-roygbivandcan1357 d17ae32b1d fix(ai): preserve enum keys in Google schema defaults
(cherry picked from commit 226f00efb3c330f5ed6b0583c4b65e2fa75b9f5b)
2026-07-30 01:27:34 +02:00
Royandcan1357 16e03728f0 fix(ai): omit unsupported Google enum values
(cherry picked from commit 6cc7916f9ff508ee0864229fe83a3c31a585f832)
2026-07-30 01:27:34 +02:00
roboompandcan1357 8c3b316be5 fix(ai): harden harmony escaping for wire aliases and history replay
Address PR #6918 review:
- Gate escaping on the wire model id via isHarmonyDialectModel
  (requestModelId ?? id), so deployment/catalog aliases whose local id
  is opaque but whose wire id is gpt-5.x are still escaped.
- Escape client-boundary text of replayed native-history items
  (user/developer/system message text and tool-result output) before
  they hit the wire; the replay branch previously bypassed
  convertResponsesInputContent entirely, sending stored markers raw.

Applies to both the shared Responses builder and the codex builder.
Assistant output, reasoning, and tool-call arguments stay untouched.

Fixes #6913

(cherry picked from commit 2c5cf286c447122fdb7633eaf3d9371370648966)
2026-07-29 23:08:30 +02:00
roboompandcan1357 9f37b1864d fix(ai): escaped harmony control tokens in codex request input
Harmony-server models (gpt-5.x / openai-codex) reject any Responses
request whose input reproduces reserved control-token spellings such as
`<|channel|>analysis`, failing before generation with invalid_prompt /
"Request blocked". The live agent-loop builders serialized user and
tool-result text verbatim into input_text / function_call_output, so a
tool result carrying the marker (e.g. a broad `omp://` grep) poisoned
the persisted session — every later turn replayed it and failed.

Escape reserved harmony tokens on the transport copy of untrusted
user/tool text in both the shared Responses builder and the codex
builder, gated on `preferredDialect === "harmony"`. The persisted
transcript is untouched and non-harmony models are unaffected. Extends
the existing compaction-payload escaping to the request boundary and
routes both through a shared `escapeHarmonyControlTokens` helper.

Fixes #6913

(cherry picked from commit dfea56588e7aa1c35971c4684221f4a86142e04e)
2026-07-29 23:08:29 +02:00
roboomp 25c4ec07ed fix(live): honored standard proxies for sideband websocket
Centralized URL-aware proxy resolution so Codex WebSocket transports share standard proxy environment fallbacks and NO_PROXY handling.

Fixes #6770
2026-07-27 06:24:28 +00:00
roboomp 319ab0c3c6 fix(ai): reset leaked text signatures by source
Reset text replay metadata whenever the projector enters a new source block, including unsigned terminal-only blocks.

Covered a signed terminal text block followed by an unsigned block to prevent invalid signature carryover.

Fixes #6703
2026-07-26 13:54:42 +00:00
roboomp 2fb9f888ad fix(ai): preserved custom anthropic web-search history
Retained complete native web-search call/result pairs through leaked-thinking projection at their original source anchors.

Kept opaque server-tool blocks atomic during persistence, stripped them on reparent, and covered custom continuations plus compaction retention.

Fixes #6703
2026-07-26 13:32:08 +00:00
roboomp 946b7d9bd2 fix(ai): preserved disabled first-event sentinel
- Kept zero timeout resolutions distinct from missing first-event policy so the iterator does not fall back to the idle watchdog.
- Added deterministic coverage for an SSE response that opens before local prompt prefill emits its first event.
2026-07-24 15:33:27 +00:00
roboomp a421ea8acd fix(ai): disabled local first-event watchdogs
- Added a per-model first-event watchdog policy and disabled it for local OpenAI-compatible backends while retaining inter-event stall detection.
- Applied the policy to Responses and chat-completions transports with regression coverage for resolver and runtime precedence.

Fixes #6524
2026-07-24 15:19:14 +00:00
can1357 ae178422a5 fix(ai): recovered unstreamed thinking blocks with signatures
- Added handling for signature-bearing thinking blocks that never streamed deltas before closing.
- Implemented a safety net in `LeakedThinkingProjector` to recover thinking blocks with signatures missing per-block events.
- Added test coverage verifying proper projection order and recovery of unstreamed thinking signatures.
2026-07-24 15:29:54 +02:00
usr-bin-roygbiv b9504f65e7 feat: add native Codex computer use 2026-07-24 01:40:04 +00:00
roboomp 764a1f7e9c fix(ai): emitted delayed thinking signatures before block close
Deferred projected native thinking_end events until their source block ends so
stream consumers observe completed signatures before content_block_stop, even
when later projected blocks already started.

Covered the interleaved event lifecycle and Anthropic serialization path.

Fixes #6046
2026-07-21 22:41:09 +00:00
roboomp fab067953b fix(ai): tracked projected thinking blocks by source index
Mapped each native thinking content index to its projected block so a delayed
thinking_end updates the correct signature after text, tool calls, or another
thinking block has started.

Added regression coverage for two thinking blocks separated by a tool call and
finalized out of order.

Fixes #6046
2026-07-21 22:32:21 +00:00
roboomp 36280b56eb fix(ai): preserve native thinking signatures through leaked-thinking wrapper
wrapLeakedThinkingStream ignored thinking_end, where Anthropic surfaces the
completed thinkingSignature (delivered via signature_delta after every
thinking_delta). The projected native thinking block persisted an empty
signature, so continuations replayed signature:"" and Anthropic-compatible
signing endpoints rejected it.

Handle thinking_end in the wrapper and stamp the completed signature onto the
open projected thinking block via a new LeakedThinkingProjector.thinkingEnd.

Fixes #6046
2026-07-21 20:16:23 +00:00
can1357 18a24f8c45 style: formatted merge resolutions with biome 2026-07-18 19:59:20 +02:00
can1357 91bf49f897 fix(ai): traverse object-valued additionalProperties in grammar sanitizer
Object-form additionalProperties/unevaluatedProperties are genuine
subschemas whose interior may still hold the bare booleans emitted by
toolWireSchema; skipping them let llama.cpp reach an Unrecognized
schema: true. Boolean forms stay intact for closed/open-object grammar
semantics. Flagged by Codex review on #5919.
2026-07-18 19:58:23 +02:00
can1357 c2b241401b Merge PR #5919: fix(providers): sanitize boolean subschemas for grammar backends (@roboomp)
# Conflicts:
#	packages/catalog/src/compat/openai.ts
#	packages/catalog/src/types.ts
2026-07-18 19:58:22 +02:00
roboomp d4a9d50a5b fix(ai): normalized boolean schemas for moonshot
Coerced boolean subschemas into MFJS-compatible object forms while preserving boolean keyword values.

Fixes #5952
2026-07-18 03:52:16 +00:00
roboomp 2eb35e300f fix(providers): sanitize boolean subschemas for grammar backends
Local grammar-constrained OpenAI-compatible servers (llama.cpp, LM Studio,
vLLM) build a GBNF grammar from tool JSON Schemas and 400 with
"Unrecognized schema: true" on a bare boolean subschema. The task tool's
open outputSchema field normalizes to boolean `true` (issue #1179), which
the converter cannot compile, breaking every tool request.

Add a "grammar" tool-schema flavor, auto-detected for local backends, that
widens bare boolean/empty subschemas into a value-accepting primitive union
while preserving closed-object `additionalProperties: false`.

Fixes #5914
2026-07-17 22:35:44 +00:00
roboomp 7e8c4fc01f fix(extensions): restored legacy provider compatibility
Restored the historical assistant-message stream factory and synchronous auth-storage facade needed by pi-provider-kimi-code.

Fixes #5879
2026-07-17 16:54:47 +00: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 8ff821515d fix(ai): honor NO_PROXY ports for secure websockets 2026-07-16 03:41:17 +02:00
can1357 8932acb6f3 fix(schema): scope boolean coercion to google transports 2026-07-16 03:31:58 +02:00
roboomp cd41719757 fix(schema): stripped conditional keywords for google/cca
Added dependencies, dependentSchemas, and dependentRequired to UNSUPPORTED_SCHEMA_FIELDS so both the Google and CCA normalizers drop them before serializing to the OpenAPI-style Schema wire, which cannot model draft-2019 conditional keywords.

Kept them in the MCP subschema-map path (still coercing boolean entries) and documented the additions in CONSTRAINTS.md.

Fixes #5604
2026-07-15 19:47:02 +00:00
roboomp c6c063ee00 fix(schema): rejected not schemas on cca transport
Added not to the CCA residual incompatibility gate so false boolean subschemas fall back before reaching the legacy object-shaped parameters wire.

Made residual scanning schema-map aware to avoid treating a property literally named not as the unsupported keyword, and added root, property, and dependentSchemas regressions.

Fixes #5604
2026-07-15 19:34:49 +00:00
roboomp da3e500637 fix(schema): handled boolean schema-map entries
Generalized the schema-map walk context beyond properties to include patternProperties, dependencies, dependentSchemas, $defs, and definitions. Each arbitrary map entry is now treated as a subschema, so bare booleans coerce before reaching Google/CCA.

Reused the shared map/array keyword tables in the Ollama sanitizer and added a dependentSchemas regression for both Google and CCA normalizers.

Fixes #5604
2026-07-15 19:27:00 +00:00
roboomp 508dbbbc5a fix(schema): coerce boolean subschemas for google/cca transport
Boolean JSON Schema subschemas (`true`/`false`, draft 6+) in MCP tool
inputs passed through normalizeSchemaForGoogle/normalizeSchemaForCCA
untouched. The Cloud Code Assist / Gemini protobuf Schema type has no
representation for a bare boolean, so requests bounced with a 400
INVALID_ARGUMENT before reaching the model.

Coerce booleans to their object equivalents (`true` -> `{}`,
`false` -> `{ not: {} }`) at the single normalizeSchemaNode choke point,
but only in genuine subschema slots (root, combiner branches,
subschema-valued keywords, property values). Keyword-slot booleans
(`nullable`, `enum` entries, `additionalProperties`) stay untouched so
Moonshot/MCP open-record markers survive.

Fixes #5604
2026-07-15 19:15:07 +00:00
roboomp c49c693b73 fix(ai): retried codex pre-response watchdog timeouts
Gave each Codex SSE transport attempt an independent pre-response watchdog while reserving the retry-loop signal for caller cancellation.

Added provider-level coverage for retry recovery and explicit abort behavior.

Fixes #5329
2026-07-14 18:26:35 +00: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