@code-yeongyu/senpi-ai 2026.9.30 → 2026.10.1
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/README.md +189 -19
- package/dist/api/anthropic-messages.js +168 -32
- package/dist/api/azure-openai-responses.js +23 -10
- package/dist/api/bedrock-converse-stream.js +12 -4
- package/dist/api/cloudflare-workers-ai-system-one.d.ts +4 -0
- package/dist/api/cloudflare-workers-ai-system-one.js +43 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts +3 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.js +4 -0
- package/dist/api/cloudflare.d.ts +2 -0
- package/dist/api/cloudflare.js +2 -0
- package/dist/api/context-room.d.ts +2 -2
- package/dist/api/cursor-agent.js +19 -10
- package/dist/api/devin-agent/request.d.ts +9 -9
- package/dist/api/devin-agent/request.js +14 -10
- package/dist/api/google-generative-ai.js +20 -80
- package/dist/api/google-shared.d.ts +13 -4
- package/dist/api/google-shared.js +54 -4
- package/dist/api/google-vertex.js +19 -62
- package/dist/api/llama-cpp-classify.d.ts +33 -0
- package/dist/api/llama-cpp-classify.js +365 -0
- package/dist/api/llama-cpp-classify.lazy.d.ts +3 -0
- package/dist/api/llama-cpp-classify.lazy.js +4 -0
- package/dist/api/mistral-conversations.d.ts +1 -1
- package/dist/api/mistral-conversations.js +36 -29
- package/dist/api/openai-codex-responses.d.ts +1 -1
- package/dist/api/openai-codex-responses.js +72 -37
- package/dist/api/openai-completions.d.ts +3 -2
- package/dist/api/openai-completions.js +76 -50
- package/dist/api/openai-images-params.d.ts +2 -2
- package/dist/api/openai-images.d.ts +1 -1
- package/dist/api/openai-responses-shared.d.ts +31 -8
- package/dist/api/openai-responses-shared.js +115 -27
- package/dist/api/openai-responses.d.ts +1 -1
- package/dist/api/openai-responses.js +38 -33
- package/dist/api/openrouter-images.d.ts +2 -1
- package/dist/api/openrouter-images.js +1 -0
- package/dist/api/pi-messages.d.ts +3 -3
- package/dist/api/pi-messages.js +3 -2
- package/dist/api/simple-options.d.ts +2 -2
- package/dist/api/simple-options.js +1 -0
- package/dist/api/system-one-shared.d.ts +23 -0
- package/dist/api/system-one-shared.js +183 -0
- package/dist/api/transform-messages.js +5 -2
- package/dist/api/typesafe-system-one.d.ts +4 -0
- package/dist/api/typesafe-system-one.js +19 -0
- package/dist/api/typesafe-system-one.lazy.d.ts +3 -0
- package/dist/api/typesafe-system-one.lazy.js +4 -0
- package/dist/api-registry.d.ts +3 -3
- package/dist/auth/helpers.js +1 -1
- package/dist/auth/oauth/anthropic-callback-listener.js +1 -1
- package/dist/auth/oauth/callback-server.d.ts +55 -0
- package/dist/auth/oauth/callback-server.js +146 -0
- package/dist/auth/oauth/chatgpt-subscription.d.ts +1 -1
- package/dist/auth/oauth/chatgpt-subscription.js +20 -124
- package/dist/auth/oauth/devin-callback.js +1 -1
- package/dist/auth/oauth/load.d.ts +4 -0
- package/dist/auth/oauth/load.js +10 -0
- package/dist/auth/oauth/meta.d.ts +17 -0
- package/dist/auth/oauth/meta.js +190 -0
- package/dist/auth/oauth/openai-chatgpt.d.ts +9 -0
- package/dist/auth/oauth/openai-chatgpt.js +266 -0
- package/dist/auth/oauth/openrouter.d.ts +1 -1
- package/dist/auth/oauth/openrouter.js +19 -138
- package/dist/auth/oauth/radius.d.ts +1 -1
- package/dist/auth/oauth/radius.js +21 -89
- package/dist/auth/resolve.d.ts +3 -8
- package/dist/auth/resolve.js +3 -18
- package/dist/auth/types.d.ts +10 -1
- package/dist/bun-oauth.js +4 -0
- package/dist/cli.js +3 -1
- package/dist/compat.js +17 -14
- package/dist/env-api-keys.js +2 -0
- package/dist/image-models.d.ts +19 -8
- package/dist/image-models.js +14 -13
- package/dist/images-api-registry.d.ts +8 -8
- package/dist/images.d.ts +7 -2
- package/dist/images.js +5 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/model-catalog.d.ts +27 -9
- package/dist/model-catalog.js +24 -2
- package/dist/model.d.ts +13 -13
- package/dist/models-store.d.ts +3 -2
- package/dist/models.d.ts +106 -36
- package/dist/models.generated.d.ts +142 -42
- package/dist/models.generated.js +142 -42
- package/dist/models.js +174 -36
- package/dist/providers/alibaba-token-plan.models.d.ts +4 -2
- package/dist/providers/alibaba-token-plan.models.js +4 -2
- package/dist/providers/all.d.ts +72 -19
- package/dist/providers/all.js +28 -22
- package/dist/providers/amazon-bedrock.models.d.ts +4 -2
- package/dist/providers/amazon-bedrock.models.js +4 -2
- package/dist/providers/ant-ling.models.d.ts +4 -2
- package/dist/providers/ant-ling.models.js +4 -2
- package/dist/providers/anthropic.models.d.ts +4 -2
- package/dist/providers/anthropic.models.js +4 -2
- package/dist/providers/azure-openai-responses.models.d.ts +4 -2
- package/dist/providers/azure-openai-responses.models.js +4 -2
- package/dist/providers/bai.models.d.ts +4 -2
- package/dist/providers/bai.models.js +4 -2
- package/dist/providers/baseten.models.d.ts +4 -2
- package/dist/providers/baseten.models.js +4 -2
- package/dist/providers/cerebras.models.d.ts +4 -2
- package/dist/providers/cerebras.models.js +4 -2
- package/dist/providers/chatgpt-subscription.models.d.ts +4 -2
- package/dist/providers/chatgpt-subscription.models.js +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.d.ts +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.js +4 -2
- package/dist/providers/cloudflare-stream.d.ts +6 -2
- package/dist/providers/cloudflare-stream.js +6 -0
- package/dist/providers/cloudflare-workers-ai.js +10 -3
- package/dist/providers/cloudflare-workers-ai.models.d.ts +4 -2
- package/dist/providers/cloudflare-workers-ai.models.js +4 -2
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/alibaba-token-plan.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/ant-ling.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/providers/data/bai.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/chatgpt-subscription.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/deepseek.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google-vertex.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/groq.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/meta.json +1 -0
- package/dist/providers/data/minimax-cn.json +1 -1
- package/dist/providers/data/minimax.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/providers/data/moonshotai.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/openai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/radius.json +1 -0
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/typesafe.json +1 -0
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
- package/dist/providers/data/xiaomi.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/deepseek.models.d.ts +4 -2
- package/dist/providers/deepseek.models.js +4 -2
- package/dist/providers/faux.d.ts +7 -2
- package/dist/providers/faux.js +31 -22
- package/dist/providers/fireworks.models.d.ts +4 -2
- package/dist/providers/fireworks.models.js +4 -2
- package/dist/providers/github-copilot.models.d.ts +4 -2
- package/dist/providers/github-copilot.models.js +4 -2
- package/dist/providers/google-vertex.models.d.ts +4 -2
- package/dist/providers/google-vertex.models.js +4 -2
- package/dist/providers/google.models.d.ts +4 -2
- package/dist/providers/google.models.js +4 -2
- package/dist/providers/groq.models.d.ts +4 -2
- package/dist/providers/groq.models.js +4 -2
- package/dist/providers/huggingface.models.d.ts +4 -2
- package/dist/providers/huggingface.models.js +4 -2
- package/dist/providers/images/register-builtins.d.ts +2 -2
- package/dist/providers/kimi-coding.models.d.ts +54 -7
- package/dist/providers/kimi-coding.models.js +34 -7
- package/dist/providers/meta.d.ts +3 -0
- package/dist/providers/meta.js +24 -0
- package/dist/providers/meta.models.d.ts +6 -0
- package/dist/providers/meta.models.js +8 -0
- package/dist/providers/minimax-cn.models.d.ts +4 -2
- package/dist/providers/minimax-cn.models.js +4 -2
- package/dist/providers/minimax.models.d.ts +4 -2
- package/dist/providers/minimax.models.js +4 -2
- package/dist/providers/mistral.models.d.ts +4 -2
- package/dist/providers/mistral.models.js +4 -2
- package/dist/providers/moonshotai-cn.models.d.ts +4 -2
- package/dist/providers/moonshotai-cn.models.js +4 -2
- package/dist/providers/moonshotai.models.d.ts +4 -2
- package/dist/providers/moonshotai.models.js +4 -2
- package/dist/providers/nvidia.models.d.ts +4 -2
- package/dist/providers/nvidia.models.js +4 -2
- package/dist/providers/openai.js +4 -2
- package/dist/providers/openai.models.d.ts +4 -2
- package/dist/providers/openai.models.js +4 -2
- package/dist/providers/opencode-go.models.d.ts +4 -2
- package/dist/providers/opencode-go.models.js +4 -2
- package/dist/providers/opencode.d.ts +3 -1
- package/dist/providers/opencode.js +5 -2
- package/dist/providers/opencode.models.d.ts +4 -2
- package/dist/providers/opencode.models.js +4 -2
- package/dist/providers/opengateway.models.d.ts +4 -2
- package/dist/providers/opengateway.models.js +4 -2
- package/dist/providers/openrouter.js +11 -2
- package/dist/providers/openrouter.models.d.ts +4 -2
- package/dist/providers/openrouter.models.js +4 -2
- package/dist/providers/qwen-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-cn.models.js +4 -2
- package/dist/providers/qwen-token-plan-individual.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-individual.models.js +4 -2
- package/dist/providers/qwen-token-plan.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan.models.js +4 -2
- package/dist/providers/radius.js +19 -5
- package/dist/providers/radius.models.d.ts +6 -0
- package/dist/providers/radius.models.js +8 -0
- package/dist/providers/together.models.d.ts +4 -2
- package/dist/providers/together.models.js +4 -2
- package/dist/providers/typesafe.d.ts +3 -0
- package/dist/providers/typesafe.js +18 -0
- package/dist/providers/typesafe.models.d.ts +6 -0
- package/dist/providers/typesafe.models.js +8 -0
- package/dist/providers/venice.models.d.ts +4 -2
- package/dist/providers/venice.models.js +4 -2
- package/dist/providers/vercel-ai-gateway.js +5 -2
- package/dist/providers/vercel-ai-gateway.models.d.ts +4 -2
- package/dist/providers/vercel-ai-gateway.models.js +4 -2
- package/dist/providers/xai.models.d.ts +4 -2
- package/dist/providers/xai.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.js +4 -2
- package/dist/providers/xiaomi.models.d.ts +4 -2
- package/dist/providers/xiaomi.models.js +4 -2
- package/dist/providers/zai-coding-cn.models.d.ts +4 -2
- package/dist/providers/zai-coding-cn.models.js +4 -2
- package/dist/providers/zai.models.d.ts +4 -2
- package/dist/providers/zai.models.js +4 -2
- package/dist/tool-call-middleware/context-transformer.d.ts +8 -5
- package/dist/tool-call-middleware/context-transformer.js +44 -15
- package/dist/types.d.ts +262 -28
- package/dist/utils/diagnostics.d.ts +3 -2
- package/dist/utils/estimate.d.ts +2 -2
- package/dist/utils/estimate.js +22 -30
- package/dist/utils/headers.d.ts +1 -1
- package/dist/utils/headers.js +10 -8
- package/dist/utils/model-operations.d.ts +11 -0
- package/dist/utils/model-operations.js +47 -0
- package/dist/utils/models-error.d.ts +8 -0
- package/dist/utils/models-error.js +18 -0
- package/dist/utils/overflow.d.ts +1 -0
- package/dist/utils/overflow.js +11 -5
- package/dist/utils/prompt-cache-ttl.js +10 -3
- package/dist/utils/retry.js +9 -0
- package/dist/utils/text.d.ts +9 -1
- package/dist/utils/text.js +26 -0
- package/dist/utils/transcript.d.ts +85 -0
- package/dist/utils/transcript.js +205 -0
- package/package.json +3 -4
- package/dist/image-models.generated.d.ts +0 -925
- package/dist/image-models.generated.js +0 -927
- package/dist/images-models.d.ts +0 -95
- package/dist/images-models.js +0 -141
- package/dist/providers/openai-images.d.ts +0 -3
- package/dist/providers/openai-images.js +0 -16
- package/dist/providers/openrouter-images.d.ts +0 -3
- package/dist/providers/openrouter-images.js +0 -22
- /package/dist/{auth/oauth → utils}/oauth-page.d.ts +0 -0
- /package/dist/{auth/oauth → utils}/oauth-page.js +0 -0
|
@@ -13,8 +13,10 @@ import { awaitProviderTransport, iterateProviderTransport, openAICompatibleProvi
|
|
|
13
13
|
import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
14
14
|
import { retryProviderStreamRequest } from "../utils/provider-retry.js";
|
|
15
15
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
16
|
+
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
16
17
|
import { sendWithForcedToolChoiceFallback } from "../utils/tool-choice-fallback.js";
|
|
17
18
|
import { normalizeToolParametersForMoonshot, normalizeToolParametersForOpenAICompat, } from "../utils/tool-schema-compat.js";
|
|
19
|
+
import { getCurrentTools, getDeclaredTools, resolveTranscript, resolveTranscriptTools, } from "../utils/transcript.js";
|
|
18
20
|
import { appendGrammarToolInputJsonDelta, createGrammarToolInputProperties, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
|
|
19
21
|
import { withGitHubCopilotFailureNote } from "./github-copilot-errors.js";
|
|
20
22
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
|
|
@@ -122,24 +124,26 @@ function hasToolHistory(messages) {
|
|
|
122
124
|
}
|
|
123
125
|
return false;
|
|
124
126
|
}
|
|
125
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Kimi `deferredToolsMode`: a current tool named by any tool result's `addedToolNames` leaves the
|
|
129
|
+
* top-level `tools` field and is loaded by a Kimi tools system message after that result.
|
|
130
|
+
*/
|
|
131
|
+
function resolveKimiDeferredTools(messages, compat) {
|
|
132
|
+
const deferred = new Map();
|
|
133
|
+
if (compat.deferredToolsMode !== "kimi")
|
|
134
|
+
return deferred;
|
|
126
135
|
const names = new Set();
|
|
127
136
|
for (const message of messages) {
|
|
128
|
-
if (message.role
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
137
|
+
if (message.role !== "toolResult")
|
|
138
|
+
continue;
|
|
139
|
+
for (const name of message.addedToolNames ?? [])
|
|
140
|
+
names.add(name);
|
|
133
141
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));
|
|
140
|
-
return Array.from(names)
|
|
141
|
-
.map((name) => toolsByName.get(name))
|
|
142
|
-
.filter((tool) => tool !== undefined);
|
|
142
|
+
for (const tool of getCurrentTools(messages)) {
|
|
143
|
+
if (names.has(tool.name))
|
|
144
|
+
deferred.set(tool.name, tool);
|
|
145
|
+
}
|
|
146
|
+
return deferred;
|
|
143
147
|
}
|
|
144
148
|
function isTextContentBlock(block) {
|
|
145
149
|
return block.type === "text";
|
|
@@ -297,6 +301,7 @@ function resolveCacheRetention(cacheRetention, env) {
|
|
|
297
301
|
}
|
|
298
302
|
export const stream = (model, context, options) => {
|
|
299
303
|
const stream = new AssistantMessageEventStream();
|
|
304
|
+
const normalizedContext = resolveTranscript(context, getCompat(model).supportsMidConvoSystemMessages);
|
|
300
305
|
(async () => {
|
|
301
306
|
const output = {
|
|
302
307
|
role: "assistant",
|
|
@@ -326,11 +331,11 @@ export const stream = (model, context, options) => {
|
|
|
326
331
|
try {
|
|
327
332
|
const clientAuth = resolveOpenAIClientAuth(model.provider, options?.apiKey, options?.headers);
|
|
328
333
|
const compat = getCompat(model);
|
|
329
|
-
const grammarToolInputProperties = createGrammarToolInputProperties(
|
|
334
|
+
const grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(normalizedContext.messages), compat.supportsOpenAIGrammarTools);
|
|
330
335
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env);
|
|
331
336
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
332
|
-
const client = createClient(model,
|
|
333
|
-
let params = buildParams(model,
|
|
337
|
+
const client = createClient(model, normalizedContext, clientAuth.apiKey, clientAuth.headers, options?.fetch, cacheSessionId, compat);
|
|
338
|
+
let params = buildParams(model, normalizedContext, options, compat, cacheRetention, grammarToolInputProperties);
|
|
334
339
|
const nextParams = await options?.onPayload?.(params, model);
|
|
335
340
|
if (nextParams !== undefined) {
|
|
336
341
|
params = nextParams;
|
|
@@ -579,6 +584,7 @@ export const stream = (model, context, options) => {
|
|
|
579
584
|
}
|
|
580
585
|
};
|
|
581
586
|
for await (const chunk of openaiStream) {
|
|
587
|
+
await options?.onProviderStreamEvent?.(chunk, model);
|
|
582
588
|
if (!chunk || typeof chunk !== "object")
|
|
583
589
|
continue;
|
|
584
590
|
// OpenAI documents ChatCompletionChunk.id as the unique chat completion identifier,
|
|
@@ -833,7 +839,10 @@ function createClient(model, context, apiKey, optionsHeaders, fetch, sessionId,
|
|
|
833
839
|
defaultHeaders: headers,
|
|
834
840
|
});
|
|
835
841
|
}
|
|
836
|
-
function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env), grammarToolInputProperties = createGrammarToolInputProperties(context.
|
|
842
|
+
function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env), grammarToolInputProperties = createGrammarToolInputProperties(getDeclaredTools(context.messages), compat.supportsOpenAIGrammarTools)) {
|
|
843
|
+
const transcriptTools = resolveTranscriptTools(context.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true);
|
|
844
|
+
const kimiDeferredTools = resolveKimiDeferredTools(context.messages, compat);
|
|
845
|
+
const requestTools = transcriptTools.requestTools.filter((tool) => !kimiDeferredTools.has(tool.name));
|
|
837
846
|
const messages = convertMessages(model, context, compat, {
|
|
838
847
|
preserveThinking: options?.reasoningEffort !== undefined,
|
|
839
848
|
grammarToolInputProperties,
|
|
@@ -864,6 +873,7 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
864
873
|
}
|
|
865
874
|
if (options?.maxTokens) {
|
|
866
875
|
if (compat.maxTokensField === "max_tokens") {
|
|
876
|
+
// Deprecated by OpenAI, but some OpenAI-compatible providers only accept max_tokens.
|
|
867
877
|
params.max_tokens = options.maxTokens;
|
|
868
878
|
}
|
|
869
879
|
else {
|
|
@@ -873,10 +883,8 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
873
883
|
if (options?.temperature !== undefined) {
|
|
874
884
|
params.temperature = options.temperature;
|
|
875
885
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
if (activeTools && activeTools.length > 0) {
|
|
879
|
-
params.tools = convertTools(activeTools, compat);
|
|
886
|
+
if (requestTools.length > 0) {
|
|
887
|
+
params.tools = convertTools(requestTools, compat);
|
|
880
888
|
if (compat.zaiToolStream) {
|
|
881
889
|
params.tool_stream = true;
|
|
882
890
|
}
|
|
@@ -1040,10 +1048,8 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
|
|
|
1040
1048
|
}
|
|
1041
1049
|
}
|
|
1042
1050
|
applyExtraBody(params, options?.extraBody, OPENAI_COMPLETIONS_RESERVED_BODY_KEYS);
|
|
1043
|
-
// Last so custom keys override the named request fields.
|
|
1044
|
-
|
|
1045
|
-
Object.assign(params, options.samplingParams);
|
|
1046
|
-
}
|
|
1051
|
+
// Last so custom keys override the named request fields. Per-request keys override model defaults.
|
|
1052
|
+
Object.assign(params, model.samplingParams, options?.samplingParams);
|
|
1047
1053
|
return params;
|
|
1048
1054
|
}
|
|
1049
1055
|
function resolveThinkingTokenBudgetField(compat) {
|
|
@@ -1173,6 +1179,7 @@ function appendUserMessage(params, content, mergeAdjacentUserMessages) {
|
|
|
1173
1179
|
previous.content = [...previousContent, ...currentContent];
|
|
1174
1180
|
}
|
|
1175
1181
|
export function convertMessages(model, context, compat, options = {}) {
|
|
1182
|
+
const normalizedContext = resolveTranscript(context, compat.supportsMidConvoSystemMessages);
|
|
1176
1183
|
const params = [];
|
|
1177
1184
|
const normalizeToolCallId = (id) => {
|
|
1178
1185
|
// Handle pipe-separated IDs from OpenAI Responses API
|
|
@@ -1202,16 +1209,16 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1202
1209
|
const prefix = sanitizedId.slice(0, Math.max(1, 40 - hash.length - 1));
|
|
1203
1210
|
return `${prefix}_${hash}`;
|
|
1204
1211
|
};
|
|
1205
|
-
const transformedMessages = transformMessages(
|
|
1212
|
+
const transformedMessages = transformMessages(normalizedContext.messages, model, (id) => normalizeToolCallId(id), {
|
|
1206
1213
|
preserveThinking: options.preserveThinking,
|
|
1207
1214
|
normalizeSameModelToolCallIds: true,
|
|
1208
1215
|
});
|
|
1209
1216
|
const mergeAdjacentUserMessages = !model.baseUrl.includes("api.openai.com");
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1217
|
+
const transcriptTools = resolveTranscriptTools(normalizedContext.messages, compat.supportsMidConvoSystemMessages === true && compat.supportsMidConvoToolAdditions === true);
|
|
1218
|
+
const kimiDeferredTools = resolveKimiDeferredTools(normalizedContext.messages, compat);
|
|
1219
|
+
// One ledger for both in-place loading paths: transcript system messages and `addedToolNames`.
|
|
1220
|
+
const loadedToolNames = new Set();
|
|
1221
|
+
const instructionRole = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
|
|
1215
1222
|
let lastRole = null;
|
|
1216
1223
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1217
1224
|
const msg = transformedMessages[i];
|
|
@@ -1223,12 +1230,32 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1223
1230
|
content: "I have processed the tool results.",
|
|
1224
1231
|
});
|
|
1225
1232
|
}
|
|
1226
|
-
if (msg.role === "
|
|
1233
|
+
if (msg.role === "system") {
|
|
1234
|
+
const addedTools = i > 0 && transcriptTools.anchorsAdditions
|
|
1235
|
+
? (msg.toolsAdded ?? []).filter((tool) => !loadedToolNames.has(tool.name))
|
|
1236
|
+
: [];
|
|
1237
|
+
for (const tool of addedTools)
|
|
1238
|
+
loadedToolNames.add(tool.name);
|
|
1239
|
+
if (addedTools.length > 0) {
|
|
1240
|
+
const kimiToolMessage = {
|
|
1241
|
+
role: "system",
|
|
1242
|
+
tools: convertTools(addedTools, compat),
|
|
1243
|
+
};
|
|
1244
|
+
params.push(kimiToolMessage);
|
|
1245
|
+
}
|
|
1246
|
+
const text = i === 0 ? getSystemMessageText(msg) : renderSystemMessageUpdate(msg);
|
|
1247
|
+
if (text.length > 0) {
|
|
1248
|
+
params.push({ role: instructionRole, content: sanitizeSurrogates(text) });
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
else if (msg.role === "user") {
|
|
1227
1252
|
if (typeof msg.content === "string") {
|
|
1228
1253
|
appendUserMessage(params, sanitizeSurrogates(msg.content), mergeAdjacentUserMessages);
|
|
1229
1254
|
}
|
|
1230
1255
|
else {
|
|
1231
|
-
const content = msg.content
|
|
1256
|
+
const content = msg.content
|
|
1257
|
+
.filter((item) => item.type !== "text" || item.text.length > 0)
|
|
1258
|
+
.map((item) => {
|
|
1232
1259
|
if (item.type === "text") {
|
|
1233
1260
|
return {
|
|
1234
1261
|
type: "text",
|
|
@@ -1361,7 +1388,7 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1361
1388
|
}
|
|
1362
1389
|
else if (msg.role === "toolResult") {
|
|
1363
1390
|
const imageBlocks = [];
|
|
1364
|
-
const
|
|
1391
|
+
const deferredTools = [];
|
|
1365
1392
|
let j = i;
|
|
1366
1393
|
for (; j < transformedMessages.length && transformedMessages[j].role === "toolResult"; j++) {
|
|
1367
1394
|
const toolMsg = transformedMessages[j];
|
|
@@ -1384,10 +1411,12 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1384
1411
|
Object.assign(toolResultMsg, { name: toolMsg.toolName });
|
|
1385
1412
|
}
|
|
1386
1413
|
params.push(toolResultMsg);
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1414
|
+
for (const name of toolMsg.addedToolNames ?? []) {
|
|
1415
|
+
const tool = kimiDeferredTools.get(name);
|
|
1416
|
+
if (!tool || loadedToolNames.has(name))
|
|
1417
|
+
continue;
|
|
1418
|
+
loadedToolNames.add(name);
|
|
1419
|
+
deferredTools.push(tool);
|
|
1391
1420
|
}
|
|
1392
1421
|
if (hasImages && model.input.includes("image")) {
|
|
1393
1422
|
for (const block of toolMsg.content) {
|
|
@@ -1425,16 +1454,13 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1425
1454
|
else {
|
|
1426
1455
|
lastRole = "toolResult";
|
|
1427
1456
|
}
|
|
1428
|
-
if (
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
// Kimi accepts a system message with tools but omits the standard content field.
|
|
1436
|
-
params.push(kimiToolMessage);
|
|
1437
|
-
}
|
|
1457
|
+
if (deferredTools.length > 0) {
|
|
1458
|
+
const kimiToolMessage = {
|
|
1459
|
+
role: "system",
|
|
1460
|
+
tools: convertTools(deferredTools, compat),
|
|
1461
|
+
};
|
|
1462
|
+
// Kimi accepts a system message with tools but omits the standard content field.
|
|
1463
|
+
params.push(kimiToolMessage);
|
|
1438
1464
|
}
|
|
1439
1465
|
continue;
|
|
1440
1466
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Uploadable } from "openai";
|
|
2
2
|
import type { ImageGenerateParamsNonStreaming } from "openai/resources/images.js";
|
|
3
|
-
import type { ImageContent,
|
|
3
|
+
import type { ImageApi, ImageContent, ImageModel, ImagesContext, ImagesOptions } from "../types.ts";
|
|
4
4
|
export type OpenAIImageQuality = "auto" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
5
5
|
export type OpenAIImageSize = "auto" | "1024x1024" | "1536x1024" | "1024x1536" | `${number}x${number}`;
|
|
6
6
|
export type OpenAIImageBackground = "auto" | "transparent" | "opaque";
|
|
@@ -55,6 +55,6 @@ export type OpenAIImageOutputOptions = {
|
|
|
55
55
|
* compression is a jpeg/webp-only integer percentage, and a mask edits an image.
|
|
56
56
|
*/
|
|
57
57
|
export declare function parseOpenAIImageOutputOptions(input: OpenAIImageOutputOptionsInput): OpenAIImageOutputOptions;
|
|
58
|
-
export declare function buildParams(model:
|
|
58
|
+
export declare function buildParams(model: ImageModel<ImageApi>, context: ImagesContext, options?: OpenAIImagesOptions): OpenAIImageParams;
|
|
59
59
|
export declare function isImageParams(value: unknown): value is OpenAIImageParams;
|
|
60
60
|
//# sourceMappingURL=openai-images-params.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ImagesFunction } from "../types.ts";
|
|
2
2
|
import { type OpenAIImagesOptions } from "./openai-images-params.ts";
|
|
3
3
|
export { type OpenAIImageBackground, type OpenAIImageModeration, type OpenAIImageOutputFormat, type OpenAIImageQuality, type OpenAIImageSize, type OpenAIImagesOptions, parseOpenAIImageOutputOptions, parseOpenAIImageSize, } from "./openai-images-params.ts";
|
|
4
|
-
export declare const generateImages: ImagesFunction<
|
|
4
|
+
export declare const generateImages: ImagesFunction<OpenAIImagesOptions>;
|
|
5
5
|
//# sourceMappingURL=openai-images.d.ts.map
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import type { Tool as OpenAITool, ResponseCreateParamsStreaming, ResponseInput, ResponseStreamEvent } from "openai/resources/responses/responses.js";
|
|
2
|
-
import type { Api, AssistantMessage,
|
|
2
|
+
import type { Api, AssistantMessage, Message, Model, StreamOptions, Tool, TranscriptContext, Usage } from "../types.ts";
|
|
3
3
|
import type { AssistantMessageEventStream } from "../utils/event-stream.ts";
|
|
4
4
|
export interface OpenAIResponsesStreamOptions {
|
|
5
|
-
|
|
5
|
+
onProviderStreamEvent?: StreamOptions["onProviderStreamEvent"];
|
|
6
|
+
serviceTier?: ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast";
|
|
6
7
|
grammarToolInputProperties?: ReadonlyMap<string, string>;
|
|
7
|
-
resolveServiceTier?: (responseServiceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | undefined, requestServiceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | undefined) => ResponseCreateParamsStreaming["service_tier"] | "fast" | undefined;
|
|
8
|
-
applyServiceTierPricing?: (usage: Usage, serviceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | undefined) => void;
|
|
8
|
+
resolveServiceTier?: (responseServiceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast" | undefined, requestServiceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast" | undefined) => ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast" | undefined;
|
|
9
|
+
applyServiceTierPricing?: (usage: Usage, serviceTier: ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast" | undefined) => void;
|
|
9
10
|
}
|
|
10
11
|
export interface ConvertResponsesMessagesOptions {
|
|
11
12
|
includeSystemPrompt?: boolean;
|
|
12
13
|
preserveThinking?: boolean;
|
|
13
14
|
preserveTextSignatures?: boolean;
|
|
14
15
|
grammarToolInputProperties?: ReadonlyMap<string, string>;
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
/** Whether later system messages are sent in place; otherwise they are folded into the leading prompt. */
|
|
17
|
+
supportsMidConvoSystemMessages?: boolean;
|
|
18
|
+
supportsAdditionalTools?: boolean;
|
|
19
|
+
supportsToolSearch?: boolean;
|
|
17
20
|
toolOptions?: ConvertResponsesToolsOptions;
|
|
18
21
|
/**
|
|
19
22
|
* Send the system prompt as one `input_text` block carrying an explicit
|
|
@@ -28,10 +31,30 @@ export interface ConvertResponsesToolsOptions {
|
|
|
28
31
|
strict?: boolean | null;
|
|
29
32
|
supportsStrictMode?: boolean;
|
|
30
33
|
supportsOpenAIGrammarTools?: boolean;
|
|
31
|
-
|
|
34
|
+
toolSearchResult?: boolean;
|
|
32
35
|
}
|
|
33
36
|
export declare const CUSTOM_TOOL_CALL_ITEM_ID_SENTINEL = "custom";
|
|
34
|
-
export
|
|
37
|
+
export type ResponsesDeferredToolsMode = "additional-tools" | "tool-search";
|
|
38
|
+
/** `additional_tools` items win over client tool search when a model supports both. */
|
|
39
|
+
export declare function resolveResponsesDeferredToolsMode(compat: {
|
|
40
|
+
supportsAdditionalTools?: boolean;
|
|
41
|
+
supportsToolSearch?: boolean;
|
|
42
|
+
} | undefined): ResponsesDeferredToolsMode | undefined;
|
|
43
|
+
export interface ResponsesToolPlacement {
|
|
44
|
+
/** Tools sent in the top-level `tools` field. */
|
|
45
|
+
requestTools: Tool[];
|
|
46
|
+
/** Whether later system messages load their own `toolsAdded` in place. */
|
|
47
|
+
anchorsAdditions: boolean;
|
|
48
|
+
/** Tools a tool result loads in place through `addedToolNames`. */
|
|
49
|
+
deferred: ReadonlyMap<string, Tool>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Upstream transcript placement plus the fork's `addedToolNames` deferral: a current tool first named by a
|
|
53
|
+
* tool result's `addedToolNames` (before any call to it) leaves the top-level `tools` field and is loaded
|
|
54
|
+
* where that result appears, so lazy activation never rewrites the cached prefix.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveResponsesToolPlacement(messages: readonly Message[], supportsToolAdditions: boolean): ResponsesToolPlacement;
|
|
57
|
+
export declare function convertResponsesMessages<TApi extends Api>(model: Model<TApi>, context: TranscriptContext, allowedToolCallProviders: ReadonlySet<string>, options?: ConvertResponsesMessagesOptions): ResponseInput;
|
|
35
58
|
export declare function convertResponsesTools(tools: readonly Tool[], options?: ConvertResponsesToolsOptions): OpenAITool[];
|
|
36
59
|
export declare function processResponsesStream<TApi extends Api>(openaiStream: AsyncIterable<ResponseStreamEvent>, output: AssistantMessage, stream: AssistantMessageEventStream, model: Model<TApi>, options?: OpenAIResponsesStreamOptions): Promise<void>;
|
|
37
60
|
//# sourceMappingURL=openai-responses-shared.d.ts.map
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CONTEXT_PROVENANCE_FIELD, contextProvenanceFingerprint, getContextProvenance, } from "../context-provenance.js";
|
|
2
2
|
import { calculateCost, supportsConfigurationUpdate } from "../models.js";
|
|
3
|
+
import { splitDeferredTools } from "../utils/deferred-tools.js";
|
|
3
4
|
import { shortHash } from "../utils/hash.js";
|
|
4
5
|
import { parseStreamingJson } from "../utils/json-parse.js";
|
|
5
6
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
7
|
+
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
8
|
+
import { getCurrentTools, getDeclaredTools, resolveTranscript, resolveTranscriptTools } from "../utils/transcript.js";
|
|
6
9
|
import { appendGrammarToolInputJsonDelta, getGrammarToolInput, getJsonSchemaToolParameters, resolveGrammarConstrainedSampling, resolveJsonSchemaStrictSampling, } from "./constrained-sampling.js";
|
|
7
10
|
import { parsePromptCacheDiagnostics } from "./openai-responses-prompt-cache.js";
|
|
8
11
|
import { withResponsesCompletionGrace } from "./responses-completion-grace.js";
|
|
@@ -113,11 +116,36 @@ function withContextProvenance(item, message, seal) {
|
|
|
113
116
|
}
|
|
114
117
|
return item;
|
|
115
118
|
}
|
|
119
|
+
/** `additional_tools` items win over client tool search when a model supports both. */
|
|
120
|
+
export function resolveResponsesDeferredToolsMode(compat) {
|
|
121
|
+
if (compat?.supportsAdditionalTools)
|
|
122
|
+
return "additional-tools";
|
|
123
|
+
return compat?.supportsToolSearch ? "tool-search" : undefined;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Upstream transcript placement plus the fork's `addedToolNames` deferral: a current tool first named by a
|
|
127
|
+
* tool result's `addedToolNames` (before any call to it) leaves the top-level `tools` field and is loaded
|
|
128
|
+
* where that result appears, so lazy activation never rewrites the cached prefix.
|
|
129
|
+
*/
|
|
130
|
+
export function resolveResponsesToolPlacement(messages, supportsToolAdditions) {
|
|
131
|
+
const transcriptTools = resolveTranscriptTools(messages, supportsToolAdditions);
|
|
132
|
+
const { deferred } = splitDeferredTools({ messages: [...messages], tools: getCurrentTools(messages) }, supportsToolAdditions);
|
|
133
|
+
return {
|
|
134
|
+
requestTools: transcriptTools.requestTools.filter((tool) => !deferred.has(tool.name)),
|
|
135
|
+
anchorsAdditions: transcriptTools.anchorsAdditions,
|
|
136
|
+
deferred,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
116
139
|
// =============================================================================
|
|
117
140
|
// Message conversion
|
|
118
141
|
// =============================================================================
|
|
119
142
|
export function convertResponsesMessages(model, context, allowedToolCallProviders, options) {
|
|
143
|
+
const normalizedContext = resolveTranscript(context, options?.supportsMidConvoSystemMessages);
|
|
120
144
|
const messages = [];
|
|
145
|
+
const deferredToolsMode = resolveResponsesDeferredToolsMode(options);
|
|
146
|
+
const toolPlacement = resolveResponsesToolPlacement(normalizedContext.messages, deferredToolsMode !== undefined);
|
|
147
|
+
const declaredTools = getDeclaredTools(normalizedContext.messages);
|
|
148
|
+
// One ledger for both in-place loading paths: transcript system messages and `addedToolNames`.
|
|
121
149
|
const loadedToolNames = new Set();
|
|
122
150
|
const normalizeIdPart = (part) => {
|
|
123
151
|
const sanitized = part.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -146,25 +174,52 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
146
174
|
}
|
|
147
175
|
return `${normalizedCallId}|${normalizedItemId}`;
|
|
148
176
|
};
|
|
149
|
-
const transformedMessages = transformMessages(
|
|
177
|
+
const transformedMessages = transformMessages(normalizedContext.messages, model, normalizeToolCallId, {
|
|
150
178
|
preserveThinking: options?.preserveThinking,
|
|
151
179
|
preserveTextSignatures: options?.preserveTextSignatures,
|
|
152
180
|
});
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
const appendSystemToolAdditions = (message, seed) => {
|
|
182
|
+
const tools = toolPlacement.anchorsAdditions
|
|
183
|
+
? (message.toolsAdded ?? []).filter((tool) => !loadedToolNames.has(tool.name))
|
|
184
|
+
: [];
|
|
185
|
+
if (tools.length === 0)
|
|
186
|
+
return;
|
|
187
|
+
for (const tool of tools)
|
|
188
|
+
loadedToolNames.add(tool.name);
|
|
189
|
+
if (options?.supportsAdditionalTools) {
|
|
190
|
+
messages.push({
|
|
191
|
+
type: "additional_tools",
|
|
192
|
+
role: "developer",
|
|
193
|
+
tools: convertResponsesTools(tools, options.toolOptions),
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
164
196
|
}
|
|
165
|
-
|
|
197
|
+
if (!options?.supportsToolSearch)
|
|
198
|
+
return;
|
|
199
|
+
const names = tools.map((tool) => tool.name);
|
|
200
|
+
const callId = `pi_tool_load_${shortHash(`${seed}:${names.join(",")}`)}`;
|
|
201
|
+
messages.push({
|
|
202
|
+
type: "tool_search_call",
|
|
203
|
+
call_id: callId,
|
|
204
|
+
execution: "client",
|
|
205
|
+
status: "completed",
|
|
206
|
+
arguments: { query: names.join(" "), limit: names.length },
|
|
207
|
+
});
|
|
208
|
+
messages.push({
|
|
209
|
+
type: "tool_search_output",
|
|
210
|
+
call_id: callId,
|
|
211
|
+
execution: "client",
|
|
212
|
+
status: "completed",
|
|
213
|
+
tools: convertResponsesTools(tools, { ...options.toolOptions, toolSearchResult: true }),
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
const includeInitialSystemMessage = options?.includeSystemPrompt ?? true;
|
|
217
|
+
const compat = model.compat;
|
|
218
|
+
const instructionRole = model.reasoning && compat?.supportsDeveloperRole !== false ? "developer" : "system";
|
|
166
219
|
let msgIndex = 0;
|
|
220
|
+
let sourceIndex = 0;
|
|
167
221
|
for (const msg of transformedMessages) {
|
|
222
|
+
const isLeadingSystemMessage = sourceIndex++ === 0 && msg.role === "system";
|
|
168
223
|
if (msg.role === "configurationUpdate") {
|
|
169
224
|
if (!supportsConfigurationUpdate(model))
|
|
170
225
|
continue;
|
|
@@ -180,7 +235,25 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
180
235
|
}
|
|
181
236
|
continue;
|
|
182
237
|
}
|
|
183
|
-
if (msg.role === "
|
|
238
|
+
if (msg.role === "system") {
|
|
239
|
+
if (!isLeadingSystemMessage)
|
|
240
|
+
appendSystemToolAdditions(msg, `system:${msgIndex}`);
|
|
241
|
+
if (!isLeadingSystemMessage || includeInitialSystemMessage) {
|
|
242
|
+
const text = isLeadingSystemMessage ? getSystemMessageText(msg) : renderSystemMessageUpdate(msg);
|
|
243
|
+
if (text.length > 0 && isLeadingSystemMessage && options?.systemPromptCacheBreakpoint === true) {
|
|
244
|
+
const block = {
|
|
245
|
+
type: "input_text",
|
|
246
|
+
text: sanitizeSurrogates(text),
|
|
247
|
+
prompt_cache_breakpoint: { mode: "explicit" },
|
|
248
|
+
};
|
|
249
|
+
messages.push({ role: instructionRole, content: [block] });
|
|
250
|
+
}
|
|
251
|
+
else if (text.length > 0) {
|
|
252
|
+
messages.push({ role: instructionRole, content: sanitizeSurrogates(text) });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else if (msg.role === "user") {
|
|
184
257
|
if (typeof msg.content === "string") {
|
|
185
258
|
messages.push(withContextProvenance({
|
|
186
259
|
role: "user",
|
|
@@ -259,7 +332,7 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
259
332
|
const [callId, itemIdRaw] = toolCall.id.split("|");
|
|
260
333
|
const customInputProperty = options?.grammarToolInputProperties?.get(toolCall.name);
|
|
261
334
|
const isPersistedFreeform = itemIdRaw === CUSTOM_TOOL_CALL_ITEM_ID_SENTINEL;
|
|
262
|
-
const isFreeform = isFreeformToolName(toolCall.name,
|
|
335
|
+
const isFreeform = isFreeformToolName(toolCall.name, declaredTools) || isPersistedFreeform;
|
|
263
336
|
let itemId = isPersistedFreeform ? undefined : itemIdRaw;
|
|
264
337
|
// An active grammar declaration wins over sentinel recovery below: its
|
|
265
338
|
// named input property is richer than the persisted freeform fallback.
|
|
@@ -272,7 +345,7 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
272
345
|
(!isFreeform && customInputProperty === undefined && !itemId?.startsWith("fc_"))) {
|
|
273
346
|
itemId = undefined;
|
|
274
347
|
}
|
|
275
|
-
const canReplayNamespace = isSameModel ||
|
|
348
|
+
const canReplayNamespace = isSameModel || toolPlacement.deferred.has(toolCall.name);
|
|
276
349
|
if (customInputProperty !== undefined) {
|
|
277
350
|
output.push({
|
|
278
351
|
type: "custom_tool_call",
|
|
@@ -326,7 +399,7 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
326
399
|
output,
|
|
327
400
|
}, msg, options?.sealContextProvenance));
|
|
328
401
|
}
|
|
329
|
-
else if (isFreeformToolName(msg.toolName,
|
|
402
|
+
else if (isFreeformToolName(msg.toolName, declaredTools) || isPersistedFreeform) {
|
|
330
403
|
messages.push(withContextProvenance({
|
|
331
404
|
type: "custom_tool_call_output",
|
|
332
405
|
call_id: callId,
|
|
@@ -339,20 +412,20 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
339
412
|
}
|
|
340
413
|
const deferredTools = [];
|
|
341
414
|
for (const name of msg.addedToolNames ?? []) {
|
|
342
|
-
const tool =
|
|
415
|
+
const tool = toolPlacement.deferred.get(name);
|
|
343
416
|
if (!tool || loadedToolNames.has(name))
|
|
344
417
|
continue;
|
|
345
418
|
loadedToolNames.add(name);
|
|
346
419
|
deferredTools.push(tool);
|
|
347
420
|
}
|
|
348
|
-
if (deferredTools.length > 0 &&
|
|
421
|
+
if (deferredTools.length > 0 && deferredToolsMode === "additional-tools") {
|
|
349
422
|
messages.push(withContextProvenance({
|
|
350
423
|
type: "additional_tools",
|
|
351
424
|
role: "developer",
|
|
352
|
-
tools: convertResponsesTools(deferredTools, options
|
|
353
|
-
}, msg, options
|
|
425
|
+
tools: convertResponsesTools(deferredTools, options?.toolOptions),
|
|
426
|
+
}, msg, options?.sealContextProvenance));
|
|
354
427
|
}
|
|
355
|
-
else if (deferredTools.length > 0 &&
|
|
428
|
+
else if (deferredTools.length > 0 && deferredToolsMode === "tool-search") {
|
|
356
429
|
const names = deferredTools.map((tool) => tool.name);
|
|
357
430
|
const searchCallId = `pi_tool_load_${shortHash(`${msg.toolCallId}:${names.join(",")}`)}`;
|
|
358
431
|
messages.push(withContextProvenance({
|
|
@@ -369,12 +442,13 @@ export function convertResponsesMessages(model, context, allowedToolCallProvider
|
|
|
369
442
|
status: "completed",
|
|
370
443
|
tools: convertResponsesTools(deferredTools, {
|
|
371
444
|
...options?.toolOptions,
|
|
372
|
-
|
|
445
|
+
toolSearchResult: true,
|
|
373
446
|
}),
|
|
374
447
|
}, msg, options?.sealContextProvenance));
|
|
375
448
|
}
|
|
376
449
|
}
|
|
377
|
-
|
|
450
|
+
if (!isLeadingSystemMessage)
|
|
451
|
+
msgIndex++;
|
|
378
452
|
}
|
|
379
453
|
return messages;
|
|
380
454
|
}
|
|
@@ -397,7 +471,7 @@ export function convertResponsesTools(tools, options) {
|
|
|
397
471
|
syntax: grammar.format,
|
|
398
472
|
definition: grammar.definition,
|
|
399
473
|
},
|
|
400
|
-
...(options?.
|
|
474
|
+
...(options?.toolSearchResult ? { defer_loading: true } : {}),
|
|
401
475
|
};
|
|
402
476
|
}
|
|
403
477
|
if (tool.freeform) {
|
|
@@ -406,7 +480,7 @@ export function convertResponsesTools(tools, options) {
|
|
|
406
480
|
name: tool.name,
|
|
407
481
|
description: tool.description,
|
|
408
482
|
format: tool.freeform,
|
|
409
|
-
...(options?.
|
|
483
|
+
...(options?.toolSearchResult ? { defer_loading: true } : {}),
|
|
410
484
|
};
|
|
411
485
|
}
|
|
412
486
|
const constrainedStrict = resolveJsonSchemaStrictSampling(tool, supportsStrictMode);
|
|
@@ -416,7 +490,7 @@ export function convertResponsesTools(tools, options) {
|
|
|
416
490
|
name: tool.name,
|
|
417
491
|
description: tool.description,
|
|
418
492
|
parameters: getJsonSchemaToolParameters(tool, strict === true),
|
|
419
|
-
...(options?.
|
|
493
|
+
...(options?.toolSearchResult ? { defer_loading: true } : {}),
|
|
420
494
|
};
|
|
421
495
|
if (supportsStrictMode) {
|
|
422
496
|
functionTool.strict = strict;
|
|
@@ -712,6 +786,7 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
712
786
|
}
|
|
713
787
|
};
|
|
714
788
|
for await (const event of withResponsesCompletionGrace(openaiStream)) {
|
|
789
|
+
await options?.onProviderStreamEvent?.(event, model);
|
|
715
790
|
if (event.type === "response.created") {
|
|
716
791
|
output.responseId = event.response.id;
|
|
717
792
|
}
|
|
@@ -920,6 +995,19 @@ export async function processResponsesStream(openaiStream, output, stream, model
|
|
|
920
995
|
if (!sawTerminalResponseEvent && !hasFinalizedToolCall) {
|
|
921
996
|
throw new Error("OpenAI Responses stream ended before a terminal response event");
|
|
922
997
|
}
|
|
998
|
+
// The agent runs every tool call in the final message. Refuse to hand over calls whose
|
|
999
|
+
// output_item.done never arrived: their arguments may be cut off or mixed up, e.g. when a
|
|
1000
|
+
// non-compliant server omits output_index. Finished calls have their scratch buffers removed.
|
|
1001
|
+
if (output.stopReason === "toolUse") {
|
|
1002
|
+
for (const block of output.content) {
|
|
1003
|
+
if (block.type !== "toolCall")
|
|
1004
|
+
continue;
|
|
1005
|
+
const toolCall = block;
|
|
1006
|
+
if (toolCall.partialJson !== undefined || toolCall.customInput !== undefined) {
|
|
1007
|
+
throw new Error(`OpenAI Responses stream completed with an unfinished tool call: ${toolCall.name} (${toolCall.id})`);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
923
1011
|
}
|
|
924
1012
|
function mapStopReason(status, incompleteReason) {
|
|
925
1013
|
if (!status)
|
|
@@ -17,7 +17,7 @@ export interface CachedWebSocketConnection {
|
|
|
17
17
|
export interface OpenAIResponsesOptions extends StreamOptions {
|
|
18
18
|
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
19
19
|
reasoningSummary?: "auto" | "detailed" | "concise" | null;
|
|
20
|
-
serviceTier?: ResponseCreateParamsStreaming["service_tier"] | "fast";
|
|
20
|
+
serviceTier?: ResponseCreateParamsStreaming["service_tier"] | "fast" | "ultrafast";
|
|
21
21
|
toolChoice?: ResponseCreateParamsStreaming["tool_choice"];
|
|
22
22
|
}
|
|
23
23
|
/**
|