@linxiraos/pi-ai 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +123 -30
- package/package.json +135 -136
- package/src/auth/sqlite-credential-store.ts +0 -56
- package/src/auth-retry.ts +5 -4
- package/src/auth-storage.ts +122 -112
- package/src/dialect/owned-stream.ts +3 -0
- package/src/error/auth-classify.ts +7 -6
- package/src/error/aws.ts +5 -1
- package/src/error/flags.ts +25 -1
- package/src/error/provider.ts +6 -5
- package/src/error/rate-limit.ts +71 -1
- package/src/providers/amazon-bedrock.ts +38 -0
- package/src/providers/anthropic-client.ts +6 -10
- package/src/providers/anthropic.ts +107 -259
- package/src/providers/aws-credentials.ts +222 -29
- package/src/providers/azure-openai-responses.ts +1 -0
- package/src/providers/cursor/exec-modern.ts +1 -0
- package/src/providers/cursor-pi-args.ts +22 -0
- package/src/providers/cursor.ts +81 -1
- package/src/providers/devin.ts +3 -3
- package/src/providers/google-antigravity-forced-tool.md +1 -0
- package/src/providers/google-gemini-cli.ts +83 -40
- package/src/providers/google-shared.ts +22 -8
- package/src/providers/ollama.ts +15 -3
- package/src/providers/openai-codex/request-transformer.ts +47 -21
- package/src/providers/openai-codex-responses.ts +3 -3
- package/src/providers/openai-reasoning-fallback.ts +21 -8
- package/src/providers/openai-responses.ts +77 -12
- package/src/providers/openai-shared.ts +114 -15
- package/src/providers/pi-native-server.ts +1 -0
- package/src/providers/register-builtins.ts +18 -14
- package/src/providers/vision-guard.ts +15 -3
- package/src/registry/amazon-bedrock.ts +9 -14
- package/src/registry/api-key-login.ts +26 -12
- package/src/registry/aws.ts +16 -8
- package/src/registry/cloudflare-ai-gateway.ts +10 -29
- package/src/registry/kagi.ts +11 -29
- package/src/registry/litellm.ts +11 -29
- package/src/registry/llama-cpp.ts +11 -21
- package/src/registry/lm-studio.ts +9 -20
- package/src/registry/oauth/callback-server.ts +93 -5
- package/src/registry/oauth/google-antigravity.ts +99 -44
- package/src/registry/oauth/perplexity.ts +32 -4
- package/src/registry/parallel.ts +10 -28
- package/src/registry/tavily.ts +9 -27
- package/src/registry/together.ts +7 -3
- package/src/registry/vercel-ai-gateway.ts +10 -28
- package/src/registry/vllm.ts +11 -21
- package/src/stream.ts +459 -53
- package/src/types.ts +23 -0
- package/src/usage/alibaba-token-plan.ts +8 -15
- package/src/usage/claude.ts +12 -19
- package/src/usage/cursor.ts +179 -59
- package/src/usage/gemini.ts +4 -3
- package/src/usage/github-copilot.ts +3 -2
- package/src/usage/google-antigravity.ts +10 -17
- package/src/usage/kimi.ts +35 -17
- package/src/usage/minimax-code.ts +7 -27
- package/src/usage/openai-codex-reset.ts +3 -2
- package/src/usage/openai-codex.ts +5 -5
- package/src/usage/opencode-go.ts +170 -60
- package/src/usage/shared.ts +33 -10
- package/src/usage/synthetic.ts +4 -11
- package/src/usage/umans.ts +2 -2
- package/src/usage/xai-oauth.ts +62 -34
- package/src/usage/zai.ts +4 -6
- package/src/usage.ts +0 -20
- package/src/utils/aws-profile.ts +39 -1
- package/src/utils/block-symbols.ts +18 -0
- package/src/utils/empty-completion-retry.ts +4 -1
- package/src/utils/leaked-thinking-stream.ts +3 -0
- package/src/utils/openrouter-headers.ts +4 -4
- package/src/utils/thinking-loop.ts +17 -38
- package/dist/types/api-registry.d.ts +0 -30
- package/dist/types/auth/sqlite-credential-store.d.ts +0 -117
- package/dist/types/auth-broker/client.d.ts +0 -93
- package/dist/types/auth-broker/discover.d.ts +0 -39
- package/dist/types/auth-broker/index.d.ts +0 -7
- package/dist/types/auth-broker/refresher.d.ts +0 -25
- package/dist/types/auth-broker/remote-store.d.ts +0 -136
- package/dist/types/auth-broker/server.d.ts +0 -48
- package/dist/types/auth-broker/snapshot-cache.d.ts +0 -17
- package/dist/types/auth-broker/types.d.ts +0 -152
- package/dist/types/auth-broker/wire-schema-resource.d.ts +0 -53
- package/dist/types/auth-broker/wire-schemas.d.ts +0 -5
- package/dist/types/auth-gateway/http.d.ts +0 -56
- package/dist/types/auth-gateway/index.d.ts +0 -3
- package/dist/types/auth-gateway/server.d.ts +0 -36
- package/dist/types/auth-gateway/types.d.ts +0 -127
- package/dist/types/auth-retry.d.ts +0 -150
- package/dist/types/auth-storage.d.ts +0 -1258
- package/dist/types/dialect/anthropic.d.ts +0 -15
- package/dist/types/dialect/catalog.d.ts +0 -3
- package/dist/types/dialect/coercion.d.ts +0 -23
- package/dist/types/dialect/deepseek.d.ts +0 -14
- package/dist/types/dialect/demotion.d.ts +0 -30
- package/dist/types/dialect/examples.d.ts +0 -18
- package/dist/types/dialect/factory.d.ts +0 -3
- package/dist/types/dialect/fenced-thinking.d.ts +0 -53
- package/dist/types/dialect/gemini.d.ts +0 -17
- package/dist/types/dialect/gemma.d.ts +0 -15
- package/dist/types/dialect/glm.d.ts +0 -9
- package/dist/types/dialect/harmony.d.ts +0 -8
- package/dist/types/dialect/hermes.d.ts +0 -9
- package/dist/types/dialect/history.d.ts +0 -3
- package/dist/types/dialect/index.d.ts +0 -11
- package/dist/types/dialect/inventory.d.ts +0 -9
- package/dist/types/dialect/kimi.d.ts +0 -14
- package/dist/types/dialect/minimax.d.ts +0 -3
- package/dist/types/dialect/owned-stream.d.ts +0 -4
- package/dist/types/dialect/qwen3.d.ts +0 -9
- package/dist/types/dialect/rendering.d.ts +0 -54
- package/dist/types/dialect/thinking.d.ts +0 -6
- package/dist/types/dialect/types.d.ts +0 -68
- package/dist/types/dialect/xml.d.ts +0 -9
- package/dist/types/error/abort.d.ts +0 -14
- package/dist/types/error/auth-classify.d.ts +0 -20
- package/dist/types/error/auth.d.ts +0 -27
- package/dist/types/error/aws.d.ts +0 -27
- package/dist/types/error/classes.d.ts +0 -106
- package/dist/types/error/finalize.d.ts +0 -39
- package/dist/types/error/flags.d.ts +0 -94
- package/dist/types/error/format.d.ts +0 -20
- package/dist/types/error/gateway.d.ts +0 -20
- package/dist/types/error/index.d.ts +0 -14
- package/dist/types/error/oauth.d.ts +0 -43
- package/dist/types/error/provider.d.ts +0 -42
- package/dist/types/error/rate-limit.d.ts +0 -80
- package/dist/types/error/retryable.d.ts +0 -27
- package/dist/types/error/validation.d.ts +0 -32
- package/dist/types/index.d.ts +0 -51
- package/dist/types/provider-details.d.ts +0 -24
- package/dist/types/providers/amazon-bedrock.d.ts +0 -39
- package/dist/types/providers/anthropic-client.d.ts +0 -106
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +0 -937
- package/dist/types/providers/anthropic-messages-server.d.ts +0 -17
- package/dist/types/providers/anthropic-wire.d.ts +0 -345
- package/dist/types/providers/anthropic.d.ts +0 -261
- package/dist/types/providers/aws-credentials.d.ts +0 -48
- package/dist/types/providers/aws-eventstream.d.ts +0 -39
- package/dist/types/providers/aws-sigv4.d.ts +0 -55
- package/dist/types/providers/azure-openai-responses.d.ts +0 -16
- package/dist/types/providers/bedrock-mantle.d.ts +0 -13
- package/dist/types/providers/claude-code-fingerprint.d.ts +0 -19
- package/dist/types/providers/cowork-fetch.d.ts +0 -3
- package/dist/types/providers/cursor/exec-modern.d.ts +0 -98
- package/dist/types/providers/cursor-pi-args.d.ts +0 -105
- package/dist/types/providers/cursor.d.ts +0 -221
- package/dist/types/providers/devin.d.ts +0 -12
- package/dist/types/providers/error-message.d.ts +0 -25
- package/dist/types/providers/github-copilot-headers.d.ts +0 -40
- package/dist/types/providers/gitlab-duo-workflow.d.ts +0 -254
- package/dist/types/providers/gitlab-duo.d.ts +0 -27
- package/dist/types/providers/google-auth.d.ts +0 -24
- package/dist/types/providers/google-gemini-cli.d.ts +0 -120
- package/dist/types/providers/google-shared.d.ts +0 -203
- package/dist/types/providers/google-types.d.ts +0 -155
- package/dist/types/providers/google-vertex.d.ts +0 -7
- package/dist/types/providers/google.d.ts +0 -4
- package/dist/types/providers/grammar.d.ts +0 -1
- package/dist/types/providers/kimi.d.ts +0 -27
- package/dist/types/providers/mock.d.ts +0 -179
- package/dist/types/providers/ollama.d.ts +0 -8
- package/dist/types/providers/openai-anthropic-shim.d.ts +0 -35
- package/dist/types/providers/openai-chat-server-schema.d.ts +0 -1311
- package/dist/types/providers/openai-chat-server.d.ts +0 -16
- package/dist/types/providers/openai-chat-wire.d.ts +0 -669
- package/dist/types/providers/openai-codex/request-transformer.d.ts +0 -109
- package/dist/types/providers/openai-codex/response-handler.d.ts +0 -26
- package/dist/types/providers/openai-codex-responses.d.ts +0 -238
- package/dist/types/providers/openai-completions.d.ts +0 -48
- package/dist/types/providers/openai-reasoning-fallback.d.ts +0 -25
- package/dist/types/providers/openai-responses-server-schema.d.ts +0 -1314
- package/dist/types/providers/openai-responses-server.d.ts +0 -17
- package/dist/types/providers/openai-responses-wire.d.ts +0 -6099
- package/dist/types/providers/openai-responses.d.ts +0 -131
- package/dist/types/providers/openai-shared.d.ts +0 -624
- package/dist/types/providers/pi-native-client.d.ts +0 -13
- package/dist/types/providers/pi-native-server.d.ts +0 -69
- package/dist/types/providers/register-builtins.d.ts +0 -37
- package/dist/types/providers/synthetic.d.ts +0 -26
- package/dist/types/providers/transform-messages.d.ts +0 -32
- package/dist/types/providers/vision-guard.d.ts +0 -20
- package/dist/types/registry/aiand.d.ts +0 -7
- package/dist/types/registry/aimlapi.d.ts +0 -4
- package/dist/types/registry/alibaba-coding-plan.d.ts +0 -8
- package/dist/types/registry/alibaba-token-plan.d.ts +0 -18
- package/dist/types/registry/amazon-bedrock.d.ts +0 -5
- package/dist/types/registry/anthropic.d.ts +0 -10
- package/dist/types/registry/api-key-login.d.ts +0 -42
- package/dist/types/registry/api-key-validation.d.ts +0 -43
- package/dist/types/registry/aws.d.ts +0 -13
- package/dist/types/registry/azure.d.ts +0 -4
- package/dist/types/registry/baseten.d.ts +0 -7
- package/dist/types/registry/bedrock-mantle.d.ts +0 -22
- package/dist/types/registry/cerebras.d.ts +0 -7
- package/dist/types/registry/cloudflare-ai-gateway.d.ts +0 -13
- package/dist/types/registry/coreweave.d.ts +0 -7
- package/dist/types/registry/cursor.d.ts +0 -7
- package/dist/types/registry/deepseek.d.ts +0 -8
- package/dist/types/registry/derived.d.ts +0 -5
- package/dist/types/registry/devin.d.ts +0 -8
- package/dist/types/registry/exa.d.ts +0 -8
- package/dist/types/registry/firepass.d.ts +0 -16
- package/dist/types/registry/fireworks.d.ts +0 -7
- package/dist/types/registry/github-copilot.d.ts +0 -7
- package/dist/types/registry/gitlab-duo-workflow.d.ts +0 -10
- package/dist/types/registry/gitlab-duo.d.ts +0 -9
- package/dist/types/registry/gmi-cloud.d.ts +0 -7
- package/dist/types/registry/google-antigravity.d.ts +0 -9
- package/dist/types/registry/google-gemini-cli.d.ts +0 -9
- package/dist/types/registry/google-vertex.d.ts +0 -5
- package/dist/types/registry/google.d.ts +0 -4
- package/dist/types/registry/groq.d.ts +0 -4
- package/dist/types/registry/huggingface.d.ts +0 -7
- package/dist/types/registry/index.d.ts +0 -4
- package/dist/types/registry/kagi.d.ts +0 -14
- package/dist/types/registry/kilo.d.ts +0 -7
- package/dist/types/registry/kimi-code.d.ts +0 -7
- package/dist/types/registry/litellm.d.ts +0 -13
- package/dist/types/registry/llama-cpp.d.ts +0 -8
- package/dist/types/registry/lm-studio.d.ts +0 -8
- package/dist/types/registry/meta.d.ts +0 -7
- package/dist/types/registry/minimax-code-cn.d.ts +0 -6
- package/dist/types/registry/minimax-code.d.ts +0 -6
- package/dist/types/registry/minimax.d.ts +0 -4
- package/dist/types/registry/mistral.d.ts +0 -4
- package/dist/types/registry/moonshot.d.ts +0 -7
- package/dist/types/registry/nanogpt.d.ts +0 -7
- package/dist/types/registry/novita.d.ts +0 -6
- package/dist/types/registry/nvidia.d.ts +0 -7
- package/dist/types/registry/oauth/anthropic-constants.d.ts +0 -12
- package/dist/types/registry/oauth/anthropic.d.ts +0 -24
- package/dist/types/registry/oauth/callback-server.d.ts +0 -74
- package/dist/types/registry/oauth/cursor.d.ts +0 -16
- package/dist/types/registry/oauth/device-code.d.ts +0 -25
- package/dist/types/registry/oauth/devin.d.ts +0 -5
- package/dist/types/registry/oauth/github-copilot.d.ts +0 -30
- package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +0 -6
- package/dist/types/registry/oauth/gitlab-duo.d.ts +0 -3
- package/dist/types/registry/oauth/google-antigravity.d.ts +0 -11
- package/dist/types/registry/oauth/google-gemini-cli.d.ts +0 -22
- package/dist/types/registry/oauth/google-oauth-shared.d.ts +0 -56
- package/dist/types/registry/oauth/index.d.ts +0 -45
- package/dist/types/registry/oauth/kimi.d.ts +0 -21
- package/dist/types/registry/oauth/minimax-code.d.ts +0 -27
- package/dist/types/registry/oauth/openai-codex.d.ts +0 -33
- package/dist/types/registry/oauth/opencode.d.ts +0 -18
- package/dist/types/registry/oauth/perplexity.d.ts +0 -9
- package/dist/types/registry/oauth/pkce.d.ts +0 -8
- package/dist/types/registry/oauth/types.d.ts +0 -87
- package/dist/types/registry/oauth/wafer.d.ts +0 -1
- package/dist/types/registry/oauth/xai-oauth.d.ts +0 -46
- package/dist/types/registry/oauth/xiaomi.d.ts +0 -25
- package/dist/types/registry/oauth/zai.d.ts +0 -25
- package/dist/types/registry/ollama-cloud.d.ts +0 -7
- package/dist/types/registry/ollama.d.ts +0 -12
- package/dist/types/registry/openai-codex-device.d.ts +0 -8
- package/dist/types/registry/openai-codex.d.ts +0 -9
- package/dist/types/registry/openai.d.ts +0 -4
- package/dist/types/registry/opencode-go.d.ts +0 -6
- package/dist/types/registry/opencode-zen.d.ts +0 -6
- package/dist/types/registry/openrouter.d.ts +0 -13
- package/dist/types/registry/parallel.d.ts +0 -14
- package/dist/types/registry/perplexity.d.ts +0 -7
- package/dist/types/registry/qianfan.d.ts +0 -7
- package/dist/types/registry/qwen-portal.d.ts +0 -7
- package/dist/types/registry/registry.d.ts +0 -367
- package/dist/types/registry/sakana.d.ts +0 -7
- package/dist/types/registry/siliconflow-cn.d.ts +0 -7
- package/dist/types/registry/siliconflow.d.ts +0 -7
- package/dist/types/registry/synthetic.d.ts +0 -6
- package/dist/types/registry/tavily.d.ts +0 -14
- package/dist/types/registry/together.d.ts +0 -6
- package/dist/types/registry/types.d.ts +0 -75
- package/dist/types/registry/umans.d.ts +0 -7
- package/dist/types/registry/venice.d.ts +0 -13
- package/dist/types/registry/vercel-ai-gateway.d.ts +0 -7
- package/dist/types/registry/vllm.d.ts +0 -7
- package/dist/types/registry/wafer-serverless.d.ts +0 -6
- package/dist/types/registry/xai-oauth.d.ts +0 -7
- package/dist/types/registry/xai.d.ts +0 -7
- package/dist/types/registry/xiaomi-token-plan-ams.d.ts +0 -6
- package/dist/types/registry/xiaomi-token-plan-cn.d.ts +0 -6
- package/dist/types/registry/xiaomi-token-plan-sgp.d.ts +0 -6
- package/dist/types/registry/xiaomi.d.ts +0 -6
- package/dist/types/registry/zai.d.ts +0 -15
- package/dist/types/registry/zenmux.d.ts +0 -7
- package/dist/types/registry/zhipu-coding-plan.d.ts +0 -7
- package/dist/types/stream.d.ts +0 -46
- package/dist/types/types.d.ts +0 -1064
- package/dist/types/usage/alibaba-token-plan.d.ts +0 -3
- package/dist/types/usage/claude.d.ts +0 -4
- package/dist/types/usage/cursor.d.ts +0 -4
- package/dist/types/usage/gemini.d.ts +0 -2
- package/dist/types/usage/github-copilot.d.ts +0 -7
- package/dist/types/usage/google-antigravity.d.ts +0 -15
- package/dist/types/usage/kimi.d.ts +0 -2
- package/dist/types/usage/minimax-code.d.ts +0 -3
- package/dist/types/usage/ollama.d.ts +0 -5
- package/dist/types/usage/openai-codex-base-url.d.ts +0 -18
- package/dist/types/usage/openai-codex-reset.d.ts +0 -88
- package/dist/types/usage/openai-codex.d.ts +0 -10
- package/dist/types/usage/opencode-go.d.ts +0 -2
- package/dist/types/usage/shared.d.ts +0 -1
- package/dist/types/usage/synthetic.d.ts +0 -2
- package/dist/types/usage/umans.d.ts +0 -2
- package/dist/types/usage/xai-oauth.d.ts +0 -12
- package/dist/types/usage/zai.d.ts +0 -3
- package/dist/types/usage.d.ts +0 -527
- package/dist/types/utils/abort.d.ts +0 -25
- package/dist/types/utils/anthropic-auth.d.ts +0 -35
- package/dist/types/utils/aws-profile.d.ts +0 -17
- package/dist/types/utils/block-symbols.d.ts +0 -62
- package/dist/types/utils/deterministic-id.d.ts +0 -16
- package/dist/types/utils/empty-completion-retry.d.ts +0 -21
- package/dist/types/utils/event-stream.d.ts +0 -39
- package/dist/types/utils/foundry.d.ts +0 -1
- package/dist/types/utils/google-validation.d.ts +0 -2
- package/dist/types/utils/harmony-leak.d.ts +0 -135
- package/dist/types/utils/http-inspector.d.ts +0 -49
- package/dist/types/utils/idle-iterator.d.ts +0 -149
- package/dist/types/utils/leaked-thinking-stream.d.ts +0 -33
- package/dist/types/utils/openai-http.d.ts +0 -48
- package/dist/types/utils/openrouter-headers.d.ts +0 -1
- package/dist/types/utils/parse-bind.d.ts +0 -23
- package/dist/types/utils/provider-response.d.ts +0 -3
- package/dist/types/utils/proxy.d.ts +0 -39
- package/dist/types/utils/request-debug.d.ts +0 -29
- package/dist/types/utils/retry-after.d.ts +0 -4
- package/dist/types/utils/retry.d.ts +0 -14
- package/dist/types/utils/schema/adapt.d.ts +0 -24
- package/dist/types/utils/schema/compatibility.d.ts +0 -30
- package/dist/types/utils/schema/dereference.d.ts +0 -11
- package/dist/types/utils/schema/draft.d.ts +0 -10
- package/dist/types/utils/schema/equality.d.ts +0 -4
- package/dist/types/utils/schema/fields.d.ts +0 -54
- package/dist/types/utils/schema/index.d.ts +0 -14
- package/dist/types/utils/schema/json-schema-validator.d.ts +0 -20
- package/dist/types/utils/schema/meta-validator.d.ts +0 -2
- package/dist/types/utils/schema/normalize.d.ts +0 -153
- package/dist/types/utils/schema/spill.d.ts +0 -8
- package/dist/types/utils/schema/stamps.d.ts +0 -17
- package/dist/types/utils/schema/strict-tool-validation.d.ts +0 -16
- package/dist/types/utils/schema/types.d.ts +0 -4
- package/dist/types/utils/schema/typescript.d.ts +0 -24
- package/dist/types/utils/schema/wire.d.ts +0 -52
- package/dist/types/utils/sdk-stream-timeout.d.ts +0 -33
- package/dist/types/utils/sse-debug.d.ts +0 -5
- package/dist/types/utils/stream-markup-healing.d.ts +0 -87
- package/dist/types/utils/thinking-loop.d.ts +0 -102
- package/dist/types/utils/tool-call-loop-guard.d.ts +0 -26
- package/dist/types/utils/tool-choice.d.ts +0 -52
- package/dist/types/utils/validation.d.ts +0 -28
- package/dist/types/utils.d.ts +0 -57
|
@@ -7,7 +7,6 @@ import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
|
7
7
|
import { scheduler } from "node:timers/promises";
|
|
8
8
|
import { calculateCost } from "@linxiraos/pi-catalog/models";
|
|
9
9
|
import {
|
|
10
|
-
ANTIGRAVITY_SYSTEM_INSTRUCTION,
|
|
11
10
|
getAntigravityModelWireProfile,
|
|
12
11
|
getAntigravityUserAgent,
|
|
13
12
|
getGeminiCliHeaders,
|
|
@@ -31,11 +30,12 @@ import { normalizeSystemPrompts } from "../utils";
|
|
|
31
30
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
32
31
|
import { extractGoogleValidationUrl, formatGoogleValidationRequiredMessage } from "../utils/google-validation";
|
|
33
32
|
import type { RawHttpRequestDump } from "../utils/http-inspector";
|
|
34
|
-
import { armPreResponseTimeout, getStreamFirstEventTimeoutMs } from "../utils/idle-iterator";
|
|
33
|
+
import { armPreResponseTimeout, getStreamFirstEventTimeoutMs, iterateWithIdleTimeout } from "../utils/idle-iterator";
|
|
35
34
|
// Refresh is the sole responsibility of AuthStorage (broker-aware, single-flighted);
|
|
36
35
|
// the stream provider trusts the access token threaded through `options.apiKey`.
|
|
37
36
|
import { normalizeSchemaForCCA } from "../utils/schema";
|
|
38
37
|
import { StreamMarkupHealing, type StreamMarkupHealingEvent } from "../utils/stream-markup-healing";
|
|
38
|
+
import forcedToolDirective from "./google-antigravity-forced-tool.md" with { type: "text" };
|
|
39
39
|
import type { Content, FunctionCallingConfigMode, ThinkingConfig } from "./google-shared";
|
|
40
40
|
import {
|
|
41
41
|
convertMessages,
|
|
@@ -315,16 +315,12 @@ const ANTIGRAVITY_DAILY_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
|
|
|
315
315
|
const ANTIGRAVITY_SANDBOX_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
|
|
316
316
|
const ANTIGRAVITY_ENDPOINT_FALLBACKS = [ANTIGRAVITY_DAILY_ENDPOINT, ANTIGRAVITY_SANDBOX_ENDPOINT] as const;
|
|
317
317
|
|
|
318
|
-
export {
|
|
319
|
-
ANTIGRAVITY_SYSTEM_INSTRUCTION,
|
|
320
|
-
getAntigravityUserAgent,
|
|
321
|
-
getGeminiCliHeaders,
|
|
322
|
-
getGeminiCliUserAgent,
|
|
323
|
-
} from "@linxiraos/pi-catalog/wire/gemini-headers";
|
|
324
|
-
|
|
325
318
|
// Retry configuration
|
|
326
319
|
const MAX_RETRIES = 3;
|
|
327
320
|
const BASE_DELAY_MS = 1000;
|
|
321
|
+
const FLASH_FIRST_EVENT_TIMEOUT_MS = 60_000;
|
|
322
|
+
const DEFAULT_FIRST_EVENT_TIMEOUT_MS = 300_000;
|
|
323
|
+
const FIRST_EVENT_TIMEOUT_ERROR = "Cloud Code Assist stream timed out while waiting for the first event";
|
|
328
324
|
const RATE_LIMIT_BUDGET_MS = 5 * 60 * 1000;
|
|
329
325
|
const CLAUDE_THINKING_BETA_HEADER = "interleaved-thinking-2025-05-14";
|
|
330
326
|
const GOOGLE_GEMINI_REFRESH_SKEW_MS = 60_000;
|
|
@@ -338,11 +334,6 @@ function needsClaudeThinkingBetaHeader(model: Model<"google-gemini-cli">): boole
|
|
|
338
334
|
return model.provider === "google-antigravity" && model.id.startsWith("claude-") && model.reasoning;
|
|
339
335
|
}
|
|
340
336
|
|
|
341
|
-
function shouldInjectAntigravitySystemInstruction(modelId: string): boolean {
|
|
342
|
-
const normalized = modelId.toLowerCase();
|
|
343
|
-
return normalized.includes("claude") || normalized.includes("gemini-3");
|
|
344
|
-
}
|
|
345
|
-
|
|
346
337
|
const optionalCredentialString = type("unknown").pipe(raw => {
|
|
347
338
|
const out = type("string")(raw);
|
|
348
339
|
return out instanceof type.errors ? undefined : out;
|
|
@@ -616,17 +607,23 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
616
607
|
headers: requestHeaders,
|
|
617
608
|
};
|
|
618
609
|
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
//
|
|
622
|
-
//
|
|
610
|
+
// The provider owns the first-event watchdog so a silent successful
|
|
611
|
+
// response can fail over to the alternate Antigravity endpoint before
|
|
612
|
+
// anything user-visible has streamed. Flash should not inherit the
|
|
613
|
+
// five-minute allowance reserved for cold Pro reasoning starts.
|
|
623
614
|
const firstEventTimeoutMs =
|
|
624
|
-
options?.streamFirstEventTimeoutMs ??
|
|
615
|
+
options?.streamFirstEventTimeoutMs ??
|
|
616
|
+
getStreamFirstEventTimeoutMs(
|
|
617
|
+
undefined,
|
|
618
|
+
model.id.includes("flash") ? FLASH_FIRST_EVENT_TIMEOUT_MS : DEFAULT_FIRST_EVENT_TIMEOUT_MS,
|
|
619
|
+
);
|
|
625
620
|
const callerSignal = options?.signal;
|
|
626
621
|
const toolNames = new Set(context.tools?.map(t => t.name) ?? []);
|
|
627
622
|
const isFlashLeakModel = model.id.includes("flash");
|
|
628
623
|
|
|
629
624
|
let started = false;
|
|
625
|
+
// Once any stream event starts, the endpoint is committed downstream.
|
|
626
|
+
// Failover remains safe only while `started` is false.
|
|
630
627
|
let sawFinishReason = false;
|
|
631
628
|
let lastResponseId: string | undefined;
|
|
632
629
|
const ensureStarted = () => {
|
|
@@ -653,7 +650,9 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
653
650
|
sawFinishReason = false;
|
|
654
651
|
};
|
|
655
652
|
|
|
656
|
-
const streamResponse = async (
|
|
653
|
+
const streamResponse = async (
|
|
654
|
+
activeResponse: Response,
|
|
655
|
+
): Promise<{ meaningful: boolean; strippedPlanningLeak: boolean }> => {
|
|
657
656
|
if (!activeResponse.body) {
|
|
658
657
|
throw new AIError.ProviderResponseError("No response body", {
|
|
659
658
|
provider: model.provider,
|
|
@@ -673,6 +672,7 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
673
672
|
let isBuffering = false;
|
|
674
673
|
let textBuffer = "";
|
|
675
674
|
let bufferedTextSignature: string | undefined;
|
|
675
|
+
let strippedPlanningLeak = false;
|
|
676
676
|
|
|
677
677
|
const endCurrentBlock = (): void => {
|
|
678
678
|
if (!currentBlock) return;
|
|
@@ -755,11 +755,24 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
755
755
|
}
|
|
756
756
|
};
|
|
757
757
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
options
|
|
761
|
-
|
|
762
|
-
|
|
758
|
+
const responseAbortController = new AbortController();
|
|
759
|
+
const responseSignal = options?.signal
|
|
760
|
+
? AbortSignal.any([options.signal, responseAbortController.signal])
|
|
761
|
+
: responseAbortController.signal;
|
|
762
|
+
const chunks = iterateWithIdleTimeout(
|
|
763
|
+
readSseJson<CloudCodeAssistResponseChunk>(activeResponse.body, responseSignal, event =>
|
|
764
|
+
options?.onSseEvent?.({ event: event.event, data: event.data, raw: [...event.raw] }, model),
|
|
765
|
+
),
|
|
766
|
+
{
|
|
767
|
+
firstItemTimeoutMs: firstEventTimeoutMs,
|
|
768
|
+
errorMessage: FIRST_EVENT_TIMEOUT_ERROR,
|
|
769
|
+
firstItemErrorMessage: FIRST_EVENT_TIMEOUT_ERROR,
|
|
770
|
+
onFirstItemTimeout: () =>
|
|
771
|
+
responseAbortController.abort(new AIError.StreamTimeoutError(FIRST_EVENT_TIMEOUT_ERROR)),
|
|
772
|
+
abortSignal: options?.signal,
|
|
773
|
+
},
|
|
774
|
+
);
|
|
775
|
+
for await (const chunk of chunks) {
|
|
763
776
|
if (chunk.error) {
|
|
764
777
|
const detail = chunk.error.message || chunk.error.status || "unknown error";
|
|
765
778
|
const message = `Cloud Code Assist stream error: ${detail}`;
|
|
@@ -815,6 +828,7 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
815
828
|
if (isBuffering) {
|
|
816
829
|
const buffered = consumePlanningBuffer(textBuffer, toolNames);
|
|
817
830
|
if (buffered.kind !== "incomplete") {
|
|
831
|
+
if (buffered.kind === "leak") strippedPlanningLeak = true;
|
|
818
832
|
const visibleSignature = bufferedTextSignature;
|
|
819
833
|
isBuffering = false;
|
|
820
834
|
textBuffer = "";
|
|
@@ -895,6 +909,7 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
895
909
|
const buffered = consumePlanningBuffer(textBuffer, toolNames, true);
|
|
896
910
|
|
|
897
911
|
if (buffered.kind !== "incomplete") {
|
|
912
|
+
if (buffered.kind === "leak") strippedPlanningLeak = true;
|
|
898
913
|
feedVisibleText(buffered.visibleText, bufferedTextSignature);
|
|
899
914
|
}
|
|
900
915
|
bufferedTextSignature = undefined;
|
|
@@ -905,10 +920,18 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
905
920
|
flushVisibleText(bufferedTextSignature);
|
|
906
921
|
endCurrentBlock();
|
|
907
922
|
|
|
908
|
-
return
|
|
923
|
+
return {
|
|
924
|
+
meaningful: hasMeaningfulGoogleContent(output),
|
|
925
|
+
strippedPlanningLeak,
|
|
926
|
+
};
|
|
909
927
|
};
|
|
910
928
|
|
|
911
929
|
let receivedContent = false;
|
|
930
|
+
const hasThinkingOutput = () =>
|
|
931
|
+
output.content.some(
|
|
932
|
+
block =>
|
|
933
|
+
block.type === "thinking" && (block.thinking.trim().length > 0 || Boolean(block.thinkingSignature)),
|
|
934
|
+
);
|
|
912
935
|
|
|
913
936
|
for (let i = 0; i < endpoints.length; i++) {
|
|
914
937
|
const endpoint = endpoints[i];
|
|
@@ -998,11 +1021,26 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
998
1021
|
}
|
|
999
1022
|
|
|
1000
1023
|
const streamed = await streamResponse(currentResponse);
|
|
1001
|
-
|
|
1002
|
-
|
|
1024
|
+
// Eventless silence may fail over to the alternate Antigravity
|
|
1025
|
+
// endpoint. Once thinking has streamed, the endpoint is already
|
|
1026
|
+
// committed downstream; Advisor mode may accept that silence,
|
|
1027
|
+
// while normal sessions surface it to final-output recovery.
|
|
1028
|
+
const thoughtOnly = hasThinkingOutput();
|
|
1029
|
+
const acceptedSilence =
|
|
1030
|
+
options?.acceptEmptyResponse === true &&
|
|
1031
|
+
!streamed.strippedPlanningLeak &&
|
|
1032
|
+
(isLastEndpoint || thoughtOnly);
|
|
1033
|
+
if (output.stopReason !== "stop" || streamed.meaningful || acceptedSilence) {
|
|
1034
|
+
receivedContent = streamed.meaningful || acceptedSilence;
|
|
1003
1035
|
break;
|
|
1004
1036
|
}
|
|
1005
1037
|
|
|
1038
|
+
// A thought-only STOP is a complete provider response, not a
|
|
1039
|
+
// transiently empty transport. Replaying the identical request
|
|
1040
|
+
// burns another full reasoning pass; let session recovery add
|
|
1041
|
+
// an explicit final-output reminder instead.
|
|
1042
|
+
if (thoughtOnly) break;
|
|
1043
|
+
|
|
1006
1044
|
if (emptyAttempt < MAX_EMPTY_STREAM_RETRIES) {
|
|
1007
1045
|
resetOutput();
|
|
1008
1046
|
}
|
|
@@ -1016,10 +1054,16 @@ export const streamGoogleGeminiCli: StreamFunction<"google-gemini-cli"> = (
|
|
|
1016
1054
|
}
|
|
1017
1055
|
|
|
1018
1056
|
if (!receivedContent) {
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1057
|
+
const thoughtOnly = hasThinkingOutput();
|
|
1058
|
+
throw new AIError.ProviderResponseError(
|
|
1059
|
+
thoughtOnly
|
|
1060
|
+
? "Cloud Code Assist API returned a thought-only response without final output"
|
|
1061
|
+
: "Cloud Code Assist API returned an empty response",
|
|
1062
|
+
{
|
|
1063
|
+
provider: model.provider,
|
|
1064
|
+
kind: thoughtOnly ? "empty-output" : "empty-body",
|
|
1065
|
+
},
|
|
1066
|
+
);
|
|
1023
1067
|
}
|
|
1024
1068
|
|
|
1025
1069
|
if (options?.signal?.aborted) {
|
|
@@ -1285,14 +1329,6 @@ export function buildRequest(
|
|
|
1285
1329
|
};
|
|
1286
1330
|
}
|
|
1287
1331
|
|
|
1288
|
-
if (isAntigravity && shouldInjectAntigravitySystemInstruction(model.id)) {
|
|
1289
|
-
const existingParts = request.systemInstruction?.parts ?? [];
|
|
1290
|
-
request.systemInstruction = {
|
|
1291
|
-
role: "user",
|
|
1292
|
-
parts: [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }, ...existingParts],
|
|
1293
|
-
};
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
1332
|
if (context.tools && context.tools.length > 0) {
|
|
1297
1333
|
const convertedTools = convertTools(context.tools, model);
|
|
1298
1334
|
request.tools = isAntigravity ? normalizeAntigravityTools(convertedTools) : convertedTools;
|
|
@@ -1313,6 +1349,13 @@ export function buildRequest(
|
|
|
1313
1349
|
},
|
|
1314
1350
|
};
|
|
1315
1351
|
}
|
|
1352
|
+
// Cloud Code Assist drops `toolConfig` on Antigravity's Gemini routes:
|
|
1353
|
+
// the backend answers in text under `mode: "ANY"` and still emits calls
|
|
1354
|
+
// under `"NONE"`. Claude routes implement it, so only Gemini needs the
|
|
1355
|
+
// forced choice restated in the transcript.
|
|
1356
|
+
if (isAntigravity && !isClaudeModel(model.id) && request.toolConfig?.functionCallingConfig.mode === "ANY") {
|
|
1357
|
+
contents.push({ role: "user", parts: [{ text: forcedToolDirective }] });
|
|
1358
|
+
}
|
|
1316
1359
|
}
|
|
1317
1360
|
// Antigravity's default tool mode is VALIDATED (verified for Gemini and
|
|
1318
1361
|
// Claude); an explicit non-auto tool choice above wins.
|
|
@@ -233,6 +233,8 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
|
|
|
233
233
|
const parts: Part[] = [];
|
|
234
234
|
// Check if message is from same provider and model - only then keep thinking blocks
|
|
235
235
|
const isSameProviderAndModel = msg.provider === model.provider && msg.model === model.id;
|
|
236
|
+
const dropsUnsignedThinking =
|
|
237
|
+
model.provider === "google-antigravity" && model.id.toLowerCase().includes("claude");
|
|
236
238
|
|
|
237
239
|
for (const block of msg.content) {
|
|
238
240
|
if (block.type === "text") {
|
|
@@ -247,6 +249,7 @@ export function convertMessages<T extends GoogleApiType>(model: Model<T>, contex
|
|
|
247
249
|
// Skip empty thinking blocks
|
|
248
250
|
if (!block.thinking || block.thinking.trim() === "") continue;
|
|
249
251
|
const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thinkingSignature);
|
|
252
|
+
if (dropsUnsignedThinking && !thoughtSignature) continue;
|
|
250
253
|
if (thoughtSignature) {
|
|
251
254
|
parts.push({
|
|
252
255
|
thought: true,
|
|
@@ -858,13 +861,18 @@ export function buildGoogleGenerateContentParams<T extends "google-generative-ai
|
|
|
858
861
|
config.toolConfig = undefined;
|
|
859
862
|
}
|
|
860
863
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
864
|
+
const thinking = options.thinking;
|
|
865
|
+
if (
|
|
866
|
+
thinking &&
|
|
867
|
+
model.reasoning &&
|
|
868
|
+
(thinking.enabled || thinking.level !== undefined || thinking.budgetTokens !== undefined)
|
|
869
|
+
) {
|
|
870
|
+
const cfg: ThinkingConfig = { includeThoughts: thinking.enabled && !options.hideThinkingSummary };
|
|
871
|
+
if (thinking.level !== undefined) {
|
|
872
|
+
// GoogleThinkingLevel mirrors the SDK's ThinkingLevel string enum values 1:1.
|
|
873
|
+
cfg.thinkingLevel = thinking.level as ThinkingLevel;
|
|
874
|
+
} else if (thinking.budgetTokens !== undefined) {
|
|
875
|
+
cfg.thinkingBudget = thinking.budgetTokens;
|
|
868
876
|
}
|
|
869
877
|
config.thinkingConfig = cfg;
|
|
870
878
|
}
|
|
@@ -1031,7 +1039,13 @@ export function streamGoogleGenAI<T extends "google-generative-ai" | "google-ver
|
|
|
1031
1039
|
},
|
|
1032
1040
|
});
|
|
1033
1041
|
|
|
1034
|
-
if (
|
|
1042
|
+
if (
|
|
1043
|
+
output.stopReason !== "stop" ||
|
|
1044
|
+
hasMeaningfulGoogleContent(output) ||
|
|
1045
|
+
options?.acceptEmptyResponse === true
|
|
1046
|
+
) {
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1035
1049
|
if (emptyAttempt >= MAX_EMPTY_STREAM_RETRIES) {
|
|
1036
1050
|
throw new AIError.ProviderResponseError(
|
|
1037
1051
|
`Google API returned an empty response (finishReason STOP with no content) after ${MAX_EMPTY_STREAM_RETRIES + 1} attempts`,
|
package/src/providers/ollama.ts
CHANGED
|
@@ -328,15 +328,27 @@ function createChatBody(model: Model<"ollama-chat">, context: Context, options:
|
|
|
328
328
|
const toolChoice = mapToolChoice(options?.toolChoice);
|
|
329
329
|
const selectedTools = selectToolsForToolChoice(context.tools, options?.toolChoice);
|
|
330
330
|
const tools = convertTools(selectedTools);
|
|
331
|
+
const runtimeOptions: { num_predict?: number; temperature?: number; top_p?: number } = {};
|
|
332
|
+
let hasRuntimeOptions = false;
|
|
333
|
+
if (options?.maxTokens !== undefined && !model.omitMaxOutputTokens) {
|
|
334
|
+
runtimeOptions.num_predict = resolveNumPredict(model, options.maxTokens);
|
|
335
|
+
hasRuntimeOptions = true;
|
|
336
|
+
}
|
|
337
|
+
if (options?.temperature !== undefined) {
|
|
338
|
+
runtimeOptions.temperature = options.temperature;
|
|
339
|
+
hasRuntimeOptions = true;
|
|
340
|
+
}
|
|
341
|
+
if (options?.topP !== undefined) {
|
|
342
|
+
runtimeOptions.top_p = options.topP;
|
|
343
|
+
hasRuntimeOptions = true;
|
|
344
|
+
}
|
|
331
345
|
return {
|
|
332
346
|
model: model.id,
|
|
333
347
|
messages: convertMessages(model, context),
|
|
334
348
|
...(tools ? { tools } : {}),
|
|
335
349
|
...(think !== undefined ? { think } : {}),
|
|
336
350
|
...(toolChoice !== undefined ? { tool_choice: toolChoice } : {}),
|
|
337
|
-
...(options
|
|
338
|
-
? { options: { num_predict: resolveNumPredict(model, options.maxTokens) } }
|
|
339
|
-
: {}),
|
|
351
|
+
...(hasRuntimeOptions ? { options: runtimeOptions } : {}),
|
|
340
352
|
stream: true,
|
|
341
353
|
};
|
|
342
354
|
}
|
|
@@ -32,6 +32,8 @@ export interface ReasoningConfig {
|
|
|
32
32
|
export interface CodexRequestOptions {
|
|
33
33
|
/** User-facing effort; maps 1:1 onto the wire tier of the same name. */
|
|
34
34
|
reasoningEffort?: CodexCallerEffort | "none";
|
|
35
|
+
/** Suppress native reasoning by sending `reasoning.effort: "none"`. */
|
|
36
|
+
reasoningOff?: boolean;
|
|
35
37
|
reasoningSummary?: ReasoningConfig["summary"] | null;
|
|
36
38
|
/** Explicit `reasoning.context` override. Omitted by default; Responses Lite forces `all_turns` as required by that transport. */
|
|
37
39
|
reasoningContext?: CodexReasoningContext;
|
|
@@ -109,6 +111,22 @@ export function resolveCodexResponsesLite(
|
|
|
109
111
|
return model.useResponsesLite === true;
|
|
110
112
|
}
|
|
111
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Whether to request `stream_options.reasoning_summary_delivery =
|
|
116
|
+
* "sequential_cutoff"` (codex-rs `concurrent_reasoning_summaries`), enabled by
|
|
117
|
+
* `PI_CODEX_CONCURRENT_SUMMARIES=1`.
|
|
118
|
+
*
|
|
119
|
+
* Off by default because the mode cancels summary sections still in flight when
|
|
120
|
+
* the reasoning item closes: measured over 12 interleaved turns it halved
|
|
121
|
+
* visible thinking (0.83 vs 1.67 summary parts, 37 vs 69 chars per turn) and
|
|
122
|
+
* produced no summary at all on 3 of 12 turns. codex-rs ships it disabled too
|
|
123
|
+
* (`Stage::UnderDevelopment`, `default_enabled: false`).
|
|
124
|
+
*/
|
|
125
|
+
function concurrentSummariesEnabled(): boolean {
|
|
126
|
+
const env = $env.PI_CODEX_CONCURRENT_SUMMARIES?.trim().toLowerCase();
|
|
127
|
+
return env === "1" || env === "true";
|
|
128
|
+
}
|
|
129
|
+
|
|
112
130
|
/**
|
|
113
131
|
* Clamp a user-facing effort to the model's ladder, then remap to the wire
|
|
114
132
|
* tier. User efforts map 1:1 onto wire tiers; the effort map only covers
|
|
@@ -145,12 +163,14 @@ function getReasoningConfig(
|
|
|
145
163
|
const config: ReasoningConfig = {
|
|
146
164
|
effort: effort === "none" ? "none" : mapCodexWireEffort(model, effort),
|
|
147
165
|
};
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
// The backend only emits reasoning summaries when `reasoning.summary` is
|
|
167
|
+
// present: omitting it yields zero `response.reasoning_summary_text.*`
|
|
168
|
+
// events (measured against gpt-5.5, gpt-5.6-sol and gpt-5.6-terra). So
|
|
169
|
+
// `undefined` means "default on" — matching `applyResponsesCompatPolicy`
|
|
170
|
+
// on the plain Responses path — and only an explicit `null` (the caller
|
|
171
|
+
// hiding thinking) opts out.
|
|
172
|
+
if (options.reasoningSummary !== null && supportsCodexReasoningSummary(model.id)) {
|
|
173
|
+
config.summary = options.reasoningSummary ?? "auto";
|
|
154
174
|
}
|
|
155
175
|
return config;
|
|
156
176
|
}
|
|
@@ -436,20 +456,25 @@ export async function transformRequestBody(
|
|
|
436
456
|
applyCodexResponsesLiteShape(body);
|
|
437
457
|
}
|
|
438
458
|
|
|
439
|
-
if (options.reasoningEffort !== undefined || responsesLite) {
|
|
440
|
-
const reasoningConfig =
|
|
441
|
-
|
|
459
|
+
if (options.reasoningOff || options.reasoningEffort !== undefined || responsesLite) {
|
|
460
|
+
const reasoningConfig: Partial<ReasoningConfig> = options.reasoningOff
|
|
461
|
+
? { effort: "none" }
|
|
462
|
+
: options.reasoningEffort !== undefined
|
|
463
|
+
? getReasoningConfig(model, options.reasoningEffort, options)
|
|
464
|
+
: {};
|
|
442
465
|
body.reasoning = {
|
|
443
466
|
...body.reasoning,
|
|
444
467
|
...reasoningConfig,
|
|
445
468
|
};
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
469
|
+
// Lite requires `all_turns` even for opaque/codenamed model ids. Only explicit
|
|
470
|
+
// full-transport overrides are gated by the known model wire generation.
|
|
471
|
+
if (responsesLite) {
|
|
472
|
+
body.reasoning.context = "all_turns";
|
|
473
|
+
} else if (options.reasoningContext !== undefined) {
|
|
474
|
+
if (options.reasoningContext === "all_turns" && !supportsAllTurnsReasoningContext(model.id)) {
|
|
450
475
|
delete body.reasoning.context;
|
|
451
476
|
} else {
|
|
452
|
-
body.reasoning.context =
|
|
477
|
+
body.reasoning.context = options.reasoningContext;
|
|
453
478
|
}
|
|
454
479
|
}
|
|
455
480
|
} else {
|
|
@@ -458,16 +483,17 @@ export async function transformRequestBody(
|
|
|
458
483
|
// Catalog pro aliases (`gpt-5.6-*-pro`): applied after the effort branch so
|
|
459
484
|
// the mode is sent even when no effort is set (the branch above deletes
|
|
460
485
|
// `body.reasoning` in that case) — mode and effort are independent fields.
|
|
461
|
-
if (model.reasoningMode) {
|
|
486
|
+
if (model.reasoningMode && !options.reasoningOff) {
|
|
462
487
|
body.reasoning = { ...body.reasoning, mode: model.reasoningMode };
|
|
463
488
|
}
|
|
464
489
|
|
|
465
|
-
// Concurrent reasoning summaries (codex-rs `concurrent_reasoning_summaries`
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
|
|
490
|
+
// Concurrent reasoning summaries (codex-rs `concurrent_reasoning_summaries`):
|
|
491
|
+
// `sequential_cutoff` lets the server stream output without blocking on
|
|
492
|
+
// summary generation, delivering each completed section as an atomic
|
|
493
|
+
// `response.reasoning_summary_text.done`. Opt-in only — see
|
|
494
|
+
// {@link concurrentSummariesEnabled} for why. Requires a requested summary;
|
|
495
|
+
// codex-rs additionally gates on its OpenAI provider check, inherent here.
|
|
496
|
+
if (body.reasoning?.summary !== undefined && concurrentSummariesEnabled()) {
|
|
471
497
|
body.stream_options = { reasoning_summary_delivery: "sequential_cutoff" };
|
|
472
498
|
} else {
|
|
473
499
|
delete body.stream_options;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as os from "node:os";
|
|
2
1
|
import { scheduler } from "node:timers/promises";
|
|
3
2
|
import { calculateCost } from "@linxiraos/pi-catalog/models";
|
|
4
3
|
import {
|
|
@@ -19,8 +18,8 @@ import {
|
|
|
19
18
|
parseStreamingJson,
|
|
20
19
|
readSseJson,
|
|
21
20
|
structuredCloneJSON,
|
|
21
|
+
USER_AGENT,
|
|
22
22
|
} from "@linxiraos/pi-utils";
|
|
23
|
-
import packageJson from "../../package.json" with { type: "json" };
|
|
24
23
|
import * as AIError from "../error";
|
|
25
24
|
import { getEnvApiKey, isOfficialCodexApiUrl } from "../stream";
|
|
26
25
|
import type {
|
|
@@ -1530,6 +1529,7 @@ export async function buildTransformedCodexRequestBody(
|
|
|
1530
1529
|
}
|
|
1531
1530
|
const codexOptions: CodexRequestOptions = {
|
|
1532
1531
|
reasoningEffort: options?.reasoning,
|
|
1532
|
+
reasoningOff: options?.forceReasoningOff,
|
|
1533
1533
|
reasoningSummary: options?.reasoningSummary,
|
|
1534
1534
|
reasoningContext: options?.reasoningContext,
|
|
1535
1535
|
textVerbosity: options?.textVerbosity,
|
|
@@ -4250,7 +4250,7 @@ function createCodexHeaders(
|
|
|
4250
4250
|
headers.set(OPENAI_HEADERS.BETA, betaHeader);
|
|
4251
4251
|
headers.set(OPENAI_HEADERS.ORIGINATOR, OPENAI_HEADER_VALUES.ORIGINATOR_CODEX);
|
|
4252
4252
|
headers.set(OPENAI_HEADERS.VERSION, codexClientVersion);
|
|
4253
|
-
headers.set("User-Agent",
|
|
4253
|
+
headers.set("User-Agent", USER_AGENT);
|
|
4254
4254
|
if (sessionId) {
|
|
4255
4255
|
headers.set(OPENAI_HEADERS.CONVERSATION_ID, sessionId);
|
|
4256
4256
|
headers.set(OPENAI_HEADERS.SESSION_ID, sessionId);
|
|
@@ -132,7 +132,13 @@ function collectMessageParts(error: unknown, captured: CapturedHttpErrorResponse
|
|
|
132
132
|
return parts.join("\n");
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Text that identifies a 400 as being about the reasoning-effort field.
|
|
137
|
+
* OpenAI-compatible gateways (cliproxy, …) never name the field — they reject
|
|
138
|
+
* the value alone with `level "none" not supported, valid levels: low, …` — so
|
|
139
|
+
* the allowed-level phrasing counts as a mention too.
|
|
140
|
+
*/
|
|
141
|
+
const REASONING_EFFORT_FIELD_PATTERN = /reasoning[_. ]effort|reasoning value|(?:valid|supported|allowed) levels?/i;
|
|
136
142
|
|
|
137
143
|
function mentionsReasoningEffort(error: unknown, captured: CapturedHttpErrorResponse | undefined): boolean {
|
|
138
144
|
const param = capturedStringField(captured, "param");
|
|
@@ -168,10 +174,13 @@ function isInvalidReasoningEffortError(
|
|
|
168
174
|
if (/(?:unsupported|not supported)[^\n]*(?:reasoning[_. ]effort|reasoning value)/i.test(message)) {
|
|
169
175
|
return true;
|
|
170
176
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
// Gateways put the rejected value first (`level "none" not supported`), the
|
|
178
|
+
// official API puts the verdict first (`Unsupported value: 'none'`).
|
|
179
|
+
const quoted = `["'\`]${escapeRegExp(currentEffort)}["'\`]`;
|
|
180
|
+
return (
|
|
181
|
+
new RegExp(`(?:invalid|unsupported|not supported)[^\\n]*${quoted}`, "i").test(message) ||
|
|
182
|
+
new RegExp(`${quoted}[^\\n]*(?:invalid|unsupported|not supported)`, "i").test(message)
|
|
183
|
+
);
|
|
175
184
|
}
|
|
176
185
|
|
|
177
186
|
function escapeRegExp(value: string): string {
|
|
@@ -186,9 +195,12 @@ function parseKnownReasoningValues(text: string): Set<string> {
|
|
|
186
195
|
values.add(quotedMatch[1]!.toLowerCase());
|
|
187
196
|
quotedMatch = quotedPattern.exec(text);
|
|
188
197
|
}
|
|
189
|
-
const allowedMatch =
|
|
198
|
+
const allowedMatch =
|
|
199
|
+
/(?:must be|one of|allowed values?|supported values?(?: are)?|expected|(?:valid|supported|allowed) levels?(?: are)?)[^.\n]+/i.exec(
|
|
200
|
+
text,
|
|
201
|
+
);
|
|
190
202
|
if (allowedMatch) {
|
|
191
|
-
const allowedText = allowedMatch[
|
|
203
|
+
const allowedText = allowedMatch[0]!;
|
|
192
204
|
const barePattern = /\b(none|minimal|low|medium|high|xhigh|max)\b/gi;
|
|
193
205
|
let bareMatch = barePattern.exec(allowedText);
|
|
194
206
|
while (bareMatch !== null) {
|
|
@@ -201,7 +213,8 @@ function parseKnownReasoningValues(text: string): Set<string> {
|
|
|
201
213
|
|
|
202
214
|
function parseAllowedReasoningValues(message: string, currentEffort: string): Set<string> | undefined {
|
|
203
215
|
const values = parseKnownReasoningValues(message);
|
|
204
|
-
const hasAllowedCue =
|
|
216
|
+
const hasAllowedCue =
|
|
217
|
+
/must be|one of|allowed values?|supported values?|expected|(?:valid|supported|allowed) levels?/i.test(message);
|
|
205
218
|
values.delete(currentEffort.toLowerCase());
|
|
206
219
|
if (!hasAllowedCue && values.size === 0) return undefined;
|
|
207
220
|
return values;
|