@pentoshi/clai 4.0.3 → 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 +45 -9
- 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/confirm-port.js +6 -3
- package/dist/agent/confirm-port.js.map +1 -1
- 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 +412 -181
- 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/agent/turn-outcome.d.ts +1 -1
- package/dist/agent/turn-outcome.js +2 -12
- package/dist/agent/turn-outcome.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 +23 -16
- 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 +22 -11
- package/dist/app/controllers/session-controller.js +137 -92
- 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-continuation.d.ts +0 -6
- package/dist/app/controllers/turn-continuation.js +4 -21
- package/dist/app/controllers/turn-continuation.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/app/ports/transcript-item.d.ts +9 -1
- package/dist/classic/app/ClassicApp.js +3 -3
- 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 +4 -9
- package/dist/classic/app/wiring-interactions.js.map +1 -1
- package/dist/classic/blocks/TurnSummaryBlock.d.ts +3 -0
- package/dist/classic/blocks/TurnSummaryBlock.js +6 -0
- package/dist/classic/blocks/TurnSummaryBlock.js.map +1 -0
- package/dist/classic/blocks/tool-lines.js +2 -1
- package/dist/classic/blocks/tool-lines.js.map +1 -1
- package/dist/classic/blocks/turn-summary-lines.d.ts +3 -0
- package/dist/classic/blocks/turn-summary-lines.js +7 -0
- package/dist/classic/blocks/turn-summary-lines.js.map +1 -0
- package/dist/classic/chrome/status-rows.d.ts +0 -1
- package/dist/classic/chrome/status-rows.js +0 -12
- package/dist/classic/chrome/status-rows.js.map +1 -1
- package/dist/classic/feed/Feed.js +2 -0
- package/dist/classic/feed/Feed.js.map +1 -1
- package/dist/classic/feed/feed-blocks.d.ts +1 -1
- package/dist/classic/feed/feed-blocks.js +3 -0
- package/dist/classic/feed/feed-blocks.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 +56 -1
- 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.d.ts +3 -0
- package/dist/llm/fireworks.js +103 -0
- package/dist/llm/fireworks.js.map +1 -0
- 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.d.ts +3 -0
- package/dist/llm/hetzner.js +98 -0
- package/dist/llm/hetzner.js.map +1 -0
- package/dist/llm/http.d.ts +60 -10
- package/dist/llm/http.js +465 -156
- 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 +839 -624
- 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 +198 -21
- 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 +504 -102
- 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 +13 -6
- 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 +7 -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/fs.d.ts +5 -3
- package/dist/tools/fs.js +8 -5
- package/dist/tools/fs.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/plan/plan-view.js +5 -3
- package/dist/tui-v2/components/plan/plan-view.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/status/status-line.js +1 -14
- package/dist/tui-v2/components/status/status-line.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/components/transcript/notice-row.d.ts +3 -1
- package/dist/tui-v2/components/transcript/notice-row.js +28 -3
- package/dist/tui-v2/components/transcript/notice-row.js.map +1 -1
- package/dist/tui-v2/components/transcript/thinking-block.d.ts +0 -5
- package/dist/tui-v2/components/transcript/thinking-block.js +3 -8
- package/dist/tui-v2/components/transcript/thinking-block.js.map +1 -1
- package/dist/tui-v2/components/transcript/tool-card.js +16 -7
- package/dist/tui-v2/components/transcript/tool-card.js.map +1 -1
- package/dist/tui-v2/components/transcript/transcript-row.d.ts +0 -2
- package/dist/tui-v2/components/transcript/transcript-row.js +7 -3
- package/dist/tui-v2/components/transcript/transcript-row.js.map +1 -1
- package/dist/tui-v2/components/transcript/transcript-view.js +1 -3
- package/dist/tui-v2/components/transcript/transcript-view.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 +3 -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 +5 -0
- package/dist/ui-core/rendering/duration.js +43 -0
- package/dist/ui-core/rendering/duration.js.map +1 -0
- 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/rendering/transcript-semantic.js +2 -0
- package/dist/ui-core/rendering/transcript-semantic.js.map +1 -1
- package/dist/ui-core/state/transcript-compaction.js +2 -0
- package/dist/ui-core/state/transcript-compaction.js.map +1 -1
- package/dist/ui-core/state/transcript-hydrate.js +34 -4
- 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 +96 -8
- 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 +9 -1
- package/dist/ui-core/state/transcript-types.js +3 -1
- 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)
|
|
@@ -204,13 +264,34 @@ function buildResponsesBody(options) {
|
|
|
204
264
|
}
|
|
205
265
|
return JSON.stringify(body);
|
|
206
266
|
}
|
|
267
|
+
const META_MAX_OUTPUT_TOKENS_CAP = 65536;
|
|
268
|
+
const MAX_INCOMPLETE_BUDGET_RETRIES = 2;
|
|
269
|
+
const incompleteBudgetRetries = new WeakMap();
|
|
270
|
+
function incompleteBudgetRetry(request, reasoningOn) {
|
|
271
|
+
const used = incompleteBudgetRetries.get(request) ?? 0;
|
|
272
|
+
const currentBudget = Math.max(16, request.maxTokens ?? (reasoningOn ? 8192 : 4096));
|
|
273
|
+
const nextBudget = Math.min(currentBudget * 2, META_MAX_OUTPUT_TOKENS_CAP);
|
|
274
|
+
if (used >= MAX_INCOMPLETE_BUDGET_RETRIES || nextBudget <= currentBudget)
|
|
275
|
+
return undefined;
|
|
276
|
+
const retryRequest = { ...request, maxTokens: nextBudget };
|
|
277
|
+
incompleteBudgetRetries.set(retryRequest, used + 1);
|
|
278
|
+
return retryRequest;
|
|
279
|
+
}
|
|
280
|
+
function budgetExhaustedError(request, reasoningOn, payload) {
|
|
281
|
+
const currentBudget = Math.max(16, request.maxTokens ?? (reasoningOn ? 8192 : 4096));
|
|
282
|
+
const effort = metaReasoningPayload(request.thinking)?.effort;
|
|
283
|
+
const retried = (incompleteBudgetRetries.get(request) ?? 0) > 0;
|
|
284
|
+
return new ProviderError(`Meta Model API spent the entire output budget (${currentBudget} tokens${effort ? `, mostly on reasoning at ${effort} effort` : ""}) without producing an answer${retried ? ", even after raising max_output_tokens" : ""}. Lower the effort with /effort high or raise max_tokens.`, undefined, payload.slice(0, 1000));
|
|
285
|
+
}
|
|
207
286
|
function parseResponsesOutput(data) {
|
|
208
287
|
const output = Array.isArray(data.output) ? data.output : [];
|
|
209
288
|
let text = "";
|
|
210
289
|
let reasoningSummary = "";
|
|
211
290
|
const toolCalls = [];
|
|
212
291
|
const reasoningItems = [];
|
|
213
|
-
|
|
292
|
+
const reasoningItemSequences = [];
|
|
293
|
+
const toolCallSequences = [];
|
|
294
|
+
for (const [sequence, item] of output.entries()) {
|
|
214
295
|
if (!item || typeof item !== "object")
|
|
215
296
|
continue;
|
|
216
297
|
const obj = item;
|
|
@@ -229,12 +310,8 @@ function parseResponsesOutput(data) {
|
|
|
229
310
|
if (s)
|
|
230
311
|
reasoningSummary += s;
|
|
231
312
|
if (typeof obj.encrypted_content === "string" && obj.encrypted_content) {
|
|
232
|
-
reasoningItems.push({
|
|
233
|
-
|
|
234
|
-
...(typeof obj.id === "string" ? { id: obj.id } : {}),
|
|
235
|
-
summary: Array.isArray(obj.summary) ? obj.summary : [],
|
|
236
|
-
encrypted_content: obj.encrypted_content,
|
|
237
|
-
});
|
|
313
|
+
reasoningItems.push({ ...obj });
|
|
314
|
+
reasoningItemSequences.push(sequence);
|
|
238
315
|
}
|
|
239
316
|
}
|
|
240
317
|
else if (obj.type === "function_call") {
|
|
@@ -253,23 +330,52 @@ function parseResponsesOutput(data) {
|
|
|
253
330
|
catch {
|
|
254
331
|
args = parseToolArguments(rawArgs);
|
|
255
332
|
}
|
|
333
|
+
const toolCallIndex = toolCalls.length;
|
|
256
334
|
toolCalls.push({ id: callId, name: canonical, args, rawArguments: rawArgs });
|
|
335
|
+
toolCallSequences.push({ sequence, toolCallIndex });
|
|
257
336
|
}
|
|
258
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
|
+
});
|
|
259
344
|
const usage = parseMetaUsage(data.usage);
|
|
260
|
-
return {
|
|
345
|
+
return {
|
|
346
|
+
text,
|
|
347
|
+
toolCalls,
|
|
348
|
+
usage,
|
|
349
|
+
reasoningSummary,
|
|
350
|
+
reasoningItems,
|
|
351
|
+
reasoningItemPositions,
|
|
352
|
+
};
|
|
261
353
|
}
|
|
262
|
-
function
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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;
|
|
273
379
|
}
|
|
274
380
|
function readWithAbort(reader, signal) {
|
|
275
381
|
if (signal.aborted) {
|
|
@@ -306,6 +412,7 @@ function readWithAbort(reader, signal) {
|
|
|
306
412
|
}
|
|
307
413
|
export const metaProvider = {
|
|
308
414
|
id: "meta",
|
|
415
|
+
reasoningStyle: "meta",
|
|
309
416
|
displayName: "Meta Model API",
|
|
310
417
|
defaultModel: defaultModels.meta,
|
|
311
418
|
envVar: "MODEL_API_KEY",
|
|
@@ -345,187 +452,49 @@ export const metaProvider = {
|
|
|
345
452
|
if (!auth.apiKey)
|
|
346
453
|
throw new Error("Meta Model API key is required");
|
|
347
454
|
const model = request.model ?? defaultModels.meta;
|
|
348
|
-
|
|
349
|
-
const body = buildResponsesBody({
|
|
350
|
-
model,
|
|
351
|
-
messages: request.messages,
|
|
352
|
-
maxTokens: request.maxTokens,
|
|
353
|
-
temperature: request.temperature,
|
|
354
|
-
stream: false,
|
|
355
|
-
reasoning: request.thinking,
|
|
356
|
-
supportsVision,
|
|
357
|
-
tools: request.tools,
|
|
358
|
-
parallelToolCalls: request.parallelToolCalls,
|
|
359
|
-
});
|
|
360
|
-
let response;
|
|
361
|
-
try {
|
|
362
|
-
response = await fetch(`${baseUrl}/responses`, {
|
|
363
|
-
method: "POST",
|
|
364
|
-
signal: request.signal ?? null,
|
|
365
|
-
headers: {
|
|
366
|
-
"content-type": "application/json",
|
|
367
|
-
accept: "application/json",
|
|
368
|
-
authorization: `Bearer ${auth.apiKey}`,
|
|
369
|
-
},
|
|
370
|
-
body,
|
|
371
|
-
verbose: process.env.CLAI_VERBOSE === "true",
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
catch (error) {
|
|
375
|
-
if (error instanceof Error && error.name === "AbortError")
|
|
376
|
-
throw error;
|
|
377
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
378
|
-
throw new ProviderError(`Meta Model API request could not be sent (${msg}). Check connectivity to ${baseUrl}.`);
|
|
379
|
-
}
|
|
380
|
-
let data;
|
|
381
|
-
try {
|
|
382
|
-
data = await readJson(response);
|
|
383
|
-
}
|
|
384
|
-
catch (error) {
|
|
385
|
-
if (error instanceof ProviderError) {
|
|
386
|
-
throw new ProviderError(`Meta Model API (model=${model}): ${error.message}`, error.status, error.body, error.retryAfterSeconds);
|
|
387
|
-
}
|
|
388
|
-
throw error;
|
|
389
|
-
}
|
|
390
|
-
const parsed = parseResponsesOutput(data);
|
|
391
|
-
const usage = parsed.usage ?? parseMetaUsage(data.usage);
|
|
392
|
-
const effort = metaReasoningPayload(request.thinking)?.effort;
|
|
393
|
-
const full = foldResponsesReasoning(parsed.text, parsed.reasoningSummary, usage, effort);
|
|
394
|
-
if (!full.trim() && parsed.toolCalls.length === 0) {
|
|
395
|
-
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.`);
|
|
396
|
-
}
|
|
397
|
-
return {
|
|
398
|
-
text: full,
|
|
455
|
+
return runGenerationAttempt(request, {
|
|
399
456
|
provider: "meta",
|
|
400
457
|
model,
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
:
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const outputIdleTimeoutMs = Math.round(Math.max(idleTimeoutMs, initialIdleTimeoutMs) * 1.5);
|
|
418
|
-
const idleController = new AbortController();
|
|
419
|
-
let transportTimer;
|
|
420
|
-
let outputTimer;
|
|
421
|
-
let idleFired = false;
|
|
422
|
-
let firedWatchdog;
|
|
423
|
-
let firedBudgetMs = initialIdleTimeoutMs;
|
|
424
|
-
let sawTransportActivity = false;
|
|
425
|
-
let sawStreamProgress = false;
|
|
426
|
-
const fireStall = (watchdog, budgetMs) => {
|
|
427
|
-
if (idleFired)
|
|
428
|
-
return;
|
|
429
|
-
idleFired = true;
|
|
430
|
-
firedWatchdog = watchdog;
|
|
431
|
-
firedBudgetMs = budgetMs;
|
|
432
|
-
idleController.abort();
|
|
433
|
-
};
|
|
434
|
-
const armTransportTimer = (budgetMs) => {
|
|
435
|
-
if (transportTimer)
|
|
436
|
-
clearTimeout(transportTimer);
|
|
437
|
-
transportTimer = setTimeout(() => fireStall("transport", budgetMs), budgetMs);
|
|
438
|
-
};
|
|
439
|
-
const noteTransportActivity = () => {
|
|
440
|
-
sawTransportActivity = true;
|
|
441
|
-
armTransportTimer(idleTimeoutMs);
|
|
442
|
-
};
|
|
443
|
-
const resetIdleTimer = () => {
|
|
444
|
-
sawStreamProgress = true;
|
|
445
|
-
noteTransportActivity();
|
|
446
|
-
if (outputTimer)
|
|
447
|
-
clearTimeout(outputTimer);
|
|
448
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
449
|
-
};
|
|
450
|
-
armTransportTimer(initialIdleTimeoutMs);
|
|
451
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
452
|
-
const clearIdleTimers = () => {
|
|
453
|
-
if (transportTimer)
|
|
454
|
-
clearTimeout(transportTimer);
|
|
455
|
-
if (outputTimer)
|
|
456
|
-
clearTimeout(outputTimer);
|
|
457
|
-
transportTimer = undefined;
|
|
458
|
-
outputTimer = undefined;
|
|
459
|
-
};
|
|
460
|
-
const onCallerAbort = () => idleController.abort(request.signal?.reason);
|
|
461
|
-
request.signal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
462
|
-
const body = buildResponsesBody({
|
|
463
|
-
model,
|
|
464
|
-
messages: request.messages,
|
|
465
|
-
maxTokens: request.maxTokens,
|
|
466
|
-
temperature: request.temperature,
|
|
467
|
-
stream: true,
|
|
468
|
-
reasoning: request.thinking,
|
|
469
|
-
supportsVision,
|
|
470
|
-
tools: request.tools,
|
|
471
|
-
parallelToolCalls: request.parallelToolCalls,
|
|
472
|
-
});
|
|
473
|
-
let response;
|
|
474
|
-
let lastFetchError;
|
|
475
|
-
for (let fetchAttempt = 0; fetchAttempt < 2; fetchAttempt++) {
|
|
476
|
-
if (fetchAttempt > 0) {
|
|
477
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
478
|
-
if (request.signal?.aborted)
|
|
479
|
-
throw request.signal.reason;
|
|
480
|
-
if (idleFired)
|
|
481
|
-
break;
|
|
482
|
-
armTransportTimer(initialIdleTimeoutMs);
|
|
483
|
-
if (outputTimer) {
|
|
484
|
-
clearTimeout(outputTimer);
|
|
485
|
-
outputTimer = setTimeout(() => fireStall("output", outputIdleTimeoutMs), outputIdleTimeoutMs);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
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;
|
|
488
474
|
try {
|
|
489
|
-
response = await
|
|
475
|
+
response = await generationFetch(`${baseUrl}/responses`, {
|
|
490
476
|
method: "POST",
|
|
491
|
-
signal:
|
|
477
|
+
signal: request.signal ?? null,
|
|
492
478
|
headers: {
|
|
493
479
|
"content-type": "application/json",
|
|
494
|
-
accept: "
|
|
480
|
+
accept: "application/json",
|
|
495
481
|
authorization: `Bearer ${auth.apiKey}`,
|
|
496
482
|
},
|
|
497
483
|
body,
|
|
498
484
|
verbose: process.env.CLAI_VERBOSE === "true",
|
|
499
485
|
});
|
|
500
|
-
lastFetchError = undefined;
|
|
501
|
-
break;
|
|
502
486
|
}
|
|
503
487
|
catch (error) {
|
|
504
|
-
|
|
505
|
-
if (idleFired) {
|
|
506
|
-
clearIdleTimers();
|
|
507
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
508
|
-
throw new ProviderError(`Meta Model API request timed out before any response (${Math.round(firedBudgetMs / 1000)}s) — no data arrived on the connection.`);
|
|
509
|
-
}
|
|
510
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
511
|
-
const transient = /fetch failed|network error|etimedout|enotfound|econnreset|premature close|socket.*closed|aborted without reason/i.test(msg);
|
|
512
|
-
if (!transient || sawStreamProgress)
|
|
488
|
+
if (error instanceof Error && error.name === "AbortError")
|
|
513
489
|
throw error;
|
|
514
|
-
|
|
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}.`);
|
|
515
494
|
}
|
|
516
|
-
|
|
517
|
-
if (!response) {
|
|
518
|
-
clearIdleTimers();
|
|
519
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
520
|
-
if (lastFetchError)
|
|
521
|
-
throw lastFetchError;
|
|
522
|
-
throw new ProviderError(`Meta Model API request failed before a response was received.`);
|
|
523
|
-
}
|
|
524
|
-
if (!response.ok) {
|
|
525
|
-
clearIdleTimers();
|
|
526
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
495
|
+
let data;
|
|
527
496
|
try {
|
|
528
|
-
await readJson(response);
|
|
497
|
+
data = await readJson(response);
|
|
529
498
|
}
|
|
530
499
|
catch (error) {
|
|
531
500
|
if (error instanceof ProviderError) {
|
|
@@ -533,470 +502,716 @@ export const metaProvider = {
|
|
|
533
502
|
}
|
|
534
503
|
throw error;
|
|
535
504
|
}
|
|
536
|
-
}
|
|
537
|
-
if (!response.body) {
|
|
538
|
-
clearIdleTimers();
|
|
539
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
540
|
-
throw new ProviderError(`Meta Model API returned no stream body`);
|
|
541
|
-
}
|
|
542
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
543
|
-
if (response.status === 202 || /\bapplication\/json\b/i.test(contentType)) {
|
|
544
|
-
clearIdleTimers();
|
|
545
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
546
|
-
const data = await readJson(response);
|
|
547
|
-
if (response.status === 202) {
|
|
548
|
-
const requestId = data.requestId ?? data.id;
|
|
549
|
-
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));
|
|
550
|
-
}
|
|
551
505
|
const parsed = parseResponsesOutput(data);
|
|
552
|
-
const
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
? { reasoningBlock: { text: parsed.reasoningSummary, items: parsed.reasoningItems } }
|
|
567
|
-
: {}),
|
|
568
|
-
};
|
|
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
|
+
}
|
|
569
520
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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.`);
|
|
525
|
+
}
|
|
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,
|
|
600
609
|
});
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
enterReasoning();
|
|
630
|
-
reasoningSeen += text;
|
|
631
|
-
full += text;
|
|
632
|
-
onToken(text);
|
|
633
|
-
};
|
|
634
|
-
const cleanup = () => {
|
|
635
|
-
clearIdleTimers();
|
|
636
|
-
request.signal?.removeEventListener("abort", onCallerAbort);
|
|
637
|
-
idleController.signal.removeEventListener("abort", cancelReaderOnAbort);
|
|
638
|
-
};
|
|
639
|
-
const cancelReaderOnAbort = () => {
|
|
640
|
-
reader.cancel().catch(() => undefined);
|
|
641
|
-
};
|
|
642
|
-
idleController.signal.addEventListener("abort", cancelReaderOnAbort, { once: true });
|
|
643
|
-
const sseFrames = createSseFrameAssembler();
|
|
644
|
-
try {
|
|
645
|
-
while (true) {
|
|
646
|
-
request.signal?.throwIfAborted();
|
|
647
|
-
if (idleController.signal.aborted)
|
|
648
|
-
throw new Error("Stream aborted");
|
|
649
|
-
const { done, value } = await readWithAbort(reader, idleController.signal);
|
|
650
|
-
request.signal?.throwIfAborted();
|
|
651
|
-
if (idleController.signal.aborted)
|
|
652
|
-
throw new Error("Stream aborted");
|
|
653
|
-
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;
|
|
654
638
|
break;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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);
|
|
700
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);
|
|
701
709
|
return {
|
|
702
|
-
text:
|
|
710
|
+
text: parsed.text,
|
|
703
711
|
provider: "meta",
|
|
704
712
|
model,
|
|
705
|
-
...(toolCalls.length ? { toolCalls } : {}),
|
|
706
|
-
...(
|
|
707
|
-
...(
|
|
708
|
-
...
|
|
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 } : {}),
|
|
709
720
|
};
|
|
710
721
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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`);
|
|
717
734
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
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;
|
|
724
772
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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 };
|
|
731
791
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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)
|
|
735
846
|
continue;
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
const callId = typeof item.call_id === "string" ? item.call_id : id;
|
|
743
|
-
const name = typeof item.name === "string" ? item.name : "";
|
|
744
|
-
const args = typeof item.arguments === "string" ? item.arguments : "";
|
|
745
|
-
toolCallState.set(id, { id, callId, name, arguments: args });
|
|
746
|
-
resetIdleTimer();
|
|
747
|
-
if (request.onToolCallDelta) {
|
|
748
|
-
const canonical = name ? fromWireName(name) ?? name : undefined;
|
|
749
|
-
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);
|
|
750
853
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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 });
|
|
757
873
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
}
|
|
764
|
-
if (type === "response.output_item.done") {
|
|
765
|
-
const item = parsed.item;
|
|
766
|
-
if (item?.type === "reasoning")
|
|
767
|
-
noteReasoningItem(item);
|
|
768
|
-
if (item?.type === "function_call") {
|
|
769
|
-
const id = typeof item.id === "string" ? item.id : typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
770
|
-
if (id && toolCallState.has(id)) {
|
|
771
|
-
const state = toolCallState.get(id);
|
|
772
|
-
if (typeof item.arguments === "string" && item.arguments.length > state.arguments.length)
|
|
773
|
-
state.arguments = item.arguments;
|
|
774
|
-
if (typeof item.name === "string" && !state.name)
|
|
775
|
-
state.name = item.name;
|
|
776
|
-
if (typeof item.call_id === "string" && !state.callId)
|
|
777
|
-
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.`);
|
|
778
879
|
}
|
|
779
|
-
|
|
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
|
+
};
|
|
780
889
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
}
|
|
785
|
-
if (type === "response.content_part.added" || type === "response.content_part.done") {
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
if (type === "response.output_text.delta") {
|
|
789
|
-
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
790
|
-
if (delta) {
|
|
791
|
-
resetIdleTimer();
|
|
792
|
-
emitVisible(delta);
|
|
890
|
+
let parsed;
|
|
891
|
+
try {
|
|
892
|
+
parsed = JSON.parse(payload);
|
|
793
893
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
if (type === "response.reasoning_summary_text.delta") {
|
|
797
|
-
const delta = typeof parsed.delta === "string" ? parsed.delta : "";
|
|
798
|
-
if (delta) {
|
|
799
|
-
resetIdleTimer();
|
|
800
|
-
emitReasoningDelta(delta);
|
|
894
|
+
catch {
|
|
895
|
+
continue;
|
|
801
896
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (remaining) {
|
|
809
|
-
resetIdleTimer();
|
|
810
|
-
emitReasoningDelta(remaining);
|
|
811
|
-
}
|
|
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));
|
|
812
903
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
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
|
+
}
|
|
826
929
|
resetIdleTimer();
|
|
827
930
|
if (request.onToolCallDelta) {
|
|
828
|
-
const canonical =
|
|
829
|
-
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);
|
|
830
941
|
}
|
|
831
942
|
}
|
|
832
|
-
else {
|
|
833
|
-
toolCallState.set(targetId, { id: targetId, callId: targetId, name: "", arguments: delta });
|
|
943
|
+
else if (item.type === "message") {
|
|
834
944
|
resetIdleTimer();
|
|
835
945
|
}
|
|
946
|
+
continue;
|
|
836
947
|
}
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
|
|
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
|
+
}
|
|
842
966
|
resetIdleTimer();
|
|
843
967
|
}
|
|
968
|
+
if (item && typeof item.status === "string")
|
|
969
|
+
finishReason = item.status;
|
|
970
|
+
continue;
|
|
844
971
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
if (type === "response.function_call_arguments.done") {
|
|
848
|
-
const args = typeof parsed.arguments === "string" ? parsed.arguments : typeof parsed.argument === "string" ? parsed.argument : "";
|
|
849
|
-
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
850
|
-
let targetId = itemId;
|
|
851
|
-
if (!targetId && typeof parsed.output_index === "number")
|
|
852
|
-
targetId = outputIndexToItemId.get(parsed.output_index);
|
|
853
|
-
if (targetId && toolCallState.has(targetId) && args) {
|
|
854
|
-
toolCallState.get(targetId).arguments = args;
|
|
972
|
+
if (type === "response.content_part.added" || type === "response.content_part.done") {
|
|
973
|
+
continue;
|
|
855
974
|
}
|
|
856
|
-
|
|
857
|
-
const
|
|
858
|
-
if (
|
|
859
|
-
|
|
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;
|
|
860
982
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (u)
|
|
869
|
-
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;
|
|
870
990
|
}
|
|
871
|
-
if (
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
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
|
+
}
|
|
880
999
|
}
|
|
881
|
-
|
|
882
|
-
|
|
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
|
+
}
|
|
883
1022
|
}
|
|
884
|
-
|
|
885
|
-
const
|
|
886
|
-
if (
|
|
887
|
-
const
|
|
888
|
-
|
|
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();
|
|
889
1029
|
}
|
|
890
1030
|
}
|
|
1031
|
+
continue;
|
|
891
1032
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
streamUsage = u;
|
|
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
|
+
}
|
|
907
1047
|
resetIdleTimer();
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
if (type === "response.completed") {
|
|
1051
|
+
sawTerminalProof = "response-completed";
|
|
1052
|
+
const resp = (parsed.response ?? parsed);
|
|
1053
|
+
if (resp.usage) {
|
|
1054
|
+
const u = parseMetaUsage(resp.usage);
|
|
1055
|
+
if (u)
|
|
1056
|
+
streamUsage = u;
|
|
1057
|
+
}
|
|
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
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
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;
|
|
908
1129
|
}
|
|
909
|
-
}
|
|
910
|
-
const choice = parsed.choices;
|
|
911
|
-
if (choice) {
|
|
912
|
-
const chunkUsage = parseMetaUsage(parsed.usage);
|
|
913
|
-
if (chunkUsage)
|
|
914
|
-
streamUsage = chunkUsage;
|
|
915
1130
|
}
|
|
916
1131
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
full += REASONING_OPEN;
|
|
924
|
-
visible = full;
|
|
925
|
-
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);
|
|
926
1138
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
onToken(REASONING_CLOSE);
|
|
932
|
-
inReasoning = false;
|
|
933
|
-
}
|
|
934
|
-
else {
|
|
935
|
-
exitReasoning();
|
|
936
|
-
}
|
|
937
|
-
cleanup();
|
|
938
|
-
const toolCalls = [];
|
|
939
|
-
for (const [, state] of toolCallState) {
|
|
940
|
-
if (!state.name && !state.arguments)
|
|
941
|
-
continue;
|
|
942
|
-
const name = state.name || "";
|
|
943
|
-
const canonical = name ? fromWireName(name) ?? name : "";
|
|
944
|
-
if (!canonical)
|
|
945
|
-
continue;
|
|
946
|
-
const raw = state.arguments;
|
|
947
|
-
let args;
|
|
948
|
-
try {
|
|
949
|
-
const parsed = JSON.parse(raw || "{}");
|
|
950
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
951
|
-
args = parsed;
|
|
952
|
-
else
|
|
953
|
-
args = {};
|
|
1139
|
+
cleanup();
|
|
1140
|
+
let metaToolArgumentBytes = 0;
|
|
1141
|
+
for (const state of toolCallState.values()) {
|
|
1142
|
+
metaToolArgumentBytes += state.arguments.length;
|
|
954
1143
|
}
|
|
955
|
-
|
|
956
|
-
|
|
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 });
|
|
957
1173
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
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.`);
|
|
963
1179
|
}
|
|
964
|
-
|
|
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
|
+
};
|
|
965
1189
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
catch (error) {
|
|
977
|
-
if (idleFired) {
|
|
978
|
-
const seconds = Math.round(firedBudgetMs / 1000);
|
|
979
|
-
if (firedWatchdog === "transport" || !sawTransportActivity) {
|
|
980
|
-
if (!sawTransportActivity) {
|
|
981
|
-
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.`);
|
|
982
1198
|
}
|
|
983
|
-
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."));
|
|
984
1203
|
}
|
|
985
|
-
throw
|
|
986
|
-
(sawStreamProgress
|
|
987
|
-
? " 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."
|
|
988
|
-
: " — the connection stayed open but the model never produced anything. Try another model, or disable thinking with /effort off."));
|
|
1204
|
+
throw error;
|
|
989
1205
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1206
|
+
finally {
|
|
1207
|
+
cleanup();
|
|
1208
|
+
void reader.cancel().catch(() => undefined);
|
|
1209
|
+
try {
|
|
1210
|
+
reader.releaseLock();
|
|
1211
|
+
}
|
|
1212
|
+
catch { }
|
|
997
1213
|
}
|
|
998
|
-
|
|
999
|
-
}
|
|
1214
|
+
});
|
|
1000
1215
|
},
|
|
1001
1216
|
};
|
|
1002
1217
|
//# sourceMappingURL=meta.js.map
|