@pentoshi/clai 4.1.0 → 4.2.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/README.md +14 -0
- package/dist/agent/compaction-executor.d.ts +68 -0
- package/dist/agent/compaction-executor.js +343 -0
- package/dist/agent/compaction-executor.js.map +1 -0
- package/dist/agent/context-breakdown.js +2 -0
- package/dist/agent/context-breakdown.js.map +1 -1
- package/dist/agent/context-manager.d.ts +23 -9
- package/dist/agent/context-manager.js +72 -43
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/events.d.ts +3 -0
- package/dist/agent/loop-guard.d.ts +2 -0
- package/dist/agent/loop-guard.js +48 -3
- package/dist/agent/loop-guard.js.map +1 -1
- package/dist/agent/prompt-composer.js +6 -6
- package/dist/agent/prompt-composer.js.map +1 -1
- package/dist/agent/reliability-policy.d.ts +1 -0
- package/dist/agent/reliability-policy.js +6 -3
- package/dist/agent/reliability-policy.js.map +1 -1
- package/dist/agent/request-accounting.d.ts +97 -0
- package/dist/agent/request-accounting.js +207 -0
- package/dist/agent/request-accounting.js.map +1 -0
- package/dist/agent/request-budget.d.ts +2 -2
- package/dist/agent/request-budget.js +2 -4
- package/dist/agent/request-budget.js.map +1 -1
- package/dist/agent/runner.d.ts +8 -2
- package/dist/agent/runner.js +409 -178
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/session-title.d.ts +0 -26
- package/dist/agent/session-title.js +0 -80
- package/dist/agent/session-title.js.map +1 -1
- package/dist/agent/tool-history.d.ts +2 -2
- package/dist/agent/tool-history.js +19 -6
- package/dist/agent/tool-history.js.map +1 -1
- package/dist/app/adapters/agent-event-adapter.js +19 -0
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/adapters/current-agent-adapter.js +4 -0
- package/dist/app/adapters/current-agent-adapter.js.map +1 -1
- package/dist/app/commands/catalog.js +24 -0
- package/dist/app/commands/catalog.js.map +1 -1
- package/dist/app/controllers/cancel-coordinator.d.ts +51 -0
- package/dist/app/controllers/cancel-coordinator.js +48 -0
- package/dist/app/controllers/cancel-coordinator.js.map +1 -0
- package/dist/app/controllers/session-compact-helper.d.ts +19 -2
- package/dist/app/controllers/session-compact-helper.js +100 -127
- package/dist/app/controllers/session-compact-helper.js.map +1 -1
- package/dist/app/controllers/session-context-usage.d.ts +32 -15
- package/dist/app/controllers/session-context-usage.js +186 -51
- package/dist/app/controllers/session-context-usage.js.map +1 -1
- package/dist/app/controllers/session-controller.d.ts +20 -11
- package/dist/app/controllers/session-controller.js +111 -90
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/controllers/session-naming.d.ts +31 -0
- package/dist/app/controllers/session-naming.js +173 -0
- package/dist/app/controllers/session-naming.js.map +1 -0
- package/dist/app/controllers/session-persistence.d.ts +2 -2
- package/dist/app/controllers/session-persistence.js +3 -6
- package/dist/app/controllers/session-persistence.js.map +1 -1
- package/dist/app/controllers/session-turn-request.d.ts +2 -1
- package/dist/app/controllers/session-turn-request.js +3 -0
- package/dist/app/controllers/session-turn-request.js.map +1 -1
- package/dist/app/controllers/turn-controller.d.ts +2 -1
- package/dist/app/controllers/turn-controller.js +1 -0
- package/dist/app/controllers/turn-controller.js.map +1 -1
- package/dist/app/events/app-event.d.ts +9 -0
- package/dist/app/events/app-event.js.map +1 -1
- package/dist/app/ports/agent-port.d.ts +8 -1
- package/dist/classic/app/ClassicApp.js +2 -1
- package/dist/classic/app/ClassicApp.js.map +1 -1
- package/dist/classic/app/app-wiring.js +1 -2
- package/dist/classic/app/app-wiring.js.map +1 -1
- package/dist/classic/app/wiring-interactions.js +2 -7
- package/dist/classic/app/wiring-interactions.js.map +1 -1
- package/dist/classic/blocks/tool-lines.js +2 -1
- package/dist/classic/blocks/tool-lines.js.map +1 -1
- package/dist/classic/input/cancel-ladder.d.ts +2 -19
- package/dist/classic/input/cancel-ladder.js +13 -20
- package/dist/classic/input/cancel-ladder.js.map +1 -1
- package/dist/commands/providers.js +2 -0
- package/dist/commands/providers.js.map +1 -1
- package/dist/llm/adapters/anthropic-tools.d.ts +31 -14
- package/dist/llm/adapters/anthropic-tools.js +124 -29
- package/dist/llm/adapters/anthropic-tools.js.map +1 -1
- package/dist/llm/adapters/gemini-tools.d.ts +16 -4
- package/dist/llm/adapters/gemini-tools.js +117 -16
- package/dist/llm/adapters/gemini-tools.js.map +1 -1
- package/dist/llm/adapters/openai-tools.d.ts +13 -2
- package/dist/llm/adapters/openai-tools.js +58 -11
- package/dist/llm/adapters/openai-tools.js.map +1 -1
- package/dist/llm/agentrouter.js +68 -45
- package/dist/llm/agentrouter.js.map +1 -1
- package/dist/llm/anthropic.js +69 -36
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/aws-mantle.js +70 -32
- package/dist/llm/aws-mantle.js.map +1 -1
- package/dist/llm/bynara.js +26 -69
- package/dist/llm/bynara.js.map +1 -1
- package/dist/llm/capabilities.d.ts +2 -1
- package/dist/llm/capabilities.js +47 -0
- package/dist/llm/capabilities.js.map +1 -1
- package/dist/llm/context-snapshot.d.ts +100 -0
- package/dist/llm/context-snapshot.js +277 -0
- package/dist/llm/context-snapshot.js.map +1 -0
- package/dist/llm/context-windows.d.ts +10 -0
- package/dist/llm/context-windows.js +129 -0
- package/dist/llm/context-windows.js.map +1 -0
- package/dist/llm/custom-provider-profile.d.ts +75 -0
- package/dist/llm/custom-provider-profile.js +558 -0
- package/dist/llm/custom-provider-profile.js.map +1 -0
- package/dist/llm/custom-providers.d.ts +13 -1
- package/dist/llm/custom-providers.js +77 -25
- package/dist/llm/custom-providers.js.map +1 -1
- package/dist/llm/effort-fallback.d.ts +44 -0
- package/dist/llm/effort-fallback.js +101 -0
- package/dist/llm/effort-fallback.js.map +1 -0
- package/dist/llm/fireworks.js +4 -0
- package/dist/llm/fireworks.js.map +1 -1
- package/dist/llm/free.js +4 -0
- package/dist/llm/free.js.map +1 -1
- package/dist/llm/gemini.d.ts +1 -1
- package/dist/llm/gemini.js +89 -51
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/groq.js +4 -0
- package/dist/llm/groq.js.map +1 -1
- package/dist/llm/hetzner.js +4 -0
- package/dist/llm/hetzner.js.map +1 -1
- package/dist/llm/http.d.ts +49 -10
- package/dist/llm/http.js +417 -153
- package/dist/llm/http.js.map +1 -1
- package/dist/llm/kimchi.js +4 -0
- package/dist/llm/kimchi.js.map +1 -1
- package/dist/llm/lightning.js +4 -0
- package/dist/llm/lightning.js.map +1 -1
- package/dist/llm/meta.d.ts +2 -0
- package/dist/llm/meta.js +811 -655
- package/dist/llm/meta.js.map +1 -1
- package/dist/llm/modal.js +4 -0
- package/dist/llm/modal.js.map +1 -1
- package/dist/llm/model-families.d.ts +9 -0
- package/dist/llm/model-families.js +39 -0
- package/dist/llm/model-families.js.map +1 -0
- package/dist/llm/nvidia.js +4 -0
- package/dist/llm/nvidia.js.map +1 -1
- package/dist/llm/ollama.js +44 -40
- package/dist/llm/ollama.js.map +1 -1
- package/dist/llm/openai.js +4 -0
- package/dist/llm/openai.js.map +1 -1
- package/dist/llm/openrouter.js +4 -0
- package/dist/llm/openrouter.js.map +1 -1
- package/dist/llm/operation-ledger.d.ts +60 -0
- package/dist/llm/operation-ledger.js +136 -0
- package/dist/llm/operation-ledger.js.map +1 -0
- package/dist/llm/operation-usage.d.ts +32 -0
- package/dist/llm/operation-usage.js +172 -0
- package/dist/llm/operation-usage.js.map +1 -0
- package/dist/llm/orcarouter.d.ts +7 -0
- package/dist/llm/orcarouter.js +166 -0
- package/dist/llm/orcarouter.js.map +1 -0
- package/dist/llm/provider-profile-layers.d.ts +7 -0
- package/dist/llm/provider-profile-layers.js +961 -0
- package/dist/llm/provider-profile-layers.js.map +1 -0
- package/dist/llm/provider-profile.d.ts +181 -0
- package/dist/llm/provider-profile.js +329 -0
- package/dist/llm/provider-profile.js.map +1 -0
- package/dist/llm/provider-profiles.d.ts +13 -0
- package/dist/llm/provider-profiles.js +86 -0
- package/dist/llm/provider-profiles.js.map +1 -0
- package/dist/llm/provider.d.ts +2 -0
- package/dist/llm/provider.js +67 -0
- package/dist/llm/provider.js.map +1 -1
- package/dist/llm/qwen-cloud.js +4 -0
- package/dist/llm/qwen-cloud.js.map +1 -1
- package/dist/llm/reasoning-artifacts.d.ts +101 -0
- package/dist/llm/reasoning-artifacts.js +440 -0
- package/dist/llm/reasoning-artifacts.js.map +1 -0
- package/dist/llm/request-fingerprint.d.ts +10 -0
- package/dist/llm/request-fingerprint.js +313 -0
- package/dist/llm/request-fingerprint.js.map +1 -0
- package/dist/llm/request-plan.d.ts +119 -0
- package/dist/llm/request-plan.js +279 -0
- package/dist/llm/request-plan.js.map +1 -0
- package/dist/llm/router.d.ts +19 -1
- package/dist/llm/router.js +447 -75
- package/dist/llm/router.js.map +1 -1
- package/dist/llm/stream-events.d.ts +47 -0
- package/dist/llm/stream-events.js +55 -0
- package/dist/llm/stream-events.js.map +1 -0
- package/dist/llm/stream-terminal.d.ts +30 -0
- package/dist/llm/stream-terminal.js +51 -0
- package/dist/llm/stream-terminal.js.map +1 -0
- package/dist/llm/token-estimate-calibration.d.ts +23 -0
- package/dist/llm/token-estimate-calibration.js +140 -0
- package/dist/llm/token-estimate-calibration.js.map +1 -0
- package/dist/llm/token-usage.d.ts +35 -5
- package/dist/llm/token-usage.js +212 -162
- package/dist/llm/token-usage.js.map +1 -1
- package/dist/llm/tokenrouter.js +8 -2
- package/dist/llm/tokenrouter.js.map +1 -1
- package/dist/modes/ask.js +11 -5
- package/dist/modes/ask.js.map +1 -1
- package/dist/noninteractive/start-noninteractive.js +31 -2
- package/dist/noninteractive/start-noninteractive.js.map +1 -1
- package/dist/noninteractive/stream-blocks.js +15 -4
- package/dist/noninteractive/stream-blocks.js.map +1 -1
- package/dist/prompts/embedded.js +1 -1
- package/dist/prompts/embedded.js.map +1 -1
- package/dist/prompts/system.agent.md +6 -0
- package/dist/store/config.js +5 -1
- package/dist/store/config.js.map +1 -1
- package/dist/store/history.d.ts +2 -0
- package/dist/store/history.js +19 -10
- package/dist/store/history.js.map +1 -1
- package/dist/store/plan.js +20 -14
- package/dist/store/plan.js.map +1 -1
- package/dist/tools/elevated-shell.d.ts +1 -1
- package/dist/tools/elevated-shell.js +24 -72
- package/dist/tools/elevated-shell.js.map +1 -1
- package/dist/tools/nmap-runner.js +30 -36
- package/dist/tools/nmap-runner.js.map +1 -1
- package/dist/tools/sudo-session.d.ts +83 -0
- package/dist/tools/sudo-session.js +124 -0
- package/dist/tools/sudo-session.js.map +1 -0
- package/dist/tui-v2/app/App.js +9 -24
- package/dist/tui-v2/app/App.js.map +1 -1
- package/dist/tui-v2/components/status/context-limit-chip.js +2 -2
- package/dist/tui-v2/components/status/context-limit-chip.js.map +1 -1
- package/dist/tui-v2/components/transcript/intro-card.js +2 -1
- package/dist/tui-v2/components/transcript/intro-card.js.map +1 -1
- package/dist/tui-v2/composer/composer-editor.js +2 -1
- package/dist/tui-v2/composer/composer-editor.js.map +1 -1
- package/dist/types.d.ts +156 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/ui-core/bootstrap/composition-root.d.ts +2 -0
- package/dist/ui-core/bootstrap/composition-root.js +26 -3
- package/dist/ui-core/bootstrap/composition-root.js.map +1 -1
- package/dist/ui-core/commands/picker-commands.js +11 -5
- package/dist/ui-core/commands/picker-commands.js.map +1 -1
- package/dist/ui-core/commands/session-commands.js +41 -5
- package/dist/ui-core/commands/session-commands.js.map +1 -1
- package/dist/ui-core/plan/plan-lifecycle.js +3 -2
- package/dist/ui-core/plan/plan-lifecycle.js.map +1 -1
- package/dist/ui-core/rendering/context-limit.js +4 -1
- package/dist/ui-core/rendering/context-limit.js.map +1 -1
- package/dist/ui-core/rendering/duration.d.ts +2 -1
- package/dist/ui-core/rendering/duration.js +13 -5
- package/dist/ui-core/rendering/duration.js.map +1 -1
- package/dist/ui-core/rendering/intro-header.js +2 -2
- package/dist/ui-core/rendering/intro-header.js.map +1 -1
- package/dist/ui-core/rendering/theme.d.ts +1 -0
- package/dist/ui-core/rendering/theme.js +2 -0
- package/dist/ui-core/rendering/theme.js.map +1 -1
- package/dist/ui-core/state/transcript-hydrate.js +3 -3
- package/dist/ui-core/state/transcript-hydrate.js.map +1 -1
- package/dist/ui-core/state/transcript-reducer.d.ts +5 -0
- package/dist/ui-core/state/transcript-reducer.js +76 -3
- package/dist/ui-core/state/transcript-reducer.js.map +1 -1
- package/dist/ui-core/state/transcript-store.d.ts +10 -1
- package/dist/ui-core/state/transcript-store.js +22 -1
- package/dist/ui-core/state/transcript-store.js.map +1 -1
- package/dist/ui-core/state/transcript-types.d.ts +2 -0
- package/dist/ui-core/state/transcript-types.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +6 -1
package/dist/llm/meta.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { defaultModels } from "./provider.js";
|
|
2
2
|
import { readJson, ingestOpenAiModelCatalog, ProviderError, createSseFrameAssembler, THINKING_STREAM_IDLE_TIMEOUT_MS, THINKING_STREAM_INITIAL_IDLE_TIMEOUT_MS, STREAM_STALL_MARKER, } from "./http.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { completeGenerationAttempt, generationFetch, runGenerationAttempt, } from "./operation-usage.js";
|
|
4
|
+
import { isOperationPolicyError } from "./operation-ledger.js";
|
|
5
5
|
import { toWireName, fromWireName, parseToolArguments } from "./tool-protocol.js";
|
|
6
6
|
import { normalizeTokenUsage } from "./token-usage.js";
|
|
7
|
-
import {
|
|
7
|
+
import { createReasoningArtifact, createReasoningArtifactProvenance, reasoningArtifactItems, reasoningArtifactsForMessage, selectReasoningArtifactsForReplay, } from "./reasoning-artifacts.js";
|
|
8
|
+
import { compileRequestPlan } from "./request-plan.js";
|
|
9
|
+
import { emitStreamReasoningArtifacts, emitStreamReasoningDelta, } from "./stream-events.js";
|
|
10
|
+
import { META_STREAM_TERMINAL, requireTerminalProof, } from "./stream-terminal.js";
|
|
8
11
|
const baseUrl = "https://api.meta.ai/v1";
|
|
9
12
|
const modelCache = new Map();
|
|
10
13
|
const CACHE_TTL_MS = 60 * 60 * 1000;
|
|
@@ -34,7 +37,32 @@ function metaReasoningPayload(reasoning) {
|
|
|
34
37
|
summary = "auto";
|
|
35
38
|
return { effort: eff, summary };
|
|
36
39
|
}
|
|
37
|
-
function
|
|
40
|
+
function metaReplayArtifacts(message, replay) {
|
|
41
|
+
return selectReasoningArtifactsForReplay({
|
|
42
|
+
artifacts: reasoningArtifactsForMessage(message),
|
|
43
|
+
target: replay.target,
|
|
44
|
+
context: { hasToolCalls: Boolean(message.toolCalls?.length) },
|
|
45
|
+
observe: replay.observe,
|
|
46
|
+
})
|
|
47
|
+
.filter((artifact) => artifact.kind === "encrypted")
|
|
48
|
+
.sort((left, right) => left.position.sequence - right.position.sequence)
|
|
49
|
+
.map((artifact) => {
|
|
50
|
+
const byId = artifact.position.toolCallId
|
|
51
|
+
? message.toolCalls?.findIndex((toolCall) => toolCall.id === artifact.position.toolCallId)
|
|
52
|
+
: undefined;
|
|
53
|
+
const toolCallIndex = artifact.position.toolCallIndex ??
|
|
54
|
+
(byId !== undefined && byId >= 0 ? byId : undefined);
|
|
55
|
+
return {
|
|
56
|
+
items: reasoningArtifactItems(artifact),
|
|
57
|
+
...(toolCallIndex === undefined ? {} : { toolCallIndex }),
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function appendMetaReplayItems(input, entries) {
|
|
62
|
+
for (const entry of entries)
|
|
63
|
+
input.push(...entry.items);
|
|
64
|
+
}
|
|
65
|
+
function toResponsesInput(messages, supportsVision, replay) {
|
|
38
66
|
const input = [];
|
|
39
67
|
for (const m of messages) {
|
|
40
68
|
if (m.role === "system") {
|
|
@@ -74,13 +102,19 @@ function toResponsesInput(messages, supportsVision) {
|
|
|
74
102
|
continue;
|
|
75
103
|
}
|
|
76
104
|
if (m.role === "assistant") {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
const replayArtifacts = metaReplayArtifacts(m, replay);
|
|
106
|
+
const leadingArtifacts = replayArtifacts.filter((artifact) => artifact.toolCallIndex === undefined);
|
|
107
|
+
const artifactsByTool = new Map();
|
|
108
|
+
for (const artifact of replayArtifacts) {
|
|
109
|
+
if (artifact.toolCallIndex === undefined)
|
|
110
|
+
continue;
|
|
111
|
+
const current = artifactsByTool.get(artifact.toolCallIndex) ?? [];
|
|
112
|
+
current.push(artifact);
|
|
113
|
+
artifactsByTool.set(artifact.toolCallIndex, current);
|
|
81
114
|
}
|
|
82
115
|
const hasTools = m.toolCalls && m.toolCalls.length > 0;
|
|
83
116
|
if (hasTools) {
|
|
117
|
+
appendMetaReplayItems(input, leadingArtifacts);
|
|
84
118
|
if (m.content && m.content.trim()) {
|
|
85
119
|
input.push({
|
|
86
120
|
type: "message",
|
|
@@ -89,7 +123,8 @@ function toResponsesInput(messages, supportsVision) {
|
|
|
89
123
|
content: [{ type: "output_text", text: m.content }],
|
|
90
124
|
});
|
|
91
125
|
}
|
|
92
|
-
for (const tc of m.toolCalls) {
|
|
126
|
+
for (const [toolCallIndex, tc] of m.toolCalls.entries()) {
|
|
127
|
+
appendMetaReplayItems(input, artifactsByTool.get(toolCallIndex) ?? []);
|
|
93
128
|
const wire = toWireName(tc.name);
|
|
94
129
|
input.push({
|
|
95
130
|
type: "function_call",
|
|
@@ -100,6 +135,7 @@ function toResponsesInput(messages, supportsVision) {
|
|
|
100
135
|
}
|
|
101
136
|
continue;
|
|
102
137
|
}
|
|
138
|
+
appendMetaReplayItems(input, replayArtifacts);
|
|
103
139
|
if (m.content !== undefined && m.content !== null) {
|
|
104
140
|
input.push({
|
|
105
141
|
type: "message",
|
|
@@ -130,7 +166,7 @@ function toResponsesTools(tools) {
|
|
|
130
166
|
parameters: t.parameters,
|
|
131
167
|
}));
|
|
132
168
|
}
|
|
133
|
-
function parseMetaUsage(raw) {
|
|
169
|
+
export function parseMetaUsage(raw) {
|
|
134
170
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
135
171
|
return undefined;
|
|
136
172
|
const u = raw;
|
|
@@ -140,16 +176,27 @@ function parseMetaUsage(raw) {
|
|
|
140
176
|
const outputTokens = u.output_tokens ??
|
|
141
177
|
u.completion_tokens ??
|
|
142
178
|
u.outputTokens;
|
|
143
|
-
const totalTokens = u.total_tokens ??
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
179
|
+
const totalTokens = u.total_tokens ??
|
|
180
|
+
u.totalTokens;
|
|
181
|
+
const inputDetails = u.input_tokens_details;
|
|
182
|
+
const promptDetails = u.prompt_tokens_details;
|
|
183
|
+
const outputDetails = u.output_tokens_details;
|
|
184
|
+
const completionDetails = u.completion_tokens_details;
|
|
185
|
+
const cached = inputDetails?.cached_tokens ?? promptDetails?.cached_tokens;
|
|
186
|
+
const cacheCreation = inputDetails?.cache_creation_tokens ??
|
|
187
|
+
promptDetails?.cache_creation_tokens ??
|
|
188
|
+
u.cache_creation_input_tokens;
|
|
189
|
+
const uncached = inputDetails?.uncached_tokens ??
|
|
190
|
+
promptDetails?.uncached_tokens ??
|
|
191
|
+
u.prompt_cache_miss_tokens;
|
|
192
|
+
const reasoning = outputDetails?.reasoning_tokens ?? completionDetails?.reasoning_tokens;
|
|
148
193
|
return normalizeTokenUsage({
|
|
149
194
|
promptTokens: inputTokens,
|
|
150
195
|
completionTokens: outputTokens,
|
|
151
196
|
totalTokens,
|
|
152
197
|
cachedPromptTokens: typeof cached === "number" ? cached : undefined,
|
|
198
|
+
cacheCreationTokens: typeof cacheCreation === "number" ? cacheCreation : undefined,
|
|
199
|
+
uncachedPromptTokens: typeof uncached === "number" ? uncached : undefined,
|
|
153
200
|
reasoningTokens: typeof reasoning === "number" ? reasoning : undefined,
|
|
154
201
|
exact: true,
|
|
155
202
|
});
|
|
@@ -170,29 +217,42 @@ function extractReasoningSummary(item) {
|
|
|
170
217
|
return out;
|
|
171
218
|
}
|
|
172
219
|
function buildResponsesBody(options) {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
const tools = toResponsesTools(options.tools);
|
|
176
|
-
const reasoningOn = Boolean(options.reasoning?.enabled);
|
|
177
|
-
const defaultMax = reasoningOn ? 8192 : 4096;
|
|
178
|
-
const effectiveMax = Math.max(16, options.maxTokens ?? defaultMax);
|
|
179
|
-
const sampling = resolveSampling({
|
|
220
|
+
const plan = compileRequestPlan({
|
|
221
|
+
provider: "meta",
|
|
180
222
|
model: options.model,
|
|
181
|
-
|
|
182
|
-
|
|
223
|
+
messages: options.messages,
|
|
224
|
+
stream: options.stream,
|
|
225
|
+
endpoint: baseUrl,
|
|
226
|
+
reasoning: options.reasoning,
|
|
227
|
+
tools: options.tools,
|
|
228
|
+
parallelToolCalls: options.parallelToolCalls,
|
|
229
|
+
temperature: options.temperature,
|
|
230
|
+
maxTokens: options.maxTokens,
|
|
183
231
|
});
|
|
232
|
+
const reasoning = metaReasoningPayload(plan.controls.reasoning);
|
|
233
|
+
const input = toResponsesInput([...plan.timeline.messages], plan.images.visionAccepted, {
|
|
234
|
+
target: plan.replay.target,
|
|
235
|
+
observe: options.reasoningArtifactReplayObserver,
|
|
236
|
+
});
|
|
237
|
+
const tools = toResponsesTools(plan.tools.definitions.length ? [...plan.tools.definitions] : undefined);
|
|
238
|
+
const reasoningOn = Boolean(plan.controls.reasoning?.enabled);
|
|
239
|
+
const defaultMax = reasoningOn ? 8192 : 4096;
|
|
240
|
+
const effectiveMax = Math.max(16, plan.controls.requestedMaxTokens ?? defaultMax);
|
|
184
241
|
const body = {
|
|
185
242
|
model: options.model,
|
|
186
243
|
input,
|
|
187
244
|
store: false,
|
|
188
|
-
|
|
245
|
+
// Turn and compaction requests share one bucket on purpose so a compaction
|
|
246
|
+
// prompt can reuse the turn's cached prefix. Auxiliary requests get their
|
|
247
|
+
// own bucket so their unrelated short prefix cannot evict it.
|
|
248
|
+
prompt_cache_key: options.purpose === "auxiliary" ? "clai-auxiliary" : "clai",
|
|
189
249
|
prompt_cache_retention: "24h",
|
|
190
250
|
include: ["reasoning.encrypted_content"],
|
|
191
251
|
max_output_tokens: effectiveMax,
|
|
192
|
-
temperature:
|
|
252
|
+
temperature: plan.controls.temperature,
|
|
193
253
|
};
|
|
194
|
-
if (
|
|
195
|
-
body.top_p =
|
|
254
|
+
if (plan.controls.topP !== undefined)
|
|
255
|
+
body.top_p = plan.controls.topP;
|
|
196
256
|
if (reasoning)
|
|
197
257
|
body.reasoning = reasoning;
|
|
198
258
|
if (options.stream)
|
|
@@ -229,7 +289,9 @@ function parseResponsesOutput(data) {
|
|
|
229
289
|
let reasoningSummary = "";
|
|
230
290
|
const toolCalls = [];
|
|
231
291
|
const reasoningItems = [];
|
|
232
|
-
|
|
292
|
+
const reasoningItemSequences = [];
|
|
293
|
+
const toolCallSequences = [];
|
|
294
|
+
for (const [sequence, item] of output.entries()) {
|
|
233
295
|
if (!item || typeof item !== "object")
|
|
234
296
|
continue;
|
|
235
297
|
const obj = item;
|
|
@@ -248,12 +310,8 @@ function parseResponsesOutput(data) {
|
|
|
248
310
|
if (s)
|
|
249
311
|
reasoningSummary += s;
|
|
250
312
|
if (typeof obj.encrypted_content === "string" && obj.encrypted_content) {
|
|
251
|
-
reasoningItems.push({
|
|
252
|
-
|
|
253
|
-
...(typeof obj.id === "string" ? { id: obj.id } : {}),
|
|
254
|
-
summary: Array.isArray(obj.summary) ? obj.summary : [],
|
|
255
|
-
encrypted_content: obj.encrypted_content,
|
|
256
|
-
});
|
|
313
|
+
reasoningItems.push({ ...obj });
|
|
314
|
+
reasoningItemSequences.push(sequence);
|
|
257
315
|
}
|
|
258
316
|
}
|
|
259
317
|
else if (obj.type === "function_call") {
|
|
@@ -272,23 +330,52 @@ function parseResponsesOutput(data) {
|
|
|
272
330
|
catch {
|
|
273
331
|
args = parseToolArguments(rawArgs);
|
|
274
332
|
}
|
|
333
|
+
const toolCallIndex = toolCalls.length;
|
|
275
334
|
toolCalls.push({ id: callId, name: canonical, args, rawArguments: rawArgs });
|
|
335
|
+
toolCallSequences.push({ sequence, toolCallIndex });
|
|
276
336
|
}
|
|
277
337
|
}
|
|
338
|
+
const reasoningItemPositions = reasoningItemSequences.map((sequence) => {
|
|
339
|
+
const followingTool = toolCallSequences.find((toolCall) => toolCall.sequence > sequence);
|
|
340
|
+
return followingTool
|
|
341
|
+
? { sequence, toolCallIndex: followingTool.toolCallIndex }
|
|
342
|
+
: { sequence };
|
|
343
|
+
});
|
|
278
344
|
const usage = parseMetaUsage(data.usage);
|
|
279
|
-
return {
|
|
345
|
+
return {
|
|
346
|
+
text,
|
|
347
|
+
toolCalls,
|
|
348
|
+
usage,
|
|
349
|
+
reasoningSummary,
|
|
350
|
+
reasoningItems,
|
|
351
|
+
reasoningItemPositions,
|
|
352
|
+
};
|
|
280
353
|
}
|
|
281
|
-
function
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
354
|
+
function metaReasoningArtifacts(model, items, positions) {
|
|
355
|
+
const provenance = createReasoningArtifactProvenance({
|
|
356
|
+
provider: "meta",
|
|
357
|
+
model,
|
|
358
|
+
dialect: "meta-responses",
|
|
359
|
+
endpoint: baseUrl,
|
|
360
|
+
});
|
|
361
|
+
const artifacts = items.map((item, index) => {
|
|
362
|
+
const position = positions[index] ?? { sequence: index };
|
|
363
|
+
const replayable = position.toolCallIndex !== undefined;
|
|
364
|
+
return createReasoningArtifact({
|
|
365
|
+
kind: "encrypted",
|
|
366
|
+
raw: item,
|
|
367
|
+
provenance,
|
|
368
|
+
replay: replayable
|
|
369
|
+
? { scope: "tool-turn", persistence: "tool-turn" }
|
|
370
|
+
: { scope: "none", persistence: "never" },
|
|
371
|
+
position: {
|
|
372
|
+
sequence: position.sequence,
|
|
373
|
+
placement: replayable ? "before-tool-call" : "assistant",
|
|
374
|
+
...(replayable ? { toolCallIndex: position.toolCallIndex } : {}),
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
return artifacts.length ? artifacts : undefined;
|
|
292
379
|
}
|
|
293
380
|
function readWithAbort(reader, signal) {
|
|
294
381
|
if (signal.aborted) {
|
|
@@ -325,6 +412,7 @@ function readWithAbort(reader, signal) {
|
|
|
325
412
|
}
|
|
326
413
|
export const metaProvider = {
|
|
327
414
|
id: "meta",
|
|
415
|
+
reasoningStyle: "meta",
|
|
328
416
|
displayName: "Meta Model API",
|
|
329
417
|
defaultModel: defaultModels.meta,
|
|
330
418
|
envVar: "MODEL_API_KEY",
|
|
@@ -364,197 +452,49 @@ export const metaProvider = {
|
|
|
364
452
|
if (!auth.apiKey)
|
|
365
453
|
throw new Error("Meta Model API key is required");
|
|
366
454
|
const model = request.model ?? defaultModels.meta;
|
|
367
|
-
|
|
368
|
-
const body = buildResponsesBody({
|
|
369
|
-
model,
|
|
370
|
-
messages: request.messages,
|
|
371
|
-
maxTokens: request.maxTokens,
|
|
372
|
-
temperature: request.temperature,
|
|
373
|
-
stream: false,
|
|
374
|
-
reasoning: request.thinking,
|
|
375
|
-
supportsVision,
|
|
376
|
-
tools: request.tools,
|
|
377
|
-
parallelToolCalls: request.parallelToolCalls,
|
|
378
|
-
});
|
|
379
|
-
let response;
|
|
380
|
-
try {
|
|
381
|
-
response = await fetch(`${baseUrl}/responses`, {
|
|
382
|
-
method: "POST",
|
|
383
|
-
signal: request.signal ?? null,
|
|
384
|
-
headers: {
|
|
385
|
-
"content-type": "application/json",
|
|
386
|
-
accept: "application/json",
|
|
387
|
-
authorization: `Bearer ${auth.apiKey}`,
|
|
388
|
-
},
|
|
389
|
-
body,
|
|
390
|
-
verbose: process.env.CLAI_VERBOSE === "true",
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
catch (error) {
|
|
394
|
-
if (error instanceof Error && error.name === "AbortError")
|
|
395
|
-
throw error;
|
|
396
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
397
|
-
throw new ProviderError(`Meta Model API request could not be sent (${msg}). Check connectivity to ${baseUrl}.`);
|
|
398
|
-
}
|
|
399
|
-
let data;
|
|
400
|
-
try {
|
|
401
|
-
data = await readJson(response);
|
|
402
|
-
}
|
|
403
|
-
catch (error) {
|
|
404
|
-
if (error instanceof ProviderError) {
|
|
405
|
-
throw new ProviderError(`Meta Model API (model=${model}): ${error.message}`, error.status, error.body, error.retryAfterSeconds);
|
|
406
|
-
}
|
|
407
|
-
throw error;
|
|
408
|
-
}
|
|
409
|
-
const parsed = parseResponsesOutput(data);
|
|
410
|
-
const usage = parsed.usage ?? parseMetaUsage(data.usage);
|
|
411
|
-
const effort = metaReasoningPayload(request.thinking)?.effort;
|
|
412
|
-
const full = foldResponsesReasoning(parsed.text, parsed.reasoningSummary, usage, effort);
|
|
413
|
-
if (!parsed.text.trim() && parsed.toolCalls.length === 0) {
|
|
414
|
-
const respStatus = data.status;
|
|
415
|
-
const details = data.incomplete_details;
|
|
416
|
-
if (respStatus === "incomplete" && details?.reason === "max_output_tokens") {
|
|
417
|
-
const retryRequest = incompleteBudgetRetry(request, Boolean(request.thinking?.enabled));
|
|
418
|
-
if (retryRequest)
|
|
419
|
-
return metaProvider.complete(retryRequest, auth);
|
|
420
|
-
throw budgetExhaustedError(request, Boolean(request.thinking?.enabled), JSON.stringify(data));
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (!full.trim() && parsed.toolCalls.length === 0) {
|
|
424
|
-
throw new ProviderError(`Meta Model API returned no completion text (model=${model}). The response was empty — try /effort off, raise max_tokens, or pick another model with /model.`);
|
|
425
|
-
}
|
|
426
|
-
return {
|
|
427
|
-
text: full,
|
|
455
|
+
return runGenerationAttempt(request, {
|
|
428
456
|
provider: "meta",
|
|
429
457
|
model,
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
:
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const outputIdleTimeoutMs = Math.round(Math.max(idleTimeoutMs, initialIdleTimeoutMs) * 1.5);
|
|
447
|
-
const idleController = new AbortController();
|
|
448
|
-
let transportTimer;
|
|
449
|
-
let outputTimer;
|
|
450
|
-
let idleFired = false;
|
|
451
|
-
let firedWatchdog;
|
|
452
|
-
let firedBudgetMs = initialIdleTimeoutMs;
|
|
453
|
-
let sawTransportActivity = false;
|
|
454
|
-
let sawStreamProgress = false;
|
|
455
|
-
const fireStall = (watchdog, budgetMs) => {
|
|
456
|
-
if (idleFired)
|
|
457
|
-
return;
|
|
458
|
-
idleFired = true;
|
|
459
|
-
firedWatchdog = watchdog;
|
|
460
|
-
firedBudgetMs = budgetMs;
|
|
461
|
-
idleController.abort();
|
|
462
|
-
};
|
|
463
|
-
const armTransportTimer = (budgetMs) => {
|
|
464
|
-
if (transportTimer)
|
|
465
|
-
clearTimeout(transportTimer);
|
|
466
|
-
transportTimer = setTimeout(() => fireStall("transport", budgetMs), budgetMs);
|
|
467
|
-
};
|
|
468
|
-
const noteTransportActivity = () => {
|
|
469
|
-
sawTransportActivity = true;
|
|
470
|
-
armTransportTimer(idleTimeoutMs);
|
|
471
|
-
};
|
|
472
|
-
const resetIdleTimer = () => {
|
|
473
|
-
sawStreamProgress = true;
|
|
474
|
-
noteTransportActivity();
|
|
475
|
-
if (outputTimer)
|
|
476
|
-
clearTimeout(outputTimer);
|
|
477
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
478
|
-
};
|
|
479
|
-
armTransportTimer(initialIdleTimeoutMs);
|
|
480
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
481
|
-
const clearIdleTimers = () => {
|
|
482
|
-
if (transportTimer)
|
|
483
|
-
clearTimeout(transportTimer);
|
|
484
|
-
if (outputTimer)
|
|
485
|
-
clearTimeout(outputTimer);
|
|
486
|
-
transportTimer = undefined;
|
|
487
|
-
outputTimer = undefined;
|
|
488
|
-
};
|
|
489
|
-
const onCallerAbort = () => idleController.abort(request.signal?.reason);
|
|
490
|
-
request.signal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
491
|
-
const body = buildResponsesBody({
|
|
492
|
-
model,
|
|
493
|
-
messages: request.messages,
|
|
494
|
-
maxTokens: request.maxTokens,
|
|
495
|
-
temperature: request.temperature,
|
|
496
|
-
stream: true,
|
|
497
|
-
reasoning: request.thinking,
|
|
498
|
-
supportsVision,
|
|
499
|
-
tools: request.tools,
|
|
500
|
-
parallelToolCalls: request.parallelToolCalls,
|
|
501
|
-
});
|
|
502
|
-
let response;
|
|
503
|
-
let lastFetchError;
|
|
504
|
-
for (let fetchAttempt = 0; fetchAttempt < 2; fetchAttempt++) {
|
|
505
|
-
if (fetchAttempt > 0) {
|
|
506
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
507
|
-
if (request.signal?.aborted)
|
|
508
|
-
throw request.signal.reason;
|
|
509
|
-
if (idleFired)
|
|
510
|
-
break;
|
|
511
|
-
armTransportTimer(initialIdleTimeoutMs);
|
|
512
|
-
if (outputTimer) {
|
|
513
|
-
clearTimeout(outputTimer);
|
|
514
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
458
|
+
mode: "complete",
|
|
459
|
+
reason: request.attemptReason ?? "initial",
|
|
460
|
+
}, async () => {
|
|
461
|
+
const body = buildResponsesBody({
|
|
462
|
+
model,
|
|
463
|
+
messages: request.messages,
|
|
464
|
+
maxTokens: request.maxTokens,
|
|
465
|
+
temperature: request.temperature,
|
|
466
|
+
stream: false,
|
|
467
|
+
reasoning: request.thinking,
|
|
468
|
+
tools: request.tools,
|
|
469
|
+
parallelToolCalls: request.parallelToolCalls,
|
|
470
|
+
purpose: request.purpose,
|
|
471
|
+
reasoningArtifactReplayObserver: request.onReasoningArtifactReplayDecision,
|
|
472
|
+
});
|
|
473
|
+
let response;
|
|
517
474
|
try {
|
|
518
|
-
response = await
|
|
475
|
+
response = await generationFetch(`${baseUrl}/responses`, {
|
|
519
476
|
method: "POST",
|
|
520
|
-
signal:
|
|
477
|
+
signal: request.signal ?? null,
|
|
521
478
|
headers: {
|
|
522
479
|
"content-type": "application/json",
|
|
523
|
-
accept: "
|
|
480
|
+
accept: "application/json",
|
|
524
481
|
authorization: `Bearer ${auth.apiKey}`,
|
|
525
482
|
},
|
|
526
483
|
body,
|
|
527
484
|
verbose: process.env.CLAI_VERBOSE === "true",
|
|
528
485
|
});
|
|
529
|
-
lastFetchError = undefined;
|
|
530
|
-
break;
|
|
531
486
|
}
|
|
532
487
|
catch (error) {
|
|
533
|
-
|
|
534
|
-
if (idleFired) {
|
|
535
|
-
clearIdleTimers();
|
|
536
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
537
|
-
throw new ProviderError(`Meta Model API request timed out before any response (${Math.round(firedBudgetMs / 1000)}s) — no data arrived on the connection.`);
|
|
538
|
-
}
|
|
539
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
540
|
-
const transient = /fetch failed|network error|etimedout|enotfound|econnreset|premature close|socket.*closed|aborted without reason/i.test(msg);
|
|
541
|
-
if (!transient || sawStreamProgress)
|
|
488
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
542
489
|
throw error;
|
|
543
|
-
|
|
490
|
+
if (isOperationPolicyError(error))
|
|
491
|
+
throw error;
|
|
492
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
493
|
+
throw new ProviderError(`Meta Model API request could not be sent (${msg}). Check connectivity to ${baseUrl}.`);
|
|
544
494
|
}
|
|
545
|
-
|
|
546
|
-
if (!response) {
|
|
547
|
-
clearIdleTimers();
|
|
548
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
549
|
-
if (lastFetchError)
|
|
550
|
-
throw lastFetchError;
|
|
551
|
-
throw new ProviderError(`Meta Model API request failed before a response was received.`);
|
|
552
|
-
}
|
|
553
|
-
if (!response.ok) {
|
|
554
|
-
clearIdleTimers();
|
|
555
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
495
|
+
let data;
|
|
556
496
|
try {
|
|
557
|
-
await readJson(response);
|
|
497
|
+
data = await readJson(response);
|
|
558
498
|
}
|
|
559
499
|
catch (error) {
|
|
560
500
|
if (error instanceof ProviderError) {
|
|
@@ -562,500 +502,716 @@ export const metaProvider = {
|
|
|
562
502
|
}
|
|
563
503
|
throw error;
|
|
564
504
|
}
|
|
565
|
-
}
|
|
566
|
-
if (!response.body) {
|
|
567
|
-
clearIdleTimers();
|
|
568
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
569
|
-
throw new ProviderError(`Meta Model API returned no stream body`);
|
|
570
|
-
}
|
|
571
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
572
|
-
if (response.status === 202 || /\bapplication\/json\b/i.test(contentType)) {
|
|
573
|
-
clearIdleTimers();
|
|
574
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
575
|
-
const data = await readJson(response);
|
|
576
|
-
if (response.status === 202) {
|
|
577
|
-
const requestId = data.requestId ?? data.id;
|
|
578
|
-
throw new ProviderError(`Meta Model API returned a pending async response${requestId ? ` (${requestId})` : ""}; streaming did not start.`, response.status, JSON.stringify(data).slice(0, 1_000));
|
|
579
|
-
}
|
|
580
505
|
const parsed = parseResponsesOutput(data);
|
|
581
|
-
const
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
506
|
+
const reasoningArtifacts = metaReasoningArtifacts(model, parsed.reasoningItems, parsed.reasoningItemPositions);
|
|
507
|
+
const usage = parsed.usage ?? parseMetaUsage(data.usage);
|
|
508
|
+
if (!parsed.text.trim() && parsed.toolCalls.length === 0) {
|
|
509
|
+
const respStatus = data.status;
|
|
510
|
+
const details = data.incomplete_details;
|
|
511
|
+
if (respStatus === "incomplete" && details?.reason === "max_output_tokens") {
|
|
512
|
+
const retryRequest = incompleteBudgetRetry(request, Boolean(request.thinking?.enabled));
|
|
513
|
+
if (retryRequest) {
|
|
514
|
+
completeGenerationAttempt("failure", usage);
|
|
515
|
+
retryRequest.attemptReason = "provider-retry";
|
|
516
|
+
return metaProvider.complete(retryRequest, auth);
|
|
517
|
+
}
|
|
518
|
+
throw budgetExhaustedError(request, Boolean(request.thinking?.enabled), JSON.stringify(data));
|
|
519
|
+
}
|
|
592
520
|
}
|
|
593
|
-
if (
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
text: full,
|
|
598
|
-
provider: "meta",
|
|
599
|
-
model,
|
|
600
|
-
...(parsed.toolCalls.length ? { toolCalls: parsed.toolCalls } : {}),
|
|
601
|
-
...(parsed.toolCalls.length ? { finishReason: "tool_calls" } : { finishReason: "stop" }),
|
|
602
|
-
...(usageTmp ? { usage: usageTmp } : {}),
|
|
603
|
-
...(parsed.reasoningItems.length
|
|
604
|
-
? { reasoningBlock: { text: parsed.reasoningSummary, items: parsed.reasoningItems } }
|
|
605
|
-
: {}),
|
|
606
|
-
};
|
|
521
|
+
if (!parsed.text.trim() &&
|
|
522
|
+
parsed.toolCalls.length === 0 &&
|
|
523
|
+
!parsed.reasoningSummary.trim()) {
|
|
524
|
+
throw new ProviderError(`Meta Model API returned no completion text (model=${model}). The response was empty — try /effort off, raise max_tokens, or pick another model with /model.`);
|
|
607
525
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
526
|
+
return {
|
|
527
|
+
text: parsed.text,
|
|
528
|
+
provider: "meta",
|
|
529
|
+
model,
|
|
530
|
+
...(parsed.toolCalls.length ? { toolCalls: parsed.toolCalls } : {}),
|
|
531
|
+
...(parsed.toolCalls.length ? { finishReason: "tool_calls" } : { finishReason: "stop" }),
|
|
532
|
+
...(usage ? { usage } : {}),
|
|
533
|
+
...(parsed.reasoningItems.length
|
|
534
|
+
? { reasoningBlock: { text: parsed.reasoningSummary, items: parsed.reasoningItems } }
|
|
535
|
+
: {}),
|
|
536
|
+
...(reasoningArtifacts ? { reasoningArtifacts } : {}),
|
|
537
|
+
};
|
|
538
|
+
});
|
|
539
|
+
},
|
|
540
|
+
async stream(request, auth, onToken) {
|
|
541
|
+
if (!auth.apiKey)
|
|
542
|
+
throw new Error("Meta Model API key is required");
|
|
543
|
+
const model = request.model ?? defaultModels.meta;
|
|
544
|
+
return runGenerationAttempt(request, {
|
|
545
|
+
provider: "meta",
|
|
546
|
+
model,
|
|
547
|
+
mode: "stream",
|
|
548
|
+
reason: request.attemptReason ?? "initial",
|
|
549
|
+
}, async () => {
|
|
550
|
+
const reasoningOn = Boolean(request.thinking?.enabled);
|
|
551
|
+
const idleTimeoutMs = THINKING_STREAM_IDLE_TIMEOUT_MS;
|
|
552
|
+
const initialIdleTimeoutMs = THINKING_STREAM_INITIAL_IDLE_TIMEOUT_MS;
|
|
553
|
+
const outputIdleTimeoutMs = Math.round(Math.max(idleTimeoutMs, initialIdleTimeoutMs) * 1.5);
|
|
554
|
+
const idleController = new AbortController();
|
|
555
|
+
let transportTimer;
|
|
556
|
+
let outputTimer;
|
|
557
|
+
let idleFired = false;
|
|
558
|
+
let firedWatchdog;
|
|
559
|
+
let firedBudgetMs = initialIdleTimeoutMs;
|
|
560
|
+
let sawTransportActivity = false;
|
|
561
|
+
let sawStreamProgress = false;
|
|
562
|
+
const fireStall = (watchdog, budgetMs) => {
|
|
563
|
+
if (idleFired)
|
|
564
|
+
return;
|
|
565
|
+
idleFired = true;
|
|
566
|
+
firedWatchdog = watchdog;
|
|
567
|
+
firedBudgetMs = budgetMs;
|
|
568
|
+
idleController.abort();
|
|
569
|
+
};
|
|
570
|
+
const armTransportTimer = (budgetMs) => {
|
|
571
|
+
if (transportTimer)
|
|
572
|
+
clearTimeout(transportTimer);
|
|
573
|
+
transportTimer = setTimeout(() => fireStall("transport", budgetMs), budgetMs);
|
|
574
|
+
};
|
|
575
|
+
const noteTransportActivity = () => {
|
|
576
|
+
sawTransportActivity = true;
|
|
577
|
+
armTransportTimer(idleTimeoutMs);
|
|
578
|
+
};
|
|
579
|
+
const resetIdleTimer = () => {
|
|
580
|
+
sawStreamProgress = true;
|
|
581
|
+
noteTransportActivity();
|
|
582
|
+
if (outputTimer)
|
|
583
|
+
clearTimeout(outputTimer);
|
|
584
|
+
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
585
|
+
};
|
|
586
|
+
armTransportTimer(initialIdleTimeoutMs);
|
|
587
|
+
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
588
|
+
const clearIdleTimers = () => {
|
|
589
|
+
if (transportTimer)
|
|
590
|
+
clearTimeout(transportTimer);
|
|
591
|
+
if (outputTimer)
|
|
592
|
+
clearTimeout(outputTimer);
|
|
593
|
+
transportTimer = undefined;
|
|
594
|
+
outputTimer = undefined;
|
|
595
|
+
};
|
|
596
|
+
const onCallerAbort = () => idleController.abort(request.signal?.reason);
|
|
597
|
+
request.signal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
598
|
+
const body = buildResponsesBody({
|
|
599
|
+
model,
|
|
600
|
+
messages: request.messages,
|
|
601
|
+
maxTokens: request.maxTokens,
|
|
602
|
+
temperature: request.temperature,
|
|
603
|
+
stream: true,
|
|
604
|
+
reasoning: request.thinking,
|
|
605
|
+
tools: request.tools,
|
|
606
|
+
parallelToolCalls: request.parallelToolCalls,
|
|
607
|
+
purpose: request.purpose,
|
|
608
|
+
reasoningArtifactReplayObserver: request.onReasoningArtifactReplayDecision,
|
|
638
609
|
});
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
enterReasoning();
|
|
668
|
-
reasoningSeen += text;
|
|
669
|
-
full += text;
|
|
670
|
-
onToken(text);
|
|
671
|
-
};
|
|
672
|
-
const cleanup = () => {
|
|
673
|
-
clearIdleTimers();
|
|
674
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
675
|
-
idleController.signal.removeEventListener("abort", cancelReaderOnAbort);
|
|
676
|
-
};
|
|
677
|
-
const cancelReaderOnAbort = () => {
|
|
678
|
-
reader.cancel().catch(() => undefined);
|
|
679
|
-
};
|
|
680
|
-
idleController.signal.addEventListener("abort", cancelReaderOnAbort, { once: true });
|
|
681
|
-
const sseFrames = createSseFrameAssembler();
|
|
682
|
-
try {
|
|
683
|
-
while (true) {
|
|
684
|
-
request.signal?.throwIfAborted();
|
|
685
|
-
if (idleController.signal.aborted)
|
|
686
|
-
throw new Error("Stream aborted");
|
|
687
|
-
const { done, value } = await readWithAbort(reader, idleController.signal);
|
|
688
|
-
request.signal?.throwIfAborted();
|
|
689
|
-
if (idleController.signal.aborted)
|
|
690
|
-
throw new Error("Stream aborted");
|
|
691
|
-
if (done)
|
|
610
|
+
let response;
|
|
611
|
+
let lastFetchError;
|
|
612
|
+
for (let fetchAttempt = 0; fetchAttempt < 2; fetchAttempt++) {
|
|
613
|
+
if (fetchAttempt > 0) {
|
|
614
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
615
|
+
if (request.signal?.aborted)
|
|
616
|
+
throw request.signal.reason;
|
|
617
|
+
if (idleFired)
|
|
618
|
+
break;
|
|
619
|
+
armTransportTimer(initialIdleTimeoutMs);
|
|
620
|
+
if (outputTimer) {
|
|
621
|
+
clearTimeout(outputTimer);
|
|
622
|
+
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
response = await generationFetch(`${baseUrl}/responses`, {
|
|
627
|
+
method: "POST",
|
|
628
|
+
signal: idleController.signal,
|
|
629
|
+
headers: {
|
|
630
|
+
"content-type": "application/json",
|
|
631
|
+
accept: "text/event-stream",
|
|
632
|
+
authorization: `Bearer ${auth.apiKey}`,
|
|
633
|
+
},
|
|
634
|
+
body,
|
|
635
|
+
verbose: process.env.CLAI_VERBOSE === "true",
|
|
636
|
+
});
|
|
637
|
+
lastFetchError = undefined;
|
|
692
638
|
break;
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
639
|
+
}
|
|
640
|
+
catch (error) {
|
|
641
|
+
lastFetchError = error;
|
|
642
|
+
if (idleFired) {
|
|
643
|
+
clearIdleTimers();
|
|
644
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
645
|
+
throw new ProviderError(`Meta Model API request timed out before any response (${Math.round(firedBudgetMs / 1000)}s) — no data arrived on the connection.`);
|
|
646
|
+
}
|
|
647
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
648
|
+
const transient = /fetch failed|network error|etimedout|enotfound|econnreset|premature close|socket.*closed|aborted without reason/i.test(msg);
|
|
649
|
+
if (!transient || sawStreamProgress)
|
|
650
|
+
throw error;
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (!response) {
|
|
655
|
+
clearIdleTimers();
|
|
656
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
657
|
+
if (lastFetchError)
|
|
658
|
+
throw lastFetchError;
|
|
659
|
+
throw new ProviderError(`Meta Model API request failed before a response was received.`);
|
|
660
|
+
}
|
|
661
|
+
if (!response.ok) {
|
|
662
|
+
clearIdleTimers();
|
|
663
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
664
|
+
try {
|
|
665
|
+
await readJson(response);
|
|
666
|
+
}
|
|
667
|
+
catch (error) {
|
|
668
|
+
if (error instanceof ProviderError) {
|
|
669
|
+
throw new ProviderError(`Meta Model API (model=${model}): ${error.message}`, error.status, error.body, error.retryAfterSeconds);
|
|
670
|
+
}
|
|
671
|
+
throw error;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
if (!response.body) {
|
|
675
|
+
clearIdleTimers();
|
|
676
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
677
|
+
throw new ProviderError(`Meta Model API returned no stream body`);
|
|
678
|
+
}
|
|
679
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
680
|
+
if (response.status === 202 || /\bapplication\/json\b/i.test(contentType)) {
|
|
681
|
+
try {
|
|
682
|
+
const data = await readJson(response, idleController.signal);
|
|
683
|
+
if (response.status === 202) {
|
|
684
|
+
const requestId = data.requestId ?? data.id;
|
|
685
|
+
throw new ProviderError(`Meta Model API returned a pending async response${requestId ? ` (${requestId})` : ""}; streaming did not start.`, response.status, JSON.stringify(data).slice(0, 1_000));
|
|
686
|
+
}
|
|
687
|
+
const parsed = parseResponsesOutput(data);
|
|
688
|
+
const reasoningArtifacts = metaReasoningArtifacts(model, parsed.reasoningItems, parsed.reasoningItemPositions);
|
|
689
|
+
const usageTmp = parsed.usage ?? parseMetaUsage(data.usage);
|
|
690
|
+
const jsonStatus = data.status;
|
|
691
|
+
const jsonDetails = data.incomplete_details;
|
|
692
|
+
if (!parsed.text.trim() && parsed.toolCalls.length === 0 && jsonStatus === "incomplete" && jsonDetails?.reason === "max_output_tokens") {
|
|
693
|
+
const retryRequest = incompleteBudgetRetry(request, reasoningOn);
|
|
694
|
+
const streamMethod = metaProvider.stream;
|
|
695
|
+
if (retryRequest && streamMethod) {
|
|
696
|
+
completeGenerationAttempt("failure", usageTmp);
|
|
697
|
+
retryRequest.attemptReason = "provider-retry";
|
|
698
|
+
return streamMethod(retryRequest, auth, onToken);
|
|
738
699
|
}
|
|
700
|
+
completeGenerationAttempt("failure", usageTmp);
|
|
701
|
+
throw budgetExhaustedError(request, reasoningOn, JSON.stringify(data));
|
|
702
|
+
}
|
|
703
|
+
if (parsed.text.trim() ||
|
|
704
|
+
parsed.toolCalls.length > 0 ||
|
|
705
|
+
parsed.reasoningSummary.trim()) {
|
|
706
|
+
emitStreamReasoningArtifacts(request.onStreamEvent, reasoningArtifacts);
|
|
707
|
+
if (parsed.text)
|
|
708
|
+
onToken(parsed.text);
|
|
739
709
|
return {
|
|
740
|
-
text:
|
|
710
|
+
text: parsed.text,
|
|
741
711
|
provider: "meta",
|
|
742
712
|
model,
|
|
743
|
-
...(toolCalls.length ? { toolCalls } : {}),
|
|
744
|
-
...(
|
|
745
|
-
...(
|
|
746
|
-
...
|
|
713
|
+
...(parsed.toolCalls.length ? { toolCalls: parsed.toolCalls } : {}),
|
|
714
|
+
...(parsed.toolCalls.length ? { finishReason: "tool_calls" } : { finishReason: "stop" }),
|
|
715
|
+
...(usageTmp ? { usage: usageTmp } : {}),
|
|
716
|
+
...(parsed.reasoningItems.length
|
|
717
|
+
? { reasoningBlock: { text: parsed.reasoningSummary, items: parsed.reasoningItems } }
|
|
718
|
+
: {}),
|
|
719
|
+
...(reasoningArtifacts ? { reasoningArtifacts } : {}),
|
|
747
720
|
};
|
|
748
721
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
722
|
+
throw new ProviderError(`Meta Model API returned JSON instead of an SSE stream, but no completion text was present.`, response.status, JSON.stringify(data).slice(0, 1_000));
|
|
723
|
+
}
|
|
724
|
+
catch (error) {
|
|
725
|
+
if (idleFired) {
|
|
726
|
+
const seconds = Math.round(firedBudgetMs / 1000);
|
|
727
|
+
if (firedWatchdog === "transport" || !sawTransportActivity) {
|
|
728
|
+
if (!sawTransportActivity) {
|
|
729
|
+
throw new ProviderError(`Meta Model API request timed out before any response (${seconds}s) — no data arrived on the connection.`);
|
|
730
|
+
}
|
|
731
|
+
throw new ProviderError(`Meta Model API stream transport timeout (${seconds}s) — no data arrived on the connection after it had started.`);
|
|
732
|
+
}
|
|
733
|
+
throw new ProviderError(`Meta Model API stream stalled — ${STREAM_STALL_MARKER} for ${seconds}s`);
|
|
755
734
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
735
|
+
throw error;
|
|
736
|
+
}
|
|
737
|
+
finally {
|
|
738
|
+
clearIdleTimers();
|
|
739
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const decoder = new TextDecoder();
|
|
743
|
+
const reader = response.body.getReader();
|
|
744
|
+
let buffer = "";
|
|
745
|
+
let full = "";
|
|
746
|
+
let visible = "";
|
|
747
|
+
let reasoningSeen = "";
|
|
748
|
+
let finishReason;
|
|
749
|
+
let sawTerminalProof;
|
|
750
|
+
let streamUsage;
|
|
751
|
+
const toolCallState = new Map();
|
|
752
|
+
const outputIndexToItemId = new Map();
|
|
753
|
+
const outputIndexToToolCallIndex = new Map();
|
|
754
|
+
let responseId;
|
|
755
|
+
const reasoningItems = [];
|
|
756
|
+
const reasoningItemSequences = [];
|
|
757
|
+
const reasoningItemToolCallIndices = [];
|
|
758
|
+
const reasoningItemIndexes = new Map();
|
|
759
|
+
const noteReasoningItem = (item, sequence, toolCallIndex) => {
|
|
760
|
+
const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : "";
|
|
761
|
+
if (!encrypted)
|
|
762
|
+
return;
|
|
763
|
+
const id = typeof item.id === "string" ? item.id : undefined;
|
|
764
|
+
const key = id ?? encrypted.slice(0, 64);
|
|
765
|
+
const existingIndex = reasoningItemIndexes.get(key);
|
|
766
|
+
if (existingIndex !== undefined) {
|
|
767
|
+
reasoningItems[existingIndex] = { ...item };
|
|
768
|
+
if (sequence !== undefined)
|
|
769
|
+
reasoningItemSequences[existingIndex] = sequence;
|
|
770
|
+
if (toolCallIndex !== undefined) {
|
|
771
|
+
reasoningItemToolCallIndices[existingIndex] = toolCallIndex;
|
|
762
772
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
reasoningItemIndexes.set(key, reasoningItems.length);
|
|
776
|
+
reasoningItems.push({ ...item });
|
|
777
|
+
reasoningItemSequences.push(sequence ?? Number.MAX_SAFE_INTEGER);
|
|
778
|
+
reasoningItemToolCallIndices.push(toolCallIndex);
|
|
779
|
+
};
|
|
780
|
+
const reasoningReplay = () => {
|
|
781
|
+
if (!reasoningItems.length) {
|
|
782
|
+
return reasoningSeen ? { reasoningBlock: { text: reasoningSeen } } : {};
|
|
783
|
+
}
|
|
784
|
+
const toolCallSequences = [...outputIndexToToolCallIndex.entries()]
|
|
785
|
+
.map(([sequence, toolCallIndex]) => ({ sequence, toolCallIndex }))
|
|
786
|
+
.sort((left, right) => left.sequence - right.sequence);
|
|
787
|
+
const positions = reasoningItemSequences.map((sequence, index) => {
|
|
788
|
+
const storedToolCallIndex = reasoningItemToolCallIndices[index];
|
|
789
|
+
if (storedToolCallIndex !== undefined) {
|
|
790
|
+
return { sequence, toolCallIndex: storedToolCallIndex };
|
|
769
791
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
792
|
+
const followingTool = toolCallSequences.find((toolCall) => toolCall.sequence > sequence);
|
|
793
|
+
return followingTool
|
|
794
|
+
? { sequence, toolCallIndex: followingTool.toolCallIndex }
|
|
795
|
+
: { sequence };
|
|
796
|
+
});
|
|
797
|
+
const reasoningArtifacts = metaReasoningArtifacts(model, reasoningItems, positions);
|
|
798
|
+
emitStreamReasoningArtifacts(request.onStreamEvent, reasoningArtifacts);
|
|
799
|
+
return {
|
|
800
|
+
reasoningBlock: { text: reasoningSeen, items: reasoningItems },
|
|
801
|
+
...(reasoningArtifacts ? { reasoningArtifacts } : {}),
|
|
802
|
+
};
|
|
803
|
+
};
|
|
804
|
+
const emitVisible = (text) => {
|
|
805
|
+
if (!text)
|
|
806
|
+
return;
|
|
807
|
+
visible += text;
|
|
808
|
+
full += text;
|
|
809
|
+
onToken(text);
|
|
810
|
+
};
|
|
811
|
+
const emitReasoningDelta = (text) => {
|
|
812
|
+
if (!text)
|
|
813
|
+
return;
|
|
814
|
+
reasoningSeen += text;
|
|
815
|
+
emitStreamReasoningDelta(request.onStreamEvent, text);
|
|
816
|
+
};
|
|
817
|
+
const cleanup = () => {
|
|
818
|
+
clearIdleTimers();
|
|
819
|
+
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
820
|
+
idleController.signal.removeEventListener("abort", cancelReaderOnAbort);
|
|
821
|
+
};
|
|
822
|
+
const cancelReaderOnAbort = () => {
|
|
823
|
+
reader.cancel().catch(() => undefined);
|
|
824
|
+
};
|
|
825
|
+
idleController.signal.addEventListener("abort", cancelReaderOnAbort, { once: true });
|
|
826
|
+
const sseFrames = createSseFrameAssembler();
|
|
827
|
+
try {
|
|
828
|
+
while (true) {
|
|
829
|
+
request.signal?.throwIfAborted();
|
|
830
|
+
if (idleController.signal.aborted)
|
|
831
|
+
throw new Error("Stream aborted");
|
|
832
|
+
const { done, value } = await readWithAbort(reader, idleController.signal);
|
|
833
|
+
request.signal?.throwIfAborted();
|
|
834
|
+
if (idleController.signal.aborted)
|
|
835
|
+
throw new Error("Stream aborted");
|
|
836
|
+
if (done)
|
|
837
|
+
break;
|
|
838
|
+
if (value && value.byteLength > 0)
|
|
839
|
+
noteTransportActivity();
|
|
840
|
+
buffer += decoder.decode(value, { stream: true });
|
|
841
|
+
const lines = buffer.split("\n");
|
|
842
|
+
buffer = lines.pop() ?? "";
|
|
843
|
+
for (const line of lines) {
|
|
844
|
+
const payload = sseFrames.pushLine(line);
|
|
845
|
+
if (payload === undefined)
|
|
773
846
|
continue;
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
const callId = typeof item.call_id === "string" ? item.call_id : id;
|
|
781
|
-
const name = typeof item.name === "string" ? item.name : "";
|
|
782
|
-
const args = typeof item.arguments === "string" ? item.arguments : "";
|
|
783
|
-
toolCallState.set(id, { id, callId, name, arguments: args });
|
|
784
|
-
resetIdleTimer();
|
|
785
|
-
if (request.onToolCallDelta) {
|
|
786
|
-
const canonical = name ? fromWireName(name) ?? name : undefined;
|
|
787
|
-
request.onToolCallDelta({ index: toolCallState.size - 1, ...(callId ? { id: callId } : {}), ...(canonical ? { name: canonical } : {}), argumentsBytes: args.length });
|
|
847
|
+
if (payload === "[DONE]") {
|
|
848
|
+
if (!reasoningSeen.trim() && streamUsage?.reasoningTokens && streamUsage.reasoningTokens > 0 && (visible.trim() || toolCallState.size > 0)) {
|
|
849
|
+
const effort = metaReasoningPayload(request.thinking)?.effort;
|
|
850
|
+
const effortText = effort ? ` at ${effort} effort` : "";
|
|
851
|
+
const note = `Reasoning is private on Meta Model API: the model reasoned${effortText} and used ${streamUsage.reasoningTokens.toLocaleString("en-US")} reasoning tokens, but the API returns no reasoning text to display.`;
|
|
852
|
+
emitReasoningDelta(note);
|
|
788
853
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
854
|
+
cleanup();
|
|
855
|
+
const toolCalls = [];
|
|
856
|
+
for (const [, state] of toolCallState) {
|
|
857
|
+
if (!state.name)
|
|
858
|
+
continue;
|
|
859
|
+
const canonical = state.name ? fromWireName(state.name) ?? state.name : state.name ?? "";
|
|
860
|
+
const raw = state.arguments;
|
|
861
|
+
let args;
|
|
862
|
+
try {
|
|
863
|
+
const parsed = JSON.parse(raw);
|
|
864
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
865
|
+
args = parsed;
|
|
866
|
+
else
|
|
867
|
+
args = {};
|
|
868
|
+
}
|
|
869
|
+
catch {
|
|
870
|
+
args = parseToolArguments(raw);
|
|
871
|
+
}
|
|
872
|
+
toolCalls.push({ id: state.callId ?? state.id ?? `call_${toolCalls.length}`, name: canonical, args, rawArguments: raw });
|
|
795
873
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
802
|
-
if (type === "response.output_item.done") {
|
|
803
|
-
const item = parsed.item;
|
|
804
|
-
if (item?.type === "reasoning")
|
|
805
|
-
noteReasoningItem(item);
|
|
806
|
-
if (item?.type === "function_call") {
|
|
807
|
-
const id = typeof item.id === "string" ? item.id : typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
808
|
-
if (id && toolCallState.has(id)) {
|
|
809
|
-
const state = toolCallState.get(id);
|
|
810
|
-
if (typeof item.arguments === "string" && item.arguments.length > state.arguments.length)
|
|
811
|
-
state.arguments = item.arguments;
|
|
812
|
-
if (typeof item.name === "string" && !state.name)
|
|
813
|
-
state.name = item.name;
|
|
814
|
-
if (typeof item.call_id === "string" && !state.callId)
|
|
815
|
-
state.callId = item.call_id;
|
|
874
|
+
if (!visible.trim() && toolCalls.length === 0) {
|
|
875
|
+
if (reasoningSeen.trim()) {
|
|
876
|
+
return { text: full, provider: "meta", model, finishReason: finishReason ?? "stop", ...(streamUsage ? { usage: streamUsage } : {}), ...reasoningReplay() };
|
|
877
|
+
}
|
|
878
|
+
throw new ProviderError(`Meta Model API completed without a visible answer.`);
|
|
816
879
|
}
|
|
817
|
-
|
|
880
|
+
return {
|
|
881
|
+
text: full,
|
|
882
|
+
provider: "meta",
|
|
883
|
+
model,
|
|
884
|
+
...(toolCalls.length ? { toolCalls } : {}),
|
|
885
|
+
...(finishReason ? { finishReason } : toolCalls.length ? { finishReason: "tool_calls" } : {}),
|
|
886
|
+
...(streamUsage ? { usage: streamUsage } : {}),
|
|
887
|
+
...reasoningReplay(),
|
|
888
|
+
};
|
|
818
889
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
if (type === "response.content_part.added" || type === "response.content_part.done") {
|
|
824
|
-
continue;
|
|
825
|
-
}
|
|
826
|
-
if (type === "response.output_text.delta") {
|
|
827
|
-
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
828
|
-
if (delta) {
|
|
829
|
-
resetIdleTimer();
|
|
830
|
-
emitVisible(delta);
|
|
890
|
+
let parsed;
|
|
891
|
+
try {
|
|
892
|
+
parsed = JSON.parse(payload);
|
|
831
893
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
if (type === "response.reasoning_summary_text.delta") {
|
|
835
|
-
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
836
|
-
if (delta) {
|
|
837
|
-
resetIdleTimer();
|
|
838
|
-
emitReasoningDelta(delta);
|
|
894
|
+
catch {
|
|
895
|
+
continue;
|
|
839
896
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (remaining) {
|
|
847
|
-
resetIdleTimer();
|
|
848
|
-
emitReasoningDelta(remaining);
|
|
849
|
-
}
|
|
897
|
+
if (parsed.error) {
|
|
898
|
+
const rawDetail = typeof parsed.error === "string"
|
|
899
|
+
? parsed.error
|
|
900
|
+
: parsed.error.message ?? parsed.error.type ?? "unknown error";
|
|
901
|
+
const detail = rawDetail.trim().length <= 2 ? `${rawDetail} — ${payload.slice(0, 300)}` : rawDetail;
|
|
902
|
+
throw new ProviderError(`Meta Model API stream error: ${detail}`, undefined, payload.slice(0, 1000));
|
|
850
903
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
if (
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
904
|
+
const type = parsed.type;
|
|
905
|
+
if (type === "response.created" || type === "response.in_progress") {
|
|
906
|
+
const resp = (parsed.response ?? parsed);
|
|
907
|
+
if (typeof resp.id === "string")
|
|
908
|
+
responseId = resp.id;
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
if (type === "response.output_item.added") {
|
|
912
|
+
const item = parsed.item;
|
|
913
|
+
if (!item)
|
|
914
|
+
continue;
|
|
915
|
+
const outputIndex = typeof parsed.output_index === "number" ? parsed.output_index : undefined;
|
|
916
|
+
const itemId = typeof item.id === "string" ? item.id : typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
917
|
+
if (outputIndex !== undefined && itemId)
|
|
918
|
+
outputIndexToItemId.set(outputIndex, itemId);
|
|
919
|
+
if (item.type === "function_call") {
|
|
920
|
+
const id = typeof item.id === "string" ? item.id : typeof item.call_id === "string" ? item.call_id : itemId ?? `call_${toolCallState.size}`;
|
|
921
|
+
const callId = typeof item.call_id === "string" ? item.call_id : id;
|
|
922
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
923
|
+
const args = typeof item.arguments === "string" ? item.arguments : "";
|
|
924
|
+
const toolCallIndex = toolCallState.size;
|
|
925
|
+
toolCallState.set(id, { id, callId, name, arguments: args });
|
|
926
|
+
if (outputIndex !== undefined) {
|
|
927
|
+
outputIndexToToolCallIndex.set(outputIndex, toolCallIndex);
|
|
928
|
+
}
|
|
864
929
|
resetIdleTimer();
|
|
865
930
|
if (request.onToolCallDelta) {
|
|
866
|
-
const canonical =
|
|
867
|
-
request.onToolCallDelta({ index:
|
|
931
|
+
const canonical = name ? fromWireName(name) ?? name : undefined;
|
|
932
|
+
request.onToolCallDelta({ index: toolCallState.size - 1, ...(callId ? { id: callId } : {}), ...(canonical ? { name: canonical } : {}), argumentsBytes: args.length });
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
else if (item.type === "reasoning") {
|
|
936
|
+
noteReasoningItem(item, outputIndex);
|
|
937
|
+
const s = extractReasoningSummary(item);
|
|
938
|
+
if (s) {
|
|
939
|
+
resetIdleTimer();
|
|
940
|
+
emitReasoningDelta(s);
|
|
868
941
|
}
|
|
869
942
|
}
|
|
870
|
-
else {
|
|
871
|
-
toolCallState.set(targetId, { id: targetId, callId: targetId, name: "", arguments: delta });
|
|
943
|
+
else if (item.type === "message") {
|
|
872
944
|
resetIdleTimer();
|
|
873
945
|
}
|
|
946
|
+
continue;
|
|
874
947
|
}
|
|
875
|
-
|
|
876
|
-
const
|
|
877
|
-
if (
|
|
878
|
-
|
|
879
|
-
|
|
948
|
+
if (type === "response.output_item.done") {
|
|
949
|
+
const item = parsed.item;
|
|
950
|
+
if (item?.type === "reasoning") {
|
|
951
|
+
noteReasoningItem(item, typeof parsed.output_index === "number"
|
|
952
|
+
? parsed.output_index
|
|
953
|
+
: undefined);
|
|
954
|
+
}
|
|
955
|
+
if (item?.type === "function_call") {
|
|
956
|
+
const id = typeof item.id === "string" ? item.id : typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
957
|
+
if (id && toolCallState.has(id)) {
|
|
958
|
+
const state = toolCallState.get(id);
|
|
959
|
+
if (typeof item.arguments === "string" && item.arguments.length > state.arguments.length)
|
|
960
|
+
state.arguments = item.arguments;
|
|
961
|
+
if (typeof item.name === "string" && !state.name)
|
|
962
|
+
state.name = item.name;
|
|
963
|
+
if (typeof item.call_id === "string" && !state.callId)
|
|
964
|
+
state.callId = item.call_id;
|
|
965
|
+
}
|
|
880
966
|
resetIdleTimer();
|
|
881
967
|
}
|
|
968
|
+
if (item && typeof item.status === "string")
|
|
969
|
+
finishReason = item.status;
|
|
970
|
+
continue;
|
|
882
971
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (type === "response.function_call_arguments.done") {
|
|
886
|
-
const args = typeof parsed.arguments === "string" ? parsed.arguments : typeof parsed.argument === "string" ? parsed.argument : "";
|
|
887
|
-
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
888
|
-
let targetId = itemId;
|
|
889
|
-
if (!targetId && typeof parsed.output_index === "number")
|
|
890
|
-
targetId = outputIndexToItemId.get(parsed.output_index);
|
|
891
|
-
if (targetId && toolCallState.has(targetId) && args) {
|
|
892
|
-
toolCallState.get(targetId).arguments = args;
|
|
972
|
+
if (type === "response.content_part.added" || type === "response.content_part.done") {
|
|
973
|
+
continue;
|
|
893
974
|
}
|
|
894
|
-
|
|
895
|
-
const
|
|
896
|
-
if (
|
|
897
|
-
|
|
975
|
+
if (type === "response.output_text.delta") {
|
|
976
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
977
|
+
if (delta) {
|
|
978
|
+
resetIdleTimer();
|
|
979
|
+
emitVisible(delta);
|
|
980
|
+
}
|
|
981
|
+
continue;
|
|
898
982
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
if (u)
|
|
907
|
-
streamUsage = u;
|
|
983
|
+
if (type === "response.reasoning_summary_text.delta") {
|
|
984
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
985
|
+
if (delta) {
|
|
986
|
+
resetIdleTimer();
|
|
987
|
+
emitReasoningDelta(delta);
|
|
988
|
+
}
|
|
989
|
+
continue;
|
|
908
990
|
}
|
|
909
|
-
if (
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
exitReasoning();
|
|
991
|
+
if (type === "response.reasoning_summary_text.done") {
|
|
992
|
+
const textVal = typeof parsed.text === "string" ? parsed.text : "";
|
|
993
|
+
if (textVal && !reasoningSeen.includes(textVal)) {
|
|
994
|
+
const remaining = textVal.slice(reasoningSeen.length);
|
|
995
|
+
if (remaining) {
|
|
996
|
+
resetIdleTimer();
|
|
997
|
+
emitReasoningDelta(remaining);
|
|
998
|
+
}
|
|
918
999
|
}
|
|
919
|
-
|
|
920
|
-
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
if (type === "response.function_call_arguments.delta") {
|
|
1003
|
+
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
1004
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : typeof parsed.itemId === "string" ? parsed.itemId : undefined;
|
|
1005
|
+
let targetId = itemId;
|
|
1006
|
+
if (!targetId && typeof parsed.output_index === "number")
|
|
1007
|
+
targetId = outputIndexToItemId.get(parsed.output_index);
|
|
1008
|
+
if (targetId) {
|
|
1009
|
+
const state = toolCallState.get(targetId);
|
|
1010
|
+
if (state) {
|
|
1011
|
+
state.arguments += delta;
|
|
1012
|
+
resetIdleTimer();
|
|
1013
|
+
if (request.onToolCallDelta) {
|
|
1014
|
+
const canonical = state.name ? fromWireName(state.name) ?? state.name : undefined;
|
|
1015
|
+
request.onToolCallDelta({ index: Array.from(toolCallState.keys()).indexOf(targetId), ...(state.callId ? { id: state.callId } : {}), ...(canonical ? { name: canonical } : {}), argumentsBytes: state.arguments.length });
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
toolCallState.set(targetId, { id: targetId, callId: targetId, name: "", arguments: delta });
|
|
1020
|
+
resetIdleTimer();
|
|
1021
|
+
}
|
|
921
1022
|
}
|
|
922
|
-
|
|
923
|
-
const
|
|
924
|
-
if (
|
|
925
|
-
const
|
|
926
|
-
|
|
1023
|
+
else if (delta) {
|
|
1024
|
+
const anyKey = Array.from(toolCallState.keys()).pop();
|
|
1025
|
+
if (anyKey) {
|
|
1026
|
+
const state = toolCallState.get(anyKey);
|
|
1027
|
+
state.arguments += delta;
|
|
1028
|
+
resetIdleTimer();
|
|
927
1029
|
}
|
|
928
1030
|
}
|
|
1031
|
+
continue;
|
|
929
1032
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1033
|
+
if (type === "response.function_call_arguments.done") {
|
|
1034
|
+
const args = typeof parsed.arguments === "string" ? parsed.arguments : typeof parsed.argument === "string" ? parsed.argument : "";
|
|
1035
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
1036
|
+
let targetId = itemId;
|
|
1037
|
+
if (!targetId && typeof parsed.output_index === "number")
|
|
1038
|
+
targetId = outputIndexToItemId.get(parsed.output_index);
|
|
1039
|
+
if (targetId && toolCallState.has(targetId) && args) {
|
|
1040
|
+
toolCallState.get(targetId).arguments = args;
|
|
1041
|
+
}
|
|
1042
|
+
else if (args && toolCallState.size > 0) {
|
|
1043
|
+
const lastKey = Array.from(toolCallState.keys()).pop();
|
|
1044
|
+
if (!toolCallState.get(lastKey).arguments)
|
|
1045
|
+
toolCallState.get(lastKey).arguments = args;
|
|
1046
|
+
}
|
|
1047
|
+
resetIdleTimer();
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
if (type === "response.completed") {
|
|
1051
|
+
sawTerminalProof = "response-completed";
|
|
1052
|
+
const resp = (parsed.response ?? parsed);
|
|
937
1053
|
if (resp.usage) {
|
|
938
1054
|
const u = parseMetaUsage(resp.usage);
|
|
939
1055
|
if (u)
|
|
940
1056
|
streamUsage = u;
|
|
941
1057
|
}
|
|
942
|
-
if (
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1058
|
+
if (typeof resp.status === "string")
|
|
1059
|
+
finishReason = resp.status;
|
|
1060
|
+
if (Array.isArray(resp.output)) {
|
|
1061
|
+
const out = parseResponsesOutput(resp);
|
|
1062
|
+
for (const [index, item] of out.reasoningItems.entries()) {
|
|
1063
|
+
const position = out.reasoningItemPositions[index];
|
|
1064
|
+
noteReasoningItem(item, position?.sequence, position?.toolCallIndex);
|
|
1065
|
+
}
|
|
1066
|
+
if (out.reasoningSummary && !reasoningSeen.trim()) {
|
|
1067
|
+
emitReasoningDelta(out.reasoningSummary);
|
|
1068
|
+
}
|
|
1069
|
+
if (out.text && !visible.trim()) {
|
|
1070
|
+
emitVisible(out.text);
|
|
1071
|
+
}
|
|
1072
|
+
for (const tc of out.toolCalls) {
|
|
1073
|
+
const exists = Array.from(toolCallState.values()).some((s) => s.callId === tc.id);
|
|
1074
|
+
if (!exists) {
|
|
1075
|
+
const id = tc.id;
|
|
1076
|
+
toolCallState.set(id, { id, callId: tc.id, name: toWireName(tc.name), arguments: tc.rawArguments ?? JSON.stringify(tc.args) });
|
|
1077
|
+
}
|
|
949
1078
|
}
|
|
950
|
-
throw budgetExhaustedError(request, reasoningOn, payload);
|
|
951
1079
|
}
|
|
952
|
-
finishReason = "incomplete";
|
|
953
1080
|
continue;
|
|
954
1081
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1082
|
+
if (type === "response.failed" || type === "response.incomplete") {
|
|
1083
|
+
const resp = (parsed.response ?? parsed);
|
|
1084
|
+
if (type === "response.incomplete") {
|
|
1085
|
+
const details = resp.incomplete_details;
|
|
1086
|
+
const reason = typeof details?.reason === "string" ? details.reason : "";
|
|
1087
|
+
if (resp.usage) {
|
|
1088
|
+
const u = parseMetaUsage(resp.usage);
|
|
1089
|
+
if (u)
|
|
1090
|
+
streamUsage = u;
|
|
1091
|
+
}
|
|
1092
|
+
if (reason === "max_output_tokens" && !visible.trim() && toolCallState.size === 0) {
|
|
1093
|
+
const retryRequest = reasoningSeen.trim()
|
|
1094
|
+
? undefined
|
|
1095
|
+
: incompleteBudgetRetry(request, reasoningOn);
|
|
1096
|
+
const streamMethod = metaProvider.stream;
|
|
1097
|
+
if (retryRequest && streamMethod && !request.signal?.aborted) {
|
|
1098
|
+
cleanup();
|
|
1099
|
+
completeGenerationAttempt("failure", streamUsage);
|
|
1100
|
+
retryRequest.attemptReason = "provider-retry";
|
|
1101
|
+
return streamMethod(retryRequest, auth, onToken);
|
|
1102
|
+
}
|
|
1103
|
+
completeGenerationAttempt("failure", streamUsage);
|
|
1104
|
+
throw budgetExhaustedError(request, reasoningOn, payload);
|
|
1105
|
+
}
|
|
1106
|
+
finishReason = "incomplete";
|
|
1107
|
+
sawTerminalProof = "response-incomplete";
|
|
1108
|
+
continue;
|
|
1109
|
+
}
|
|
1110
|
+
const err = resp.error;
|
|
1111
|
+
const rawDetail = err?.message ?? err?.code ?? type;
|
|
1112
|
+
const rawStr = String(rawDetail);
|
|
1113
|
+
const detail = rawStr.trim().length <= 2 ? `${rawStr} — ${payload.slice(0, 300)}` : rawStr;
|
|
1114
|
+
throw new ProviderError(`Meta Model API stream error: ${detail}`, undefined, payload.slice(0, 1000));
|
|
1115
|
+
}
|
|
1116
|
+
const usageField = parsed.usage;
|
|
1117
|
+
if (usageField) {
|
|
1118
|
+
const u = parseMetaUsage(usageField);
|
|
1119
|
+
if (u) {
|
|
1120
|
+
streamUsage = u;
|
|
1121
|
+
resetIdleTimer();
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
const choice = parsed.choices;
|
|
1125
|
+
if (choice) {
|
|
1126
|
+
const chunkUsage = parseMetaUsage(parsed.usage);
|
|
1127
|
+
if (chunkUsage)
|
|
1128
|
+
streamUsage = chunkUsage;
|
|
967
1129
|
}
|
|
968
|
-
}
|
|
969
|
-
const choice = parsed.choices;
|
|
970
|
-
if (choice) {
|
|
971
|
-
const chunkUsage = parseMetaUsage(parsed.usage);
|
|
972
|
-
if (chunkUsage)
|
|
973
|
-
streamUsage = chunkUsage;
|
|
974
1130
|
}
|
|
975
1131
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
full += REASONING_OPEN;
|
|
983
|
-
visible = full;
|
|
984
|
-
onToken(REASONING_OPEN);
|
|
1132
|
+
if (!reasoningSeen.trim() && streamUsage?.reasoningTokens && streamUsage.reasoningTokens > 0 && (visible.trim() || toolCallState.size > 0)) {
|
|
1133
|
+
const effort = metaReasoningPayload(request.thinking)?.effort;
|
|
1134
|
+
const effortText = effort ? ` at ${effort} effort` : "";
|
|
1135
|
+
const note = `Reasoning is private on Meta Model API: the model reasoned${effortText} and used ${streamUsage.reasoningTokens.toLocaleString("en-US")} reasoning tokens, but the API returns no reasoning text to display.`;
|
|
1136
|
+
reasoningSeen += note;
|
|
1137
|
+
emitStreamReasoningDelta(request.onStreamEvent, note);
|
|
985
1138
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
onToken(REASONING_CLOSE);
|
|
991
|
-
inReasoning = false;
|
|
992
|
-
}
|
|
993
|
-
else {
|
|
994
|
-
exitReasoning();
|
|
995
|
-
}
|
|
996
|
-
cleanup();
|
|
997
|
-
const toolCalls = [];
|
|
998
|
-
for (const [, state] of toolCallState) {
|
|
999
|
-
if (!state.name && !state.arguments)
|
|
1000
|
-
continue;
|
|
1001
|
-
const name = state.name || "";
|
|
1002
|
-
const canonical = name ? fromWireName(name) ?? name : "";
|
|
1003
|
-
if (!canonical)
|
|
1004
|
-
continue;
|
|
1005
|
-
const raw = state.arguments;
|
|
1006
|
-
let args;
|
|
1007
|
-
try {
|
|
1008
|
-
const parsed = JSON.parse(raw || "{}");
|
|
1009
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
1010
|
-
args = parsed;
|
|
1011
|
-
else
|
|
1012
|
-
args = {};
|
|
1139
|
+
cleanup();
|
|
1140
|
+
let metaToolArgumentBytes = 0;
|
|
1141
|
+
for (const state of toolCallState.values()) {
|
|
1142
|
+
metaToolArgumentBytes += state.arguments.length;
|
|
1013
1143
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1144
|
+
requireTerminalProof({
|
|
1145
|
+
provider: "Meta Model API",
|
|
1146
|
+
policy: META_STREAM_TERMINAL,
|
|
1147
|
+
signal: sawTerminalProof,
|
|
1148
|
+
answerBytes: full.length,
|
|
1149
|
+
reasoningBytes: reasoningSeen.length,
|
|
1150
|
+
toolArgumentBytes: metaToolArgumentBytes,
|
|
1151
|
+
});
|
|
1152
|
+
const toolCalls = [];
|
|
1153
|
+
for (const [, state] of toolCallState) {
|
|
1154
|
+
if (!state.name && !state.arguments)
|
|
1155
|
+
continue;
|
|
1156
|
+
const name = state.name || "";
|
|
1157
|
+
const canonical = name ? fromWireName(name) ?? name : "";
|
|
1158
|
+
if (!canonical)
|
|
1159
|
+
continue;
|
|
1160
|
+
const raw = state.arguments;
|
|
1161
|
+
let args;
|
|
1162
|
+
try {
|
|
1163
|
+
const parsed = JSON.parse(raw || "{}");
|
|
1164
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
1165
|
+
args = parsed;
|
|
1166
|
+
else
|
|
1167
|
+
args = {};
|
|
1168
|
+
}
|
|
1169
|
+
catch {
|
|
1170
|
+
args = parseToolArguments(raw);
|
|
1171
|
+
}
|
|
1172
|
+
toolCalls.push({ id: state.callId ?? state.id ?? `call_${toolCalls.length}`, name: canonical, args, rawArguments: raw });
|
|
1016
1173
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1174
|
+
if (!visible.trim() && toolCalls.length === 0) {
|
|
1175
|
+
if (reasoningSeen.trim()) {
|
|
1176
|
+
return { text: full, provider: "meta", model, finishReason: finishReason ?? "stop", ...(streamUsage ? { usage: streamUsage } : {}), ...reasoningReplay() };
|
|
1177
|
+
}
|
|
1178
|
+
throw new ProviderError(`Meta Model API completed without a visible answer.`);
|
|
1022
1179
|
}
|
|
1023
|
-
|
|
1180
|
+
return {
|
|
1181
|
+
text: full,
|
|
1182
|
+
provider: "meta",
|
|
1183
|
+
model,
|
|
1184
|
+
...(toolCalls.length ? { toolCalls } : {}),
|
|
1185
|
+
...(finishReason ? { finishReason } : toolCalls.length ? { finishReason: "tool_calls" } : {}),
|
|
1186
|
+
...(streamUsage ? { usage: streamUsage } : {}),
|
|
1187
|
+
...reasoningReplay(),
|
|
1188
|
+
};
|
|
1024
1189
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
catch (error) {
|
|
1036
|
-
if (idleFired) {
|
|
1037
|
-
const seconds = Math.round(firedBudgetMs / 1000);
|
|
1038
|
-
if (firedWatchdog === "transport" || !sawTransportActivity) {
|
|
1039
|
-
if (!sawTransportActivity) {
|
|
1040
|
-
throw new ProviderError(`Meta Model API request timed out before any response (${seconds}s) — no data arrived on the connection.`);
|
|
1190
|
+
catch (error) {
|
|
1191
|
+
if (idleFired) {
|
|
1192
|
+
const seconds = Math.round(firedBudgetMs / 1000);
|
|
1193
|
+
if (firedWatchdog === "transport" || !sawTransportActivity) {
|
|
1194
|
+
if (!sawTransportActivity) {
|
|
1195
|
+
throw new ProviderError(`Meta Model API request timed out before any response (${seconds}s) — no data arrived on the connection.`);
|
|
1196
|
+
}
|
|
1197
|
+
throw new ProviderError(`Meta Model API stream transport timeout (${seconds}s) — no data arrived on the connection after it had started.`);
|
|
1041
1198
|
}
|
|
1042
|
-
throw new ProviderError(`Meta Model API stream
|
|
1199
|
+
throw new ProviderError(`Meta Model API stream stalled — ${STREAM_STALL_MARKER} for ${seconds}s` +
|
|
1200
|
+
(sawStreamProgress
|
|
1201
|
+
? " after it had already started producing output. The connection stayed open, so the model was most likely buffering one very large tool call. Split large writes into smaller sequential calls, or try a smaller model / disable thinking with /effort off."
|
|
1202
|
+
: " — the connection stayed open but the model never produced anything. Try another model, or disable thinking with /effort off."));
|
|
1043
1203
|
}
|
|
1044
|
-
throw
|
|
1045
|
-
(sawStreamProgress
|
|
1046
|
-
? " after it had already started producing output. The connection stayed open, so the model was most likely buffering one very large tool call. Split large writes into smaller sequential calls, or try a smaller model / disable thinking with /effort off."
|
|
1047
|
-
: " — the connection stayed open but the model never produced anything. Try another model, or disable thinking with /effort off."));
|
|
1204
|
+
throw error;
|
|
1048
1205
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1206
|
+
finally {
|
|
1207
|
+
cleanup();
|
|
1208
|
+
void reader.cancel().catch(() => undefined);
|
|
1209
|
+
try {
|
|
1210
|
+
reader.releaseLock();
|
|
1211
|
+
}
|
|
1212
|
+
catch { }
|
|
1056
1213
|
}
|
|
1057
|
-
|
|
1058
|
-
}
|
|
1214
|
+
});
|
|
1059
1215
|
},
|
|
1060
1216
|
};
|
|
1061
1217
|
//# sourceMappingURL=meta.js.map
|