@sentry/junior 0.203.0 → 0.205.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/dist/agent-D4nu8MQV.js +17521 -0
- package/dist/agent-hooks-DXHpTJ4m.js +4042 -0
- package/dist/agent-runner-C04colea.js +678 -0
- package/dist/api/schema.d.ts +2736 -2639
- package/dist/api/schema.js +4 -169
- package/dist/api.d.ts +23 -17
- package/dist/api.js +3881 -5326
- package/dist/app-Cb776lL8.d.ts +247 -0
- package/dist/app.d.ts +4 -520
- package/dist/app.js +9524 -11875
- package/dist/auth-pause-state-C2P3guS1.js +168 -0
- package/dist/catalog-runtime-CXw3asJD.js +7 -0
- package/dist/checkpoint-CrViJ8Ps.js +2450 -0
- package/dist/cli/chat.d.ts +20 -0
- package/dist/cli/chat.js +229 -336
- package/dist/cli/check.d.ts +8 -0
- package/dist/cli/check.js +513 -806
- package/dist/cli/env.d.ts +13 -0
- package/dist/cli/env.js +63 -12
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.js +90 -159
- package/dist/cli/main.d.ts +6 -0
- package/dist/cli/main.js +43 -64
- package/dist/cli/plugins.d.ts +13 -0
- package/dist/cli/plugins.js +148 -227
- package/dist/cli/run.d.ts +16 -0
- package/dist/cli/run.js +52 -8
- package/dist/cli/snapshot-create.d.ts +4 -0
- package/dist/cli/snapshot-create.js +71 -125
- package/dist/cli/upgrade.d.ts +15 -0
- package/dist/cli/upgrade.js +232 -335
- package/dist/config-BOtJQ7Pc.js +941 -0
- package/dist/context-B45_WqVX.js +298 -0
- package/dist/conversation-privacy-BZRA6Pes.js +182 -0
- package/dist/conversation-work-C6y3T5Hx.js +51 -0
- package/dist/credential-sync-Bep34IB_.js +2661 -0
- package/dist/db-BeyXKJOI.d.ts +5 -0
- package/dist/destinations-BeBiJeEM.js +29 -0
- package/dist/execution-stats-B6lgWxCK.js +373 -0
- package/dist/executor-BlUhFL7_.js +721 -0
- package/dist/experimental-CIXf7Uye.js +46 -0
- package/dist/history-ClE4toxe.d.ts +32 -0
- package/dist/history-CqTuSAdI.js +441 -0
- package/dist/instrumentation.d.ts +3 -3
- package/dist/instrumentation.js +130 -176
- package/dist/job-queue-DLMqIK74.js +63 -0
- package/dist/logging-BMJzdDlP.js +1210 -0
- package/dist/model-profile-CZmVoGdX.js +49 -0
- package/dist/nitro.d.ts +31 -36
- package/dist/nitro.js +275 -456
- package/dist/oauth-callback-server-WwG5_Zgm.js +130 -0
- package/dist/oauth-relay-CdCnu80W.js +62 -0
- package/dist/package-discovery-7a9YqLhE.js +455 -0
- package/dist/pending-auth-CUbXq06G.js +185 -0
- package/dist/plugin-module-BKGOXca2.js +81 -0
- package/dist/plugins-BI9A1vKA.d.ts +95 -0
- package/dist/plugins-egKWjgue.js +99 -0
- package/dist/private-trace-result-BLvBjy_e.js +16 -0
- package/dist/profile-T0tXE4zu.js +861 -0
- package/dist/registry-BA0__8ai.js +1419 -0
- package/dist/reporting-schema-DosTN__Q.js +105 -0
- package/dist/resolve-bvD1ORdv.js +546 -0
- package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
- package/dist/runner-BXYxfIUL.js +392 -0
- package/dist/sandbox-egress-signals-ngEPjSEW.js +46 -0
- package/dist/schema-Rn8-XEaN.js +1140 -0
- package/dist/sentry-CD3SdJl-.js +26 -0
- package/dist/skills-DJOlYdBs.js +316 -0
- package/dist/spawn-h0R1bTEo.js +29 -0
- package/dist/stats-3YZn-Swi.js +2648 -0
- package/dist/store-C5qxF2ac.d.ts +208 -0
- package/dist/task-queue-CoXwd2eq.js +136 -0
- package/dist/task-runner-B2_mJZj0.js +639 -0
- package/dist/thread-state-CqZ1m-es.js +431 -0
- package/dist/turn-execution-fI6PZ0iI.js +47 -0
- package/dist/turn-lifecycle-CcnwrOcp.js +54 -0
- package/dist/usage-B5SfMb3H.js +296 -0
- package/dist/usage-schema-CKaDkH_j.js +20 -0
- package/dist/validation-DfWcvhuS.js +40 -0
- package/dist/vercel-queue-DIkVcfK4.js +167 -0
- package/dist/vercel.d.ts +6 -6
- package/dist/vercel.js +14 -6
- package/dist/version-CnXZ614E.d.ts +5 -0
- package/dist/version-oD-oPrbO.js +8 -0
- package/dist/version.d.ts +2 -4
- package/dist/version.js +2 -6
- package/dist/web-authorization-Crbzlmzo.js +76 -0
- package/dist/web-input-BOuq3oKK.js +494 -0
- package/dist/work-B91LQKHr.js +509 -0
- package/dist/worker-BcRRTe6k.js +625 -0
- package/package.json +9 -9
- package/dist/agent-hooks-GB2VPTNA.js +0 -51
- package/dist/catalog-runtime-UBLIWD3O.js +0 -14
- package/dist/chunk-2LYHWMR4.js +0 -46
- package/dist/chunk-352OWAZH.js +0 -320
- package/dist/chunk-3Y47VMHV.js +0 -6
- package/dist/chunk-3YJSKOWF.js +0 -164
- package/dist/chunk-4KSSKTQ5.js +0 -229
- package/dist/chunk-4UO6FK4G.js +0 -64
- package/dist/chunk-5AHX53NQ.js +0 -717
- package/dist/chunk-5J3E5FWA.js +0 -700
- package/dist/chunk-5PDAG6O3.js +0 -206
- package/dist/chunk-6Y5B5PEX.js +0 -80
- package/dist/chunk-7GWQ5S5R.js +0 -2086
- package/dist/chunk-7H2VZTWN.js +0 -103
- package/dist/chunk-7NL7T6VU.js +0 -406
- package/dist/chunk-A5L27LE4.js +0 -387
- package/dist/chunk-ADIAWL34.js +0 -81
- package/dist/chunk-ASTEMBKJ.js +0 -519
- package/dist/chunk-CEMMLV5L.js +0 -98
- package/dist/chunk-CM5HNV2W.js +0 -131
- package/dist/chunk-CRTRBBRI.js +0 -105
- package/dist/chunk-DA2KGZZI.js +0 -13
- package/dist/chunk-DIB4GX3G.js +0 -8
- package/dist/chunk-DKIJ2RP5.js +0 -68
- package/dist/chunk-DWPN6SCH.js +0 -172
- package/dist/chunk-EDKUFGPL.js +0 -64
- package/dist/chunk-ENY6SKIU.js +0 -1228
- package/dist/chunk-F4MGCZOX.js +0 -2943
- package/dist/chunk-FA6POGLH.js +0 -70
- package/dist/chunk-FSUR7GTG.js +0 -20475
- package/dist/chunk-GKEOHJL5.js +0 -1856
- package/dist/chunk-GMCB6W5Y.js +0 -333
- package/dist/chunk-IE2VPG7O.js +0 -1135
- package/dist/chunk-IZ5B5IHQ.js +0 -3656
- package/dist/chunk-JAL3CH4G.js +0 -27
- package/dist/chunk-KIIEUXD3.js +0 -1764
- package/dist/chunk-KXU4NIL7.js +0 -692
- package/dist/chunk-MTM5IFCY.js +0 -1190
- package/dist/chunk-N7TMSOZH.js +0 -235
- package/dist/chunk-NCEBK6PH.js +0 -36
- package/dist/chunk-NHJU2ZAL.js +0 -56
- package/dist/chunk-P6KTRNVC.js +0 -321
- package/dist/chunk-PDO5BLNM.js +0 -22
- package/dist/chunk-PDRNLLFT.js +0 -3295
- package/dist/chunk-PEQXYSSE.js +0 -45
- package/dist/chunk-PKEX2AQX.js +0 -198
- package/dist/chunk-PSJCGIGO.js +0 -1163
- package/dist/chunk-PZUSUL55.js +0 -506
- package/dist/chunk-R45M4TUS.js +0 -37
- package/dist/chunk-RC745GGZ.js +0 -122
- package/dist/chunk-SP3QKZXJ.js +0 -820
- package/dist/chunk-TXKUKMVO.js +0 -417
- package/dist/chunk-UE4GPWSD.js +0 -931
- package/dist/chunk-UIE3R5XU.js +0 -17
- package/dist/chunk-UXPG6ZIN.js +0 -84
- package/dist/chunk-VFUK3X5B.js +0 -50
- package/dist/chunk-VNMJWREK.js +0 -787
- package/dist/chunk-VZ7CSOX2.js +0 -706
- package/dist/chunk-WCNQJKFT.js +0 -10
- package/dist/chunk-WDZR3QQM.js +0 -135
- package/dist/chunk-WLYVJCHV.js +0 -1433
- package/dist/chunk-WS7NAFTM.js +0 -1520
- package/dist/chunk-X6GDDWQH.js +0 -60
- package/dist/chunk-XPDEYNQI.js +0 -102
- package/dist/chunk-XRW44VGM.js +0 -58
- package/dist/chunk-Y2CM7HXH.js +0 -111
- package/dist/chunk-Y7X25LFY.js +0 -15
- package/dist/conversation-work-VIOQ5ZF3.js +0 -54
- package/dist/db-NGDJV7YH.js +0 -26
- package/dist/discovery-DWVDM7UK.js +0 -44
- package/dist/experimental-P5FZM4CU.js +0 -12
- package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
- package/dist/oauth-relay-5XPVRPYB.js +0 -8
- package/dist/plugins-YTYJMMJF.js +0 -14
- package/dist/runner-ORTNSB2Q.js +0 -522
- package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
- package/dist/sentry-MB3NL3IR.js +0 -42
- package/dist/skills-H376WQOH.js +0 -27
- package/dist/spawn-T43WHLOS.js +0 -42
- package/dist/task-runner-LBZWF32V.js +0 -36
- package/dist/validation-REJLRKI6.js +0 -17
- package/dist/work-3KJ3RE76.js +0 -51
- package/dist/worker-QFEBU72E.js +0 -24
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
|
|
2
|
+
import { A as createAgentInvocationSchema, M as AgentInvocationLimitError, O as agentBindingSchema, f as PluginCredentialFailureError, j as AgentInvocationBusyError, k as agentInvocationSchema, tt as AuthorizationFlowDisabledError } from "./agent-D4nu8MQV.js";
|
|
3
|
+
import { Ct as getConversationEventStore, Dt as getSqlExecutor, Tt as getConversationStore } from "./agent-hooks-DXHpTJ4m.js";
|
|
4
|
+
import { f as juniorAgentBindings, p as juniorAgentInvocations } from "./executor-BlUhFL7_.js";
|
|
5
|
+
import { B as openConversationProjection, o as failTurnRecord, r as saveTurnCheckpoint, s as getTurnRecord, xt as getTerminalAssistantMessages } from "./checkpoint-CrViJ8Ps.js";
|
|
6
|
+
import { pt as appendAndEnqueueInboundMessage } from "./stats-3YZn-Swi.js";
|
|
7
|
+
import { _ as isTurnInputCommitLostError, h as getConversationTurnBoundaryError, p as TurnInputCommitLostError, s as getAssistantReplyText } from "./pending-auth-CUbXq06G.js";
|
|
8
|
+
import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-CcnwrOcp.js";
|
|
9
|
+
import { n as executeTurn, t as AgentRunError } from "./turn-execution-fI6PZ0iI.js";
|
|
10
|
+
import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState } from "./thread-state-CqZ1m-es.js";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { and, asc, count, eq, inArray } from "drizzle-orm";
|
|
14
|
+
//#region src/chat/agent-invocations/store.ts
|
|
15
|
+
const CREATE_LOCK_PREFIX = "junior:agent_invocation:create";
|
|
16
|
+
const TERMINAL_AGENT_INVOCATION_STATUSES = [
|
|
17
|
+
"blocked",
|
|
18
|
+
"completed",
|
|
19
|
+
"failed"
|
|
20
|
+
];
|
|
21
|
+
const NON_TERMINAL_AGENT_INVOCATION_STATUSES = [
|
|
22
|
+
"pending",
|
|
23
|
+
"running",
|
|
24
|
+
"awaiting_resume"
|
|
25
|
+
];
|
|
26
|
+
function stableId(prefix, ...parts) {
|
|
27
|
+
return `${prefix}:${createHash("sha256").update(parts.join("\0")).digest("hex").slice(0, 32)}`;
|
|
28
|
+
}
|
|
29
|
+
/** Return the stable identity for one retry-safe delegated task. */
|
|
30
|
+
function getAgentInvocationId(parentConversationId, idempotencyKey) {
|
|
31
|
+
return stableId("agent-invocation", parentConversationId, idempotencyKey);
|
|
32
|
+
}
|
|
33
|
+
/** Return the stable child identity for one invocation without a named binding. */
|
|
34
|
+
function getUnnamedAgentConversationId(invocationId) {
|
|
35
|
+
return stableId("agent", invocationId);
|
|
36
|
+
}
|
|
37
|
+
/** Return the stable child identity for one named binding. */
|
|
38
|
+
function getNamedAgentConversationId(parentConversationId, name) {
|
|
39
|
+
return stableId("agent", parentConversationId, name);
|
|
40
|
+
}
|
|
41
|
+
/** Return the stable turn identity advanced by one agent invocation. */
|
|
42
|
+
function getAgentInvocationTurnId(invocationId) {
|
|
43
|
+
return `agent-invocation:${invocationId}`;
|
|
44
|
+
}
|
|
45
|
+
/** Return the stable mailbox identity for one agent invocation. */
|
|
46
|
+
function getAgentInvocationMessageId(invocationId) {
|
|
47
|
+
return `agent-invocation:${invocationId}:input`;
|
|
48
|
+
}
|
|
49
|
+
function bindingFromRow(row) {
|
|
50
|
+
return agentBindingSchema.parse({
|
|
51
|
+
childConversationId: row.childConversationId,
|
|
52
|
+
name: row.name,
|
|
53
|
+
parentConversationId: row.parentConversationId
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function invocationFromRow(row) {
|
|
57
|
+
return agentInvocationSchema.parse({
|
|
58
|
+
actor: row.actor,
|
|
59
|
+
...row.agentName ? { agentName: row.agentName } : void 0,
|
|
60
|
+
childConversationId: row.childConversationId,
|
|
61
|
+
createdAtMs: row.createdAt.getTime(),
|
|
62
|
+
...row.credentialContext ? { credentialContext: row.credentialContext } : void 0,
|
|
63
|
+
destination: row.destination,
|
|
64
|
+
...row.errorMessage !== null ? { errorMessage: row.errorMessage } : void 0,
|
|
65
|
+
input: row.input,
|
|
66
|
+
invocationId: row.invocationId,
|
|
67
|
+
mailboxStatus: row.mailboxStatus,
|
|
68
|
+
parentConversationId: row.parentConversationId,
|
|
69
|
+
...row.reasoningLevel ? { reasoningLevel: row.reasoningLevel } : void 0,
|
|
70
|
+
...row.result !== null ? { result: row.result } : void 0,
|
|
71
|
+
source: row.source,
|
|
72
|
+
status: row.status,
|
|
73
|
+
...row.terminalAt ? { terminalAtMs: row.terminalAt.getTime() } : void 0,
|
|
74
|
+
updatedAtMs: row.updatedAt.getTime()
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Require every durable creation input to match before replaying one key. */
|
|
78
|
+
function sameCreateInput(invocation, input) {
|
|
79
|
+
return invocation.parentConversationId === input.parentConversationId && invocation.agentName === input.agentName && invocation.input === input.input && invocation.reasoningLevel === input.reasoningLevel && JSON.stringify(invocation.actor) === JSON.stringify(input.actor) && JSON.stringify(invocation.credentialContext) === JSON.stringify(input.credentialContext) && JSON.stringify(invocation.destination) === JSON.stringify(input.destination);
|
|
80
|
+
}
|
|
81
|
+
/** Read one named child binding in its parent-agent scope. */
|
|
82
|
+
async function getAgentBinding(args) {
|
|
83
|
+
const rows = await getSqlExecutor().db().select().from(juniorAgentBindings).where(and(eq(juniorAgentBindings.parentConversationId, args.parentConversationId), eq(juniorAgentBindings.name, args.name)));
|
|
84
|
+
return rows[0] ? bindingFromRow(rows[0]) : void 0;
|
|
85
|
+
}
|
|
86
|
+
/** Read one durable agent invocation. */
|
|
87
|
+
async function getAgentInvocation(invocationId) {
|
|
88
|
+
const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.invocationId, invocationId));
|
|
89
|
+
return rows[0] ? invocationFromRow(rows[0]) : void 0;
|
|
90
|
+
}
|
|
91
|
+
/** Resolve the single invocation that may resume for one child conversation. */
|
|
92
|
+
async function getActiveAgentInvocationForConversation(childConversationId) {
|
|
93
|
+
const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.childConversationId, childConversationId), inArray(juniorAgentInvocations.status, ["running", "awaiting_resume"]))).orderBy(asc(juniorAgentInvocations.createdAt)).limit(2);
|
|
94
|
+
if (rows.length > 1) throw new Error(`Child conversation ${childConversationId} has multiple active agent invocations`);
|
|
95
|
+
return rows[0] ? invocationFromRow(rows[0]) : void 0;
|
|
96
|
+
}
|
|
97
|
+
async function getNonTerminalAgentInvocationForConversation(childConversationId) {
|
|
98
|
+
const rows = await getSqlExecutor().db().select().from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.childConversationId, childConversationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))).orderBy(asc(juniorAgentInvocations.createdAt)).limit(1);
|
|
99
|
+
return rows[0] ? invocationFromRow(rows[0]) : void 0;
|
|
100
|
+
}
|
|
101
|
+
async function countNonTerminalAgentInvocationsForParent(parentConversationId) {
|
|
102
|
+
return (await getSqlExecutor().db().select({ value: count() }).from(juniorAgentInvocations).where(and(eq(juniorAgentInvocations.parentConversationId, parentConversationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES))))[0]?.value ?? 0;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create or replay one invocation, reusing named child conversations and
|
|
106
|
+
* keeping unnamed child identities scoped to the invocation.
|
|
107
|
+
*/
|
|
108
|
+
async function createAgentInvocation(rawInput, nowMs = Date.now()) {
|
|
109
|
+
const input = createAgentInvocationSchema.parse(rawInput);
|
|
110
|
+
const invocationId = getAgentInvocationId(input.parentConversationId, input.idempotencyKey);
|
|
111
|
+
const childConversationId = input.agentName ? getNamedAgentConversationId(input.parentConversationId, input.agentName) : getUnnamedAgentConversationId(invocationId);
|
|
112
|
+
const lockName = `${CREATE_LOCK_PREFIX}:${input.parentConversationId}`;
|
|
113
|
+
return await getSqlExecutor().withLock(lockName, async () => {
|
|
114
|
+
const existing = await getAgentInvocation(invocationId);
|
|
115
|
+
if (existing) {
|
|
116
|
+
if (!sameCreateInput(existing, input)) throw new Error(`Agent invocation idempotency key was reused with different input for ${invocationId}`);
|
|
117
|
+
return existing;
|
|
118
|
+
}
|
|
119
|
+
if (await countNonTerminalAgentInvocationsForParent(input.parentConversationId) >= 8) throw new AgentInvocationLimitError(8);
|
|
120
|
+
await getConversationStore().createChild({
|
|
121
|
+
childConversationId,
|
|
122
|
+
parentConversationId: input.parentConversationId,
|
|
123
|
+
nowMs,
|
|
124
|
+
source: "internal"
|
|
125
|
+
});
|
|
126
|
+
if (input.agentName) {
|
|
127
|
+
await getSqlExecutor().db().insert(juniorAgentBindings).values({
|
|
128
|
+
childConversationId,
|
|
129
|
+
name: input.agentName,
|
|
130
|
+
parentConversationId: input.parentConversationId
|
|
131
|
+
}).onConflictDoNothing();
|
|
132
|
+
const binding = await getAgentBinding({
|
|
133
|
+
name: input.agentName,
|
|
134
|
+
parentConversationId: input.parentConversationId
|
|
135
|
+
});
|
|
136
|
+
if (!binding || binding.childConversationId !== childConversationId) throw new Error(`Named agent binding did not resolve to ${childConversationId}`);
|
|
137
|
+
if (await getNonTerminalAgentInvocationForConversation(childConversationId)) throw new AgentInvocationBusyError(input.agentName);
|
|
138
|
+
}
|
|
139
|
+
await getSqlExecutor().db().insert(juniorAgentInvocations).values({
|
|
140
|
+
invocationId,
|
|
141
|
+
parentConversationId: input.parentConversationId,
|
|
142
|
+
childConversationId,
|
|
143
|
+
agentName: input.agentName ?? null,
|
|
144
|
+
input: input.input,
|
|
145
|
+
actor: input.actor,
|
|
146
|
+
credentialContext: input.credentialContext ?? null,
|
|
147
|
+
source: { kind: "agent_invocation" },
|
|
148
|
+
destination: input.destination,
|
|
149
|
+
reasoningLevel: input.reasoningLevel ?? null,
|
|
150
|
+
status: "pending",
|
|
151
|
+
mailboxStatus: "pending",
|
|
152
|
+
createdAt: new Date(nowMs),
|
|
153
|
+
updatedAt: new Date(nowMs),
|
|
154
|
+
terminalAt: null
|
|
155
|
+
}).onConflictDoNothing();
|
|
156
|
+
const invocation = await getAgentInvocation(invocationId);
|
|
157
|
+
if (!invocation || !sameCreateInput(invocation, input)) throw new Error(`Agent invocation creation raced for ${invocationId}`);
|
|
158
|
+
return invocation;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** List bounded invocation records whose mailbox append still needs repair. */
|
|
162
|
+
async function listPendingAgentInvocationMailboxAppends(limit = 100) {
|
|
163
|
+
return (await getSqlExecutor().db().select().from(juniorAgentInvocations).where(eq(juniorAgentInvocations.mailboxStatus, "pending")).orderBy(asc(juniorAgentInvocations.createdAt)).limit(limit)).map(invocationFromRow);
|
|
164
|
+
}
|
|
165
|
+
/** Record that the invocation's idempotent mailbox append completed. */
|
|
166
|
+
async function markAgentInvocationMailboxAppended(invocationId, nowMs = Date.now()) {
|
|
167
|
+
await getSqlExecutor().db().update(juniorAgentInvocations).set({
|
|
168
|
+
mailboxStatus: "appended",
|
|
169
|
+
updatedAt: new Date(nowMs)
|
|
170
|
+
}).where(eq(juniorAgentInvocations.invocationId, invocationId));
|
|
171
|
+
}
|
|
172
|
+
/** Mark one non-terminal invocation as actively executing. */
|
|
173
|
+
async function markAgentInvocationRunning(invocationId, nowMs = Date.now()) {
|
|
174
|
+
await getSqlExecutor().db().update(juniorAgentInvocations).set({
|
|
175
|
+
status: "running",
|
|
176
|
+
updatedAt: new Date(nowMs)
|
|
177
|
+
}).where(and(eq(juniorAgentInvocations.invocationId, invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
|
|
178
|
+
return await getAgentInvocation(invocationId);
|
|
179
|
+
}
|
|
180
|
+
/** Mark one invocation as waiting for another shared execution slice. */
|
|
181
|
+
async function markAgentInvocationAwaitingResume(invocationId, nowMs = Date.now()) {
|
|
182
|
+
await getSqlExecutor().db().update(juniorAgentInvocations).set({
|
|
183
|
+
status: "awaiting_resume",
|
|
184
|
+
updatedAt: new Date(nowMs)
|
|
185
|
+
}).where(and(eq(juniorAgentInvocations.invocationId, invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
|
|
186
|
+
}
|
|
187
|
+
/** Persist one terminal invocation result without overwriting an earlier result. */
|
|
188
|
+
async function completeAgentInvocation(args) {
|
|
189
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
190
|
+
await getSqlExecutor().db().update(juniorAgentInvocations).set({
|
|
191
|
+
status: args.status,
|
|
192
|
+
result: args.status === "completed" ? args.result : null,
|
|
193
|
+
errorMessage: args.status === "completed" ? null : args.errorMessage,
|
|
194
|
+
terminalAt: new Date(nowMs),
|
|
195
|
+
updatedAt: new Date(nowMs)
|
|
196
|
+
}).where(and(eq(juniorAgentInvocations.invocationId, args.invocationId), inArray(juniorAgentInvocations.status, NON_TERMINAL_AGENT_INVOCATION_STATUSES)));
|
|
197
|
+
return await getAgentInvocation(args.invocationId);
|
|
198
|
+
}
|
|
199
|
+
/** Return whether an agent invocation has finished. */
|
|
200
|
+
function isTerminalAgentInvocation(invocation) {
|
|
201
|
+
return TERMINAL_AGENT_INVOCATION_STATUSES.includes(invocation.status);
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/chat/agent-invocations/work.ts
|
|
205
|
+
var work_exports = /* @__PURE__ */ __exportAll({
|
|
206
|
+
buildAgentInvocationInboundMessage: () => buildAgentInvocationInboundMessage,
|
|
207
|
+
createAgentInvocationWorker: () => createAgentInvocationWorker,
|
|
208
|
+
createAndEnqueueAgentInvocation: () => createAndEnqueueAgentInvocation,
|
|
209
|
+
enqueueAgentInvocation: () => enqueueAgentInvocation,
|
|
210
|
+
resolveAgentInvocationId: () => resolveAgentInvocationId,
|
|
211
|
+
routeAgentInvocationWork: () => routeAgentInvocationWork
|
|
212
|
+
});
|
|
213
|
+
const agentInvocationMailboxMetadataSchema = z.object({
|
|
214
|
+
agentInvocationId: z.string().min(1),
|
|
215
|
+
kind: z.literal("agent_invocation")
|
|
216
|
+
}).strict();
|
|
217
|
+
/** Build destinationless mailbox work that references one durable invocation. */
|
|
218
|
+
function buildAgentInvocationInboundMessage(invocation, nowMs = Date.now()) {
|
|
219
|
+
return {
|
|
220
|
+
conversationId: invocation.childConversationId,
|
|
221
|
+
createdAtMs: invocation.createdAtMs,
|
|
222
|
+
delivery: "defer",
|
|
223
|
+
inboundMessageId: getAgentInvocationMessageId(invocation.invocationId),
|
|
224
|
+
input: {
|
|
225
|
+
authorId: invocation.invocationId,
|
|
226
|
+
text: "[agent invocation]",
|
|
227
|
+
metadata: {
|
|
228
|
+
agentInvocationId: invocation.invocationId,
|
|
229
|
+
kind: "agent_invocation"
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
receivedAtMs: nowMs,
|
|
233
|
+
source: "internal"
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** Append one invocation to its child mailbox and send the normal queue wake. */
|
|
237
|
+
async function enqueueAgentInvocation(invocation, options) {
|
|
238
|
+
if (invocation.mailboxStatus === "appended") return;
|
|
239
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
240
|
+
await appendAndEnqueueInboundMessage({
|
|
241
|
+
message: buildAgentInvocationInboundMessage(invocation, nowMs),
|
|
242
|
+
conversationStore: options.conversationStore,
|
|
243
|
+
nowMs,
|
|
244
|
+
queue: options.queue,
|
|
245
|
+
state: options.state
|
|
246
|
+
});
|
|
247
|
+
await markAgentInvocationMailboxAppended(invocation.invocationId, nowMs);
|
|
248
|
+
}
|
|
249
|
+
/** Create or replay an invocation, then durably schedule its child work. */
|
|
250
|
+
async function createAndEnqueueAgentInvocation(input, options) {
|
|
251
|
+
const invocation = await createAgentInvocation(input, options.nowMs);
|
|
252
|
+
await enqueueAgentInvocation(invocation, options);
|
|
253
|
+
return await getAgentInvocation(invocation.invocationId) ?? invocation;
|
|
254
|
+
}
|
|
255
|
+
/** Require one invocation metadata reference for one leased mailbox attempt. */
|
|
256
|
+
function invocationIdFromMessages(messages) {
|
|
257
|
+
if (messages.length === 0) return;
|
|
258
|
+
const parsed = messages.map((message) => agentInvocationMailboxMetadataSchema.safeParse(message.input.metadata));
|
|
259
|
+
if (parsed.every((result) => !result.success)) return;
|
|
260
|
+
if (parsed.some((result) => !result.success)) throw new Error("Conversation mailbox mixes agent invocation and other input");
|
|
261
|
+
const invocationIds = new Set(parsed.map((result) => {
|
|
262
|
+
if (!result.success) throw new Error("Agent invocation mailbox metadata failed validation");
|
|
263
|
+
return result.data.agentInvocationId;
|
|
264
|
+
}));
|
|
265
|
+
if (invocationIds.size !== 1) throw new Error("Conversation mailbox contains multiple agent invocations in one attempt");
|
|
266
|
+
return invocationIds.values().next().value;
|
|
267
|
+
}
|
|
268
|
+
/** Resolve invocation execution from mailbox input or durable active state. */
|
|
269
|
+
async function resolveAgentInvocationId(context) {
|
|
270
|
+
const mailboxInvocationId = invocationIdFromMessages(context.attempt.messages);
|
|
271
|
+
if (mailboxInvocationId) return mailboxInvocationId;
|
|
272
|
+
if (context.attempt.messages.length > 0) return;
|
|
273
|
+
return (await getActiveAgentInvocationForConversation(context.conversationId))?.invocationId;
|
|
274
|
+
}
|
|
275
|
+
/** Project the terminal invocation into the idempotent turn lifecycle. */
|
|
276
|
+
async function persistTerminalLifecycle(invocation) {
|
|
277
|
+
const lifecycle = new ConversationTurnLifecycleService(getConversationEventStore());
|
|
278
|
+
const common = {
|
|
279
|
+
conversationId: invocation.childConversationId,
|
|
280
|
+
createdAtMs: "terminalAtMs" in invocation ? invocation.terminalAtMs : invocation.updatedAtMs,
|
|
281
|
+
turnId: getAgentInvocationTurnId(invocation.invocationId)
|
|
282
|
+
};
|
|
283
|
+
if (invocation.status === "completed") await lifecycle.complete({
|
|
284
|
+
...common,
|
|
285
|
+
outcome: invocation.result?.trim() ? "success" : "no_reply"
|
|
286
|
+
});
|
|
287
|
+
else if (invocation.status === "blocked" || invocation.status === "failed") await lifecycle.fail({
|
|
288
|
+
...common,
|
|
289
|
+
failureCode: "model_execution_failed"
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/** Stop an invocation whose worker died, or project its terminal turn result. */
|
|
293
|
+
async function projectTerminalTurn(invocation) {
|
|
294
|
+
let turn = await getTurnRecord(invocation.childConversationId, getAgentInvocationTurnId(invocation.invocationId));
|
|
295
|
+
if (!turn) return;
|
|
296
|
+
if (turn.state === "running") {
|
|
297
|
+
turn = await failTurnRecord({
|
|
298
|
+
conversationId: turn.conversationId,
|
|
299
|
+
expectedVersion: turn.version,
|
|
300
|
+
turnId: turn.turnId,
|
|
301
|
+
errorMessage: "Agent invocation lost its worker before it could pause"
|
|
302
|
+
});
|
|
303
|
+
if (!turn) return;
|
|
304
|
+
}
|
|
305
|
+
if (turn.state === "paused") return;
|
|
306
|
+
const result = getTerminalAssistantMessages(turn.piMessages).map(getAssistantReplyText).filter((text) => text !== void 0).join("\n\n");
|
|
307
|
+
const failed = turn.state !== "completed" || Boolean(turn.errorMessage);
|
|
308
|
+
return await completeAgentInvocation({
|
|
309
|
+
invocationId: invocation.invocationId,
|
|
310
|
+
...failed ? {
|
|
311
|
+
errorMessage: turn.errorMessage ?? "Agent invocation failed",
|
|
312
|
+
status: "failed"
|
|
313
|
+
} : {
|
|
314
|
+
result,
|
|
315
|
+
status: "completed"
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
/** Classify authorization failures that terminally block background work. */
|
|
320
|
+
function blockingInvocationError(error) {
|
|
321
|
+
const cause = getConversationTurnBoundaryError(error)?.cause ?? error;
|
|
322
|
+
return cause instanceof AuthorizationFlowDisabledError || cause instanceof PluginCredentialFailureError ? cause : void 0;
|
|
323
|
+
}
|
|
324
|
+
function isInvocationInputCommitLost(error) {
|
|
325
|
+
const cause = getConversationTurnBoundaryError(error)?.cause ?? error;
|
|
326
|
+
return isTurnInputCommitLostError(cause);
|
|
327
|
+
}
|
|
328
|
+
/** Save one completed agent result on its child agent invocation. */
|
|
329
|
+
async function saveAgentInvocationResult(args) {
|
|
330
|
+
const failed = args.result.diagnostics.outcome !== "success";
|
|
331
|
+
await persistThreadStateById(args.invocation.childConversationId, { sandboxRef: args.result.sandboxRef ?? args.sandboxRef });
|
|
332
|
+
if (args.result.piMessages?.length) await saveTurnCheckpoint({
|
|
333
|
+
mode: "completed",
|
|
334
|
+
conversationId: args.invocation.childConversationId,
|
|
335
|
+
turnId: args.turnId,
|
|
336
|
+
durationMs: args.result.diagnostics.durationMs,
|
|
337
|
+
usage: args.result.diagnostics.usage,
|
|
338
|
+
destination: args.invocation.destination,
|
|
339
|
+
...failed ? { errorMessage: args.result.diagnostics.errorMessage ?? "Agent invocation failed" } : void 0,
|
|
340
|
+
messages: args.result.piMessages,
|
|
341
|
+
actor: args.invocation.actor,
|
|
342
|
+
source: args.invocation.source,
|
|
343
|
+
surface: "internal"
|
|
344
|
+
});
|
|
345
|
+
const terminal = await completeAgentInvocation({
|
|
346
|
+
invocationId: args.invocation.invocationId,
|
|
347
|
+
...failed ? {
|
|
348
|
+
errorMessage: args.result.diagnostics.errorMessage ?? "Agent invocation failed",
|
|
349
|
+
status: "failed"
|
|
350
|
+
} : {
|
|
351
|
+
result: args.result.text,
|
|
352
|
+
status: "completed"
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
if (!terminal || !isTerminalAgentInvocation(terminal)) throw new Error(`Agent invocation did not finish for ${args.invocation.invocationId}`);
|
|
356
|
+
return terminal.status === "completed" ? {
|
|
357
|
+
finishedAtMs: terminal.terminalAtMs,
|
|
358
|
+
outcome: terminal.result.trim() ? "success" : "no_reply"
|
|
359
|
+
} : {
|
|
360
|
+
finishedAtMs: terminal.terminalAtMs,
|
|
361
|
+
failureCode: "model_execution_failed",
|
|
362
|
+
outcome: "failed"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/** Build the invocation consumer that advances work through the shared runner. */
|
|
366
|
+
function createAgentInvocationWorker(agentRunner) {
|
|
367
|
+
return async (context, invocationId) => {
|
|
368
|
+
let invocation = await getAgentInvocation(invocationId);
|
|
369
|
+
if (!invocation) throw new Error(`Agent invocation is missing for ${invocationId}`);
|
|
370
|
+
let acknowledged = context.attempt.messages.length === 0;
|
|
371
|
+
const acknowledge = async () => {
|
|
372
|
+
if (acknowledged) return;
|
|
373
|
+
try {
|
|
374
|
+
await context.attempt.ack();
|
|
375
|
+
} catch {
|
|
376
|
+
throw new TurnInputCommitLostError(`Conversation work lease lost before invocation inbox ack for ${context.conversationId}`);
|
|
377
|
+
}
|
|
378
|
+
acknowledged = true;
|
|
379
|
+
};
|
|
380
|
+
const turnId = getAgentInvocationTurnId(invocation.invocationId);
|
|
381
|
+
const lifecycle = new ConversationTurnLifecycleService(getConversationEventStore());
|
|
382
|
+
let sandboxRef;
|
|
383
|
+
let history;
|
|
384
|
+
let location;
|
|
385
|
+
try {
|
|
386
|
+
if (invocation.childConversationId !== context.conversationId) throw new Error(`Agent invocation ${invocationId} belongs to ${invocation.childConversationId}, not ${context.conversationId}`);
|
|
387
|
+
if (context.destination) throw new Error(`Agent invocation conversation ${context.conversationId} must not own a provider destination`);
|
|
388
|
+
if (isTerminalAgentInvocation(invocation)) {
|
|
389
|
+
await persistTerminalLifecycle(invocation);
|
|
390
|
+
await acknowledge();
|
|
391
|
+
return { status: "completed" };
|
|
392
|
+
}
|
|
393
|
+
const projected = await projectTerminalTurn(invocation);
|
|
394
|
+
if (projected && isTerminalAgentInvocation(projected)) {
|
|
395
|
+
await persistTerminalLifecycle(projected);
|
|
396
|
+
await acknowledge();
|
|
397
|
+
return { status: "completed" };
|
|
398
|
+
}
|
|
399
|
+
invocation = await markAgentInvocationRunning(invocation.invocationId) ?? invocation;
|
|
400
|
+
await lifecycle.start({
|
|
401
|
+
conversationId: invocation.childConversationId,
|
|
402
|
+
createdAtMs: invocation.createdAtMs,
|
|
403
|
+
inputMessageIds: [getAgentInvocationMessageId(invocation.invocationId)],
|
|
404
|
+
surface: "internal",
|
|
405
|
+
turnId
|
|
406
|
+
});
|
|
407
|
+
const [persisted, projection] = await Promise.all([getPersistedThreadState(invocation.childConversationId), openConversationProjection({ conversationId: invocation.childConversationId })]);
|
|
408
|
+
sandboxRef = getPersistedSandboxState(persisted);
|
|
409
|
+
history = projection.messages;
|
|
410
|
+
location = (await getConversationStore().get({ conversationId: invocation.parentConversationId }))?.location;
|
|
411
|
+
} catch (error) {
|
|
412
|
+
if (isInvocationInputCommitLost(error)) return { status: "lost_lease" };
|
|
413
|
+
if (!context.attempt.isFinalAttempt) throw error;
|
|
414
|
+
const terminal = await completeAgentInvocation({
|
|
415
|
+
invocationId: invocation.invocationId,
|
|
416
|
+
errorMessage: error instanceof Error ? error.message : "Agent invocation failed",
|
|
417
|
+
status: "failed"
|
|
418
|
+
});
|
|
419
|
+
if (terminal) await persistTerminalLifecycle(terminal);
|
|
420
|
+
await acknowledge();
|
|
421
|
+
return { status: "completed" };
|
|
422
|
+
}
|
|
423
|
+
let outcome;
|
|
424
|
+
try {
|
|
425
|
+
outcome = await executeTurn(agentRunner, {
|
|
426
|
+
conversationId: invocation.childConversationId,
|
|
427
|
+
turnId,
|
|
428
|
+
runId: invocation.invocationId,
|
|
429
|
+
instruction: { text: invocation.input },
|
|
430
|
+
history,
|
|
431
|
+
actor: invocation.actor,
|
|
432
|
+
credentialContext: invocation.credentialContext,
|
|
433
|
+
destination: invocation.destination,
|
|
434
|
+
source: invocation.source,
|
|
435
|
+
...location ? { location } : void 0,
|
|
436
|
+
surface: "internal",
|
|
437
|
+
disabledFeatures: [
|
|
438
|
+
"handoff",
|
|
439
|
+
"interactive-auth",
|
|
440
|
+
"subagents"
|
|
441
|
+
],
|
|
442
|
+
reasoning: invocation.reasoningLevel,
|
|
443
|
+
state: { sandboxRef },
|
|
444
|
+
durability: {
|
|
445
|
+
onInputCommitted: acknowledge,
|
|
446
|
+
shouldYield: context.shouldYield,
|
|
447
|
+
onSandboxRefChanged: async (nextSandboxRef) => {
|
|
448
|
+
sandboxRef = nextSandboxRef;
|
|
449
|
+
await persistThreadStateById(invocation.childConversationId, { sandboxRef });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}, async (result) => await saveAgentInvocationResult({
|
|
453
|
+
invocation,
|
|
454
|
+
result,
|
|
455
|
+
sandboxRef,
|
|
456
|
+
turnId
|
|
457
|
+
}));
|
|
458
|
+
} catch (error) {
|
|
459
|
+
if (!(error instanceof AgentRunError)) throw error;
|
|
460
|
+
const runError = error.cause;
|
|
461
|
+
if (isInvocationInputCommitLost(runError)) return { status: "lost_lease" };
|
|
462
|
+
const blocking = blockingInvocationError(runError);
|
|
463
|
+
if (blocking) {
|
|
464
|
+
const terminal = await completeAgentInvocation({
|
|
465
|
+
invocationId: invocation.invocationId,
|
|
466
|
+
errorMessage: blocking.message,
|
|
467
|
+
status: "blocked"
|
|
468
|
+
});
|
|
469
|
+
if (terminal) await persistTerminalLifecycle(terminal);
|
|
470
|
+
await acknowledge();
|
|
471
|
+
return { status: "completed" };
|
|
472
|
+
}
|
|
473
|
+
if (!context.attempt.isFinalAttempt) throw runError;
|
|
474
|
+
const terminal = await completeAgentInvocation({
|
|
475
|
+
invocationId: invocation.invocationId,
|
|
476
|
+
errorMessage: runError instanceof Error ? runError.message : "Agent invocation failed",
|
|
477
|
+
status: "failed"
|
|
478
|
+
});
|
|
479
|
+
if (terminal) await persistTerminalLifecycle(terminal);
|
|
480
|
+
await acknowledge();
|
|
481
|
+
return { status: "completed" };
|
|
482
|
+
}
|
|
483
|
+
if (outcome.status === "suspended") {
|
|
484
|
+
await markAgentInvocationAwaitingResume(invocation.invocationId);
|
|
485
|
+
return { status: "yielded" };
|
|
486
|
+
}
|
|
487
|
+
if (outcome.status === "awaiting_auth") {
|
|
488
|
+
const terminal = await completeAgentInvocation({
|
|
489
|
+
invocationId: invocation.invocationId,
|
|
490
|
+
errorMessage: `Agent invocation requires ${outcome.providerDisplayName} authorization`,
|
|
491
|
+
status: "blocked"
|
|
492
|
+
});
|
|
493
|
+
if (terminal) await persistTerminalLifecycle(terminal);
|
|
494
|
+
await acknowledge();
|
|
495
|
+
return { status: "completed" };
|
|
496
|
+
}
|
|
497
|
+
await acknowledge();
|
|
498
|
+
return { status: "completed" };
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/** Route invocation-backed work before falling through to existing consumers. */
|
|
502
|
+
function routeAgentInvocationWork(options) {
|
|
503
|
+
return async (context) => {
|
|
504
|
+
const invocationId = await resolveAgentInvocationId(context);
|
|
505
|
+
return invocationId ? await options.invocationWorker(context, invocationId) : await options.fallbackWorker(context);
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
//#endregion
|
|
509
|
+
export { work_exports as a, resolveAgentInvocationId as i, createAndEnqueueAgentInvocation as n, listPendingAgentInvocationMailboxAppends as o, enqueueAgentInvocation as r, createAgentInvocationWorker as t };
|