@linxiraos/pi-ai 1.0.0
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 +5066 -0
- package/README.md +1195 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth/sqlite-credential-store.d.ts +117 -0
- package/dist/types/auth-broker/client.d.ts +93 -0
- package/dist/types/auth-broker/discover.d.ts +39 -0
- package/dist/types/auth-broker/index.d.ts +7 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +136 -0
- package/dist/types/auth-broker/server.d.ts +48 -0
- package/dist/types/auth-broker/snapshot-cache.d.ts +17 -0
- package/dist/types/auth-broker/types.d.ts +152 -0
- package/dist/types/auth-broker/wire-schema-resource.d.ts +53 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +5 -0
- package/dist/types/auth-gateway/http.d.ts +56 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +36 -0
- package/dist/types/auth-gateway/types.d.ts +127 -0
- package/dist/types/auth-retry.d.ts +150 -0
- package/dist/types/auth-storage.d.ts +1258 -0
- package/dist/types/dialect/anthropic.d.ts +15 -0
- package/dist/types/dialect/catalog.d.ts +3 -0
- package/dist/types/dialect/coercion.d.ts +23 -0
- package/dist/types/dialect/deepseek.d.ts +14 -0
- package/dist/types/dialect/demotion.d.ts +30 -0
- package/dist/types/dialect/examples.d.ts +18 -0
- package/dist/types/dialect/factory.d.ts +3 -0
- package/dist/types/dialect/fenced-thinking.d.ts +53 -0
- package/dist/types/dialect/gemini.d.ts +17 -0
- package/dist/types/dialect/gemma.d.ts +15 -0
- package/dist/types/dialect/glm.d.ts +9 -0
- package/dist/types/dialect/harmony.d.ts +8 -0
- package/dist/types/dialect/hermes.d.ts +9 -0
- package/dist/types/dialect/history.d.ts +3 -0
- package/dist/types/dialect/index.d.ts +11 -0
- package/dist/types/dialect/inventory.d.ts +9 -0
- package/dist/types/dialect/kimi.d.ts +14 -0
- package/dist/types/dialect/minimax.d.ts +3 -0
- package/dist/types/dialect/owned-stream.d.ts +4 -0
- package/dist/types/dialect/qwen3.d.ts +9 -0
- package/dist/types/dialect/rendering.d.ts +54 -0
- package/dist/types/dialect/thinking.d.ts +6 -0
- package/dist/types/dialect/types.d.ts +68 -0
- package/dist/types/dialect/xml.d.ts +9 -0
- package/dist/types/error/abort.d.ts +14 -0
- package/dist/types/error/auth-classify.d.ts +20 -0
- package/dist/types/error/auth.d.ts +27 -0
- package/dist/types/error/aws.d.ts +27 -0
- package/dist/types/error/classes.d.ts +106 -0
- package/dist/types/error/finalize.d.ts +39 -0
- package/dist/types/error/flags.d.ts +94 -0
- package/dist/types/error/format.d.ts +20 -0
- package/dist/types/error/gateway.d.ts +20 -0
- package/dist/types/error/index.d.ts +14 -0
- package/dist/types/error/oauth.d.ts +43 -0
- package/dist/types/error/provider.d.ts +42 -0
- package/dist/types/error/rate-limit.d.ts +80 -0
- package/dist/types/error/retryable.d.ts +27 -0
- package/dist/types/error/validation.d.ts +32 -0
- package/dist/types/index.d.ts +51 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/providers/amazon-bedrock.d.ts +39 -0
- package/dist/types/providers/anthropic-client.d.ts +106 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +937 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic-wire.d.ts +345 -0
- package/dist/types/providers/anthropic.d.ts +261 -0
- package/dist/types/providers/aws-credentials.d.ts +48 -0
- package/dist/types/providers/aws-eventstream.d.ts +39 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +16 -0
- package/dist/types/providers/bedrock-mantle.d.ts +13 -0
- package/dist/types/providers/claude-code-fingerprint.d.ts +19 -0
- package/dist/types/providers/cowork-fetch.d.ts +3 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor-pi-args.d.ts +105 -0
- package/dist/types/providers/cursor.d.ts +221 -0
- package/dist/types/providers/devin.d.ts +12 -0
- package/dist/types/providers/error-message.d.ts +25 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo-workflow.d.ts +254 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +24 -0
- package/dist/types/providers/google-gemini-cli.d.ts +120 -0
- package/dist/types/providers/google-shared.d.ts +203 -0
- package/dist/types/providers/google-types.d.ts +155 -0
- package/dist/types/providers/google-vertex.d.ts +7 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/mock.d.ts +179 -0
- package/dist/types/providers/ollama.d.ts +8 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +35 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +1311 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-chat-wire.d.ts +669 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +109 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +26 -0
- package/dist/types/providers/openai-codex-responses.d.ts +238 -0
- package/dist/types/providers/openai-completions.d.ts +48 -0
- package/dist/types/providers/openai-reasoning-fallback.d.ts +25 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +1314 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-wire.d.ts +6099 -0
- package/dist/types/providers/openai-responses.d.ts +131 -0
- package/dist/types/providers/openai-shared.d.ts +624 -0
- package/dist/types/providers/pi-native-client.d.ts +13 -0
- package/dist/types/providers/pi-native-server.d.ts +69 -0
- package/dist/types/providers/register-builtins.d.ts +37 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +32 -0
- package/dist/types/providers/vision-guard.d.ts +20 -0
- package/dist/types/registry/aiand.d.ts +7 -0
- package/dist/types/registry/aimlapi.d.ts +4 -0
- package/dist/types/registry/alibaba-coding-plan.d.ts +8 -0
- package/dist/types/registry/alibaba-token-plan.d.ts +18 -0
- package/dist/types/registry/amazon-bedrock.d.ts +5 -0
- package/dist/types/registry/anthropic.d.ts +10 -0
- package/dist/types/registry/api-key-login.d.ts +42 -0
- package/dist/types/registry/api-key-validation.d.ts +43 -0
- package/dist/types/registry/aws.d.ts +13 -0
- package/dist/types/registry/azure.d.ts +4 -0
- package/dist/types/registry/baseten.d.ts +7 -0
- package/dist/types/registry/bedrock-mantle.d.ts +22 -0
- package/dist/types/registry/cerebras.d.ts +7 -0
- package/dist/types/registry/cloudflare-ai-gateway.d.ts +13 -0
- package/dist/types/registry/coreweave.d.ts +7 -0
- package/dist/types/registry/cursor.d.ts +7 -0
- package/dist/types/registry/deepseek.d.ts +8 -0
- package/dist/types/registry/derived.d.ts +5 -0
- package/dist/types/registry/devin.d.ts +8 -0
- package/dist/types/registry/exa.d.ts +8 -0
- package/dist/types/registry/firepass.d.ts +16 -0
- package/dist/types/registry/fireworks.d.ts +7 -0
- package/dist/types/registry/github-copilot.d.ts +7 -0
- package/dist/types/registry/gitlab-duo-workflow.d.ts +10 -0
- package/dist/types/registry/gitlab-duo.d.ts +9 -0
- package/dist/types/registry/gmi-cloud.d.ts +7 -0
- package/dist/types/registry/google-antigravity.d.ts +9 -0
- package/dist/types/registry/google-gemini-cli.d.ts +9 -0
- package/dist/types/registry/google-vertex.d.ts +5 -0
- package/dist/types/registry/google.d.ts +4 -0
- package/dist/types/registry/groq.d.ts +4 -0
- package/dist/types/registry/huggingface.d.ts +7 -0
- package/dist/types/registry/index.d.ts +4 -0
- package/dist/types/registry/kagi.d.ts +14 -0
- package/dist/types/registry/kilo.d.ts +7 -0
- package/dist/types/registry/kimi-code.d.ts +7 -0
- package/dist/types/registry/litellm.d.ts +13 -0
- package/dist/types/registry/llama-cpp.d.ts +8 -0
- package/dist/types/registry/lm-studio.d.ts +8 -0
- package/dist/types/registry/meta.d.ts +7 -0
- package/dist/types/registry/minimax-code-cn.d.ts +6 -0
- package/dist/types/registry/minimax-code.d.ts +6 -0
- package/dist/types/registry/minimax.d.ts +4 -0
- package/dist/types/registry/mistral.d.ts +4 -0
- package/dist/types/registry/moonshot.d.ts +7 -0
- package/dist/types/registry/nanogpt.d.ts +7 -0
- package/dist/types/registry/novita.d.ts +6 -0
- package/dist/types/registry/nvidia.d.ts +7 -0
- package/dist/types/registry/oauth/anthropic-constants.d.ts +12 -0
- package/dist/types/registry/oauth/anthropic.d.ts +24 -0
- package/dist/types/registry/oauth/callback-server.d.ts +74 -0
- package/dist/types/registry/oauth/cursor.d.ts +16 -0
- package/dist/types/registry/oauth/device-code.d.ts +25 -0
- package/dist/types/registry/oauth/devin.d.ts +5 -0
- package/dist/types/registry/oauth/github-copilot.d.ts +30 -0
- package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +6 -0
- package/dist/types/registry/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/registry/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/registry/oauth/google-gemini-cli.d.ts +22 -0
- package/dist/types/registry/oauth/google-oauth-shared.d.ts +56 -0
- package/dist/types/registry/oauth/index.d.ts +45 -0
- package/dist/types/registry/oauth/kimi.d.ts +21 -0
- package/dist/types/registry/oauth/minimax-code.d.ts +27 -0
- package/dist/types/registry/oauth/openai-codex.d.ts +33 -0
- package/dist/types/registry/oauth/opencode.d.ts +18 -0
- package/dist/types/registry/oauth/perplexity.d.ts +9 -0
- package/dist/types/registry/oauth/pkce.d.ts +8 -0
- package/dist/types/registry/oauth/types.d.ts +87 -0
- package/dist/types/registry/oauth/wafer.d.ts +1 -0
- package/dist/types/registry/oauth/xai-oauth.d.ts +46 -0
- package/dist/types/registry/oauth/xiaomi.d.ts +25 -0
- package/dist/types/registry/oauth/zai.d.ts +25 -0
- package/dist/types/registry/ollama-cloud.d.ts +7 -0
- package/dist/types/registry/ollama.d.ts +12 -0
- package/dist/types/registry/openai-codex-device.d.ts +8 -0
- package/dist/types/registry/openai-codex.d.ts +9 -0
- package/dist/types/registry/openai.d.ts +4 -0
- package/dist/types/registry/opencode-go.d.ts +6 -0
- package/dist/types/registry/opencode-zen.d.ts +6 -0
- package/dist/types/registry/openrouter.d.ts +13 -0
- package/dist/types/registry/parallel.d.ts +14 -0
- package/dist/types/registry/perplexity.d.ts +7 -0
- package/dist/types/registry/qianfan.d.ts +7 -0
- package/dist/types/registry/qwen-portal.d.ts +7 -0
- package/dist/types/registry/registry.d.ts +367 -0
- package/dist/types/registry/sakana.d.ts +7 -0
- package/dist/types/registry/siliconflow-cn.d.ts +7 -0
- package/dist/types/registry/siliconflow.d.ts +7 -0
- package/dist/types/registry/synthetic.d.ts +6 -0
- package/dist/types/registry/tavily.d.ts +14 -0
- package/dist/types/registry/together.d.ts +6 -0
- package/dist/types/registry/types.d.ts +75 -0
- package/dist/types/registry/umans.d.ts +7 -0
- package/dist/types/registry/venice.d.ts +13 -0
- package/dist/types/registry/vercel-ai-gateway.d.ts +7 -0
- package/dist/types/registry/vllm.d.ts +7 -0
- package/dist/types/registry/wafer-serverless.d.ts +6 -0
- package/dist/types/registry/xai-oauth.d.ts +7 -0
- package/dist/types/registry/xai.d.ts +7 -0
- package/dist/types/registry/xiaomi-token-plan-ams.d.ts +6 -0
- package/dist/types/registry/xiaomi-token-plan-cn.d.ts +6 -0
- package/dist/types/registry/xiaomi-token-plan-sgp.d.ts +6 -0
- package/dist/types/registry/xiaomi.d.ts +6 -0
- package/dist/types/registry/zai.d.ts +15 -0
- package/dist/types/registry/zenmux.d.ts +7 -0
- package/dist/types/registry/zhipu-coding-plan.d.ts +7 -0
- package/dist/types/stream.d.ts +46 -0
- package/dist/types/types.d.ts +1064 -0
- package/dist/types/usage/alibaba-token-plan.d.ts +3 -0
- package/dist/types/usage/claude.d.ts +4 -0
- package/dist/types/usage/cursor.d.ts +4 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +15 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +3 -0
- package/dist/types/usage/ollama.d.ts +5 -0
- package/dist/types/usage/openai-codex-base-url.d.ts +18 -0
- package/dist/types/usage/openai-codex-reset.d.ts +88 -0
- package/dist/types/usage/openai-codex.d.ts +10 -0
- package/dist/types/usage/opencode-go.d.ts +2 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/synthetic.d.ts +2 -0
- package/dist/types/usage/umans.d.ts +2 -0
- package/dist/types/usage/xai-oauth.d.ts +12 -0
- package/dist/types/usage/zai.d.ts +3 -0
- package/dist/types/usage.d.ts +527 -0
- package/dist/types/utils/abort.d.ts +25 -0
- package/dist/types/utils/anthropic-auth.d.ts +35 -0
- package/dist/types/utils/aws-profile.d.ts +17 -0
- package/dist/types/utils/block-symbols.d.ts +62 -0
- package/dist/types/utils/deterministic-id.d.ts +16 -0
- package/dist/types/utils/empty-completion-retry.d.ts +21 -0
- package/dist/types/utils/event-stream.d.ts +39 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/google-validation.d.ts +2 -0
- package/dist/types/utils/harmony-leak.d.ts +135 -0
- package/dist/types/utils/http-inspector.d.ts +49 -0
- package/dist/types/utils/idle-iterator.d.ts +149 -0
- package/dist/types/utils/leaked-thinking-stream.d.ts +33 -0
- package/dist/types/utils/openai-http.d.ts +48 -0
- package/dist/types/utils/openrouter-headers.d.ts +1 -0
- package/dist/types/utils/parse-bind.d.ts +23 -0
- package/dist/types/utils/provider-response.d.ts +3 -0
- package/dist/types/utils/proxy.d.ts +39 -0
- package/dist/types/utils/request-debug.d.ts +29 -0
- package/dist/types/utils/retry-after.d.ts +4 -0
- package/dist/types/utils/retry.d.ts +14 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +54 -0
- package/dist/types/utils/schema/index.d.ts +14 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +20 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +153 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +17 -0
- package/dist/types/utils/schema/strict-tool-validation.d.ts +16 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/typescript.d.ts +24 -0
- package/dist/types/utils/schema/wire.d.ts +52 -0
- package/dist/types/utils/sdk-stream-timeout.d.ts +33 -0
- package/dist/types/utils/sse-debug.d.ts +5 -0
- package/dist/types/utils/stream-markup-healing.d.ts +87 -0
- package/dist/types/utils/thinking-loop.d.ts +102 -0
- package/dist/types/utils/tool-call-loop-guard.d.ts +26 -0
- package/dist/types/utils/tool-choice.d.ts +52 -0
- package/dist/types/utils/validation.d.ts +28 -0
- package/dist/types/utils.d.ts +57 -0
- package/package.json +138 -0
- package/src/api-registry.ts +109 -0
- package/src/auth/sqlite-credential-store.ts +2066 -0
- package/src/auth-broker/client.ts +471 -0
- package/src/auth-broker/discover.ts +310 -0
- package/src/auth-broker/index.ts +7 -0
- package/src/auth-broker/refresher.ts +117 -0
- package/src/auth-broker/remote-store.ts +1332 -0
- package/src/auth-broker/server.ts +898 -0
- package/src/auth-broker/snapshot-cache.ts +200 -0
- package/src/auth-broker/types.ts +193 -0
- package/src/auth-broker/wire-schema-resource.ts +487 -0
- package/src/auth-broker/wire-schemas.ts +43 -0
- package/src/auth-gateway/http.ts +227 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +836 -0
- package/src/auth-gateway/types.ts +153 -0
- package/src/auth-retry.ts +401 -0
- package/src/auth-storage.ts +6540 -0
- package/src/dialect/anthropic.md +31 -0
- package/src/dialect/anthropic.ts +608 -0
- package/src/dialect/catalog.ts +29 -0
- package/src/dialect/coercion.ts +136 -0
- package/src/dialect/deepseek.md +24 -0
- package/src/dialect/deepseek.ts +609 -0
- package/src/dialect/demotion.ts +40 -0
- package/src/dialect/examples.ts +71 -0
- package/src/dialect/factory.ts +34 -0
- package/src/dialect/fenced-thinking.ts +184 -0
- package/src/dialect/gemini.md +44 -0
- package/src/dialect/gemini.ts +583 -0
- package/src/dialect/gemma.md +33 -0
- package/src/dialect/gemma.ts +387 -0
- package/src/dialect/glm.md +32 -0
- package/src/dialect/glm.ts +579 -0
- package/src/dialect/harmony.md +31 -0
- package/src/dialect/harmony.ts +345 -0
- package/src/dialect/hermes.md +25 -0
- package/src/dialect/hermes.ts +206 -0
- package/src/dialect/history.ts +81 -0
- package/src/dialect/index.ts +15 -0
- package/src/dialect/inventory.ts +30 -0
- package/src/dialect/kimi.md +24 -0
- package/src/dialect/kimi.ts +340 -0
- package/src/dialect/minimax.md +31 -0
- package/src/dialect/minimax.ts +95 -0
- package/src/dialect/owned-stream.ts +481 -0
- package/src/dialect/prompt-template.md +12 -0
- package/src/dialect/qwen3.md +28 -0
- package/src/dialect/qwen3.ts +240 -0
- package/src/dialect/rendering.ts +304 -0
- package/src/dialect/thinking.ts +292 -0
- package/src/dialect/types.ts +56 -0
- package/src/dialect/xml.md +22 -0
- package/src/dialect/xml.ts +90 -0
- package/src/error/abort.ts +18 -0
- package/src/error/auth-classify.ts +47 -0
- package/src/error/auth.ts +48 -0
- package/src/error/aws.ts +35 -0
- package/src/error/classes.ts +281 -0
- package/src/error/finalize.ts +69 -0
- package/src/error/flags.ts +602 -0
- package/src/error/format.ts +45 -0
- package/src/error/gateway.ts +96 -0
- package/src/error/index.ts +14 -0
- package/src/error/oauth.ts +58 -0
- package/src/error/provider.ts +63 -0
- package/src/error/rate-limit.ts +303 -0
- package/src/error/retryable.ts +70 -0
- package/src/error/validation.ts +44 -0
- package/src/index.ts +51 -0
- package/src/provider-details.ts +90 -0
- package/src/providers/amazon-bedrock.ts +1064 -0
- package/src/providers/anthropic-client.ts +317 -0
- package/src/providers/anthropic-messages-server-schema.ts +252 -0
- package/src/providers/anthropic-messages-server.ts +818 -0
- package/src/providers/anthropic-wire.ts +359 -0
- package/src/providers/anthropic.ts +4539 -0
- package/src/providers/aws-credentials.ts +772 -0
- package/src/providers/aws-eventstream.ts +181 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +438 -0
- package/src/providers/bedrock-mantle.ts +110 -0
- package/src/providers/claude-code-fingerprint.ts +20 -0
- package/src/providers/cowork-fetch.ts +201 -0
- package/src/providers/cursor/exec-modern.ts +496 -0
- package/src/providers/cursor/proto/agent.proto +4533 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor-pi-args.ts +165 -0
- package/src/providers/cursor.ts +4689 -0
- package/src/providers/devin/proto/buf/validate/validate.proto +468 -0
- package/src/providers/devin/proto/buf.gen.yaml +33 -0
- package/src/providers/devin/proto/buf.yaml +17 -0
- package/src/providers/devin/proto/cel/expr/checked.proto +103 -0
- package/src/providers/devin/proto/cel/expr/eval.proto +38 -0
- package/src/providers/devin/proto/cel/expr/explain.proto +15 -0
- package/src/providers/devin/proto/cel/expr/syntax.proto +113 -0
- package/src/providers/devin/proto/cel/expr/value.proto +41 -0
- package/src/providers/devin/proto/connectext/grpc/status/v1/status.proto +11 -0
- package/src/providers/devin/proto/errorspb/errors.proto +56 -0
- package/src/providers/devin/proto/errorspb/hintdetail.proto +7 -0
- package/src/providers/devin/proto/errorspb/markers.proto +10 -0
- package/src/providers/devin/proto/errorspb/tags.proto +12 -0
- package/src/providers/devin/proto/errorspb/testing.proto +6 -0
- package/src/providers/devin/proto/exa/analytics_pb/analytics.proto +188 -0
- package/src/providers/devin/proto/exa/api_server_pb/api_server.proto +2461 -0
- package/src/providers/devin/proto/exa/auth_pb/auth.proto +19 -0
- package/src/providers/devin/proto/exa/auto_cascade_common_pb/auto_cascade_common.proto +79 -0
- package/src/providers/devin/proto/exa/browser_preview_pb/browser_preview.proto +32 -0
- package/src/providers/devin/proto/exa/bug_checker_pb/bug_checker.proto +22 -0
- package/src/providers/devin/proto/exa/cascade_plugins_pb/cascade_plugins.proto +262 -0
- package/src/providers/devin/proto/exa/chat_client_server_pb/chat_client_server.proto +57 -0
- package/src/providers/devin/proto/exa/chat_pb/chat.proto +449 -0
- package/src/providers/devin/proto/exa/code_edit/code_edit_pb/code_edit.proto +186 -0
- package/src/providers/devin/proto/exa/codeium_common_pb/codeium_common.proto +4157 -0
- package/src/providers/devin/proto/exa/context_module_pb/context_module.proto +175 -0
- package/src/providers/devin/proto/exa/cortex_pb/cortex.proto +3268 -0
- package/src/providers/devin/proto/exa/dev_pb/dev.proto +26 -0
- package/src/providers/devin/proto/exa/diff_action_pb/diff_action.proto +75 -0
- package/src/providers/devin/proto/exa/eval/pr_eval/datasets_pb/datasets.proto +103 -0
- package/src/providers/devin/proto/exa/eval_pb/eval.proto +1315 -0
- package/src/providers/devin/proto/exa/extension_server_pb/extension_server.proto +556 -0
- package/src/providers/devin/proto/exa/file_system_provider_pb/file_system_provider.proto +75 -0
- package/src/providers/devin/proto/exa/index_pb/index.proto +461 -0
- package/src/providers/devin/proto/exa/knowledge_base_pb/knowledge_base.proto +144 -0
- package/src/providers/devin/proto/exa/language_server_pb/language_server.proto +2385 -0
- package/src/providers/devin/proto/exa/model_management_pb/model_management.proto +186 -0
- package/src/providers/devin/proto/exa/opensearch_clients_pb/opensearch_clients.proto +503 -0
- package/src/providers/devin/proto/exa/product_analytics_pb/product_analytics.proto +37 -0
- package/src/providers/devin/proto/exa/prompt_pb/prompt.proto +92 -0
- package/src/providers/devin/proto/exa/reactive_component_pb/reactive_component.proto +96 -0
- package/src/providers/devin/proto/exa/seat_management_pb/seat_management.proto +2680 -0
- package/src/providers/devin/proto/exa/tokenizer_pb/tokenizer.proto +37 -0
- package/src/providers/devin/proto/exa/trainer_pb/config.proto +647 -0
- package/src/providers/devin/proto/exa/tree_sitter/language_data_pb/language_data.proto +14 -0
- package/src/providers/devin/proto/exa/trust_pb/trust.proto +157 -0
- package/src/providers/devin/proto/exa/user_analytics_pb/user_analytics.proto +519 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/base/api_base.proto +28 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/datastore/datastore_v3.proto +484 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/log/log_service.proto +136 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/remote_api/remote_api.proto +42 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto +61 -0
- package/src/providers/devin/proto/grpc/binlog/v1/binarylog.proto +84 -0
- package/src/providers/devin/proto/io/prometheus/client/metrics.proto +98 -0
- package/src/providers/devin.ts +679 -0
- package/src/providers/error-message.ts +23 -0
- package/src/providers/github-copilot-headers.ts +141 -0
- package/src/providers/gitlab-duo-workflow-chatml-note.md +1 -0
- package/src/providers/gitlab-duo-workflow.ts +3135 -0
- package/src/providers/gitlab-duo.ts +399 -0
- package/src/providers/google-auth.ts +330 -0
- package/src/providers/google-gemini-cli.ts +1370 -0
- package/src/providers/google-shared.ts +1122 -0
- package/src/providers/google-types.ts +180 -0
- package/src/providers/google-vertex.ts +135 -0
- package/src/providers/google.ts +47 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +51 -0
- package/src/providers/mock.ts +514 -0
- package/src/providers/ollama.ts +776 -0
- package/src/providers/openai-anthropic-shim.ts +166 -0
- package/src/providers/openai-chat-server-schema.ts +243 -0
- package/src/providers/openai-chat-server.ts +752 -0
- package/src/providers/openai-chat-wire.ts +859 -0
- package/src/providers/openai-codex/request-transformer.ts +491 -0
- package/src/providers/openai-codex/response-handler.ts +102 -0
- package/src/providers/openai-codex-responses.ts +4716 -0
- package/src/providers/openai-completions.ts +2389 -0
- package/src/providers/openai-reasoning-fallback.ts +269 -0
- package/src/providers/openai-responses-server-schema.ts +397 -0
- package/src/providers/openai-responses-server.ts +1466 -0
- package/src/providers/openai-responses-wire.ts +6416 -0
- package/src/providers/openai-responses.ts +1393 -0
- package/src/providers/openai-shared.ts +3500 -0
- package/src/providers/pi-native-client.ts +275 -0
- package/src/providers/pi-native-server.ts +245 -0
- package/src/providers/register-builtins.ts +503 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +1083 -0
- package/src/providers/vision-guard.ts +54 -0
- package/src/registry/aiand.ts +22 -0
- package/src/registry/aimlapi.ts +6 -0
- package/src/registry/alibaba-coding-plan.ts +104 -0
- package/src/registry/alibaba-token-plan.ts +125 -0
- package/src/registry/amazon-bedrock.ts +22 -0
- package/src/registry/anthropic.ts +26 -0
- package/src/registry/api-key-login.ts +115 -0
- package/src/registry/api-key-validation.ts +145 -0
- package/src/registry/aws.ts +57 -0
- package/src/registry/azure.ts +6 -0
- package/src/registry/baseten.ts +22 -0
- package/src/registry/bedrock-mantle.ts +34 -0
- package/src/registry/cerebras.ts +23 -0
- package/src/registry/cloudflare-ai-gateway.ts +45 -0
- package/src/registry/coreweave.ts +40 -0
- package/src/registry/cursor.ts +20 -0
- package/src/registry/deepseek.ts +46 -0
- package/src/registry/derived.ts +9 -0
- package/src/registry/devin.ts +15 -0
- package/src/registry/exa.ts +19 -0
- package/src/registry/firepass.ts +32 -0
- package/src/registry/fireworks.ts +28 -0
- package/src/registry/github-copilot.ts +22 -0
- package/src/registry/gitlab-duo-workflow.ts +20 -0
- package/src/registry/gitlab-duo.ts +19 -0
- package/src/registry/gmi-cloud.ts +22 -0
- package/src/registry/google-antigravity.ts +22 -0
- package/src/registry/google-gemini-cli.ts +22 -0
- package/src/registry/google-vertex.ts +38 -0
- package/src/registry/google.ts +6 -0
- package/src/registry/groq.ts +6 -0
- package/src/registry/huggingface.ts +29 -0
- package/src/registry/index.ts +4 -0
- package/src/registry/kagi.ts +46 -0
- package/src/registry/kilo.ts +114 -0
- package/src/registry/kimi-code.ts +17 -0
- package/src/registry/litellm.ts +45 -0
- package/src/registry/llama-cpp.ts +35 -0
- package/src/registry/lm-studio.ts +31 -0
- package/src/registry/meta.ts +22 -0
- package/src/registry/minimax-code-cn.ts +12 -0
- package/src/registry/minimax-code.ts +12 -0
- package/src/registry/minimax.ts +6 -0
- package/src/registry/mistral.ts +6 -0
- package/src/registry/moonshot.ts +28 -0
- package/src/registry/nanogpt.ts +22 -0
- package/src/registry/novita.ts +25 -0
- package/src/registry/nvidia.ts +61 -0
- package/src/registry/oauth/anthropic-constants.ts +12 -0
- package/src/registry/oauth/anthropic.ts +346 -0
- package/src/registry/oauth/callback-server.ts +438 -0
- package/src/registry/oauth/cursor.ts +187 -0
- package/src/registry/oauth/device-code.ts +92 -0
- package/src/registry/oauth/devin.ts +124 -0
- package/src/registry/oauth/github-copilot.ts +369 -0
- package/src/registry/oauth/gitlab-duo-workflow.ts +146 -0
- package/src/registry/oauth/gitlab-duo.ts +222 -0
- package/src/registry/oauth/google-antigravity.ts +225 -0
- package/src/registry/oauth/google-gemini-cli.ts +297 -0
- package/src/registry/oauth/google-oauth-shared.ts +211 -0
- package/src/registry/oauth/index.ts +187 -0
- package/src/registry/oauth/kimi.ts +297 -0
- package/src/registry/oauth/minimax-code.ts +53 -0
- package/src/registry/oauth/oauth.html +317 -0
- package/src/registry/oauth/openai-codex.ts +384 -0
- package/src/registry/oauth/opencode.ts +50 -0
- package/src/registry/oauth/perplexity.ts +228 -0
- package/src/registry/oauth/pkce.ts +18 -0
- package/src/registry/oauth/types.ts +96 -0
- package/src/registry/oauth/wafer.ts +24 -0
- package/src/registry/oauth/xai-oauth.ts +559 -0
- package/src/registry/oauth/xiaomi.ts +211 -0
- package/src/registry/oauth/zai.ts +285 -0
- package/src/registry/ollama-cloud.ts +36 -0
- package/src/registry/ollama.ts +43 -0
- package/src/registry/openai-codex-device.ts +18 -0
- package/src/registry/openai-codex.ts +19 -0
- package/src/registry/openai.ts +6 -0
- package/src/registry/opencode-go.ts +12 -0
- package/src/registry/opencode-zen.ts +12 -0
- package/src/registry/openrouter.ts +28 -0
- package/src/registry/parallel.ts +45 -0
- package/src/registry/perplexity.ts +13 -0
- package/src/registry/qianfan.ts +27 -0
- package/src/registry/qwen-portal.ts +50 -0
- package/src/registry/registry.ts +182 -0
- package/src/registry/sakana.ts +22 -0
- package/src/registry/siliconflow-cn.ts +22 -0
- package/src/registry/siliconflow.ts +22 -0
- package/src/registry/synthetic.ts +21 -0
- package/src/registry/tavily.ts +45 -0
- package/src/registry/together.ts +22 -0
- package/src/registry/types.ts +86 -0
- package/src/registry/umans.ts +23 -0
- package/src/registry/venice.ts +33 -0
- package/src/registry/vercel-ai-gateway.ts +38 -0
- package/src/registry/vllm.ts +34 -0
- package/src/registry/wafer-serverless.ts +12 -0
- package/src/registry/xai-oauth.ts +17 -0
- package/src/registry/xai.ts +22 -0
- package/src/registry/xiaomi-token-plan-ams.ts +12 -0
- package/src/registry/xiaomi-token-plan-cn.ts +12 -0
- package/src/registry/xiaomi-token-plan-sgp.ts +12 -0
- package/src/registry/xiaomi.ts +12 -0
- package/src/registry/zai.ts +41 -0
- package/src/registry/zenmux.ts +22 -0
- package/src/registry/zhipu-coding-plan.ts +27 -0
- package/src/stream.ts +1944 -0
- package/src/types.ts +1243 -0
- package/src/usage/alibaba-token-plan.ts +230 -0
- package/src/usage/claude.ts +830 -0
- package/src/usage/cursor.ts +335 -0
- package/src/usage/gemini.ts +258 -0
- package/src/usage/github-copilot.ts +424 -0
- package/src/usage/google-antigravity.ts +497 -0
- package/src/usage/kimi.ts +277 -0
- package/src/usage/minimax-code.ts +291 -0
- package/src/usage/ollama.ts +41 -0
- package/src/usage/openai-codex-base-url.ts +35 -0
- package/src/usage/openai-codex-reset.ts +205 -0
- package/src/usage/openai-codex.ts +627 -0
- package/src/usage/opencode-go.ts +89 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/synthetic.ts +180 -0
- package/src/usage/umans.ts +192 -0
- package/src/usage/xai-oauth.ts +414 -0
- package/src/usage/zai.ts +370 -0
- package/src/usage.ts +411 -0
- package/src/utils/abort.ts +67 -0
- package/src/utils/anthropic-auth.ts +93 -0
- package/src/utils/aws-profile.ts +88 -0
- package/src/utils/block-symbols.ts +78 -0
- package/src/utils/deterministic-id.ts +20 -0
- package/src/utils/empty-completion-retry.ts +161 -0
- package/src/utils/event-stream.ts +202 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/google-validation.ts +25 -0
- package/src/utils/harmony-leak.ts +500 -0
- package/src/utils/http-inspector.ts +196 -0
- package/src/utils/idle-iterator.ts +531 -0
- package/src/utils/leaked-thinking-stream.ts +483 -0
- package/src/utils/openai-http.ts +119 -0
- package/src/utils/openrouter-headers.ts +12 -0
- package/src/utils/parse-bind.ts +56 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/proxy.ts +314 -0
- package/src/utils/request-debug.ts +351 -0
- package/src/utils/retry-after.ts +121 -0
- package/src/utils/retry.ts +77 -0
- package/src/utils/schema/CONSTRAINTS.md +168 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.ts +210 -0
- package/src/utils/schema/index.ts +14 -0
- package/src/utils/schema/json-schema-validator.ts +595 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +2314 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +109 -0
- package/src/utils/schema/strict-tool-validation.ts +117 -0
- package/src/utils/schema/types.ts +10 -0
- package/src/utils/schema/typescript.ts +212 -0
- package/src/utils/schema/wire.ts +662 -0
- package/src/utils/sdk-stream-timeout.ts +43 -0
- package/src/utils/sse-debug.ts +18 -0
- package/src/utils/stream-markup-healing.ts +247 -0
- package/src/utils/thinking-loop.ts +552 -0
- package/src/utils/tool-call-loop-guard.ts +107 -0
- package/src/utils/tool-choice.ts +101 -0
- package/src/utils/validation.ts +1932 -0
- package/src/utils.ts +492 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import { Effort } from "@linxiraos/pi-catalog/effort";
|
|
2
|
+
import { supportsAllTurnsReasoningContext, supportsCodexReasoningSummary } from "@linxiraos/pi-catalog/identity";
|
|
3
|
+
import { requireSupportedEffort } from "@linxiraos/pi-catalog/model-thinking";
|
|
4
|
+
import { $env } from "@linxiraos/pi-utils";
|
|
5
|
+
import type { Model } from "../../types";
|
|
6
|
+
import { mapOpenAIReasoningEffort } from "../openai-shared";
|
|
7
|
+
|
|
8
|
+
/** Reasoning replay scope for the Codex Responses API (`reasoning.context`). */
|
|
9
|
+
export type CodexReasoningContext = "auto" | "current_turn" | "all_turns";
|
|
10
|
+
|
|
11
|
+
/** User-facing effort levels accepted by Codex request options. */
|
|
12
|
+
type CodexCallerEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
13
|
+
|
|
14
|
+
/** Caller literal → catalog `Effort` bridge (the enum is nominal). */
|
|
15
|
+
const EFFORT_BY_NAME: Record<CodexCallerEffort, Effort> = {
|
|
16
|
+
minimal: Effort.Minimal,
|
|
17
|
+
low: Effort.Low,
|
|
18
|
+
medium: Effort.Medium,
|
|
19
|
+
high: Effort.High,
|
|
20
|
+
xhigh: Effort.XHigh,
|
|
21
|
+
max: Effort.Max,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export interface ReasoningConfig {
|
|
25
|
+
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
26
|
+
summary?: "auto" | "concise" | "detailed";
|
|
27
|
+
context?: CodexReasoningContext;
|
|
28
|
+
/** Pro reasoning serving mode (gpt-5.6+ catalog pro aliases). */
|
|
29
|
+
mode?: "pro";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CodexRequestOptions {
|
|
33
|
+
/** User-facing effort; maps 1:1 onto the wire tier of the same name. */
|
|
34
|
+
reasoningEffort?: CodexCallerEffort | "none";
|
|
35
|
+
reasoningSummary?: ReasoningConfig["summary"] | null;
|
|
36
|
+
/** Explicit `reasoning.context` override. Omitted by default; Responses Lite forces `all_turns` as required by that transport. */
|
|
37
|
+
reasoningContext?: CodexReasoningContext;
|
|
38
|
+
textVerbosity?: "low" | "medium" | "high";
|
|
39
|
+
include?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Responses Lite transport override; defaults to the model's
|
|
42
|
+
* `useResponsesLite`. Lite moves instructions/tools into input items,
|
|
43
|
+
* strips image detail, and disables parallel tool calling (codex-rs
|
|
44
|
+
* `use_responses_lite`).
|
|
45
|
+
*/
|
|
46
|
+
responsesLite?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InputItem {
|
|
50
|
+
id?: string | null;
|
|
51
|
+
type?: string | null;
|
|
52
|
+
role?: string;
|
|
53
|
+
content?: unknown;
|
|
54
|
+
call_id?: string | null;
|
|
55
|
+
name?: string;
|
|
56
|
+
output?: unknown;
|
|
57
|
+
arguments?: unknown;
|
|
58
|
+
action?: unknown;
|
|
59
|
+
actions?: unknown;
|
|
60
|
+
pending_safety_checks?: unknown;
|
|
61
|
+
acknowledged_safety_checks?: unknown;
|
|
62
|
+
/** `additional_tools` developer item payload (Responses Lite). */
|
|
63
|
+
tools?: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface RequestBody {
|
|
67
|
+
model: string;
|
|
68
|
+
store?: boolean;
|
|
69
|
+
stream?: boolean;
|
|
70
|
+
instructions?: string;
|
|
71
|
+
input?: InputItem[];
|
|
72
|
+
tools?: unknown;
|
|
73
|
+
tool_choice?: unknown;
|
|
74
|
+
/** Concurrent reasoning-summary delivery (codex-rs `StreamOptions`). */
|
|
75
|
+
stream_options?: { reasoning_summary_delivery: "sequential_cutoff" };
|
|
76
|
+
// Sampling controls (temperature/top_p/top_k/min_p/presence_penalty/
|
|
77
|
+
// repetition_penalty/frequency_penalty/stop) are intentionally absent: the
|
|
78
|
+
// Codex backend rejects every one with a 400 `Unsupported parameter`, so
|
|
79
|
+
// the transformer never sets them (#3117).
|
|
80
|
+
reasoning?: Partial<ReasoningConfig>;
|
|
81
|
+
text?: {
|
|
82
|
+
verbosity?: "low" | "medium" | "high";
|
|
83
|
+
};
|
|
84
|
+
include?: string[];
|
|
85
|
+
prompt_cache_key?: string;
|
|
86
|
+
prompt_cache_retention?: "in_memory" | "24h";
|
|
87
|
+
client_metadata?: Record<string, string>;
|
|
88
|
+
max_output_tokens?: number;
|
|
89
|
+
max_completion_tokens?: number;
|
|
90
|
+
service_tier?: "auto" | "default" | "flex" | "scale" | "priority" | null;
|
|
91
|
+
[key: string]: unknown;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Resolve whether a Codex request uses the Responses Lite transport: an
|
|
96
|
+
* explicit option wins, then the `PI_CODEX_RESPONSES_LITE` env override
|
|
97
|
+
* (`1`/`true` forces Lite, `0`/`false` forces the full Responses body),
|
|
98
|
+
* otherwise the model's catalog flag (codex-rs `model_info.use_responses_lite`)
|
|
99
|
+
* decides.
|
|
100
|
+
*/
|
|
101
|
+
export function resolveCodexResponsesLite(
|
|
102
|
+
model: Model<"openai-codex-responses">,
|
|
103
|
+
requested: boolean | undefined,
|
|
104
|
+
): boolean {
|
|
105
|
+
if (requested !== undefined) return requested;
|
|
106
|
+
const env = $env.PI_CODEX_RESPONSES_LITE?.trim().toLowerCase();
|
|
107
|
+
if (env === "1" || env === "true") return true;
|
|
108
|
+
if (env === "0" || env === "false") return false;
|
|
109
|
+
return model.useResponsesLite === true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Clamp a user-facing effort to the model's ladder, then remap to the wire
|
|
114
|
+
* tier. User efforts map 1:1 onto wire tiers; the effort map only covers
|
|
115
|
+
* host quirks where a wire tier genuinely does not exist (e.g. `minimal→none`).
|
|
116
|
+
* A mapped value outside the Codex wire vocabulary is a broken compat/model
|
|
117
|
+
* effort map — fail loudly rather than silently sending a different tier.
|
|
118
|
+
*/
|
|
119
|
+
function mapCodexWireEffort(
|
|
120
|
+
model: Model<"openai-codex-responses">,
|
|
121
|
+
effort: CodexCallerEffort,
|
|
122
|
+
): ReasoningConfig["effort"] {
|
|
123
|
+
const mapped = mapOpenAIReasoningEffort(model, model.compat, requireSupportedEffort(model, EFFORT_BY_NAME[effort]));
|
|
124
|
+
switch (mapped) {
|
|
125
|
+
case "none":
|
|
126
|
+
case "minimal":
|
|
127
|
+
case "low":
|
|
128
|
+
case "medium":
|
|
129
|
+
case "high":
|
|
130
|
+
case "xhigh":
|
|
131
|
+
case "max":
|
|
132
|
+
return mapped;
|
|
133
|
+
default:
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Effort map for ${model.provider}/${model.id} produced invalid Codex reasoning effort "${mapped}"`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getReasoningConfig(
|
|
141
|
+
model: Model<"openai-codex-responses">,
|
|
142
|
+
effort: NonNullable<CodexRequestOptions["reasoningEffort"]>,
|
|
143
|
+
options: CodexRequestOptions,
|
|
144
|
+
): ReasoningConfig {
|
|
145
|
+
const config: ReasoningConfig = {
|
|
146
|
+
effort: effort === "none" ? "none" : mapCodexWireEffort(model, effort),
|
|
147
|
+
};
|
|
148
|
+
if (
|
|
149
|
+
options.reasoningSummary !== undefined &&
|
|
150
|
+
options.reasoningSummary !== null &&
|
|
151
|
+
supportsCodexReasoningSummary(model.id)
|
|
152
|
+
) {
|
|
153
|
+
config.summary = options.reasoningSummary;
|
|
154
|
+
}
|
|
155
|
+
return config;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function filterInput(input: InputItem[] | undefined): InputItem[] | undefined {
|
|
159
|
+
if (!Array.isArray(input)) return input;
|
|
160
|
+
|
|
161
|
+
return input
|
|
162
|
+
.filter(item => item.type !== "item_reference")
|
|
163
|
+
.map(item => {
|
|
164
|
+
if (item.type === "computer_call") return item;
|
|
165
|
+
if (item.id != null) {
|
|
166
|
+
const { id: _id, ...rest } = item;
|
|
167
|
+
return rest as InputItem;
|
|
168
|
+
}
|
|
169
|
+
return item;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const CODEX_ORPHAN_OUTPUT_LIMIT = 16_000;
|
|
174
|
+
/** Placeholder output for a tool call whose result never landed in the input. */
|
|
175
|
+
const CODEX_INTERRUPTED_TOOL_OUTPUT =
|
|
176
|
+
"[No tool output recorded: the tool call was interrupted before it produced a result.]";
|
|
177
|
+
|
|
178
|
+
function orphanFunctionOutputToMessage(item: InputItem, callId: string): InputItem {
|
|
179
|
+
const itemRecord = item as unknown as Record<string, unknown>;
|
|
180
|
+
const toolName = typeof itemRecord.name === "string" ? itemRecord.name : "tool";
|
|
181
|
+
let text = "";
|
|
182
|
+
try {
|
|
183
|
+
const output = itemRecord.output;
|
|
184
|
+
text = typeof output === "string" ? output : JSON.stringify(output);
|
|
185
|
+
} catch {
|
|
186
|
+
text = String(itemRecord.output ?? "");
|
|
187
|
+
}
|
|
188
|
+
if (text.length > CODEX_ORPHAN_OUTPUT_LIMIT) {
|
|
189
|
+
text = `${text.slice(0, CODEX_ORPHAN_OUTPUT_LIMIT)}\n...[truncated]`;
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
type: "message",
|
|
193
|
+
role: "assistant",
|
|
194
|
+
content: `[Previous ${toolName} result; call_id=${callId}]: ${text}`,
|
|
195
|
+
} as InputItem;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
type ToolCallKind = "function" | "custom" | "computer";
|
|
199
|
+
|
|
200
|
+
function toolCallKind(type: unknown): ToolCallKind | undefined {
|
|
201
|
+
if (type === "function_call") return "function";
|
|
202
|
+
if (type === "custom_tool_call") return "custom";
|
|
203
|
+
if (type === "computer_call") return "computer";
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function toolOutputKind(type: unknown): ToolCallKind | undefined {
|
|
208
|
+
if (type === "function_call_output") return "function";
|
|
209
|
+
if (type === "custom_tool_call_output") return "custom";
|
|
210
|
+
if (type === "computer_call_output") return "computer";
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Repair both halves of unpaired tool exchanges so the Responses input grammar
|
|
216
|
+
* stays valid — the API rejects either orphan with a 400:
|
|
217
|
+
*
|
|
218
|
+
* - `function_call_output` / `custom_tool_call_output` with no matching call →
|
|
219
|
+
* folded into an assistant message (`400 No tool call found for … output`).
|
|
220
|
+
* Regression of #472 / #1351.
|
|
221
|
+
* - `function_call` / `custom_tool_call` with no matching `*_output` → a
|
|
222
|
+
* placeholder output is synthesized immediately after the call
|
|
223
|
+
* (`400 No tool output found for function call …`). Hit when the user
|
|
224
|
+
* branches/navigates the session tree to a node that ends on a tool call (the
|
|
225
|
+
* tool-result child is dropped from the reconstructed history) or when a turn
|
|
226
|
+
* is aborted/crashes after the call streamed but before its result persisted.
|
|
227
|
+
*/
|
|
228
|
+
function repairToolCallPairs(input: InputItem[]): InputItem[] {
|
|
229
|
+
const callKinds = new Map<string, ToolCallKind>();
|
|
230
|
+
const outputKinds = new Map<string, ToolCallKind>();
|
|
231
|
+
for (const item of input) {
|
|
232
|
+
const callId = typeof item.call_id === "string" ? item.call_id : undefined;
|
|
233
|
+
if (callId === undefined) continue;
|
|
234
|
+
const callKind = toolCallKind(item.type);
|
|
235
|
+
const outputKind = toolOutputKind(item.type);
|
|
236
|
+
if (callKind) callKinds.set(callId, callKind);
|
|
237
|
+
if (outputKind) outputKinds.set(callId, outputKind);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const repaired: InputItem[] = [];
|
|
241
|
+
for (const item of input) {
|
|
242
|
+
const callId = typeof item.call_id === "string" ? item.call_id : undefined;
|
|
243
|
+
const callKind = toolCallKind(item.type);
|
|
244
|
+
const outputKind = toolOutputKind(item.type);
|
|
245
|
+
|
|
246
|
+
if (outputKind && callId !== undefined && callKinds.get(callId) !== outputKind) {
|
|
247
|
+
repaired.push(orphanFunctionOutputToMessage(item, callId));
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (callKind && callId !== undefined && outputKinds.get(callId) !== callKind) {
|
|
251
|
+
if (callKind === "computer") {
|
|
252
|
+
repaired.push({
|
|
253
|
+
type: "message",
|
|
254
|
+
role: "assistant",
|
|
255
|
+
content: `[Computer call interrupted before a screenshot was recorded; call_id=${callId}]`,
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
repaired.push(item, {
|
|
260
|
+
type: callKind === "custom" ? "custom_tool_call_output" : "function_call_output",
|
|
261
|
+
call_id: callId,
|
|
262
|
+
output: CODEX_INTERRUPTED_TOOL_OUTPUT,
|
|
263
|
+
});
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
repaired.push(item);
|
|
267
|
+
}
|
|
268
|
+
return repaired;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Responses Lite requests must not pin image detail levels: codex-rs strips
|
|
273
|
+
* `detail` from every input image (message content and tool outputs) before
|
|
274
|
+
* sending, letting the server choose.
|
|
275
|
+
*/
|
|
276
|
+
function stripImageDetails(input: unknown[]): void {
|
|
277
|
+
for (const item of input) {
|
|
278
|
+
if (!item || typeof item !== "object") continue;
|
|
279
|
+
const content = "content" in item ? item.content : undefined;
|
|
280
|
+
const output = "output" in item ? item.output : undefined;
|
|
281
|
+
for (const collection of [content, output]) {
|
|
282
|
+
if (!Array.isArray(collection)) continue;
|
|
283
|
+
for (const part of collection) {
|
|
284
|
+
if (!part || typeof part !== "object") continue;
|
|
285
|
+
if (!("type" in part) || part.type !== "input_image") continue;
|
|
286
|
+
if ("detail" in part) part.detail = undefined;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Structural view of a Responses-style body mutated by the Lite rewrite.
|
|
294
|
+
* Loose (`unknown`) property types let the turn transformer (`RequestBody`)
|
|
295
|
+
* and the agent's remote-compaction payloads reuse one shaper.
|
|
296
|
+
*/
|
|
297
|
+
export interface CodexLiteShapedBody {
|
|
298
|
+
instructions?: unknown;
|
|
299
|
+
tools?: unknown;
|
|
300
|
+
tool_choice?: unknown;
|
|
301
|
+
input?: unknown;
|
|
302
|
+
parallel_tool_calls?: unknown;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Applies the Responses Lite body contract in place (codex-rs
|
|
307
|
+
* `build_responses_request` with `use_responses_lite`): strips pinned image
|
|
308
|
+
* detail, forces parallel tool calling off, moves tools into a leading
|
|
309
|
+
* `additional_tools` developer item and the base instructions into a
|
|
310
|
+
* developer message, then omits top-level `instructions`/`tools`. Because the
|
|
311
|
+
* rewrite removes top-level `tools`, a forced hosted-tool choice (e.g.
|
|
312
|
+
* `{ type: "web_search" }`) would leave the backend unable to validate the
|
|
313
|
+
* choice against a tools collection and it rejects the request with HTTP 400
|
|
314
|
+
* (#5771). Native computer and named-function choices preserve exact forcing
|
|
315
|
+
* by isolating the selected declaration and using `"required"`; other hosted
|
|
316
|
+
* choices fall back to `"auto"`. Explicit string constraints such as `"none"`
|
|
317
|
+
* and `"required"` remain valid. Shared by normal turns and both remote-compaction
|
|
318
|
+
* paths — codex-rs routes `/responses/compact` through the same builder.
|
|
319
|
+
*/
|
|
320
|
+
export function applyCodexResponsesLiteShape(body: CodexLiteShapedBody): void {
|
|
321
|
+
const input = Array.isArray(body.input) ? body.input : [];
|
|
322
|
+
stripImageDetails(input);
|
|
323
|
+
body.parallel_tool_calls = false;
|
|
324
|
+
const declaredTools = Array.isArray(body.tools) ? body.tools : [];
|
|
325
|
+
let additionalTools = declaredTools;
|
|
326
|
+
if (body.tool_choice && typeof body.tool_choice === "object" && "type" in body.tool_choice) {
|
|
327
|
+
const choice = body.tool_choice;
|
|
328
|
+
const selected = declaredTools.find(tool => {
|
|
329
|
+
if (tool === null || typeof tool !== "object" || !("type" in tool)) return false;
|
|
330
|
+
if (choice.type === "computer") return tool.type === "computer";
|
|
331
|
+
return (
|
|
332
|
+
choice.type === "function" &&
|
|
333
|
+
tool.type === "function" &&
|
|
334
|
+
"name" in choice &&
|
|
335
|
+
typeof choice.name === "string" &&
|
|
336
|
+
"name" in tool &&
|
|
337
|
+
tool.name === choice.name
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
if (selected) {
|
|
341
|
+
additionalTools = [selected];
|
|
342
|
+
body.tool_choice = "required";
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const prefix: InputItem[] = [{ type: "additional_tools", role: "developer", tools: additionalTools }];
|
|
346
|
+
if (typeof body.instructions === "string" && body.instructions.length > 0) {
|
|
347
|
+
prefix.push({
|
|
348
|
+
type: "message",
|
|
349
|
+
role: "developer",
|
|
350
|
+
content: [{ type: "input_text", text: body.instructions }],
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
body.input = [...prefix, ...input];
|
|
354
|
+
if (body.tool_choice !== "none" && body.tool_choice !== "required") {
|
|
355
|
+
body.tool_choice = "auto";
|
|
356
|
+
}
|
|
357
|
+
delete body.instructions;
|
|
358
|
+
delete body.tools;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export async function transformRequestBody(
|
|
362
|
+
body: RequestBody,
|
|
363
|
+
model: Model<"openai-codex-responses">,
|
|
364
|
+
options: CodexRequestOptions = {},
|
|
365
|
+
prompt?: { developerMessages: string[] },
|
|
366
|
+
): Promise<RequestBody> {
|
|
367
|
+
body.store = false;
|
|
368
|
+
body.stream = true;
|
|
369
|
+
|
|
370
|
+
if (body.input && Array.isArray(body.input)) {
|
|
371
|
+
body.input = filterInput(body.input);
|
|
372
|
+
if (body.input) {
|
|
373
|
+
body.input = repairToolCallPairs(body.input);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (prompt?.developerMessages && prompt.developerMessages.length > 0) {
|
|
378
|
+
const developerMessages: InputItem[] = prompt.developerMessages.map(text => ({
|
|
379
|
+
type: "message",
|
|
380
|
+
role: "developer",
|
|
381
|
+
content: [{ type: "input_text", text }],
|
|
382
|
+
}));
|
|
383
|
+
const input = Array.isArray(body.input) ? body.input : [];
|
|
384
|
+
body.input = [...developerMessages, ...input];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
let finalInstruction = prompt?.developerMessages.findLast(text => text.trim().length > 0);
|
|
388
|
+
if (finalInstruction === undefined && Array.isArray(body.input)) {
|
|
389
|
+
for (let itemIndex = body.input.length - 1; itemIndex >= 0; itemIndex -= 1) {
|
|
390
|
+
const item = body.input[itemIndex];
|
|
391
|
+
if (item.role !== "developer" || !Array.isArray(item.content)) continue;
|
|
392
|
+
for (let partIndex = item.content.length - 1; partIndex >= 0; partIndex -= 1) {
|
|
393
|
+
const part = item.content[partIndex];
|
|
394
|
+
if (
|
|
395
|
+
part &&
|
|
396
|
+
typeof part === "object" &&
|
|
397
|
+
"type" in part &&
|
|
398
|
+
part.type === "input_text" &&
|
|
399
|
+
"text" in part &&
|
|
400
|
+
typeof part.text === "string" &&
|
|
401
|
+
part.text.trim().length > 0
|
|
402
|
+
) {
|
|
403
|
+
finalInstruction = part.text;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (finalInstruction !== undefined) break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (finalInstruction === undefined && typeof body.instructions === "string" && body.instructions.trim().length > 0) {
|
|
411
|
+
finalInstruction = body.instructions;
|
|
412
|
+
}
|
|
413
|
+
if (finalInstruction !== undefined) {
|
|
414
|
+
const input = Array.isArray(body.input) ? body.input : [];
|
|
415
|
+
let hasVisibleInput = false;
|
|
416
|
+
for (const item of input) {
|
|
417
|
+
if (item.role !== "developer") {
|
|
418
|
+
hasVisibleInput = true;
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (!hasVisibleInput) {
|
|
423
|
+
body.input = [
|
|
424
|
+
...input,
|
|
425
|
+
{
|
|
426
|
+
type: "message",
|
|
427
|
+
role: "user",
|
|
428
|
+
content: [{ type: "input_text", text: finalInstruction }],
|
|
429
|
+
},
|
|
430
|
+
];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const responsesLite = resolveCodexResponsesLite(model, options.responsesLite);
|
|
435
|
+
if (responsesLite) {
|
|
436
|
+
applyCodexResponsesLiteShape(body);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (options.reasoningEffort !== undefined || responsesLite) {
|
|
440
|
+
const reasoningConfig =
|
|
441
|
+
options.reasoningEffort !== undefined ? getReasoningConfig(model, options.reasoningEffort, options) : {};
|
|
442
|
+
body.reasoning = {
|
|
443
|
+
...body.reasoning,
|
|
444
|
+
...reasoningConfig,
|
|
445
|
+
};
|
|
446
|
+
// Responses Lite requires `all_turns`; the full transport leaves context to the server unless explicitly set.
|
|
447
|
+
const context = responsesLite ? "all_turns" : options.reasoningContext;
|
|
448
|
+
if (context !== undefined) {
|
|
449
|
+
if (context === "all_turns" && !supportsAllTurnsReasoningContext(model.id)) {
|
|
450
|
+
delete body.reasoning.context;
|
|
451
|
+
} else {
|
|
452
|
+
body.reasoning.context = context;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
delete body.reasoning;
|
|
457
|
+
}
|
|
458
|
+
// Catalog pro aliases (`gpt-5.6-*-pro`): applied after the effort branch so
|
|
459
|
+
// the mode is sent even when no effort is set (the branch above deletes
|
|
460
|
+
// `body.reasoning` in that case) — mode and effort are independent fields.
|
|
461
|
+
if (model.reasoningMode) {
|
|
462
|
+
body.reasoning = { ...body.reasoning, mode: model.reasoningMode };
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Concurrent reasoning summaries (codex-rs `concurrent_reasoning_summaries`
|
|
466
|
+
// feature): `sequential_cutoff` lets the server stream output without
|
|
467
|
+
// blocking on summary generation. Only meaningful when a summary is
|
|
468
|
+
// requested; codex-rs additionally gates on its OpenAI provider check,
|
|
469
|
+
// which is inherent here.
|
|
470
|
+
if (body.reasoning?.summary !== undefined) {
|
|
471
|
+
body.stream_options = { reasoning_summary_delivery: "sequential_cutoff" };
|
|
472
|
+
} else {
|
|
473
|
+
delete body.stream_options;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (options.textVerbosity !== undefined) {
|
|
477
|
+
body.text = {
|
|
478
|
+
...body.text,
|
|
479
|
+
verbosity: options.textVerbosity,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const include = Array.isArray(options.include) ? [...options.include] : [];
|
|
484
|
+
include.push("reasoning.encrypted_content");
|
|
485
|
+
body.include = Array.from(new Set(include));
|
|
486
|
+
|
|
487
|
+
delete body.max_output_tokens;
|
|
488
|
+
delete body.max_completion_tokens;
|
|
489
|
+
|
|
490
|
+
return body;
|
|
491
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { toNumber } from "@linxiraos/pi-catalog/utils";
|
|
2
|
+
import { ProviderHttpError } from "../../error";
|
|
3
|
+
|
|
4
|
+
export type CodexRateLimit = {
|
|
5
|
+
used_percent?: number;
|
|
6
|
+
window_minutes?: number;
|
|
7
|
+
resets_at?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type CodexRateLimits = {
|
|
11
|
+
primary?: CodexRateLimit;
|
|
12
|
+
secondary?: CodexRateLimit;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type CodexErrorInfo = {
|
|
16
|
+
message: string;
|
|
17
|
+
status: number;
|
|
18
|
+
/** Machine-readable error code (`error.code` or `error.type` from the response body), when present. */
|
|
19
|
+
code?: string;
|
|
20
|
+
friendlyMessage?: string;
|
|
21
|
+
rateLimits?: CodexRateLimits;
|
|
22
|
+
raw?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Non-2xx response from the Codex backend, with the parsed body retained. */
|
|
26
|
+
export class CodexApiError extends ProviderHttpError {
|
|
27
|
+
readonly info: CodexErrorInfo;
|
|
28
|
+
|
|
29
|
+
constructor(info: CodexErrorInfo, headers?: Headers) {
|
|
30
|
+
super(info.friendlyMessage || info.message, info.status, { headers, code: info.code });
|
|
31
|
+
this.name = "CodexApiError";
|
|
32
|
+
this.info = info;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static async fromResponse(response: Response): Promise<CodexApiError> {
|
|
36
|
+
return new CodexApiError(await parseCodexError(response), response.headers);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function parseCodexError(response: Response): Promise<CodexErrorInfo> {
|
|
41
|
+
const raw = await response.text();
|
|
42
|
+
let message = raw || response.statusText || "Request failed";
|
|
43
|
+
let friendlyMessage: string | undefined;
|
|
44
|
+
let rateLimits: CodexRateLimits | undefined;
|
|
45
|
+
let errorCode: string | undefined;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(raw) as { error?: Record<string, unknown> };
|
|
49
|
+
const err = parsed?.error ?? {};
|
|
50
|
+
|
|
51
|
+
const headers = response.headers;
|
|
52
|
+
const primary = {
|
|
53
|
+
used_percent: toNumber(headers.get("x-codex-primary-used-percent")),
|
|
54
|
+
window_minutes: toInt(headers.get("x-codex-primary-window-minutes")),
|
|
55
|
+
resets_at: toInt(headers.get("x-codex-primary-reset-at")),
|
|
56
|
+
};
|
|
57
|
+
const secondary = {
|
|
58
|
+
used_percent: toNumber(headers.get("x-codex-secondary-used-percent")),
|
|
59
|
+
window_minutes: toInt(headers.get("x-codex-secondary-window-minutes")),
|
|
60
|
+
resets_at: toInt(headers.get("x-codex-secondary-reset-at")),
|
|
61
|
+
};
|
|
62
|
+
rateLimits =
|
|
63
|
+
primary.used_percent !== undefined || secondary.used_percent !== undefined
|
|
64
|
+
? { primary, secondary }
|
|
65
|
+
: undefined;
|
|
66
|
+
|
|
67
|
+
const code = String((err as { code?: string; type?: string }).code ?? (err as { type?: string }).type ?? "");
|
|
68
|
+
errorCode = code || undefined;
|
|
69
|
+
const resetsAt = (err as { resets_at?: number }).resets_at ?? primary.resets_at ?? secondary.resets_at;
|
|
70
|
+
const mins = resetsAt ? Math.max(0, Math.round((resetsAt * 1000 - Date.now()) / 60000)) : undefined;
|
|
71
|
+
|
|
72
|
+
if (/usage_limit_reached|usage_not_included/i.test(code)) {
|
|
73
|
+
const planType = (err as { plan_type?: string }).plan_type;
|
|
74
|
+
const plan = planType ? ` (${String(planType).toLowerCase()} plan)` : "";
|
|
75
|
+
const when = mins !== undefined ? ` Try again in ~${mins} min.` : "";
|
|
76
|
+
friendlyMessage = `You have hit your ChatGPT usage limit${plan}.${when}`.trim();
|
|
77
|
+
} else if (/rate_limit_exceeded/i.test(code) || response.status === 429) {
|
|
78
|
+
const when = mins !== undefined ? ` Try again in ~${mins} min.` : "";
|
|
79
|
+
friendlyMessage = `ChatGPT rate limit exceeded.${when}`.trim();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const errMessage = (err as { message?: string }).message;
|
|
83
|
+
message = errMessage || friendlyMessage || message;
|
|
84
|
+
} catch {
|
|
85
|
+
// raw body not JSON
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
message,
|
|
90
|
+
status: response.status,
|
|
91
|
+
code: errorCode,
|
|
92
|
+
friendlyMessage,
|
|
93
|
+
rateLimits,
|
|
94
|
+
raw: raw,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function toInt(v: string | null): number | undefined {
|
|
99
|
+
if (v == null) return undefined;
|
|
100
|
+
const n = parseInt(v, 10);
|
|
101
|
+
return Number.isFinite(n) ? n : undefined;
|
|
102
|
+
}
|