@nodetool-ai/websocket 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.nodetool-build-stamp +1 -1
- package/dist/collection-api.d.ts.map +1 -1
- package/dist/collection-api.js +41 -4
- package/dist/collection-api.js.map +1 -1
- package/dist/error-traces.d.ts +56 -0
- package/dist/error-traces.d.ts.map +1 -0
- package/dist/error-traces.js +179 -0
- package/dist/error-traces.js.map +1 -0
- package/dist/fake-runtime.d.ts.map +1 -1
- package/dist/fake-runtime.js +40 -3
- package/dist/fake-runtime.js.map +1 -1
- package/dist/generation-recovery.d.ts.map +1 -1
- package/dist/generation-recovery.js +26 -4
- package/dist/generation-recovery.js.map +1 -1
- package/dist/http-api.d.ts.map +1 -1
- package/dist/http-api.js +15 -0
- package/dist/http-api.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/interrupted-jobs.d.ts +14 -0
- package/dist/interrupted-jobs.d.ts.map +1 -0
- package/dist/interrupted-jobs.js +28 -0
- package/dist/interrupted-jobs.js.map +1 -0
- package/dist/lib/app-debug-service.js +1 -1
- package/dist/lib/app-debug-service.js.map +1 -1
- package/dist/lib/app-instances-service.d.ts +1284 -0
- package/dist/lib/app-instances-service.d.ts.map +1 -0
- package/dist/lib/app-instances-service.js +378 -0
- package/dist/lib/app-instances-service.js.map +1 -0
- package/dist/lib/app-run-cancellation.d.ts +4 -0
- package/dist/lib/app-run-cancellation.d.ts.map +1 -0
- package/dist/lib/app-run-cancellation.js +28 -0
- package/dist/lib/app-run-cancellation.js.map +1 -0
- package/dist/lib/applications-service.d.ts +182 -1
- package/dist/lib/applications-service.d.ts.map +1 -1
- package/dist/lib/applications-service.js +20 -4
- package/dist/lib/applications-service.js.map +1 -1
- package/dist/lib/asset-paths.d.ts +7 -11
- package/dist/lib/asset-paths.d.ts.map +1 -1
- package/dist/lib/asset-paths.js +8 -56
- package/dist/lib/asset-paths.js.map +1 -1
- package/dist/lib/asset-response.d.ts.map +1 -1
- package/dist/lib/asset-response.js +2 -1
- package/dist/lib/asset-response.js.map +1 -1
- package/dist/lib/audio-peaks.d.ts.map +1 -1
- package/dist/lib/audio-peaks.js +5 -1
- package/dist/lib/audio-peaks.js.map +1 -1
- package/dist/lib/bridge.d.ts.map +1 -1
- package/dist/lib/bridge.js.map +1 -1
- package/dist/lib/document-model-interfaces.d.ts.map +1 -1
- package/dist/lib/document-model-interfaces.js +9 -8
- package/dist/lib/document-model-interfaces.js.map +1 -1
- package/dist/lib/example-apps.d.ts +9 -0
- package/dist/lib/example-apps.d.ts.map +1 -1
- package/dist/lib/example-apps.js +61 -14
- package/dist/lib/example-apps.js.map +1 -1
- package/dist/lib/http-tracing.d.ts +12 -0
- package/dist/lib/http-tracing.d.ts.map +1 -0
- package/dist/lib/http-tracing.js +81 -0
- package/dist/lib/http-tracing.js.map +1 -0
- package/dist/lib/media.d.ts +1 -6
- package/dist/lib/media.d.ts.map +1 -1
- package/dist/lib/media.js +8 -44
- package/dist/lib/media.js.map +1 -1
- package/dist/lib/public-routes.d.ts +7 -0
- package/dist/lib/public-routes.d.ts.map +1 -1
- package/dist/lib/public-routes.js +14 -0
- package/dist/lib/public-routes.js.map +1 -1
- package/dist/lib/public-workflow-share.d.ts +20 -0
- package/dist/lib/public-workflow-share.d.ts.map +1 -0
- package/dist/lib/public-workflow-share.js +45 -0
- package/dist/lib/public-workflow-share.js.map +1 -0
- package/dist/lib/run-trace-live-delivery.d.ts +25 -0
- package/dist/lib/run-trace-live-delivery.d.ts.map +1 -0
- package/dist/lib/run-trace-live-delivery.js +91 -0
- package/dist/lib/run-trace-live-delivery.js.map +1 -0
- package/dist/lib/test-ui-run-routes.d.ts +8 -0
- package/dist/lib/test-ui-run-routes.d.ts.map +1 -0
- package/dist/lib/test-ui-run-routes.js +42 -0
- package/dist/lib/test-ui-run-routes.js.map +1 -0
- package/dist/lib/thumbnail.d.ts.map +1 -1
- package/dist/lib/thumbnail.js +12 -9
- package/dist/lib/thumbnail.js.map +1 -1
- package/dist/lib/timeline-bundle.d.ts +148 -16
- package/dist/lib/timeline-bundle.d.ts.map +1 -1
- package/dist/lib/timeline-bundle.js +12 -0
- package/dist/lib/timeline-bundle.js.map +1 -1
- package/dist/lib/video-proxy.d.ts.map +1 -1
- package/dist/lib/video-proxy.js +3 -2
- package/dist/lib/video-proxy.js.map +1 -1
- package/dist/lib/workflow-service.d.ts.map +1 -1
- package/dist/lib/workflow-service.js +4 -1
- package/dist/lib/workflow-service.js.map +1 -1
- package/dist/mcp-agent-tools.d.ts.map +1 -1
- package/dist/mcp-agent-tools.js +93 -162
- package/dist/mcp-agent-tools.js.map +1 -1
- package/dist/mcp-client-config.d.ts +64 -0
- package/dist/mcp-client-config.d.ts.map +1 -0
- package/dist/mcp-client-config.js +353 -0
- package/dist/mcp-client-config.js.map +1 -0
- package/dist/models-api.d.ts +10 -0
- package/dist/models-api.d.ts.map +1 -1
- package/dist/models-api.js +23 -0
- package/dist/models-api.js.map +1 -1
- package/dist/node-registry-setup.d.ts +1 -1
- package/dist/node-registry-setup.d.ts.map +1 -1
- package/dist/node-registry-setup.js +21 -114
- package/dist/node-registry-setup.js.map +1 -1
- package/dist/plugins/websocket.d.ts.map +1 -1
- package/dist/plugins/websocket.js +20 -57
- package/dist/plugins/websocket.js.map +1 -1
- package/dist/python-bridge-gate.d.ts +28 -0
- package/dist/python-bridge-gate.d.ts.map +1 -0
- package/dist/python-bridge-gate.js +36 -0
- package/dist/python-bridge-gate.js.map +1 -0
- package/dist/routes/app-runs.d.ts +4 -0
- package/dist/routes/app-runs.d.ts.map +1 -0
- package/dist/routes/app-runs.js +173 -0
- package/dist/routes/app-runs.js.map +1 -0
- package/dist/routes/js-scripts.d.ts +9 -3
- package/dist/routes/js-scripts.d.ts.map +1 -1
- package/dist/routes/js-scripts.js +450 -68
- package/dist/routes/js-scripts.js.map +1 -1
- package/dist/routes/nodes.d.ts.map +1 -1
- package/dist/routes/nodes.js +32 -1
- package/dist/routes/nodes.js.map +1 -1
- package/dist/routes/public-shared-workflows.d.ts +16 -0
- package/dist/routes/public-shared-workflows.d.ts.map +1 -0
- package/dist/routes/public-shared-workflows.js +55 -0
- package/dist/routes/public-shared-workflows.js.map +1 -0
- package/dist/routes/run-spans.d.ts +4 -0
- package/dist/routes/run-spans.d.ts.map +1 -0
- package/dist/routes/run-spans.js +53 -0
- package/dist/routes/run-spans.js.map +1 -0
- package/dist/routes/timeline-fonts.d.ts +22 -0
- package/dist/routes/timeline-fonts.d.ts.map +1 -1
- package/dist/routes/timeline-fonts.js +138 -7
- package/dist/routes/timeline-fonts.js.map +1 -1
- package/dist/screenshot-server.js +4 -5
- package/dist/screenshot-server.js.map +1 -1
- package/dist/sdk/sdk-model-download-service.d.ts.map +1 -1
- package/dist/sdk/sdk-model-download-service.js +5 -2
- package/dist/sdk/sdk-model-download-service.js.map +1 -1
- package/dist/server.js +86 -19
- package/dist/server.js.map +1 -1
- package/dist/session/app-run-fold.d.ts +7 -0
- package/dist/session/app-run-fold.d.ts.map +1 -0
- package/dist/session/app-run-fold.js +45 -0
- package/dist/session/app-run-fold.js.map +1 -0
- package/dist/session/chat-prompt.d.ts.map +1 -1
- package/dist/session/chat-prompt.js +37 -15
- package/dist/session/chat-prompt.js.map +1 -1
- package/dist/session/chat-turn.d.ts +1 -0
- package/dist/session/chat-turn.d.ts.map +1 -1
- package/dist/session/chat-turn.js +203 -107
- package/dist/session/chat-turn.js.map +1 -1
- package/dist/session/commands.d.ts.map +1 -1
- package/dist/session/commands.js +6 -0
- package/dist/session/commands.js.map +1 -1
- package/dist/session/inference.d.ts +5 -0
- package/dist/session/inference.d.ts.map +1 -1
- package/dist/session/inference.js +80 -9
- package/dist/session/inference.js.map +1 -1
- package/dist/session/job-execution.d.ts +7 -0
- package/dist/session/job-execution.d.ts.map +1 -1
- package/dist/session/job-execution.js +297 -7
- package/dist/session/job-execution.js.map +1 -1
- package/dist/session/model-interfaces.d.ts +2 -1
- package/dist/session/model-interfaces.d.ts.map +1 -1
- package/dist/session/model-interfaces.js +1 -0
- package/dist/session/model-interfaces.js.map +1 -1
- package/dist/storage-retention.d.ts +5 -0
- package/dist/storage-retention.d.ts.map +1 -1
- package/dist/storage-retention.js +22 -1
- package/dist/storage-retention.js.map +1 -1
- package/dist/test-ui-server.d.ts.map +1 -1
- package/dist/test-ui-server.js +21 -3
- package/dist/test-ui-server.js.map +1 -1
- package/dist/timeline-generation-recovery.d.ts +4 -0
- package/dist/timeline-generation-recovery.d.ts.map +1 -0
- package/dist/timeline-generation-recovery.js +72 -0
- package/dist/timeline-generation-recovery.js.map +1 -0
- package/dist/triggers/dispatcher.js +2 -2
- package/dist/triggers/dispatcher.js.map +1 -1
- package/dist/triggers/stores.js +8 -8
- package/dist/triggers/stores.js.map +1 -1
- package/dist/triggers/webhook-route.js +2 -2
- package/dist/triggers/webhook-route.js.map +1 -1
- package/dist/trpc/error-logging.d.ts +10 -0
- package/dist/trpc/error-logging.d.ts.map +1 -1
- package/dist/trpc/error-logging.js +21 -0
- package/dist/trpc/error-logging.js.map +1 -1
- package/dist/trpc/router.d.ts +100 -31028
- package/dist/trpc/router.d.ts.map +1 -1
- package/dist/trpc/router.js +12 -3
- package/dist/trpc/router.js.map +1 -1
- package/dist/trpc/routers/app-instances.d.ts +2269 -0
- package/dist/trpc/routers/app-instances.d.ts.map +1 -0
- package/dist/trpc/routers/app-instances.js +52 -0
- package/dist/trpc/routers/app-instances.js.map +1 -0
- package/dist/trpc/routers/app-runs.d.ts +1092 -0
- package/dist/trpc/routers/app-runs.d.ts.map +1 -0
- package/dist/trpc/routers/app-runs.js +28 -0
- package/dist/trpc/routers/app-runs.js.map +1 -0
- package/dist/trpc/routers/applications.d.ts +1095 -0
- package/dist/trpc/routers/applications.d.ts.map +1 -1
- package/dist/trpc/routers/applications.js +5 -2
- package/dist/trpc/routers/applications.js.map +1 -1
- package/dist/trpc/routers/assets.d.ts +10 -0
- package/dist/trpc/routers/assets.d.ts.map +1 -1
- package/dist/trpc/routers/assets.js +4 -0
- package/dist/trpc/routers/assets.js.map +1 -1
- package/dist/trpc/routers/bug-reports.d.ts +33 -0
- package/dist/trpc/routers/bug-reports.d.ts.map +1 -0
- package/dist/trpc/routers/bug-reports.js +69 -0
- package/dist/trpc/routers/bug-reports.js.map +1 -0
- package/dist/trpc/routers/documents.d.ts.map +1 -1
- package/dist/trpc/routers/documents.js +8 -2
- package/dist/trpc/routers/documents.js.map +1 -1
- package/dist/trpc/routers/error-traces.d.ts +132 -0
- package/dist/trpc/routers/error-traces.d.ts.map +1 -0
- package/dist/trpc/routers/error-traces.js +118 -0
- package/dist/trpc/routers/error-traces.js.map +1 -0
- package/dist/trpc/routers/extension.d.ts +3 -3
- package/dist/trpc/routers/extension.js +6 -6
- package/dist/trpc/routers/extension.js.map +1 -1
- package/dist/trpc/routers/gameDraftHistory.d.ts +8 -0
- package/dist/trpc/routers/gameDraftHistory.d.ts.map +1 -0
- package/dist/trpc/routers/gameDraftHistory.js +40 -0
- package/dist/trpc/routers/gameDraftHistory.js.map +1 -0
- package/dist/trpc/routers/games.d.ts +23691 -4799
- package/dist/trpc/routers/games.d.ts.map +1 -1
- package/dist/trpc/routers/games.js +301 -83
- package/dist/trpc/routers/games.js.map +1 -1
- package/dist/trpc/routers/jobs.d.ts +35 -0
- package/dist/trpc/routers/jobs.d.ts.map +1 -1
- package/dist/trpc/routers/jobs.js +84 -1
- package/dist/trpc/routers/jobs.js.map +1 -1
- package/dist/trpc/routers/mcp-config.d.ts +3 -1
- package/dist/trpc/routers/mcp-config.d.ts.map +1 -1
- package/dist/trpc/routers/mcp-config.js +46 -208
- package/dist/trpc/routers/mcp-config.js.map +1 -1
- package/dist/trpc/routers/models.d.ts +130 -0
- package/dist/trpc/routers/models.d.ts.map +1 -1
- package/dist/trpc/routers/models.js +99 -31
- package/dist/trpc/routers/models.js.map +1 -1
- package/dist/trpc/routers/runs.d.ts +472 -0
- package/dist/trpc/routers/runs.d.ts.map +1 -0
- package/dist/trpc/routers/runs.js +40 -0
- package/dist/trpc/routers/runs.js.map +1 -0
- package/dist/trpc/routers/settings.d.ts +3 -0
- package/dist/trpc/routers/settings.d.ts.map +1 -1
- package/dist/trpc/routers/settings.js +2 -0
- package/dist/trpc/routers/settings.js.map +1 -1
- package/dist/trpc/routers/sketch.d.ts +14 -0
- package/dist/trpc/routers/sketch.d.ts.map +1 -1
- package/dist/trpc/routers/storyboards.d.ts +732 -0
- package/dist/trpc/routers/storyboards.d.ts.map +1 -1
- package/dist/trpc/routers/timeline.d.ts +632 -63
- package/dist/trpc/routers/timeline.d.ts.map +1 -1
- package/dist/trpc/routers/timeline.js +178 -2
- package/dist/trpc/routers/timeline.js.map +1 -1
- package/dist/trpc/routers/worker.d.ts +10 -9
- package/dist/trpc/routers/worker.d.ts.map +1 -1
- package/dist/trpc/routers/worker.js +3 -2
- package/dist/trpc/routers/worker.js.map +1 -1
- package/dist/trpc/routers/workflows.d.ts +56 -3
- package/dist/trpc/routers/workflows.d.ts.map +1 -1
- package/dist/trpc/routers/workflows.js +23 -2
- package/dist/trpc/routers/workflows.js.map +1 -1
- package/dist/trpc/sandbox-coverage.d.ts.map +1 -1
- package/dist/trpc/sandbox-coverage.js +90 -0
- package/dist/trpc/sandbox-coverage.js.map +1 -1
- package/dist/websocket-client-session.d.ts +2 -0
- package/dist/websocket-client-session.d.ts.map +1 -1
- package/dist/websocket-client-session.js +14 -0
- package/dist/websocket-client-session.js.map +1 -1
- package/package.json +56 -41
- package/dist/extension-cdp-bridge.d.ts +0 -85
- package/dist/extension-cdp-bridge.d.ts.map +0 -1
- package/dist/extension-cdp-bridge.js +0 -163
- package/dist/extension-cdp-bridge.js.map +0 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { registerChatRunTrace, registerWorkflowRunTrace, withRegisteredRunTrace, settleRegisteredRunTrace } from "@nodetool-ai/execution";
|
|
2
|
+
import { getRunTraceScope, suppressRunTraceContent } from "@nodetool-ai/runtime";
|
|
3
|
+
import { TRACE_RESTRICTED_CAPABILITY_MODULES } from "@nodetool-ai/protocol";
|
|
4
|
+
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
5
|
+
import { settleRunTrace, registerRunTraceParent, registerRunTraceParents, threadHasTraceContentTools } from "@nodetool-ai/models";
|
|
6
|
+
import { capabilityModuleOf, listCapabilitySpecs } from "@nodetool-ai/agents";
|
|
1
7
|
import { createLogger } from "@nodetool-ai/config";
|
|
2
8
|
import { randomUUID } from "node:crypto";
|
|
3
9
|
import { SUPERSEDED_TOOL_RESULT, repairOrphanedToolCalls } from "../chat-tool-call-repair.js";
|
|
@@ -13,7 +19,7 @@ import { ACTIVE_MODEL_CONTEXT_KEY, DIRECT_TOOL_NAMES, RUN_BUDGET_CONTEXT_KEY, cr
|
|
|
13
19
|
import { isModelSelection, PROVIDER_IDS, NO_MODEL_SELECTED_MESSAGE, noMediaModelSelectedMessage } from "@nodetool-ai/protocol";
|
|
14
20
|
import { Tool, compactAssetUris, compactResourceIds } from "@nodetool-ai/agents";
|
|
15
21
|
import { createChatCodeActSession, createSandboxClock, sandboxPackagesForChat, CODEACT_RESIDENT_TOOL_NAMES, EXECUTE_CODE_TOOL_NAME } from "@nodetool-ai/agents";
|
|
16
|
-
import {
|
|
22
|
+
import { availableBuiltinToolNames, GOOGLE_WORKSPACE_TOOL_NAMES, APIFY_TOOL_NAMES, SERPAPI_TOOL_NAMES, capabilityForName, capabilityProviderTool, getAllMcpCapabilitySpecs, toolFromCapability, capabilityFromTool, createCapabilityRun, contextSecretAvailability, BackgroundSubtaskRegistry, PERMISSION_GATE_CONTEXT_KEY, GAME_ASSET_NODE_RUNNER_CONTEXT_KEY, extractInjectableImages, registerTemporaryImageHandle } from "@nodetool-ai/agents";
|
|
17
23
|
import { mcpToolHostDeps } from "../mcp-tool-deps.js";
|
|
18
24
|
import { externalMcpToolsFor } from "../external-mcp.js";
|
|
19
25
|
import { formatSkillCatalogForPrompt, mergeSystemSkills, formatMemoriesForPrompt } from "@nodetool-ai/agents";
|
|
@@ -25,7 +31,41 @@ import { getSetting } from "../settings-registry.js";
|
|
|
25
31
|
import { appendContextToLastUser, createWorkflowResponseContent, dbMessageToProviderMessage, extractTextContent, historySinceCompaction, invokedSkillsSection, toolResultDisplayText } from "./chat-history.js";
|
|
26
32
|
import { chooseCompactionCut, compactionThreshold, COMPACTION_SUMMARY_MAX_TOKENS, holdsTranscriptServerSide, readCompactionSettings, summarizeForCompaction } from "./chat-compaction.js";
|
|
27
33
|
import { createRelayActivityWaiter, DEFAULT_RUN_JOB_EXECUTION_OPTIONS } from "./job-execution.js";
|
|
34
|
+
function restrictedTraceToolNames() {
|
|
35
|
+
const modules = new Set(TRACE_RESTRICTED_CAPABILITY_MODULES);
|
|
36
|
+
return listCapabilitySpecs().filter((spec) => modules.has(capabilityModuleOf(spec.name) ?? "")).map((spec) => spec.name);
|
|
37
|
+
}
|
|
38
|
+
function seedStoredToolProvenance(messages) {
|
|
39
|
+
for (const message of messages) {
|
|
40
|
+
const names = message.name ? [message.name] : [];
|
|
41
|
+
if (isCompactionMessage(message)) {
|
|
42
|
+
names.push(...(message.tools ?? []));
|
|
43
|
+
}
|
|
44
|
+
for (const call of message.tool_calls ?? []) {
|
|
45
|
+
if (!isRecord(call)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (isString(call.name)) {
|
|
49
|
+
names.push(call.name);
|
|
50
|
+
}
|
|
51
|
+
if (isRecord(call.function) && isString(call.function.name)) {
|
|
52
|
+
names.push(call.function.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (const name of names) {
|
|
56
|
+
const moduleName = capabilityModuleOf(name);
|
|
57
|
+
if (moduleName === "email" || moduleName === "google" || moduleName === "browser") {
|
|
58
|
+
suppressRunTraceContent();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
28
63
|
const log = createLogger("nodetool.websocket.runner");
|
|
64
|
+
/** Providers whose credential is an account sign-in, not an API key. */
|
|
65
|
+
const SIGN_IN_PROVIDER_LABELS = {
|
|
66
|
+
[PROVIDER_IDS.CODEX]: "Codex",
|
|
67
|
+
[PROVIDER_IDS.CLAUDE_AGENT_SDK]: "Claude"
|
|
68
|
+
};
|
|
29
69
|
const GENERIC_CHAT_ERROR = "Something went wrong while processing your request. Please try again.";
|
|
30
70
|
/**
|
|
31
71
|
* Keep implementation details out of the client error envelope. Provider
|
|
@@ -105,24 +145,20 @@ function providerFailureMessage(error, providerId, model) {
|
|
|
105
145
|
const gemini = geminiFailureSummary(error, providerId);
|
|
106
146
|
const groq = groqRequestFailureMessage(error);
|
|
107
147
|
const status = httpStatusFromError(error) ?? gemini?.status ?? null;
|
|
148
|
+
const statusCode = status ?? undefined;
|
|
108
149
|
const rawMessage = groq ?? gemini?.message ?? safeClientErrorText(error);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const safe = safeClientErrorText(bodyError.message);
|
|
116
|
-
bodyMessage = safe === GENERIC_CHAT_ERROR ? null : safe;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
150
|
+
const body = isObjectLike(error) ? (error.body ?? error.response) : undefined;
|
|
151
|
+
const bodyError = isObjectLike(body) && isObjectLike(body.error) ? body.error : body;
|
|
152
|
+
const bodyText = isObjectLike(bodyError) && isString(bodyError.message)
|
|
153
|
+
? safeClientErrorText(bodyError.message)
|
|
154
|
+
: null;
|
|
155
|
+
const bodyMessage = bodyText === GENERIC_CHAT_ERROR ? null : bodyText;
|
|
120
156
|
if (providerId.toLowerCase() === "openai" &&
|
|
121
157
|
/\borganization must be verified\b/i.test(bodyMessage ?? rawMessage)) {
|
|
122
158
|
return {
|
|
123
159
|
errorType: status === null ? "error" : "http_status_error",
|
|
124
160
|
message: "This model requires a verified OpenAI organization. Verify your provider organization or choose a model your account can access.",
|
|
125
|
-
statusCode
|
|
161
|
+
statusCode
|
|
126
162
|
};
|
|
127
163
|
}
|
|
128
164
|
const detail = providerFailureDetail(error);
|
|
@@ -131,28 +167,31 @@ function providerFailureMessage(error, providerId, model) {
|
|
|
131
167
|
return {
|
|
132
168
|
errorType: "error",
|
|
133
169
|
message: `The ${target} request is too large for the model context window. Shorten the conversation or remove some attachments and try again.`,
|
|
134
|
-
statusCode
|
|
170
|
+
statusCode
|
|
135
171
|
};
|
|
136
172
|
}
|
|
137
173
|
if (detail?.code === "provider_auth") {
|
|
174
|
+
const signIn = SIGN_IN_PROVIDER_LABELS[detail.provider];
|
|
175
|
+
const remedy = signIn ? `Sign in to ${signIn} again` : "Check the API key";
|
|
138
176
|
return {
|
|
139
177
|
errorType: "error",
|
|
140
|
-
message: `Authentication failed: ${detail.provider} rejected the configured credentials.
|
|
141
|
-
statusCode
|
|
178
|
+
message: `Authentication failed: ${detail.provider} rejected the configured credentials. ${remedy} in Settings → Models & Providers.`,
|
|
179
|
+
statusCode
|
|
142
180
|
};
|
|
143
181
|
}
|
|
144
182
|
if (status === null) {
|
|
145
|
-
return { errorType: "error", message: rawMessage, statusCode
|
|
183
|
+
return { errorType: "error", message: rawMessage, statusCode };
|
|
146
184
|
}
|
|
147
|
-
|
|
185
|
+
const modelName = model || "requested";
|
|
186
|
+
let message;
|
|
148
187
|
if (gemini?.kind === "quota") {
|
|
149
188
|
message = `Account quota exhausted for ${providerId}/${model}. Check your ${providerId} quota or billing and try again later.`;
|
|
150
189
|
}
|
|
151
190
|
else if (gemini?.kind === "model") {
|
|
152
|
-
message = `Model ${
|
|
191
|
+
message = `Model ${modelName} is unavailable on ${providerId}. Choose another model or check that your account has access to it.`;
|
|
153
192
|
}
|
|
154
193
|
else if (gemini?.kind === "tools") {
|
|
155
|
-
message = `Model ${
|
|
194
|
+
message = `Model ${modelName} does not support the requested tools on ${providerId}. Choose a model with tool support or disable tools.`;
|
|
156
195
|
}
|
|
157
196
|
else if (status === 400) {
|
|
158
197
|
message = `Bad request: ${groq ?? bodyMessage ?? rawMessage}`;
|
|
@@ -168,20 +207,20 @@ function providerFailureMessage(error, providerId, model) {
|
|
|
168
207
|
"Access forbidden: You don't have permission for this resource. Check the provider key's model and account access.";
|
|
169
208
|
}
|
|
170
209
|
else if (status === 404) {
|
|
171
|
-
message = `Model ${
|
|
210
|
+
message = `Model ${modelName} was not found or is unavailable on ${providerId}. Choose another model or check account access.`;
|
|
172
211
|
}
|
|
173
212
|
else if (status === 413) {
|
|
174
|
-
const
|
|
213
|
+
const bodyDetail = bodyMessage ?? rawMessage;
|
|
175
214
|
message =
|
|
176
215
|
groq ??
|
|
177
|
-
(
|
|
216
|
+
(bodyDetail === GENERIC_CHAT_ERROR
|
|
178
217
|
? "Request is too large for the provider. Shorten the conversation or remove some attachments and try again."
|
|
179
|
-
: `Request is too large for the provider (${
|
|
218
|
+
: `Request is too large for the provider (${bodyDetail}). Shorten the conversation or remove some attachments and try again.`);
|
|
180
219
|
}
|
|
181
220
|
else if (status === 429) {
|
|
182
|
-
message =
|
|
183
|
-
|
|
184
|
-
|
|
221
|
+
message =
|
|
222
|
+
groq ??
|
|
223
|
+
"Rate limited: Too many requests or insufficient provider quota. Check your provider plan and try again later.";
|
|
185
224
|
}
|
|
186
225
|
else if (status >= 500) {
|
|
187
226
|
message =
|
|
@@ -192,7 +231,7 @@ function providerFailureMessage(error, providerId, model) {
|
|
|
192
231
|
else {
|
|
193
232
|
message = `HTTP error (${status}): ${rawMessage}`;
|
|
194
233
|
}
|
|
195
|
-
return { errorType: "http_status_error", message, statusCode
|
|
234
|
+
return { errorType: "http_status_error", message, statusCode };
|
|
196
235
|
}
|
|
197
236
|
/**
|
|
198
237
|
* How many of a user's newest memories the turn reads to build its block. The
|
|
@@ -487,11 +526,12 @@ export class ChatTurnHandler {
|
|
|
487
526
|
delete data.thread_id;
|
|
488
527
|
const userId = this.session.requireUserId();
|
|
489
528
|
delete data.user_id;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
529
|
+
const message = await Message.create({ thread_id: threadId, user_id: userId, ...data });
|
|
530
|
+
const scope = getRunTraceScope();
|
|
531
|
+
if (scope) {
|
|
532
|
+
await registerRunTraceParent(userId, scope.runId, { kind: "message", id: message.id });
|
|
533
|
+
}
|
|
534
|
+
return message;
|
|
495
535
|
}
|
|
496
536
|
/**
|
|
497
537
|
* Persist raw image bytes carried on an assistant message (native providers
|
|
@@ -923,6 +963,7 @@ export class ChatTurnHandler {
|
|
|
923
963
|
: null,
|
|
924
964
|
assetOutputMode: this.session.mode === "text" ? "data_uri" : "temp_url"
|
|
925
965
|
});
|
|
966
|
+
context.runTraceContext = getRunTraceScope() ?? null;
|
|
926
967
|
// This context is built here rather than copied from the turn, so the
|
|
927
968
|
// turn's gate has to be put on it by hand. The node's own loops read it
|
|
928
969
|
// with `gateFromContext`; a node run outside a chat turn carries none and
|
|
@@ -1043,9 +1084,32 @@ export class ChatTurnHandler {
|
|
|
1043
1084
|
log.debug("Chat message", { threadId, model, provider: providerId });
|
|
1044
1085
|
// Save user message to DB — matches Python's _save_message_to_db_async(data)
|
|
1045
1086
|
const turnMessage = await this.saveMessageToDb(data);
|
|
1087
|
+
const rootContext = createRuntimeContext({ jobId: turnMessage.id, threadId, workflowId, userId, workspace: null });
|
|
1088
|
+
await registerChatRunTrace(rootContext, { messageId: turnMessage.id, threadId });
|
|
1089
|
+
return withRegisteredRunTrace(rootContext, "chat.turn", async () => {
|
|
1090
|
+
try {
|
|
1091
|
+
if (await threadHasTraceContentTools(userId, threadId, restrictedTraceToolNames())) {
|
|
1092
|
+
suppressRunTraceContent();
|
|
1093
|
+
}
|
|
1094
|
+
await this.handlePersistedChatTurn(data, turnMessage, rootContext, requestSeq, signal);
|
|
1095
|
+
await settleRegisteredRunTrace(rootContext, signal?.aborted ? "cancelled" : "completed");
|
|
1096
|
+
}
|
|
1097
|
+
catch (error) {
|
|
1098
|
+
await settleRegisteredRunTrace(rootContext, signal?.aborted ? "cancelled" : "failed", error instanceof Error ? error.message : String(error));
|
|
1099
|
+
throw error;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
async handlePersistedChatTurn(data, turnMessage, rootContext, requestSeq, signal) {
|
|
1104
|
+
const threadId = String(data.thread_id);
|
|
1105
|
+
const workflowId = isString(data.workflow_id) ? data.workflow_id : null;
|
|
1106
|
+
const userId = this.session.requireUserId();
|
|
1107
|
+
const providerId = String(data.provider);
|
|
1108
|
+
const model = String(data.model);
|
|
1046
1109
|
if (requestSeq !== undefined && requestSeq !== this.chatRequestSeq)
|
|
1047
1110
|
return;
|
|
1048
1111
|
if (!this.session.resolveProvider) {
|
|
1112
|
+
await settleRegisteredRunTrace(rootContext, "failed", "No provider resolver configured");
|
|
1049
1113
|
await this.session.send({
|
|
1050
1114
|
type: "error",
|
|
1051
1115
|
message: "No provider resolver configured",
|
|
@@ -1134,9 +1198,12 @@ export class ChatTurnHandler {
|
|
|
1134
1198
|
toolCalls: null,
|
|
1135
1199
|
threadId: null
|
|
1136
1200
|
});
|
|
1201
|
+
const copiedMessageIds = new Set();
|
|
1137
1202
|
const convertDbMessages = (rows) => {
|
|
1138
1203
|
const out = [];
|
|
1139
1204
|
for (const m of rows) {
|
|
1205
|
+
copiedMessageIds.add(m.id);
|
|
1206
|
+
seedStoredToolProvenance([m]);
|
|
1140
1207
|
const pm = dbMessageToProviderMessage(m, this.session.userId);
|
|
1141
1208
|
if (pm)
|
|
1142
1209
|
out.push(pm);
|
|
@@ -1160,6 +1227,7 @@ export class ChatTurnHandler {
|
|
|
1160
1227
|
reverse: true,
|
|
1161
1228
|
limit: SESSION_PROBE_WINDOW
|
|
1162
1229
|
});
|
|
1230
|
+
seedStoredToolProvenance(recent);
|
|
1163
1231
|
const probeHasWholeThread = recent.length < SESSION_PROBE_WINDOW;
|
|
1164
1232
|
// `recent` is newest-first. Walk to the first boundary marker: an
|
|
1165
1233
|
// assistant carrying a session token, or a compaction record. Both claim
|
|
@@ -1209,6 +1277,9 @@ export class ChatTurnHandler {
|
|
|
1209
1277
|
systemHash: probeSession.systemHash,
|
|
1210
1278
|
checkpoint: 1
|
|
1211
1279
|
};
|
|
1280
|
+
if (probeSession.traceContentSuppressed) {
|
|
1281
|
+
priorSession.traceContentSuppressed = true;
|
|
1282
|
+
}
|
|
1212
1283
|
// Absolute position to persist: prior prefix + the prior assistant + the
|
|
1213
1284
|
// new turns — identical to what the full-load path would store.
|
|
1214
1285
|
sessionCheckpointOverride =
|
|
@@ -1217,6 +1288,10 @@ export class ChatTurnHandler {
|
|
|
1217
1288
|
const [rows] = await Message.paginate(threadId, { limit: 1000 });
|
|
1218
1289
|
const full = convertDbMessages(historySinceCompaction(rows));
|
|
1219
1290
|
full.unshift(systemChatMessage());
|
|
1291
|
+
const scope = getRunTraceScope();
|
|
1292
|
+
if (scope) {
|
|
1293
|
+
await registerRunTraceParents(userId, scope.runId, [...copiedMessageIds].map((id) => ({ kind: "message", id })));
|
|
1294
|
+
}
|
|
1220
1295
|
return full;
|
|
1221
1296
|
};
|
|
1222
1297
|
}
|
|
@@ -1237,6 +1312,9 @@ export class ChatTurnHandler {
|
|
|
1237
1312
|
priorSession = lastMatchingProviderSession(kept, providerId, model);
|
|
1238
1313
|
}
|
|
1239
1314
|
}
|
|
1315
|
+
if (priorSession?.traceContentSuppressed) {
|
|
1316
|
+
suppressRunTraceContent();
|
|
1317
|
+
}
|
|
1240
1318
|
// Expose the read-only `run_search` fan-out primitive by default. A client
|
|
1241
1319
|
// can opt out by sending `enable_read_only_search: false`.
|
|
1242
1320
|
const enableReadOnlySearch = data.enable_read_only_search !== false;
|
|
@@ -1286,13 +1364,6 @@ export class ChatTurnHandler {
|
|
|
1286
1364
|
// it starts (invariant I-2). A loop that made its own would hand every
|
|
1287
1365
|
// nested agent a fresh allowance, which is no ceiling at all.
|
|
1288
1366
|
const turnBudget = await createChatTurnBudget();
|
|
1289
|
-
const gatedRun = (context) => createCapabilityRun({
|
|
1290
|
-
context,
|
|
1291
|
-
gate: chatGate,
|
|
1292
|
-
projectId: chatProjectId,
|
|
1293
|
-
availableSecrets: contextSecretAvailability(context),
|
|
1294
|
-
budget: turnBudget
|
|
1295
|
-
});
|
|
1296
1367
|
// The user's external MCP servers (Blender, Hugging Face, …). Their tools
|
|
1297
1368
|
// are plain belt tools named `mcp_<server>_<tool>`, so every loop reaches
|
|
1298
1369
|
// them the same way; a server that does not answer is skipped, not fatal.
|
|
@@ -1305,40 +1376,48 @@ export class ChatTurnHandler {
|
|
|
1305
1376
|
error: err instanceof Error ? err.message : String(err)
|
|
1306
1377
|
});
|
|
1307
1378
|
}
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
...(
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
...
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
...getAllMcpTools({
|
|
1317
|
-
registry: this.session.nodeRegistry,
|
|
1318
|
-
providers: chatProviders,
|
|
1319
|
-
...mcpToolHostDeps()
|
|
1320
|
-
}),
|
|
1321
|
-
toolForCapabilityName("list_collections"),
|
|
1322
|
-
toolForCapabilityName("query_collection"),
|
|
1323
|
-
runNodeTool
|
|
1379
|
+
const legacyCapabilities = [runNodeTool, ...externalMcpTools].map(capabilityFromTool);
|
|
1380
|
+
const nativeSpecs = [
|
|
1381
|
+
...availableBuiltinToolNames().map((name) => capabilityForName(name).spec),
|
|
1382
|
+
...(googleWorkspace ? GOOGLE_WORKSPACE_TOOL_NAMES : []).map((name) => capabilityForName(name).spec),
|
|
1383
|
+
...[...APIFY_TOOL_NAMES, ...SERPAPI_TOOL_NAMES].map((name) => capabilityForName(name).spec),
|
|
1384
|
+
...getAllMcpCapabilitySpecs({ registry: this.session.nodeRegistry, providers: chatProviders }),
|
|
1385
|
+
capabilityForName("list_collections").spec,
|
|
1386
|
+
capabilityForName("query_collection").spec
|
|
1324
1387
|
];
|
|
1325
|
-
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
//
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1388
|
+
const specsByName = new Map();
|
|
1389
|
+
for (const spec of [...nativeSpecs, ...legacyCapabilities.map((entry) => entry.spec)]) {
|
|
1390
|
+
if (!specsByName.has(spec.name)) {
|
|
1391
|
+
specsByName.set(spec.name, spec);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
const baseSpecs = [...specsByName.values()];
|
|
1395
|
+
const legacyByName = new Map(legacyCapabilities.map((entry) => [entry.spec.name, entry]));
|
|
1396
|
+
// Delegated executors still consume Tool[]. Adapt only at that boundary.
|
|
1397
|
+
// Each child context owns a separate run so its memory and depth are local.
|
|
1398
|
+
const childRuns = new WeakMap();
|
|
1399
|
+
const childRun = (context) => {
|
|
1400
|
+
let run = childRuns.get(context);
|
|
1401
|
+
if (!run) {
|
|
1402
|
+
run = createCapabilityRun({
|
|
1403
|
+
context, gate: chatGate, nodeRegistry: this.session.nodeRegistry,
|
|
1404
|
+
providers: chatProviders, budget: turnBudget,
|
|
1405
|
+
availableSecrets: contextSecretAvailability(context),
|
|
1406
|
+
...mcpToolHostDeps(), capabilities: legacyCapabilities
|
|
1407
|
+
});
|
|
1408
|
+
childRuns.set(context, run);
|
|
1409
|
+
}
|
|
1410
|
+
return run;
|
|
1411
|
+
};
|
|
1412
|
+
const baseTools = baseSpecs.map((spec) => {
|
|
1413
|
+
const entry = legacyByName.get(spec.name)
|
|
1414
|
+
?? capabilityForName(spec.name);
|
|
1415
|
+
return toolFromCapability(entry.spec, entry.impl, childRun);
|
|
1416
|
+
});
|
|
1338
1417
|
// Inject the recursive-decomposition primitive (ungated — it spawns a
|
|
1339
1418
|
// child loop whose own tools are the gated `baseTools`). Child events
|
|
1340
1419
|
// stream back tagged with `parent_tool_call_id` so the UI can nest cards.
|
|
1341
|
-
const serverTools =
|
|
1420
|
+
const serverTools = baseSpecs.slice();
|
|
1342
1421
|
// The same runtime the delegation tools take, kept for the capability run
|
|
1343
1422
|
// below: provider, model, the parent belt, and the event forwarder.
|
|
1344
1423
|
let subAgentRuntime;
|
|
@@ -1384,18 +1463,9 @@ export class ChatTurnHandler {
|
|
|
1384
1463
|
// `parent_tool_call_id` / `subtask_depth` tagging are unchanged.
|
|
1385
1464
|
// `start_subtask` / `wait_subtasks` share the per-turn registry above:
|
|
1386
1465
|
// spawn returns immediately, and the parent collects on its own terms.
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
// effect of its own, and the child's tools are the gated `baseTools`.
|
|
1391
|
-
gate: UNGATED,
|
|
1392
|
-
availableSecrets: contextSecretAvailability(context),
|
|
1393
|
-
subAgent: subAgentRuntime,
|
|
1394
|
-
budget: turnBudget
|
|
1395
|
-
});
|
|
1396
|
-
serverTools.unshift(toolForCapabilityName("run_subtask", delegationRun));
|
|
1397
|
-
serverTools.unshift(toolForCapabilityName("start_subtask", delegationRun));
|
|
1398
|
-
serverTools.unshift(toolForCapabilityName("wait_subtasks", delegationRun));
|
|
1466
|
+
serverTools.unshift(capabilityForName("run_subtask").spec);
|
|
1467
|
+
serverTools.unshift(capabilityForName("start_subtask").spec);
|
|
1468
|
+
serverTools.unshift(capabilityForName("wait_subtasks").spec);
|
|
1399
1469
|
// Plan mode's own capability: `create_plan` runs the TaskPlanner over the
|
|
1400
1470
|
// objective and streams the plan into the thread, executing nothing. It
|
|
1401
1471
|
// is offered only here, because plan mode is the one place where a plan
|
|
@@ -1404,7 +1474,7 @@ export class ChatTurnHandler {
|
|
|
1404
1474
|
// mode the turn started in — `liveMode` covers a mid-turn switch for the
|
|
1405
1475
|
// gate, not for which tools were offered.
|
|
1406
1476
|
if (permissionMode === "plan") {
|
|
1407
|
-
serverTools.unshift(
|
|
1477
|
+
serverTools.unshift(capabilityForName("create_plan").spec);
|
|
1408
1478
|
}
|
|
1409
1479
|
// The other half: `execute_plan` runs a plan the user has already seen,
|
|
1410
1480
|
// on the same ParallelTaskExecutor `Agent` uses. It is on the belt in
|
|
@@ -1412,12 +1482,12 @@ export class ChatTurnHandler {
|
|
|
1412
1482
|
// `blocked_in_plan_mode`, which tells the model to have the user switch
|
|
1413
1483
|
// out, where dropping it from the belt entirely would only say the tool
|
|
1414
1484
|
// does not exist. It is *offered* everywhere but plan mode, below.
|
|
1415
|
-
serverTools.unshift(
|
|
1485
|
+
serverTools.unshift(capabilityForName("execute_plan").spec);
|
|
1416
1486
|
// Read-only fan-out search (opt-in). Reuses the same runtime — the
|
|
1417
1487
|
// capability filters the parent belt to its read-only allowlist
|
|
1418
1488
|
// internally, so passing the full snapshot is correct.
|
|
1419
1489
|
if (enableReadOnlySearch) {
|
|
1420
|
-
serverTools.unshift(
|
|
1490
|
+
serverTools.unshift(capabilityForName("run_search").spec);
|
|
1421
1491
|
}
|
|
1422
1492
|
}
|
|
1423
1493
|
const serverToolMap = new Map(serverTools.map((t) => [t.name, t]));
|
|
@@ -1426,7 +1496,7 @@ export class ChatTurnHandler {
|
|
|
1426
1496
|
permissionMode,
|
|
1427
1497
|
resolved: serverTools.map((t) => t.name)
|
|
1428
1498
|
});
|
|
1429
|
-
const serverSchemas = serverTools.map((t) => t
|
|
1499
|
+
const serverSchemas = serverTools.map((t) => capabilityProviderTool(t));
|
|
1430
1500
|
// Every client tool the connected UI registered is exposed. They used to be
|
|
1431
1501
|
// gated on an active workflow, which made the editor tools unreachable from
|
|
1432
1502
|
// plain chat; they are deferred behind `nodetool.searchTools()` anyway, and each one now
|
|
@@ -1484,7 +1554,11 @@ export class ChatTurnHandler {
|
|
|
1484
1554
|
workspace: chatWorkspace,
|
|
1485
1555
|
authToken: this.deps.authToken()
|
|
1486
1556
|
});
|
|
1557
|
+
ctx.runTraceContext = rootContext.runTraceContext;
|
|
1487
1558
|
ctx.set("chat_message_id", turnMessage.id);
|
|
1559
|
+
if (ctx.runTraceContext) {
|
|
1560
|
+
await registerRunTraceParents(userId, ctx.runTraceContext.runId, [...copiedMessageIds].map((id) => ({ kind: "message", id })));
|
|
1561
|
+
}
|
|
1488
1562
|
const detachPredictions = attachChatPredictionForwarder((listener) => ctx.addMessageListener(listener), (msg) => this.session.sendDetached(msg), { threadId: threadId || null, workflowId });
|
|
1489
1563
|
// A chat turn that generates an image or a video spends real money without
|
|
1490
1564
|
// ever constructing an ExecutionSession, so the ledger is attached here
|
|
@@ -1530,7 +1604,7 @@ export class ChatTurnHandler {
|
|
|
1530
1604
|
budget: turnBudget,
|
|
1531
1605
|
secretPrompt: (request) => this.requestSecretEntry(threadId, request),
|
|
1532
1606
|
...mcpToolHostDeps(),
|
|
1533
|
-
capabilities:
|
|
1607
|
+
capabilities: legacyCapabilities
|
|
1534
1608
|
});
|
|
1535
1609
|
const gameAssetRun = this.chatCapabilityRun;
|
|
1536
1610
|
const gameAssetNodeRunner = (args) => gameAssetRun.invoke("run_node", args);
|
|
@@ -1632,9 +1706,20 @@ export class ChatTurnHandler {
|
|
|
1632
1706
|
// What to persist onto the assistant message: the provider's token, but with
|
|
1633
1707
|
// the absolute checkpoint when the fast path sent only a delta (the
|
|
1634
1708
|
// provider's emitted checkpoint is relative to the trimmed view).
|
|
1635
|
-
const sessionForPersist = () =>
|
|
1636
|
-
|
|
1637
|
-
|
|
1709
|
+
const sessionForPersist = () => {
|
|
1710
|
+
if (!capturedSession) {
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
const contentSuppressed = getRunTraceScope()?.policy.contentSuppressed || priorSession?.traceContentSuppressed || capturedSession.traceContentSuppressed;
|
|
1714
|
+
const persisted = { ...capturedSession };
|
|
1715
|
+
if (sessionCheckpointOverride != null) {
|
|
1716
|
+
persisted.checkpoint = sessionCheckpointOverride;
|
|
1717
|
+
}
|
|
1718
|
+
if (contentSuppressed) {
|
|
1719
|
+
persisted.traceContentSuppressed = true;
|
|
1720
|
+
}
|
|
1721
|
+
return persisted;
|
|
1722
|
+
};
|
|
1638
1723
|
// Cap on tool-calling rounds before the loop stops. Generous enough to
|
|
1639
1724
|
// build a multi-component app UI or run a long edit session in one turn —
|
|
1640
1725
|
// 10 was too low and cut off the app builder mid-build.
|
|
@@ -1715,9 +1800,14 @@ export class ChatTurnHandler {
|
|
|
1715
1800
|
}
|
|
1716
1801
|
else if (serverTool) {
|
|
1717
1802
|
try {
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1803
|
+
const args = { ...Tool.stripMessage(toolCall.args) };
|
|
1804
|
+
if (serverTool.needsToolCallId) {
|
|
1805
|
+
args["_tool_call_id"] = toolCall.id;
|
|
1806
|
+
}
|
|
1807
|
+
if (!this.chatCapabilityRun) {
|
|
1808
|
+
throw new Error("Chat capability run is unavailable");
|
|
1809
|
+
}
|
|
1810
|
+
toolResult = await this.chatCapabilityRun.invoke(serverTool.name, args);
|
|
1721
1811
|
}
|
|
1722
1812
|
catch (err) {
|
|
1723
1813
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -2020,6 +2110,7 @@ export class ChatTurnHandler {
|
|
|
2020
2110
|
role: "user",
|
|
2021
2111
|
execution_event_type: COMPACTION_EVENT_TYPE,
|
|
2022
2112
|
content: compactionMessageContent(summary),
|
|
2113
|
+
tools: getRunTraceScope()?.policy.contentSuppressed ? restrictedTraceToolNames() : null,
|
|
2023
2114
|
created_at: Number.isFinite(boundary)
|
|
2024
2115
|
? new Date(boundary - 1).toISOString()
|
|
2025
2116
|
: cut.keep[0].created_at
|
|
@@ -2260,6 +2351,7 @@ export class ChatTurnHandler {
|
|
|
2260
2351
|
return;
|
|
2261
2352
|
}
|
|
2262
2353
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2354
|
+
await settleRegisteredRunTrace(rootContext, "failed", errMsg);
|
|
2263
2355
|
log.error("Chat processing error", { threadId, error: errMsg });
|
|
2264
2356
|
let errorType = "error";
|
|
2265
2357
|
let statusCode;
|
|
@@ -3076,6 +3168,11 @@ export class ChatTurnHandler {
|
|
|
3076
3168
|
if (cancelled())
|
|
3077
3169
|
return;
|
|
3078
3170
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3171
|
+
const scope = getRunTraceScope();
|
|
3172
|
+
if (scope) {
|
|
3173
|
+
trace.getActiveSpan()?.setStatus({ code: SpanStatusCode.ERROR });
|
|
3174
|
+
await settleRunTrace(userId, scope.runId, { status: "failed", error: scope.policy.contentSuppressed ? "Execution failed" : errMsg, secretValues: scope.secretValues, contentSuppressed: scope.policy.contentSuppressed });
|
|
3175
|
+
}
|
|
3079
3176
|
log.error("Media generation error", { threadId, mode, error: errMsg });
|
|
3080
3177
|
const failure = providerFailureMessage(err, providerId, modelId);
|
|
3081
3178
|
const failureMessage = `Generation failed: ${failure.message}`;
|
|
@@ -3160,6 +3257,11 @@ export class ChatTurnHandler {
|
|
|
3160
3257
|
"messages";
|
|
3161
3258
|
// Build chat history for params — matches Python
|
|
3162
3259
|
const [dbMessages] = await Message.paginate(threadId, { limit: 1000 });
|
|
3260
|
+
const inheritedTrace = getRunTraceScope();
|
|
3261
|
+
seedStoredToolProvenance(dbMessages);
|
|
3262
|
+
if (inheritedTrace) {
|
|
3263
|
+
await registerRunTraceParents(userId, inheritedTrace.runId, dbMessages.map((m) => ({ kind: "message", id: m.id })));
|
|
3264
|
+
}
|
|
3163
3265
|
const chatHistorySerialized = dbMessages.map((m) => ({
|
|
3164
3266
|
role: m.role,
|
|
3165
3267
|
content: m.content,
|
|
@@ -3207,6 +3309,7 @@ export class ChatTurnHandler {
|
|
|
3207
3309
|
workspace,
|
|
3208
3310
|
assetOutputMode: this.session.mode === "text" ? "data_uri" : "temp_url"
|
|
3209
3311
|
});
|
|
3312
|
+
context.runTraceContext = getRunTraceScope() ?? null;
|
|
3210
3313
|
// Expose executor/node-type resolution for sub-workflow nodes
|
|
3211
3314
|
context.setResolveExecutor((node) => this.session.resolveExecutor(node));
|
|
3212
3315
|
if (this.session.resolveNodeType) {
|
|
@@ -3215,6 +3318,8 @@ export class ChatTurnHandler {
|
|
|
3215
3318
|
: this.session.resolveNodeType;
|
|
3216
3319
|
context.setResolveNodeType((nodeType) => resolverObj.resolveNodeType(nodeType));
|
|
3217
3320
|
}
|
|
3321
|
+
await Job.create({ id: jobId, workflow_id: workflowId, user_id: userId, status: "running", params, graph });
|
|
3322
|
+
await registerWorkflowRunTrace(context, { jobId, workflowId });
|
|
3218
3323
|
// Create and run workflow (A5: via the ExecutionSession facade — see
|
|
3219
3324
|
// the identical note in `startJobInner`).
|
|
3220
3325
|
const session = await ExecutionSession.create({
|
|
@@ -3249,20 +3354,6 @@ export class ChatTurnHandler {
|
|
|
3249
3354
|
}
|
|
3250
3355
|
};
|
|
3251
3356
|
this.deps.jobs.registerJob(jobId, active);
|
|
3252
|
-
// Persist job to DB (best-effort)
|
|
3253
|
-
try {
|
|
3254
|
-
await Job.create({
|
|
3255
|
-
id: jobId,
|
|
3256
|
-
workflow_id: workflowId,
|
|
3257
|
-
user_id: userId,
|
|
3258
|
-
status: "running",
|
|
3259
|
-
params,
|
|
3260
|
-
graph
|
|
3261
|
-
});
|
|
3262
|
-
}
|
|
3263
|
-
catch (error) {
|
|
3264
|
-
this.session.logError("workflow job persistence failed", error);
|
|
3265
|
-
}
|
|
3266
3357
|
// The run already started inside `ExecutionSession.create()` above.
|
|
3267
3358
|
const executePromise = session.result;
|
|
3268
3359
|
// Stream events, collect output_update results
|
|
@@ -3441,6 +3532,11 @@ export class ChatTurnHandler {
|
|
|
3441
3532
|
}
|
|
3442
3533
|
catch (err) {
|
|
3443
3534
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3535
|
+
const scope = getRunTraceScope();
|
|
3536
|
+
if (scope) {
|
|
3537
|
+
trace.getActiveSpan()?.setStatus({ code: SpanStatusCode.ERROR });
|
|
3538
|
+
await settleRunTrace(userId, scope.runId, { status: "failed", error: scope.policy.contentSuppressed ? "Execution failed" : errMsg, secretValues: scope.secretValues, contentSuppressed: scope.policy.contentSuppressed });
|
|
3539
|
+
}
|
|
3444
3540
|
log.error("Workflow message error", {
|
|
3445
3541
|
threadId,
|
|
3446
3542
|
workflowId,
|