@koda-sl/baker-bridge 0.109.0-dev.afb6a264b → 0.109.0-dev.f7ef4c7e1
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 +89 -47
- package/dist/broker/baker-api.d.ts +23 -0
- package/dist/broker/baker-api.d.ts.map +1 -0
- package/dist/broker/baker-api.js +55 -0
- package/dist/broker/baker-api.js.map +1 -0
- package/dist/broker/broker-client.d.ts +10 -0
- package/dist/broker/broker-client.d.ts.map +1 -0
- package/dist/broker/broker-client.js +60 -0
- package/dist/broker/broker-client.js.map +1 -0
- package/dist/broker/broker-process.d.ts +10 -0
- package/dist/broker/broker-process.d.ts.map +1 -0
- package/dist/broker/broker-process.js +20 -0
- package/dist/broker/broker-process.js.map +1 -0
- package/dist/broker/broker-process.test.d.ts +2 -0
- package/dist/broker/broker-process.test.d.ts.map +1 -0
- package/dist/broker/broker-process.test.js +13 -0
- package/dist/broker/broker-process.test.js.map +1 -0
- package/dist/broker/ca.d.ts +38 -0
- package/dist/broker/ca.d.ts.map +1 -0
- package/dist/broker/ca.js +80 -0
- package/dist/broker/ca.js.map +1 -0
- package/dist/broker/ca.test.d.ts +2 -0
- package/dist/broker/ca.test.d.ts.map +1 -0
- package/dist/broker/ca.test.js +58 -0
- package/dist/broker/ca.test.js.map +1 -0
- package/dist/broker/credential-cache.d.ts +24 -0
- package/dist/broker/credential-cache.d.ts.map +1 -0
- package/dist/broker/credential-cache.js +76 -0
- package/dist/broker/credential-cache.js.map +1 -0
- package/dist/broker/credential-cache.test.d.ts +2 -0
- package/dist/broker/credential-cache.test.d.ts.map +1 -0
- package/dist/broker/credential-cache.test.js +136 -0
- package/dist/broker/credential-cache.test.js.map +1 -0
- package/dist/broker/credential-text.d.ts +45 -0
- package/dist/broker/credential-text.d.ts.map +1 -0
- package/dist/broker/credential-text.js +103 -0
- package/dist/broker/credential-text.js.map +1 -0
- package/dist/broker/credential-text.test.d.ts +2 -0
- package/dist/broker/credential-text.test.d.ts.map +1 -0
- package/dist/broker/credential-text.test.js +54 -0
- package/dist/broker/credential-text.test.js.map +1 -0
- package/dist/broker/env.d.ts +21 -0
- package/dist/broker/env.d.ts.map +1 -0
- package/dist/broker/env.js +20 -0
- package/dist/broker/env.js.map +1 -0
- package/dist/broker/main.d.ts +3 -0
- package/dist/broker/main.d.ts.map +1 -0
- package/dist/broker/main.js +57 -0
- package/dist/broker/main.js.map +1 -0
- package/dist/broker/proxy.d.ts +24 -0
- package/dist/broker/proxy.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.d.ts +2 -0
- package/dist/broker/proxy.integration.test.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.js +197 -0
- package/dist/broker/proxy.integration.test.js.map +1 -0
- package/dist/broker/proxy.js +147 -0
- package/dist/broker/proxy.js.map +1 -0
- package/dist/broker/rewrite.d.ts +44 -0
- package/dist/broker/rewrite.d.ts.map +1 -0
- package/dist/broker/rewrite.js +291 -0
- package/dist/broker/rewrite.js.map +1 -0
- package/dist/broker/rewrite.test.d.ts +2 -0
- package/dist/broker/rewrite.test.d.ts.map +1 -0
- package/dist/broker/rewrite.test.js +171 -0
- package/dist/broker/rewrite.test.js.map +1 -0
- package/dist/broker/socket-service.d.ts +18 -0
- package/dist/broker/socket-service.d.ts.map +1 -0
- package/dist/broker/socket-service.js +113 -0
- package/dist/broker/socket-service.js.map +1 -0
- package/dist/broker/socket-service.test.d.ts +2 -0
- package/dist/broker/socket-service.test.d.ts.map +1 -0
- package/dist/broker/socket-service.test.js +80 -0
- package/dist/broker/socket-service.test.js.map +1 -0
- package/dist/broker/supervisor-main.d.ts +3 -0
- package/dist/broker/supervisor-main.d.ts.map +1 -0
- package/dist/broker/supervisor-main.js +70 -0
- package/dist/broker/supervisor-main.js.map +1 -0
- package/dist/broker/supervisor.d.ts +25 -0
- package/dist/broker/supervisor.d.ts.map +1 -0
- package/dist/broker/supervisor.js +88 -0
- package/dist/broker/supervisor.js.map +1 -0
- package/dist/broker/supervisor.test.d.ts +2 -0
- package/dist/broker/supervisor.test.d.ts.map +1 -0
- package/dist/broker/supervisor.test.js +161 -0
- package/dist/broker/supervisor.test.js.map +1 -0
- package/dist/broker/token-bucket.d.ts +9 -0
- package/dist/broker/token-bucket.d.ts.map +1 -0
- package/dist/broker/token-bucket.js +18 -0
- package/dist/broker/token-bucket.js.map +1 -0
- package/dist/broker/usage-reporter.d.ts +18 -0
- package/dist/broker/usage-reporter.d.ts.map +1 -0
- package/dist/broker/usage-reporter.js +31 -0
- package/dist/broker/usage-reporter.js.map +1 -0
- package/dist/broker/usage-reporter.test.d.ts +2 -0
- package/dist/broker/usage-reporter.test.d.ts.map +1 -0
- package/dist/broker/usage-reporter.test.js +20 -0
- package/dist/broker/usage-reporter.test.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/hono/agent-session.d.ts +3 -0
- package/dist/hono/agent-session.d.ts.map +1 -1
- package/dist/hono/agent-session.js +15 -0
- package/dist/hono/agent-session.js.map +1 -1
- package/dist/hono/agent-tasks.js +4 -4
- package/dist/hono/agent-tasks.js.map +1 -1
- package/dist/hono/agent.d.ts +2 -0
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +11 -2
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/agent.test.js +8 -2
- package/dist/hono/agent.test.js.map +1 -1
- package/dist/hono/avatar-accent.d.ts +23 -5
- package/dist/hono/avatar-accent.d.ts.map +1 -1
- package/dist/hono/avatar-accent.js +54 -63
- package/dist/hono/avatar-accent.js.map +1 -1
- package/dist/hono/avatar-accent.test.js +64 -35
- package/dist/hono/avatar-accent.test.js.map +1 -1
- package/dist/hono/avatar-casting.d.ts +1 -0
- package/dist/hono/avatar-casting.d.ts.map +1 -1
- package/dist/hono/avatar-casting.js +18 -4
- package/dist/hono/avatar-casting.js.map +1 -1
- package/dist/hono/avatar-casting.test.js +5 -0
- package/dist/hono/avatar-casting.test.js.map +1 -1
- package/dist/hono/avatar-face-question.d.ts +23 -6
- package/dist/hono/avatar-face-question.d.ts.map +1 -1
- package/dist/hono/avatar-face-question.js +48 -59
- package/dist/hono/avatar-face-question.js.map +1 -1
- package/dist/hono/avatar-face-question.test.js +46 -101
- package/dist/hono/avatar-face-question.test.js.map +1 -1
- package/dist/hono/baker-ui-tool-schemas.test.js +30 -4
- package/dist/hono/baker-ui-tool-schemas.test.js.map +1 -1
- package/dist/hono/blocking-card.d.ts +12 -0
- package/dist/hono/blocking-card.d.ts.map +1 -0
- package/dist/hono/blocking-card.js +12 -0
- package/dist/hono/blocking-card.js.map +1 -0
- package/dist/hono/bridge-job.d.ts +48 -2
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +202 -34
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +344 -20
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/check-content.d.ts +49 -0
- package/dist/hono/check-content.d.ts.map +1 -0
- package/dist/hono/check-content.js +182 -0
- package/dist/hono/check-content.js.map +1 -0
- package/dist/hono/check-content.test.d.ts +2 -0
- package/dist/hono/check-content.test.d.ts.map +1 -0
- package/dist/hono/check-content.test.js +87 -0
- package/dist/hono/check-content.test.js.map +1 -0
- package/dist/hono/connection-input.d.ts +170 -12
- package/dist/hono/connection-input.d.ts.map +1 -1
- package/dist/hono/connection-input.js +166 -14
- package/dist/hono/connection-input.js.map +1 -1
- package/dist/hono/connection-input.test.js +112 -9
- package/dist/hono/connection-input.test.js.map +1 -1
- package/dist/hono/convex.d.ts +8 -0
- package/dist/hono/convex.d.ts.map +1 -1
- package/dist/hono/convex.js +8 -0
- package/dist/hono/convex.js.map +1 -1
- package/dist/hono/convex.test.js +4 -1
- package/dist/hono/convex.test.js.map +1 -1
- package/dist/hono/credential-input.d.ts +39 -0
- package/dist/hono/credential-input.d.ts.map +1 -0
- package/dist/hono/credential-input.js +78 -0
- package/dist/hono/credential-input.js.map +1 -0
- package/dist/hono/credential-scrub.d.ts +42 -0
- package/dist/hono/credential-scrub.d.ts.map +1 -0
- package/dist/hono/credential-scrub.js +173 -0
- package/dist/hono/credential-scrub.js.map +1 -0
- package/dist/hono/credential-scrub.test.d.ts +2 -0
- package/dist/hono/credential-scrub.test.d.ts.map +1 -0
- package/dist/hono/credential-scrub.test.js +130 -0
- package/dist/hono/credential-scrub.test.js.map +1 -0
- package/dist/hono/env.d.ts +1 -0
- package/dist/hono/env.d.ts.map +1 -1
- package/dist/hono/env.js +2 -0
- package/dist/hono/env.js.map +1 -1
- package/dist/hono/flow-crypto.d.ts +2 -1
- package/dist/hono/flow-crypto.d.ts.map +1 -1
- package/dist/hono/flow-crypto.js +50 -26
- package/dist/hono/flow-crypto.js.map +1 -1
- package/dist/hono/flow-crypto.test.js +32 -0
- package/dist/hono/flow-crypto.test.js.map +1 -1
- package/dist/hono/flow-input-card-fields.test.d.ts +10 -0
- package/dist/hono/flow-input-card-fields.test.d.ts.map +1 -0
- package/dist/hono/flow-input-card-fields.test.js +26 -0
- package/dist/hono/flow-input-card-fields.test.js.map +1 -0
- package/dist/hono/flow-input-fields.test.js +1 -1
- package/dist/hono/flow-input-fields.test.js.map +1 -1
- package/dist/hono/flow-input.d.ts +23 -2
- package/dist/hono/flow-input.d.ts.map +1 -1
- package/dist/hono/flow-input.js +63 -14
- package/dist/hono/flow-input.js.map +1 -1
- package/dist/hono/flow-input.test.js +67 -11
- package/dist/hono/flow-input.test.js.map +1 -1
- package/dist/hono/jev.d.ts +16 -0
- package/dist/hono/jev.d.ts.map +1 -0
- package/dist/hono/jev.js +60 -0
- package/dist/hono/jev.js.map +1 -0
- package/dist/hono/jev.test.d.ts +2 -0
- package/dist/hono/jev.test.d.ts.map +1 -0
- package/dist/hono/jev.test.js +15 -0
- package/dist/hono/jev.test.js.map +1 -0
- package/dist/hono/knowledge-content.d.ts.map +1 -1
- package/dist/hono/knowledge-content.js +4 -2
- package/dist/hono/knowledge-content.js.map +1 -1
- package/dist/hono/knowledge-content.test.js +6 -5
- package/dist/hono/knowledge-content.test.js.map +1 -1
- package/dist/hono/mcp-servers.d.ts +8 -1
- package/dist/hono/mcp-servers.d.ts.map +1 -1
- package/dist/hono/mcp-servers.js +17 -6
- package/dist/hono/mcp-servers.js.map +1 -1
- package/dist/hono/mcp-servers.test.js +25 -0
- package/dist/hono/mcp-servers.test.js.map +1 -1
- package/dist/hono/model-capabilities.d.ts.map +1 -1
- package/dist/hono/model-capabilities.js +20 -9
- package/dist/hono/model-capabilities.js.map +1 -1
- package/dist/hono/model-capabilities.test.js +16 -8
- package/dist/hono/model-capabilities.test.js.map +1 -1
- package/dist/hono/oom-priority.agent.test.d.ts +2 -0
- package/dist/hono/oom-priority.agent.test.d.ts.map +1 -0
- package/dist/hono/oom-priority.agent.test.js +138 -0
- package/dist/hono/oom-priority.agent.test.js.map +1 -0
- package/dist/hono/oom-priority.d.ts +39 -0
- package/dist/hono/oom-priority.d.ts.map +1 -0
- package/dist/hono/oom-priority.js +138 -0
- package/dist/hono/oom-priority.js.map +1 -0
- package/dist/hono/oom-priority.test.d.ts +2 -0
- package/dist/hono/oom-priority.test.d.ts.map +1 -0
- package/dist/hono/oom-priority.test.js +52 -0
- package/dist/hono/oom-priority.test.js.map +1 -0
- package/dist/hono/openrouter-session.d.ts.map +1 -1
- package/dist/hono/openrouter-session.js +12 -1
- package/dist/hono/openrouter-session.js.map +1 -1
- package/dist/hono/openrouter-session.test.js +9 -3
- package/dist/hono/openrouter-session.test.js.map +1 -1
- package/dist/hono/prompt-context.d.ts +8 -1
- package/dist/hono/prompt-context.d.ts.map +1 -1
- package/dist/hono/prompt-context.js +45 -7
- package/dist/hono/prompt-context.js.map +1 -1
- package/dist/hono/prompt-context.test.js +32 -1
- package/dist/hono/prompt-context.test.js.map +1 -1
- package/dist/hono/publish-recovery.d.ts +1 -1
- package/dist/hono/publish-recovery.d.ts.map +1 -1
- package/dist/hono/publish-recovery.js +9 -6
- package/dist/hono/publish-recovery.js.map +1 -1
- package/dist/hono/publish-recovery.test.js +11 -2
- package/dist/hono/publish-recovery.test.js.map +1 -1
- package/dist/hono/relay.d.ts +10 -1
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +6 -0
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/sandbox-content.d.ts +2 -0
- package/dist/hono/sandbox-content.d.ts.map +1 -1
- package/dist/hono/sandbox-content.js +8 -4
- package/dist/hono/sandbox-content.js.map +1 -1
- package/dist/hono/sandbox-content.test.js +20 -1
- package/dist/hono/sandbox-content.test.js.map +1 -1
- package/dist/hono/server.d.ts.map +1 -1
- package/dist/hono/server.js +32 -0
- package/dist/hono/server.js.map +1 -1
- package/dist/hono/server.test.js +21 -1
- package/dist/hono/server.test.js.map +1 -1
- package/dist/hono/session-continuity.integration.test.js +10 -1
- package/dist/hono/session-continuity.integration.test.js.map +1 -1
- package/dist/hono/tag-fields.d.ts.map +1 -1
- package/dist/hono/tag-fields.js +2 -0
- package/dist/hono/tag-fields.js.map +1 -1
- package/dist/hono/tag-input.d.ts +124 -3
- package/dist/hono/tag-input.d.ts.map +1 -1
- package/dist/hono/tag-input.js +27 -17
- package/dist/hono/tag-input.js.map +1 -1
- package/dist/hono/tag-input.test.js +19 -1
- package/dist/hono/tag-input.test.js.map +1 -1
- package/dist/hono/tool-mentions.d.ts.map +1 -1
- package/dist/hono/tool-mentions.js +1 -0
- package/dist/hono/tool-mentions.js.map +1 -1
- package/dist/hono/tool-mentions.test.js +5 -0
- package/dist/hono/tool-mentions.test.js.map +1 -1
- package/dist/hono/types.d.ts +8 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/dist/hono/workspace-script.d.ts +10 -0
- package/dist/hono/workspace-script.d.ts.map +1 -0
- package/dist/hono/workspace-script.js +19 -0
- package/dist/hono/workspace-script.js.map +1 -0
- package/dist/hono/workspace-settle.d.ts +1 -1
- package/dist/hono/workspace-settle.d.ts.map +1 -1
- package/dist/hono/workspace-settle.js +12 -8
- package/dist/hono/workspace-settle.js.map +1 -1
- package/dist/review/digest.d.ts +8 -1
- package/dist/review/digest.d.ts.map +1 -1
- package/dist/review/digest.js +10 -43
- package/dist/review/digest.js.map +1 -1
- package/dist/review/digest.test.js +11 -6
- package/dist/review/digest.test.js.map +1 -1
- package/dist/review/evidence-block.js +1 -1
- package/dist/review/evidence-block.js.map +1 -1
- package/dist/review/evidence-block.test.js +0 -10
- package/dist/review/evidence-block.test.js.map +1 -1
- package/dist/review/shell-policy.d.ts +6 -0
- package/dist/review/shell-policy.d.ts.map +1 -1
- package/dist/review/shell-policy.js +240 -72
- package/dist/review/shell-policy.js.map +1 -1
- package/dist/review/shell-policy.test.js +114 -0
- package/dist/review/shell-policy.test.js.map +1 -1
- package/package.json +9 -5
- package/dist/hono/latitude-telemetry.d.ts +0 -17
- package/dist/hono/latitude-telemetry.d.ts.map +0 -1
- package/dist/hono/latitude-telemetry.js +0 -52
- package/dist/hono/latitude-telemetry.js.map +0 -1
- package/dist/hono/latitude-telemetry.test.d.ts +0 -2
- package/dist/hono/latitude-telemetry.test.d.ts.map +0 -1
- package/dist/hono/latitude-telemetry.test.js +0 -18
- package/dist/hono/latitude-telemetry.test.js.map +0 -1
package/dist/hono/bridge-job.js
CHANGED
|
@@ -11,15 +11,18 @@ import { avatarAwaitingItsFace, avatarCreatedInAssistantMessage, avatarHandleFro
|
|
|
11
11
|
import { accentContradictsUser } from "./avatar-accent.js";
|
|
12
12
|
import { AVATAR_CASTING_TOOL_NAME, normalizeAvatarCastingToolInput, } from "./avatar-casting.js";
|
|
13
13
|
import { asksForAvatarFace, FACE_QUESTION_MESSAGE } from "./avatar-face-question.js";
|
|
14
|
-
import { CONNECTION_INPUT_TOOL_NAME, CONNECTION_PLATFORMS, normalizeConnectionInputToolInput, } from "./connection-input.js";
|
|
14
|
+
import { CONNECTION_INPUT_TOOL_NAME, CONNECTION_PLATFORMS, connectedButNotLoaded, normalizeConnectionInputToolInput, toolsConnected, } from "./connection-input.js";
|
|
15
15
|
import { messageContextTokens, pickContextWindow, streamEventContextUsage, turnContextUsage, } from "./context-usage.js";
|
|
16
|
-
import {
|
|
16
|
+
import { CREDENTIAL_INPUT_TOOL_NAME, normalizeCredentialInputToolInput, } from "./credential-input.js";
|
|
17
|
+
import { credentialScrubHooks } from "./credential-scrub.js";
|
|
18
|
+
import { agentStatedFlowMessage, FLOW_INPUT_TOOL_NAME, nodeTargetRefusals, normalizeFlowInputToolInput, readRawFlowTree, sanitizeFlowRequests, unknownFlowPrefillMessage, } from "./flow-input.js";
|
|
17
19
|
import { writesInventedLogo } from "./invented-logo.js";
|
|
18
|
-
import {
|
|
20
|
+
import { jevJudge } from "./jev.js";
|
|
19
21
|
import { composioScopesToInvalidate, failedCustomServers, reportMcpInvalid, serversConnectedWithNoTools, } from "./mcp-servers.js";
|
|
20
22
|
import { agentModelOverride, autoCompactWindowForModel, betasForModel, contextWindowForModel, } from "./model-capabilities.js";
|
|
23
|
+
import { agentShellPrefixEnv, killFirstWrapper } from "./oom-priority.js";
|
|
21
24
|
import { BEDROCK_SERVABLE_CAPABILITIES, buildAgentExtraBody, EXTRA_BODY_ENV, MODEL_CAPABILITIES_ENV, } from "./openrouter-session.js";
|
|
22
|
-
import { currentReferenceReminder } from "./prompt-context.js";
|
|
25
|
+
import { credentialReminder, currentReferenceReminder } from "./prompt-context.js";
|
|
23
26
|
import { bridgeRuntimeFiles } from "./runtime-files.js";
|
|
24
27
|
import { applyCurrentSenderAttribution, buildCleanBoundary, buildRehydratedPrompt, compactionRetryAttempt, emptyInProgressSession, isContextOverflowError, isResumeSessionError, observeInProgressSession, prepareSessionAttempt, stallContinuationAttempt, } from "./session-continuity.js";
|
|
25
28
|
import { readSessionSkills } from "./session-skills.js";
|
|
@@ -44,6 +47,35 @@ export function parsePlanDecision(value) {
|
|
|
44
47
|
}
|
|
45
48
|
return null;
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* How long a mid-turn MCP reload may hold the card's answer. Connecting a
|
|
52
|
+
* handful of HTTP servers takes seconds; past this the tools arrive next
|
|
53
|
+
* message instead, and the turn goes on.
|
|
54
|
+
*/
|
|
55
|
+
const MCP_RELOAD_TIMEOUT_MS = 30_000;
|
|
56
|
+
/** The card's resolution, with what the reload did: ready now, or which servers would not start. */
|
|
57
|
+
function withReload(resolution, reload) {
|
|
58
|
+
const missing = reload?.ready ? connectedButNotLoaded(resolution, reload.loaded) : [];
|
|
59
|
+
const failed = [...(reload?.failed ?? []), ...missing];
|
|
60
|
+
return {
|
|
61
|
+
...resolution,
|
|
62
|
+
toolsReady: reload?.ready === true && missing.length === 0,
|
|
63
|
+
...(failed.length > 0 ? { failedToLoad: failed } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** The promise's value, or `undefined` once `ms` pass without one. */
|
|
67
|
+
async function settleWithin(promise, ms) {
|
|
68
|
+
let timer;
|
|
69
|
+
const timedOut = new Promise((resolve) => {
|
|
70
|
+
timer = setTimeout(() => resolve(undefined), ms);
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
return await Promise.race([promise, timedOut]);
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
clearTimeout(timer);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
47
79
|
/**
|
|
48
80
|
* The Agent SDK matches AskUserQuestion answers to their questions by the
|
|
49
81
|
* question TEXT (see `AskUserQuestionInput.answers`), but the dashboard submits
|
|
@@ -118,11 +150,10 @@ const BASE_DISALLOWED_TOOLS = [
|
|
|
118
150
|
//
|
|
119
151
|
// Since CLI 2.1.233 the CLI additionally withholds these from
|
|
120
152
|
// Sonnet-5-and-newer models — so on Opus 5.5 this list is now
|
|
121
|
-
// belt-and-braces. It is NOT redundant
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// production agent cannot see.
|
|
153
|
+
// belt-and-braces. It is NOT redundant: Haiku 4.5 predates that gate
|
|
154
|
+
// (read off the session's own `init` tool list on 2.1.239, it is offered
|
|
155
|
+
// all four and Opus 5 none), and any override naming it would hand that
|
|
156
|
+
// agent the backlog the production agent cannot see.
|
|
126
157
|
//
|
|
127
158
|
// `TodoWrite` is gone from both — it is absent from an SDK session's
|
|
128
159
|
// tool list on either model, so in-turn planning no longer has a tool
|
|
@@ -191,6 +222,16 @@ export function reviewQueryOptions(job) {
|
|
|
191
222
|
? { outputFormat: { type: "json_schema", schema: job.review.outputSchema }, hooks: reviewOutputHooks() }
|
|
192
223
|
: {};
|
|
193
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Every job's tool results pass through the credential scrub, appended after
|
|
227
|
+
* any other PostToolUse hook so its rewrite is the one the SDK keeps.
|
|
228
|
+
*/
|
|
229
|
+
function withCredentialScrub(options) {
|
|
230
|
+
const scrub = credentialScrubHooks();
|
|
231
|
+
const hooks = { ...(options.hooks ?? {}) };
|
|
232
|
+
hooks.PostToolUse = [...(hooks.PostToolUse ?? []), ...(scrub.PostToolUse ?? [])];
|
|
233
|
+
return { ...options, hooks };
|
|
234
|
+
}
|
|
194
235
|
/**
|
|
195
236
|
* The review runs on Baker's own OpenRouter credential and its own read-only
|
|
196
237
|
* key, both replacing whatever the Runtime was started with — the client never
|
|
@@ -217,6 +258,12 @@ export const REVIEW_DEBUG_LOG = "/tmp/baker-review-cli.jsonl";
|
|
|
217
258
|
// briefly; model activity cancels it (the CLI clearly isn't idle). Turns that
|
|
218
259
|
// never ran a task skip the delay entirely.
|
|
219
260
|
const DEFAULT_TURN_END_SETTLE_MS = 1_000;
|
|
261
|
+
// When the last task settles after the clean result, the CLI wakes the model on
|
|
262
|
+
// it and streams nothing until the woken turn's first token — seconds, and 30+
|
|
263
|
+
// on a slow route. Ending input inside that silence strands the woken turn on a
|
|
264
|
+
// closed channel, and the CLI's exit at its result kills anything it backgrounds
|
|
265
|
+
// (dev, Oct 2026: a render). A settle that wakes nobody waits this long once.
|
|
266
|
+
const DEFAULT_TURN_END_WAKE_MS = 45_000;
|
|
220
267
|
// After input ends, a healthy idle CLI exits within seconds. If the stream is
|
|
221
268
|
// still open past this window with no messages arriving, the CLI is wedged —
|
|
222
269
|
// close the query so the turn can finish instead of hanging to the watchdog.
|
|
@@ -244,10 +291,10 @@ const UNATTENDED_PROMPT_MESSAGE = "This run is unattended — it was started by
|
|
|
244
291
|
* asked for in a text prompt renders a question nobody can answer. In each case the user
|
|
245
292
|
* is left waiting for something that was never going to come.
|
|
246
293
|
*/
|
|
247
|
-
function refuseMalformedCall(toolName, input, userText, priorUserText) {
|
|
294
|
+
async function refuseMalformedCall(toolName, input, judge, userText, priorUserText) {
|
|
248
295
|
if (toolName === "Bash") {
|
|
249
296
|
const command = typeof input?.command === "string" ? input.command : undefined;
|
|
250
|
-
return toolRunAsCommand(command) ?? accentContradictsUser(command, userText, priorUserText);
|
|
297
|
+
return toolRunAsCommand(command) ?? (await accentContradictsUser(command, userText, priorUserText, judge));
|
|
251
298
|
}
|
|
252
299
|
if (toolName === "Agent" || toolName === "Task") {
|
|
253
300
|
return blockingToolDelegated(typeof input?.prompt === "string" ? input.prompt : undefined);
|
|
@@ -255,11 +302,18 @@ function refuseMalformedCall(toolName, input, userText, priorUserText) {
|
|
|
255
302
|
if (toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") {
|
|
256
303
|
return writesInventedLogo(typeof input?.file_path === "string" ? input.file_path : undefined);
|
|
257
304
|
}
|
|
258
|
-
if (toolName === "AskUserQuestion" && asksForAvatarFace(input)) {
|
|
305
|
+
if (toolName === "AskUserQuestion" && (await asksForAvatarFace(input, judge))) {
|
|
259
306
|
return FACE_QUESTION_MESSAGE;
|
|
260
307
|
}
|
|
261
308
|
return null;
|
|
262
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Whether this Runtime has Credentials: the backend sets `BAKER_CREDENTIALS=1`
|
|
312
|
+
* alongside the credential broker's proxy env. Read per turn, not at import.
|
|
313
|
+
*/
|
|
314
|
+
function credentialsEnabled() {
|
|
315
|
+
return process.env.BAKER_CREDENTIALS === "1";
|
|
316
|
+
}
|
|
263
317
|
/** Blocking prompts: every tool that would leave a card the backend parks on. */
|
|
264
318
|
function deniedUnattendedPrompt(toolName) {
|
|
265
319
|
return (toolName === "AskUserQuestion" ||
|
|
@@ -267,6 +321,7 @@ function deniedUnattendedPrompt(toolName) {
|
|
|
267
321
|
toolName === TAG_INPUT_TOOL_NAME ||
|
|
268
322
|
toolName === FLOW_INPUT_TOOL_NAME ||
|
|
269
323
|
toolName === CONNECTION_INPUT_TOOL_NAME ||
|
|
324
|
+
toolName === CREDENTIAL_INPUT_TOOL_NAME ||
|
|
270
325
|
toolName === AVATAR_CASTING_TOOL_NAME);
|
|
271
326
|
}
|
|
272
327
|
export class StreamStallError extends Error {
|
|
@@ -343,8 +398,7 @@ function enrichImageError(message) {
|
|
|
343
398
|
return `${message} — likely a file whose extension lies about its format (e.g. PNG renamed .jpg) or a corrupted download. Run the image validator and check magic bytes with \`file <path>\`.`;
|
|
344
399
|
}
|
|
345
400
|
/**
|
|
346
|
-
* Which hooks a job runs. The client's agent runs the workspace's own
|
|
347
|
-
* traced to Latitude. A Session review runs none: every workspace hook is
|
|
401
|
+
* Which hooks a job runs. The client's agent runs the workspace's own. A Session review runs none: every workspace hook is
|
|
348
402
|
* written for the client's agent, and in the reviewer they speak about "this
|
|
349
403
|
* Session" with the review's read-scoped key. The SessionStart probes are
|
|
350
404
|
* refused on full-scope routes, and the reviewer filed its own "status unknown"
|
|
@@ -361,12 +415,11 @@ function hookSettingsForJob(job) {
|
|
|
361
415
|
if (job.review) {
|
|
362
416
|
return { disableAllHooks: true, permissions: { ask: ["Bash"] } };
|
|
363
417
|
}
|
|
364
|
-
|
|
365
|
-
return hooks ? { hooks } : {};
|
|
418
|
+
return {};
|
|
366
419
|
}
|
|
367
420
|
// Carry a Runtime-wide model override down to the fan-out workers.
|
|
368
421
|
//
|
|
369
|
-
// The shared subagents pin themselves to Sonnet 5 in their own frontmatter (see
|
|
422
|
+
// The shared subagents pin themselves to Sonnet 5.5 in their own frontmatter (see
|
|
370
423
|
// `DEFAULT_MODEL`). Since CLI 2.1.251 `CLAUDE_CODE_SUBAGENT_MODEL` is only the
|
|
371
424
|
// default beneath that pin; `CLAUDE_CODE_SUBAGENT_MODEL_FORCE` (2.1.257) makes it
|
|
372
425
|
// win over the frontmatter and any per-spawn model again. Absent (production),
|
|
@@ -660,6 +713,11 @@ export function createStallDetector(input) {
|
|
|
660
713
|
timer.unref?.();
|
|
661
714
|
return {
|
|
662
715
|
observeMessage: (msg) => {
|
|
716
|
+
// A tool's progress says nothing about the model: a background task's
|
|
717
|
+
// heartbeat arrives while the model's stream is stalled.
|
|
718
|
+
if (msg.type === "tool_progress") {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
663
721
|
lastMessageAt = input.now();
|
|
664
722
|
trackPendingToolUses(pendingToolUses, msg);
|
|
665
723
|
awaitingModel = (msg.type === "user" || msg.type === "stream_event") && pendingToolUses.size === 0;
|
|
@@ -788,7 +846,7 @@ beforeEndInput) {
|
|
|
788
846
|
}, timings.exitGuardMs);
|
|
789
847
|
exitGuard.unref?.();
|
|
790
848
|
};
|
|
791
|
-
const scheduleEnd = () => {
|
|
849
|
+
const scheduleEnd = (delayMs = timings.settleMs) => {
|
|
792
850
|
if (settleTimer) {
|
|
793
851
|
return;
|
|
794
852
|
}
|
|
@@ -800,7 +858,7 @@ beforeEndInput) {
|
|
|
800
858
|
endInput();
|
|
801
859
|
return;
|
|
802
860
|
}
|
|
803
|
-
settleTimer = setTimeout(endInput,
|
|
861
|
+
settleTimer = setTimeout(endInput, delayMs);
|
|
804
862
|
settleTimer.unref?.();
|
|
805
863
|
};
|
|
806
864
|
return {
|
|
@@ -866,7 +924,7 @@ beforeEndInput) {
|
|
|
866
924
|
// second result) would strand the turn until the watchdog. An emptied
|
|
867
925
|
// background_tasks_changed level counts as a settle the same way.
|
|
868
926
|
if (lastWasTaskLifecycle && cleanResultSeen && !hasInFlightWork()) {
|
|
869
|
-
scheduleEnd();
|
|
927
|
+
scheduleEnd(timings.wakeMs);
|
|
870
928
|
}
|
|
871
929
|
},
|
|
872
930
|
hasInFlightWork,
|
|
@@ -959,12 +1017,14 @@ export class BridgeJobExecutor {
|
|
|
959
1017
|
stallCheckIntervalMs;
|
|
960
1018
|
recordTurnEvent;
|
|
961
1019
|
turnEndSettleMs;
|
|
1020
|
+
turnEndWakeMs;
|
|
962
1021
|
turnEndExitGuardMs;
|
|
963
1022
|
now;
|
|
964
1023
|
readUsageBaseline;
|
|
965
1024
|
stalledCliExitMs;
|
|
966
1025
|
readFlowTree;
|
|
967
1026
|
settleWorkspace;
|
|
1027
|
+
judge;
|
|
968
1028
|
constructor(dependencies) {
|
|
969
1029
|
this.sdk = dependencies.sdk;
|
|
970
1030
|
this.relay = dependencies.relay;
|
|
@@ -977,6 +1037,7 @@ export class BridgeJobExecutor {
|
|
|
977
1037
|
this.stallCheckIntervalMs = dependencies.stallCheckIntervalMs ?? DEFAULT_STALL_CHECK_INTERVAL_MS;
|
|
978
1038
|
this.recordTurnEvent = dependencies.recordTurnEvent ?? recordTurnEvent;
|
|
979
1039
|
this.turnEndSettleMs = dependencies.turnEndSettleMs ?? DEFAULT_TURN_END_SETTLE_MS;
|
|
1040
|
+
this.turnEndWakeMs = dependencies.turnEndWakeMs ?? DEFAULT_TURN_END_WAKE_MS;
|
|
980
1041
|
this.turnEndExitGuardMs = dependencies.turnEndExitGuardMs ?? DEFAULT_TURN_END_EXIT_GUARD_MS;
|
|
981
1042
|
this.now = dependencies.now ?? Date.now;
|
|
982
1043
|
this.readUsageBaseline =
|
|
@@ -986,6 +1047,7 @@ export class BridgeJobExecutor {
|
|
|
986
1047
|
this.settleWorkspace = dependencies.settleWorkspace ?? (() => settleWorkspaceAfterTasks());
|
|
987
1048
|
this.readFlowTree =
|
|
988
1049
|
dependencies.readFlowTree ?? ((flowSlug) => readRawFlowTree(bridgeRuntimeFiles.flowsDir(), flowSlug));
|
|
1050
|
+
this.judge = dependencies.judge ?? jevJudge(process.env.OPENROUTER_API_KEY);
|
|
989
1051
|
}
|
|
990
1052
|
async execute(job, controls) {
|
|
991
1053
|
const state = createBridgeJobState();
|
|
@@ -1058,7 +1120,11 @@ export class BridgeJobExecutor {
|
|
|
1058
1120
|
const verbatim = verbatimSlashCommand(job.prompt) ??
|
|
1059
1121
|
leadingSkillCommand(job.prompt, (await readSessionSkills(bridgeRuntimeFiles.projectRoot())) ?? []);
|
|
1060
1122
|
let requestPrompt = verbatim ?? applyCurrentSenderAttribution(job.prompt, job.currentSender);
|
|
1061
|
-
const
|
|
1123
|
+
const reminders = [
|
|
1124
|
+
verbatim === null ? currentReferenceReminder(job.currentReference) : undefined,
|
|
1125
|
+
credentialReminder(job.credentials ?? [], credentialsEnabled()),
|
|
1126
|
+
].filter((text) => text !== undefined);
|
|
1127
|
+
const reminder = reminders.length > 0 ? reminders.join("\n\n") : undefined;
|
|
1062
1128
|
if (job.attachments && job.attachments.length > 0) {
|
|
1063
1129
|
requestPrompt += await this.prepareAttachments(job.attachments, "message");
|
|
1064
1130
|
}
|
|
@@ -1315,6 +1381,39 @@ export class BridgeJobExecutor {
|
|
|
1315
1381
|
return undefined;
|
|
1316
1382
|
}
|
|
1317
1383
|
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Load what the user just connected into the running query, so its tools
|
|
1386
|
+
* answer in this turn instead of the next. Asks Convex for the whole set
|
|
1387
|
+
* afresh (the same set the next turn starts from, so the tool list changes
|
|
1388
|
+
* once, not twice) and hands it to the CLI with `baker_ui` kept — the SDK
|
|
1389
|
+
* drops any in-process server missing from the call, and `baker_ui` is the
|
|
1390
|
+
* server whose tool call is resolving right now. Never throws. A server the
|
|
1391
|
+
* CLI could not start is named, because it will not start next message
|
|
1392
|
+
* either; anything else that goes wrong here loads next message.
|
|
1393
|
+
*/
|
|
1394
|
+
async reloadMcpServers(job, query) {
|
|
1395
|
+
const notReady = { ready: false, loaded: [], failed: [] };
|
|
1396
|
+
if (!this.mcpServersProvider || !query.setMcpServers) {
|
|
1397
|
+
return notReady;
|
|
1398
|
+
}
|
|
1399
|
+
try {
|
|
1400
|
+
const servers = await this.mcpServersProvider(job.threadId, job.currentSender?.userId, { fresh: true });
|
|
1401
|
+
if (!servers) {
|
|
1402
|
+
return notReady;
|
|
1403
|
+
}
|
|
1404
|
+
const result = await settleWithin(query.setMcpServers({ ...servers, baker_ui: createBakerUiServer({ credentials: credentialsEnabled() }) }), MCP_RELOAD_TIMEOUT_MS);
|
|
1405
|
+
const failed = Object.keys(result?.errors ?? {});
|
|
1406
|
+
if (failed.length > 0) {
|
|
1407
|
+
console.error(`[mcp] reload after a connection could not start ${failed.join(", ")}`);
|
|
1408
|
+
}
|
|
1409
|
+
const loaded = Object.keys(servers).filter((name) => !failed.includes(name));
|
|
1410
|
+
return { ready: result !== undefined && failed.length === 0, loaded, failed };
|
|
1411
|
+
}
|
|
1412
|
+
catch (error) {
|
|
1413
|
+
console.error(`[mcp] reload after a connection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1414
|
+
return notReady;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1318
1417
|
reportMcpFailures(job, msg) {
|
|
1319
1418
|
for (const scope of composioScopesToInvalidate(msg)) {
|
|
1320
1419
|
void reportMcpInvalid(job.threadId, { scope }, job.currentSender?.userId);
|
|
@@ -1334,7 +1433,7 @@ export class BridgeJobExecutor {
|
|
|
1334
1433
|
* handlers — except on an unattended turn, where there is nobody to answer and
|
|
1335
1434
|
* every one of them is refused up front (see `UNATTENDED_PROMPT_MESSAGE`).
|
|
1336
1435
|
*/
|
|
1337
|
-
routeToolUse(job, controls, toolName, input, opts) {
|
|
1436
|
+
async routeToolUse(job, controls, toolName, input, opts) {
|
|
1338
1437
|
const refusedShell = reviewShellRefusal(job, toolName, input);
|
|
1339
1438
|
if (refusedShell) {
|
|
1340
1439
|
return Promise.resolve({ behavior: "deny", message: refusedShell });
|
|
@@ -1350,9 +1449,9 @@ export class BridgeJobExecutor {
|
|
|
1350
1449
|
});
|
|
1351
1450
|
return Promise.resolve({ behavior: "deny", message: UNATTENDED_PROMPT_MESSAGE });
|
|
1352
1451
|
}
|
|
1353
|
-
const malformed = refuseMalformedCall(toolName, input, job.prompt, userTurnsBefore(job));
|
|
1452
|
+
const malformed = await refuseMalformedCall(toolName, input, this.judge, job.prompt, userTurnsBefore(job));
|
|
1354
1453
|
if (malformed)
|
|
1355
|
-
return
|
|
1454
|
+
return { behavior: "deny", message: malformed };
|
|
1356
1455
|
// Cast what is owed FIRST, whatever comes next — including another create. Checked
|
|
1357
1456
|
// the other way round, a second create (the agent retrying after a rejected flag,
|
|
1358
1457
|
// which is what happens in practice) would overwrite the handle and the first
|
|
@@ -1405,6 +1504,15 @@ export class BridgeJobExecutor {
|
|
|
1405
1504
|
if (toolName === CONNECTION_INPUT_TOOL_NAME) {
|
|
1406
1505
|
return this.handleConnectionInputRequest(job, controls, input, opts.toolUseID, opts.signal);
|
|
1407
1506
|
}
|
|
1507
|
+
if (toolName === CREDENTIAL_INPUT_TOOL_NAME) {
|
|
1508
|
+
if (!credentialsEnabled()) {
|
|
1509
|
+
return Promise.resolve({
|
|
1510
|
+
behavior: "deny",
|
|
1511
|
+
message: "Saved credentials are not available in this workspace. Ask the user to share what you need another way, and never ask them to paste a password or key into the chat.",
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
return this.handleCredentialInputRequest(job, controls, input, opts.toolUseID, opts.signal);
|
|
1515
|
+
}
|
|
1408
1516
|
if (toolName === AVATAR_CASTING_TOOL_NAME) {
|
|
1409
1517
|
return this.handleAvatarCastingRequest(job, controls, input, opts.toolUseID, opts.signal);
|
|
1410
1518
|
}
|
|
@@ -1443,6 +1551,10 @@ export class BridgeJobExecutor {
|
|
|
1443
1551
|
// warning to the user. Pinning it takes that threshold out of remote control.
|
|
1444
1552
|
// See `autoCompactWindowForModel` for the full chain and its ceiling.
|
|
1445
1553
|
...(autoCompactWindow !== undefined ? { autoCompactWindow } : {}),
|
|
1554
|
+
// Subagents, workflows and helper requests default to a 5-minute prompt
|
|
1555
|
+
// cache outside a Claude subscription, so a subagent waiting on a render
|
|
1556
|
+
// longer than that rewrites its whole prefix on the next call.
|
|
1557
|
+
subagentPromptCacheTtl: "1h",
|
|
1446
1558
|
// SDK rejects autoMemoryDirectory from project settings for security; must use settings tier. Gate on BAKER_CHAT_ID so local dev never writes into the monorepo.
|
|
1447
1559
|
...(process.env.BAKER_CHAT_ID
|
|
1448
1560
|
? {
|
|
@@ -1475,11 +1587,8 @@ export class BridgeJobExecutor {
|
|
|
1475
1587
|
settingSources: ["project"],
|
|
1476
1588
|
// `baker_ui` hosts in-process interactive dashboard tools (secure tag
|
|
1477
1589
|
// form). Always present; HTTP (Composio) servers merge alongside it.
|
|
1478
|
-
mcpServers: { ...(mcpServers ?? {}), baker_ui: createBakerUiServer() },
|
|
1479
|
-
|
|
1480
|
-
// `settings` to the CLI whenever it is present, so an empty object still
|
|
1481
|
-
// becomes a `--settings {}` flag tier for the CLI to parse.
|
|
1482
|
-
...(Object.keys(settings).length > 0 ? { settings } : {}),
|
|
1590
|
+
mcpServers: { ...(mcpServers ?? {}), baker_ui: createBakerUiServer({ credentials: credentialsEnabled() }) },
|
|
1591
|
+
settings,
|
|
1483
1592
|
includePartialMessages: true,
|
|
1484
1593
|
// Only the workspace's own skills. Omitting the option is NOT "skills
|
|
1485
1594
|
// off" — the CLI's defaults still load its built-in developer skills
|
|
@@ -1488,8 +1597,11 @@ export class BridgeJobExecutor {
|
|
|
1488
1597
|
// the workspace could not be read; omit rather than allowlist nothing.
|
|
1489
1598
|
...(skills ? { skills } : {}),
|
|
1490
1599
|
disallowedTools: disallowedToolsFor(job),
|
|
1491
|
-
...reviewQueryOptions(job),
|
|
1492
|
-
|
|
1600
|
+
...withCredentialScrub(reviewQueryOptions(job)),
|
|
1601
|
+
// Never omitted: since SDK 0.3.286 an omitted mode starts a third-party-provider
|
|
1602
|
+
// session (OpenRouter) in auto mode, where a classifier rather than `canUseTool`
|
|
1603
|
+
// decides tool calls.
|
|
1604
|
+
permissionMode: job.planMode ? "plan" : "default",
|
|
1493
1605
|
canUseTool: (toolName, input, opts) => this.routeToolUse(job, controls, toolName, input, opts),
|
|
1494
1606
|
// No `fallbackModel`, and no server-side refusal `fallbacks` in the extra
|
|
1495
1607
|
// body: the CLI's refusal fallback is gated on a first-party base URL (see
|
|
@@ -1513,6 +1625,13 @@ export class BridgeJobExecutor {
|
|
|
1513
1625
|
// system-reminder repeatedly pushed the agent toward that ephemeral
|
|
1514
1626
|
// backlog instead of the product's own Tasks (`baker actions`).
|
|
1515
1627
|
CLAUDE_CODE_ENABLE_TASKS: "0",
|
|
1628
|
+
// Every Bash command runs through a wrapper that makes it, not the agent
|
|
1629
|
+
// or the credential broker, what the OOM killer takes first (oom-priority.ts).
|
|
1630
|
+
...agentShellPrefixEnv(killFirstWrapper(), process.env),
|
|
1631
|
+
// The CLI clamps any Bash timeout to 10 minutes unless told otherwise;
|
|
1632
|
+
// the workspace's `inject-timeouts` hook gives a render up to 30, and at
|
|
1633
|
+
// the clamp the render was moved to the background mid-repair.
|
|
1634
|
+
BASH_MAX_TIMEOUT_MS: String(30 * 60_000),
|
|
1516
1635
|
// `citty` writes ANSI escapes into `baker --help` unconditionally —
|
|
1517
1636
|
// they are never TTY-gated, so every help read the agent does inside
|
|
1518
1637
|
// the sandbox pays ~5-10% of its tokens on colour codes it can't see.
|
|
@@ -1534,6 +1653,7 @@ export class BridgeJobExecutor {
|
|
|
1534
1653
|
...attempt.resumeOptions,
|
|
1535
1654
|
};
|
|
1536
1655
|
const query = this.sdk.query({ prompt: attempt.prompt, reminder: attempt.reminder, options });
|
|
1656
|
+
controls.reloadMcpServers = () => this.reloadMcpServers(job, query);
|
|
1537
1657
|
let queryClosed = false;
|
|
1538
1658
|
const closeQuery = () => {
|
|
1539
1659
|
if (queryClosed) {
|
|
@@ -1555,6 +1675,7 @@ export class BridgeJobExecutor {
|
|
|
1555
1675
|
throw error;
|
|
1556
1676
|
}
|
|
1557
1677
|
finally {
|
|
1678
|
+
controls.reloadMcpServers = undefined;
|
|
1558
1679
|
controls.abortSignal.removeEventListener("abort", closeQuery);
|
|
1559
1680
|
// Release the held-open input if the turn-end policy never fired (the
|
|
1560
1681
|
// stream ended on its own, or an error path closed the query). Idempotent.
|
|
@@ -1585,7 +1706,7 @@ export class BridgeJobExecutor {
|
|
|
1585
1706
|
// A reading that answers after the query drained (past its timeout) belongs
|
|
1586
1707
|
// to a query already folded into the turn — and a retry reuses `state`.
|
|
1587
1708
|
let drained = false;
|
|
1588
|
-
const turnEnd = createTurnEndController(job, query, closeQuery, { settleMs: this.turnEndSettleMs, exitGuardMs: this.turnEndExitGuardMs }, this.recordTurnEvent, async () => {
|
|
1709
|
+
const turnEnd = createTurnEndController(job, query, closeQuery, { settleMs: this.turnEndSettleMs, wakeMs: this.turnEndWakeMs, exitGuardMs: this.turnEndExitGuardMs }, this.recordTurnEvent, async () => {
|
|
1589
1710
|
const reading = await query.usage?.();
|
|
1590
1711
|
if (reading && !drained) {
|
|
1591
1712
|
settledCostUsd = recordCumulativeUsage(state, reading);
|
|
@@ -1693,6 +1814,7 @@ export class BridgeJobExecutor {
|
|
|
1693
1814
|
controls.pendingTagInputs.size > 0 ||
|
|
1694
1815
|
controls.pendingFlowInputs.size > 0 ||
|
|
1695
1816
|
controls.pendingConnectionInputs.size > 0 ||
|
|
1817
|
+
controls.pendingCredentialInputs.size > 0 ||
|
|
1696
1818
|
controls.pendingAvatarCastings.size > 0,
|
|
1697
1819
|
onStall: () => {
|
|
1698
1820
|
console.error(`[BridgeJob] no stream data for ${this.stallTimeoutMs}ms while awaiting the model — closing query for retry (thread ${job.threadId})`);
|
|
@@ -2121,6 +2243,16 @@ export class BridgeJobExecutor {
|
|
|
2121
2243
|
// Strip any secret values the model tried to prefill; their names still reach
|
|
2122
2244
|
// the user as requested fields. The backend strips again.
|
|
2123
2245
|
const sanitizedRequests = sanitizeFlowRequests(requests);
|
|
2246
|
+
// A key the card does not render is dropped there without a word, and the
|
|
2247
|
+
// person retypes what the agent already knew — refuse it before the card opens.
|
|
2248
|
+
const stated = agentStatedFlowMessage(sanitizedRequests);
|
|
2249
|
+
if (stated) {
|
|
2250
|
+
return { behavior: "deny", message: stated };
|
|
2251
|
+
}
|
|
2252
|
+
const unknownPrefill = unknownFlowPrefillMessage(sanitizedRequests);
|
|
2253
|
+
if (unknownPrefill) {
|
|
2254
|
+
return { behavior: "deny", message: unknownPrefill };
|
|
2255
|
+
}
|
|
2124
2256
|
const posted = await this.relay.flowInputRequest(target, { toolUseId, requests: sanitizedRequests });
|
|
2125
2257
|
if (!posted) {
|
|
2126
2258
|
console.error(`[request_flow_input] failed to post flow-input-request for ${toolUseId} — denying to avoid a hang`);
|
|
@@ -2171,7 +2303,7 @@ export class BridgeJobExecutor {
|
|
|
2171
2303
|
if (connections.length === 0) {
|
|
2172
2304
|
return {
|
|
2173
2305
|
behavior: "deny",
|
|
2174
|
-
message: `request_connection requires \`connections: [...]\` with at least one entry { platform, reason }
|
|
2306
|
+
message: `request_connection requires \`connections: [...]\` with at least one entry: { platform, reason } where platform is one of ${CONNECTION_PLATFORMS.join(", ")}; { server: { name, url, auth?, keyHeader?, scope? }, reason } for a remote MCP server; or { app, reason } for a managed app from \`baker mcp catalog\`. Retry with that shape.`,
|
|
2175
2307
|
};
|
|
2176
2308
|
}
|
|
2177
2309
|
const posted = await this.relay.connectionInputRequest(target, { toolUseId, connections });
|
|
@@ -2193,7 +2325,43 @@ export class BridgeJobExecutor {
|
|
|
2193
2325
|
return { behavior: "deny", message: PROMPT_UNANSWERED_MESSAGE };
|
|
2194
2326
|
}
|
|
2195
2327
|
void this.relay.connectionInputResolved(target);
|
|
2196
|
-
|
|
2328
|
+
// Loaded before the tool answers, so the model's next request already
|
|
2329
|
+
// carries the new tools. Only when an app or server came through: a
|
|
2330
|
+
// platform adds no tool, and reloading for nothing rewrites the tool list.
|
|
2331
|
+
const resolution = toolsConnected(decision.value)
|
|
2332
|
+
? withReload(decision.value, await controls.reloadMcpServers?.())
|
|
2333
|
+
: decision.value;
|
|
2334
|
+
return { behavior: "allow", updatedInput: { connections, resolution } };
|
|
2335
|
+
}
|
|
2336
|
+
async handleCredentialInputRequest(job, controls, input, toolUseId, signal) {
|
|
2337
|
+
const target = { threadId: job.threadId, turnId: job.turnId };
|
|
2338
|
+
const request = normalizeCredentialInputToolInput(input);
|
|
2339
|
+
if (!request) {
|
|
2340
|
+
return {
|
|
2341
|
+
behavior: "deny",
|
|
2342
|
+
message: "request_credential requires { label, reason, allowedHosts: [...] } (and optionally a lowercase `name`). Retry with that shape.",
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
const posted = await this.relay.credentialInputRequest(target, { toolUseId, ...request });
|
|
2346
|
+
if (!posted) {
|
|
2347
|
+
console.error(`[request_credential] failed to post credential-input-request for ${toolUseId} — denying`);
|
|
2348
|
+
return {
|
|
2349
|
+
behavior: "deny",
|
|
2350
|
+
message: "The credential request could not be delivered to the dashboard — retry request_credential in a moment.",
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
const decision = await this.awaitPromptDecision({
|
|
2354
|
+
label: "request_credential",
|
|
2355
|
+
signal,
|
|
2356
|
+
controls,
|
|
2357
|
+
pending: controls.pendingCredentialInputs,
|
|
2358
|
+
toolUseId,
|
|
2359
|
+
});
|
|
2360
|
+
if (decision.kind === "unanswered") {
|
|
2361
|
+
return { behavior: "deny", message: PROMPT_UNANSWERED_MESSAGE };
|
|
2362
|
+
}
|
|
2363
|
+
void this.relay.credentialInputResolved(target);
|
|
2364
|
+
return { behavior: "allow", updatedInput: { ...request, resolution: decision.value } };
|
|
2197
2365
|
}
|
|
2198
2366
|
async handlePlanReview(job, controls, input, toolUseId, signal) {
|
|
2199
2367
|
const target = { threadId: job.threadId, turnId: job.turnId };
|