@sentry/junior 0.203.0 → 0.204.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-CMyTD4DD.js +17509 -0
- package/dist/agent-hooks-Bbcp9e33.js +4040 -0
- package/dist/agent-runner-DNb1A49M.js +678 -0
- package/dist/api/schema.d.ts +2728 -2639
- package/dist/api/schema.js +4 -169
- package/dist/api.d.ts +23 -17
- package/dist/api.js +3881 -5326
- package/dist/app-B1TOqBI8.d.ts +246 -0
- package/dist/app.d.ts +4 -520
- package/dist/app.js +9522 -11875
- package/dist/auth-pause-state-DosEalIG.js +168 -0
- package/dist/catalog-runtime-BReos-D4.js +7 -0
- package/dist/checkpoint-CNrPyRJN.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-nGCW1OTG.js +941 -0
- package/dist/context-B45_WqVX.js +298 -0
- package/dist/conversation-privacy-B4voFRSm.js +182 -0
- package/dist/conversation-work-C6y3T5Hx.js +51 -0
- package/dist/credential-sync-kXr1hvO1.js +2660 -0
- package/dist/db-BeyXKJOI.d.ts +5 -0
- package/dist/destinations-BeBiJeEM.js +29 -0
- package/dist/execution-stats-DWfSihcH.js +373 -0
- package/dist/executor-DcMSlI5c.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-Drn_LXlM.js +63 -0
- package/dist/logging-BzAk1S_s.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-JiftokvA.js +130 -0
- package/dist/oauth-relay-CdCnu80W.js +62 -0
- package/dist/package-discovery-7a9YqLhE.js +455 -0
- package/dist/pending-auth-CWmSdZVg.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-CrT5nXbw.js +861 -0
- package/dist/registry-DH1xUo2N.js +1419 -0
- package/dist/reporting-schema-DosTN__Q.js +105 -0
- package/dist/resolve-CZHnfxaS.js +546 -0
- package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
- package/dist/runner-CZV2sC46.js +392 -0
- package/dist/sandbox-egress-signals-bHZfmhbd.js +46 -0
- package/dist/schema-Rn8-XEaN.js +1140 -0
- package/dist/sentry-CD3SdJl-.js +26 -0
- package/dist/skills-CIcDQSgM.js +316 -0
- package/dist/spawn-DdkUFRmq.js +29 -0
- package/dist/stats-DTUbAb88.js +2634 -0
- package/dist/store-C5qxF2ac.d.ts +208 -0
- package/dist/task-queue-CJIR4RF7.js +136 -0
- package/dist/task-runner-D-O3A-Cp.js +639 -0
- package/dist/thread-state-CRc9jTJS.js +431 -0
- package/dist/turn-execution-BkinIdJF.js +47 -0
- package/dist/turn-lifecycle-DQV19VTW.js +54 -0
- package/dist/usage-D3EbSO7w.js +296 -0
- package/dist/usage-schema-CKaDkH_j.js +20 -0
- package/dist/validation-C2CR-OX3.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-DxcWdoKa.js +8 -0
- package/dist/version.d.ts +2 -4
- package/dist/version.js +2 -6
- package/dist/web-authorization-RMBxAR_t.js +76 -0
- package/dist/web-input-3EPfpf55.js +494 -0
- package/dist/work-fGofI7Op.js +509 -0
- package/dist/worker-CsOLq-mR.js +625 -0
- package/package.json +8 -8
- 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,639 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
|
|
2
|
+
import { _ as parseSlackMessageTs, r as credentialSubjectSchema } from "./context-B45_WqVX.js";
|
|
3
|
+
import { Et as getDb, Tt as getConversationStore, Y as readActorIdentity, _t as createPluginLogger, gt as createPluginModel, ht as createPluginEmbedder, mt as createPluginState, u as getPlugins, ut as JUNIOR_THREAD_STATE_TTL_MS, vt as createPluginConversationEvents } from "./agent-hooks-Bbcp9e33.js";
|
|
4
|
+
import { f as sameActorIdentity } from "./history-CqTuSAdI.js";
|
|
5
|
+
import { Dt as isToolResultError, Ot as isToolResultMessage, Q as hydrateConversationMessages, bt as getPiMessageRole, jt as stripRuntimeTurnContext, kt as normalizeToolNameFromResult, s as getTurnRecord, wt as instructionTextForProjection } from "./checkpoint-CNrPyRJN.js";
|
|
6
|
+
import { w as getStateAdapter } from "./profile-CrT5nXbw.js";
|
|
7
|
+
import { u as recordTaskExecution } from "./execution-stats-DWfSihcH.js";
|
|
8
|
+
import { r as getPersistedThreadState, s as coerceThreadConversationState } from "./thread-state-CRc9jTJS.js";
|
|
9
|
+
import { i as pluginTaskParamsSchema, o as sendVercelPluginTask, r as pluginTaskId } from "./task-queue-CJIR4RF7.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import { destinationSchema, destinationVisibilitySchema, isSlackDestination, pluginRunContextSchema, replyAttributionSchema, sourceSchema, taskOutcomeSchema } from "@sentry/junior-plugin-api";
|
|
13
|
+
//#region src/chat/agent-dispatch/store.ts
|
|
14
|
+
const DISPATCH_PREFIX = "junior:agent_dispatch";
|
|
15
|
+
const DISPATCH_LOCK_TTL_MS = 6e5;
|
|
16
|
+
const DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS = 1e4;
|
|
17
|
+
const nonEmptyExactStringSchema = z.string().min(1).refine((value) => value === value.trim() && value.toLowerCase() !== "unknown");
|
|
18
|
+
const pendingDispatchMailboxAppendIndexSchema = z.array(nonEmptyExactStringSchema);
|
|
19
|
+
const dispatchStatusSchema = z.enum([
|
|
20
|
+
"pending",
|
|
21
|
+
"running",
|
|
22
|
+
"awaiting_resume",
|
|
23
|
+
"completed",
|
|
24
|
+
"failed",
|
|
25
|
+
"blocked"
|
|
26
|
+
]);
|
|
27
|
+
const dispatchActorSchema = z.object({
|
|
28
|
+
platform: z.literal("system"),
|
|
29
|
+
name: nonEmptyExactStringSchema
|
|
30
|
+
}).strict();
|
|
31
|
+
const dispatchRecordSchema = z.object({
|
|
32
|
+
actor: dispatchActorSchema,
|
|
33
|
+
createdAtMs: z.number().finite(),
|
|
34
|
+
credentialSubject: credentialSubjectSchema.optional(),
|
|
35
|
+
destination: destinationSchema,
|
|
36
|
+
destinationVisibility: destinationVisibilitySchema,
|
|
37
|
+
errorMessage: z.string().optional(),
|
|
38
|
+
id: nonEmptyExactStringSchema,
|
|
39
|
+
idempotencyKey: z.string().min(1),
|
|
40
|
+
input: z.string().min(1),
|
|
41
|
+
metadata: z.record(z.string(), z.string()).optional(),
|
|
42
|
+
plugin: nonEmptyExactStringSchema,
|
|
43
|
+
replyAttribution: replyAttributionSchema.optional(),
|
|
44
|
+
resultMessageTs: z.string().optional(),
|
|
45
|
+
source: sourceSchema,
|
|
46
|
+
outcomes: z.array(taskOutcomeSchema).max(5).optional(),
|
|
47
|
+
status: dispatchStatusSchema,
|
|
48
|
+
updatedAtMs: z.number().finite()
|
|
49
|
+
}).strict().superRefine((record, ctx) => {
|
|
50
|
+
if (!isSlackDestination(record.destination)) {
|
|
51
|
+
ctx.addIssue({
|
|
52
|
+
code: z.ZodIssueCode.custom,
|
|
53
|
+
message: "Dispatch destination platform must be slack",
|
|
54
|
+
path: ["destination"]
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const subject = record.credentialSubject;
|
|
59
|
+
if (!subject) return;
|
|
60
|
+
if (subject.allowedWhen === "private-direct-conversation") {
|
|
61
|
+
if (!record.destination.channelId.startsWith("D")) {
|
|
62
|
+
ctx.addIssue({
|
|
63
|
+
code: z.ZodIssueCode.custom,
|
|
64
|
+
message: "Dispatch credentialSubject requires a private direct Slack destination",
|
|
65
|
+
path: ["credentialSubject"]
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (subject.binding.type !== "slack-direct-conversation" || subject.binding.teamId !== record.destination.teamId || subject.binding.channelId !== record.destination.channelId) ctx.addIssue({
|
|
70
|
+
code: z.ZodIssueCode.custom,
|
|
71
|
+
message: "Dispatch credentialSubject binding must match destination",
|
|
72
|
+
path: ["credentialSubject", "binding"]
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (subject.binding.type !== subject.allowedWhen || subject.binding.plugin !== record.plugin || subject.binding.taskId !== subject.taskId) ctx.addIssue({
|
|
77
|
+
code: z.ZodIssueCode.custom,
|
|
78
|
+
message: "Dispatch credentialSubject binding must match task",
|
|
79
|
+
path: ["credentialSubject", "binding"]
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
/** Return the durable key for one plugin-facing dispatch projection. */
|
|
83
|
+
function getDispatchStorageKey(id) {
|
|
84
|
+
return `${DISPATCH_PREFIX}:record:${id}`;
|
|
85
|
+
}
|
|
86
|
+
function dispatchLockKey(id) {
|
|
87
|
+
return `${DISPATCH_PREFIX}:lock:${id}`;
|
|
88
|
+
}
|
|
89
|
+
function pendingDispatchMailboxAppendIndexKey() {
|
|
90
|
+
return `${DISPATCH_PREFIX}:incomplete`;
|
|
91
|
+
}
|
|
92
|
+
function pendingDispatchMailboxAppendIndexLockKey() {
|
|
93
|
+
return `${DISPATCH_PREFIX}:incomplete:lock`;
|
|
94
|
+
}
|
|
95
|
+
function normalizeMetadata(metadata) {
|
|
96
|
+
if (!metadata) return;
|
|
97
|
+
const entries = Object.entries(metadata).filter((entry) => typeof entry[0] === "string" && typeof entry[1] === "string");
|
|
98
|
+
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
99
|
+
}
|
|
100
|
+
function buildDispatchId(plugin, idempotencyKey) {
|
|
101
|
+
return `dispatch_${createHash("sha256").update(plugin).update("\0").update(idempotencyKey).digest("hex").slice(0, 32)}`;
|
|
102
|
+
}
|
|
103
|
+
/** Parse one durable dispatch projection record. */
|
|
104
|
+
function parseDispatchRecord(value) {
|
|
105
|
+
const parsed = dispatchRecordSchema.safeParse(value);
|
|
106
|
+
return parsed.success ? parsed.data : void 0;
|
|
107
|
+
}
|
|
108
|
+
/** Return the isolated durable conversation id for one dispatch. */
|
|
109
|
+
function getDispatchConversationId(dispatch) {
|
|
110
|
+
return `agent-dispatch:${dispatch.id}`;
|
|
111
|
+
}
|
|
112
|
+
/** Return the stable synthetic input message id for one dispatch turn. */
|
|
113
|
+
function getDispatchInputMessageId(dispatchId) {
|
|
114
|
+
return `agent-dispatch:${dispatchId}`;
|
|
115
|
+
}
|
|
116
|
+
/** Return the stable turn id used by every run of one dispatch. */
|
|
117
|
+
function getDispatchTurnId(dispatchId) {
|
|
118
|
+
return `dispatch:${dispatchId}`;
|
|
119
|
+
}
|
|
120
|
+
function toDispatchProjection(record) {
|
|
121
|
+
return {
|
|
122
|
+
id: record.id,
|
|
123
|
+
status: record.status,
|
|
124
|
+
...record.resultMessageTs ? { resultMessageTs: record.resultMessageTs } : void 0,
|
|
125
|
+
...record.errorMessage ? { errorMessage: record.errorMessage } : void 0
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/** Gate recovery to dispatches that can still make progress. */
|
|
129
|
+
function isTerminalDispatchStatus(status) {
|
|
130
|
+
return status === "completed" || status === "failed" || status === "blocked";
|
|
131
|
+
}
|
|
132
|
+
/** Serialize dispatch projection mutations. */
|
|
133
|
+
async function withDispatchLock(dispatchId, task) {
|
|
134
|
+
const state = getStateAdapter();
|
|
135
|
+
await state.connect();
|
|
136
|
+
const lock = await state.acquireLock(dispatchLockKey(dispatchId), DISPATCH_LOCK_TTL_MS);
|
|
137
|
+
if (!lock) throw new Error(`Could not acquire dispatch lock for ${dispatchId}`);
|
|
138
|
+
try {
|
|
139
|
+
return await task(state);
|
|
140
|
+
} finally {
|
|
141
|
+
await state.releaseLock(lock);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function putRecord(state, record) {
|
|
145
|
+
const parsed = dispatchRecordSchema.safeParse(record);
|
|
146
|
+
if (!parsed.success) throw new Error(`Dispatch record is invalid: ${parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"} ${issue.message}`).join("; ")}`);
|
|
147
|
+
const next = parsed.data;
|
|
148
|
+
await state.set(getDispatchStorageKey(next.id), next, JUNIOR_THREAD_STATE_TTL_MS);
|
|
149
|
+
}
|
|
150
|
+
async function updatePendingDispatchMailboxAppendIndex(state, update) {
|
|
151
|
+
const lock = await state.acquireLock(pendingDispatchMailboxAppendIndexLockKey(), DISPATCH_MAILBOX_APPEND_INDEX_LOCK_TTL_MS);
|
|
152
|
+
if (!lock) throw new Error("Could not acquire dispatch mailbox append index lock");
|
|
153
|
+
try {
|
|
154
|
+
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
155
|
+
const ids = stored === void 0 || stored === null ? [] : pendingDispatchMailboxAppendIndexSchema.parse(stored);
|
|
156
|
+
const next = [...new Set(update([...new Set(ids)]))].slice(-1e4);
|
|
157
|
+
if (next.length === ids.length && next.every((id, index) => id === ids[index])) return;
|
|
158
|
+
await state.set(pendingDispatchMailboxAppendIndexKey(), next, JUNIOR_THREAD_STATE_TTL_MS);
|
|
159
|
+
} finally {
|
|
160
|
+
await state.releaseLock(lock);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Load dispatch state for conversation work and plugin projections. */
|
|
164
|
+
async function getDispatchRecord(id) {
|
|
165
|
+
const state = getStateAdapter();
|
|
166
|
+
await state.connect();
|
|
167
|
+
return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
168
|
+
}
|
|
169
|
+
/** Create a dispatch idempotently within its owner namespace. */
|
|
170
|
+
async function createOrGetDispatch(args) {
|
|
171
|
+
const id = buildDispatchId(args.plugin, args.options.idempotencyKey);
|
|
172
|
+
return await withDispatchLock(id, async (state) => {
|
|
173
|
+
const existing = parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
174
|
+
if (existing) return {
|
|
175
|
+
record: existing,
|
|
176
|
+
status: "already_exists"
|
|
177
|
+
};
|
|
178
|
+
const metadata = normalizeMetadata(args.options.metadata);
|
|
179
|
+
const record = {
|
|
180
|
+
actor: {
|
|
181
|
+
platform: "system",
|
|
182
|
+
name: args.plugin
|
|
183
|
+
},
|
|
184
|
+
createdAtMs: args.nowMs,
|
|
185
|
+
...args.options.credentialSubject ? { credentialSubject: args.options.credentialSubject } : void 0,
|
|
186
|
+
destination: args.options.destination,
|
|
187
|
+
destinationVisibility: args.options.destinationVisibility,
|
|
188
|
+
id,
|
|
189
|
+
idempotencyKey: args.options.idempotencyKey,
|
|
190
|
+
input: args.options.input,
|
|
191
|
+
...metadata ? { metadata } : void 0,
|
|
192
|
+
plugin: args.plugin,
|
|
193
|
+
...args.options.replyAttribution ? { replyAttribution: args.options.replyAttribution } : void 0,
|
|
194
|
+
...args.options.outcomes ? { outcomes: args.options.outcomes } : void 0,
|
|
195
|
+
status: "pending",
|
|
196
|
+
source: args.options.source,
|
|
197
|
+
updatedAtMs: args.nowMs
|
|
198
|
+
};
|
|
199
|
+
await updatePendingDispatchMailboxAppendIndex(state, (ids) => ids.includes(id) ? ids : [...ids, id]);
|
|
200
|
+
await putRecord(state, record);
|
|
201
|
+
return {
|
|
202
|
+
record,
|
|
203
|
+
status: "created"
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
async function transitionDispatch(id, transition) {
|
|
208
|
+
return await withDispatchLock(id, async (state) => {
|
|
209
|
+
const current = parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
210
|
+
if (!current) return;
|
|
211
|
+
const transitioned = transition(current);
|
|
212
|
+
if (transitioned === current) return current;
|
|
213
|
+
const next = {
|
|
214
|
+
...transitioned,
|
|
215
|
+
updatedAtMs: Date.now()
|
|
216
|
+
};
|
|
217
|
+
await putRecord(state, next);
|
|
218
|
+
return next;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
/** Mark a dispatch projection as actively running. */
|
|
222
|
+
async function markDispatchRunning(id) {
|
|
223
|
+
return await transitionDispatch(id, (record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
224
|
+
...record,
|
|
225
|
+
status: "running",
|
|
226
|
+
errorMessage: void 0
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/** Project a durable awaiting-resume turn state to the plugin API. */
|
|
230
|
+
async function markDispatchAwaitingResume(id) {
|
|
231
|
+
return await transitionDispatch(id, (record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
232
|
+
...record,
|
|
233
|
+
status: "awaiting_resume"
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
async function recordEventTaskExecution(previous, next, status) {
|
|
237
|
+
if (!next || next.status !== status || previous?.status === status) return;
|
|
238
|
+
if (next.plugin !== "junior") return;
|
|
239
|
+
const eventTaskId = next.metadata?.eventTaskId;
|
|
240
|
+
if (!eventTaskId) return;
|
|
241
|
+
const conversationId = getDispatchConversationId(next);
|
|
242
|
+
const conversation = await getConversationStore().get({ conversationId });
|
|
243
|
+
await recordTaskExecution("event", eventTaskId, {
|
|
244
|
+
...conversation ? { conversationId } : void 0,
|
|
245
|
+
executionId: next.id,
|
|
246
|
+
nowMs: next.updatedAtMs,
|
|
247
|
+
status
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/** Project a blocked turn to the plugin API. */
|
|
251
|
+
async function markDispatchBlocked(id, errorMessage, resultMessageTs) {
|
|
252
|
+
const previous = await getDispatchRecord(id);
|
|
253
|
+
const next = await transitionDispatch(id, (record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
254
|
+
...record,
|
|
255
|
+
errorMessage,
|
|
256
|
+
...resultMessageTs ? { resultMessageTs } : void 0,
|
|
257
|
+
status: "blocked"
|
|
258
|
+
});
|
|
259
|
+
await recordEventTaskExecution(previous, next, "blocked");
|
|
260
|
+
return next;
|
|
261
|
+
}
|
|
262
|
+
/** Project a completed turn and its accepted Slack message to the plugin API. */
|
|
263
|
+
async function markDispatchCompleted(id, resultMessageTs) {
|
|
264
|
+
const previous = await getDispatchRecord(id);
|
|
265
|
+
const next = await transitionDispatch(id, (record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
266
|
+
...record,
|
|
267
|
+
errorMessage: void 0,
|
|
268
|
+
...resultMessageTs ? { resultMessageTs } : void 0,
|
|
269
|
+
status: "completed"
|
|
270
|
+
});
|
|
271
|
+
await recordEventTaskExecution(previous, next, "completed");
|
|
272
|
+
return next;
|
|
273
|
+
}
|
|
274
|
+
/** Project a terminal conversation turn failure to the plugin API. */
|
|
275
|
+
async function markDispatchFailed(id, errorMessage, resultMessageTs) {
|
|
276
|
+
const previous = await getDispatchRecord(id);
|
|
277
|
+
const next = await transitionDispatch(id, (record) => isTerminalDispatchStatus(record.status) ? record : {
|
|
278
|
+
...record,
|
|
279
|
+
errorMessage,
|
|
280
|
+
...resultMessageTs ? { resultMessageTs } : void 0,
|
|
281
|
+
status: "failed"
|
|
282
|
+
});
|
|
283
|
+
await recordEventTaskExecution(previous, next, "failed");
|
|
284
|
+
return next;
|
|
285
|
+
}
|
|
286
|
+
/** Remove a dispatch after its durable mailbox append has succeeded. */
|
|
287
|
+
async function confirmDispatchMailboxAppend(id) {
|
|
288
|
+
const state = getStateAdapter();
|
|
289
|
+
await state.connect();
|
|
290
|
+
await updatePendingDispatchMailboxAppendIndex(state, (ids) => ids.filter((candidate) => candidate !== id));
|
|
291
|
+
}
|
|
292
|
+
/** List dispatches whose durable mailbox append may not have completed. */
|
|
293
|
+
async function listPendingDispatchMailboxAppends() {
|
|
294
|
+
const state = getStateAdapter();
|
|
295
|
+
await state.connect();
|
|
296
|
+
const stored = await state.get(pendingDispatchMailboxAppendIndexKey());
|
|
297
|
+
return stored === void 0 || stored === null ? [] : [...new Set(pendingDispatchMailboxAppendIndexSchema.parse(stored))];
|
|
298
|
+
}
|
|
299
|
+
/** Load the dispatch under lock before its mailbox append becomes visible. */
|
|
300
|
+
async function claimDispatchMailboxAppend(id) {
|
|
301
|
+
return await withDispatchLock(id, async (state) => {
|
|
302
|
+
return parseDispatchRecord(await state.get(getDispatchStorageKey(id)));
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
/** Return a plugin-scoped dispatch projection without exposing raw runtime state. */
|
|
306
|
+
async function getPluginDispatchProjection(args) {
|
|
307
|
+
const record = await getDispatchRecord(args.id);
|
|
308
|
+
if (!record || record.plugin !== args.plugin) return;
|
|
309
|
+
return toDispatchProjection(record);
|
|
310
|
+
}
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/chat/services/turn-session-routing.ts
|
|
313
|
+
async function loadConversationChain(conversationId, conversationStore) {
|
|
314
|
+
const chain = [];
|
|
315
|
+
const seen = /* @__PURE__ */ new Set();
|
|
316
|
+
let cursor = conversationId;
|
|
317
|
+
while (cursor && !seen.has(cursor)) {
|
|
318
|
+
seen.add(cursor);
|
|
319
|
+
const conversation = await conversationStore.get({ conversationId: cursor });
|
|
320
|
+
if (!conversation) break;
|
|
321
|
+
chain.push(conversation);
|
|
322
|
+
cursor = conversation.parentConversationId;
|
|
323
|
+
}
|
|
324
|
+
return chain;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Normalize a stored Slack session source against the conversation destination.
|
|
328
|
+
*
|
|
329
|
+
* Does not create channel or thread values from the conversation id.
|
|
330
|
+
*/
|
|
331
|
+
function slackSourceForDestination(args) {
|
|
332
|
+
if (args.source?.kind !== "slack" || args.source.channelId !== args.destination.channelId) return;
|
|
333
|
+
const threadTs = args.source.threadTs?.trim();
|
|
334
|
+
return {
|
|
335
|
+
kind: "slack",
|
|
336
|
+
visibility: args.source.visibility ?? "public",
|
|
337
|
+
teamId: args.source.teamId?.trim() || args.destination.teamId,
|
|
338
|
+
channelId: args.source.channelId,
|
|
339
|
+
...threadTs ? { threadTs } : void 0
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Resolve the Conversation Location, Destination, and session Source.
|
|
344
|
+
*
|
|
345
|
+
* Reads parent Conversations when this Conversation has no Destination.
|
|
346
|
+
*/
|
|
347
|
+
async function resolveConversationRouting(args) {
|
|
348
|
+
const conversationStore = args.conversationStore ?? (await import("./agent-hooks-Bbcp9e33.js").then((n) => n.St)).getConversationStore();
|
|
349
|
+
const chain = await loadConversationChain(args.conversationId, conversationStore);
|
|
350
|
+
let destination;
|
|
351
|
+
let source;
|
|
352
|
+
let location;
|
|
353
|
+
for (const conversation of chain) {
|
|
354
|
+
destination ??= conversation.destination;
|
|
355
|
+
source ??= conversation.sessionSource;
|
|
356
|
+
location ??= conversation.location;
|
|
357
|
+
if (destination && source) break;
|
|
358
|
+
}
|
|
359
|
+
if (!destination) return;
|
|
360
|
+
if (destination.platform === "slack") {
|
|
361
|
+
const slackSource = slackSourceForDestination({
|
|
362
|
+
destination,
|
|
363
|
+
source
|
|
364
|
+
});
|
|
365
|
+
return {
|
|
366
|
+
destination,
|
|
367
|
+
...location ? { location } : void 0,
|
|
368
|
+
...slackSource ? { source: slackSource } : void 0
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
destination,
|
|
373
|
+
...location ? { location } : void 0,
|
|
374
|
+
...source ? { source } : void 0
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/** Require the Conversation Destination and Source from SQL. */
|
|
378
|
+
async function resolveTurnSessionRouting(args) {
|
|
379
|
+
const routing = await resolveConversationRouting(args);
|
|
380
|
+
if (!routing?.destination || !routing.source) throw new Error(`Conversation ${args.conversationId} is missing durable routing metadata`);
|
|
381
|
+
return {
|
|
382
|
+
destination: routing.destination,
|
|
383
|
+
...routing.location ? { location: routing.location } : void 0,
|
|
384
|
+
source: routing.source
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region src/chat/plugins/task-runner.ts
|
|
389
|
+
var task_runner_exports = /* @__PURE__ */ __exportAll({
|
|
390
|
+
processPluginTask: () => processPluginTask,
|
|
391
|
+
scheduleSessionCompletedPluginTasks: () => scheduleSessionCompletedPluginTasks
|
|
392
|
+
});
|
|
393
|
+
const PLUGIN_TASK_LOCK_TTL_MS = 3e5;
|
|
394
|
+
function isRecord(value) {
|
|
395
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
396
|
+
}
|
|
397
|
+
function textPart(value) {
|
|
398
|
+
if (isRecord(value) && value.type === "text" && typeof value.text === "string") return value.text;
|
|
399
|
+
}
|
|
400
|
+
function messageText(message) {
|
|
401
|
+
const content = message.content;
|
|
402
|
+
if (typeof content === "string") return sanitizeText(content);
|
|
403
|
+
if (!Array.isArray(content)) return "";
|
|
404
|
+
return sanitizeText(content.map(textPart).filter(Boolean).join("\n"));
|
|
405
|
+
}
|
|
406
|
+
function toolResultText(message) {
|
|
407
|
+
const record = message;
|
|
408
|
+
return sanitizeText([
|
|
409
|
+
messageText(message),
|
|
410
|
+
record.output,
|
|
411
|
+
record.result,
|
|
412
|
+
record.stdout,
|
|
413
|
+
record.stderr,
|
|
414
|
+
record.toolResult
|
|
415
|
+
].filter((value) => typeof value === "string" && value.length > 0).join("\n"));
|
|
416
|
+
}
|
|
417
|
+
function sanitizeText(text) {
|
|
418
|
+
return text.replace(/<data_base64>[\s\S]*?<\/data_base64>/g, "<data_base64>[omitted]</data_base64>").replace(/data:image\/[a-z0-9.+-]+;base64,[a-z0-9+/=]+/gi, "[image data omitted]").replaceAll("\0", " ").trim();
|
|
419
|
+
}
|
|
420
|
+
/** Build the transcript provenance for a user message from its Pi provenance. */
|
|
421
|
+
function messageProvenance(provenance) {
|
|
422
|
+
return {
|
|
423
|
+
authority: provenance.authority,
|
|
424
|
+
...provenance.actor ? { actor: provenance.actor } : void 0
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function runTranscriptEntry(message, provenance, runActor) {
|
|
428
|
+
const role = getPiMessageRole(message);
|
|
429
|
+
if (role === "user" || role === "assistant") {
|
|
430
|
+
const text = role === "user" ? instructionTextForProjection(messageText(message)) : messageText(message);
|
|
431
|
+
if (!text) return;
|
|
432
|
+
if (role === "assistant") return {
|
|
433
|
+
type: "message",
|
|
434
|
+
role,
|
|
435
|
+
text
|
|
436
|
+
};
|
|
437
|
+
return {
|
|
438
|
+
type: "message",
|
|
439
|
+
role,
|
|
440
|
+
text,
|
|
441
|
+
provenance: messageProvenance(provenance),
|
|
442
|
+
isRunActor: sameActorIdentity(provenance.actor, runActor)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (!isToolResultMessage(message)) return;
|
|
446
|
+
const toolName = normalizeToolNameFromResult(message);
|
|
447
|
+
if (!toolName) return;
|
|
448
|
+
const text = toolResultText(message);
|
|
449
|
+
return {
|
|
450
|
+
type: "toolResult",
|
|
451
|
+
toolName,
|
|
452
|
+
isError: isToolResultError(message),
|
|
453
|
+
...text ? { text } : void 0
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Slice the current turn's Pi messages with their aligned provenance and strip
|
|
458
|
+
* runtime turn context, keeping each surviving message paired with the exact
|
|
459
|
+
* provenance recorded for it. Stripping can drop or rewrite messages, so the
|
|
460
|
+
* pairing is applied per message rather than by post-strip index.
|
|
461
|
+
*/
|
|
462
|
+
function turnMessagesWithProvenance(record) {
|
|
463
|
+
const startIndex = record.turnStartMessageIndex ?? 0;
|
|
464
|
+
const messages = record.piMessages.slice(startIndex);
|
|
465
|
+
const provenance = record.piMessageProvenance.slice(startIndex);
|
|
466
|
+
const paired = [];
|
|
467
|
+
for (const [index, message] of messages.entries()) for (const stripped of stripRuntimeTurnContext([message])) paired.push({
|
|
468
|
+
message: stripped,
|
|
469
|
+
provenance: provenance[index] ?? { authority: "context" }
|
|
470
|
+
});
|
|
471
|
+
return paired;
|
|
472
|
+
}
|
|
473
|
+
/** Recover the Slack context author identity from a persisted thread message. */
|
|
474
|
+
function slackContextAuthor(location, message) {
|
|
475
|
+
const userId = message.author?.userId?.trim();
|
|
476
|
+
if (!userId) return;
|
|
477
|
+
return {
|
|
478
|
+
platform: "slack",
|
|
479
|
+
teamId: location.teamId,
|
|
480
|
+
userId,
|
|
481
|
+
...message.author?.userName ? { userName: message.author.userName } : void 0,
|
|
482
|
+
...message.author?.fullName ? { fullName: message.author.fullName } : void 0
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function slackTimestampMs(value) {
|
|
486
|
+
const timestamp = parseSlackMessageTs(value);
|
|
487
|
+
if (!timestamp) return;
|
|
488
|
+
const timestampMs = Number(timestamp) * 1e3;
|
|
489
|
+
return Number.isFinite(timestampMs) ? timestampMs : void 0;
|
|
490
|
+
}
|
|
491
|
+
function conversationMessageTimestampMs(message) {
|
|
492
|
+
if (message.meta?.slackTs !== void 0) return slackTimestampMs(message.meta.slackTs);
|
|
493
|
+
return Number.isFinite(message.createdAtMs) ? message.createdAtMs : void 0;
|
|
494
|
+
}
|
|
495
|
+
function messageExistedAtRunCompletion(message, completedAtMs) {
|
|
496
|
+
const messageTimestampMs = conversationMessageTimestampMs(message);
|
|
497
|
+
return messageTimestampMs !== void 0 && messageTimestampMs <= completedAtMs;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Project bounded public-thread context into the run transcript.
|
|
501
|
+
*
|
|
502
|
+
* Prior public Slack messages from the current Conversation are durable
|
|
503
|
+
* evidence a completed run may have acted on, so passive consumers can cite
|
|
504
|
+
* them. They are always context authority (never instruction), and private or
|
|
505
|
+
* local Conversations add nothing here.
|
|
506
|
+
*/
|
|
507
|
+
async function loadConversationContextTranscriptEntries(record, location, visibility, runActor) {
|
|
508
|
+
if (location?.provider !== "slack" || visibility !== "public") return [];
|
|
509
|
+
const state = await getPersistedThreadState(record.conversationId);
|
|
510
|
+
const conversation = coerceThreadConversationState(state);
|
|
511
|
+
await hydrateConversationMessages({
|
|
512
|
+
conversation,
|
|
513
|
+
conversationId: record.conversationId
|
|
514
|
+
});
|
|
515
|
+
const entries = [];
|
|
516
|
+
for (const message of conversation.messages) {
|
|
517
|
+
if (message.role !== "user") continue;
|
|
518
|
+
if (!messageExistedAtRunCompletion(message, record.updatedAtMs)) continue;
|
|
519
|
+
const text = sanitizeText(message.text);
|
|
520
|
+
if (!text) continue;
|
|
521
|
+
const author = slackContextAuthor(location, message);
|
|
522
|
+
entries.push({
|
|
523
|
+
type: "message",
|
|
524
|
+
role: "user",
|
|
525
|
+
text,
|
|
526
|
+
provenance: {
|
|
527
|
+
authority: "context",
|
|
528
|
+
...author ? { actor: author } : void 0
|
|
529
|
+
},
|
|
530
|
+
isRunActor: sameActorIdentity(author, runActor)
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
return entries;
|
|
534
|
+
}
|
|
535
|
+
async function withPluginTaskLock(taskId, callback) {
|
|
536
|
+
const state = getStateAdapter();
|
|
537
|
+
await state.connect();
|
|
538
|
+
const lock = await state.acquireLock(`plugin:task:${taskId}`, PLUGIN_TASK_LOCK_TTL_MS);
|
|
539
|
+
if (!lock) throw new Error(`Could not acquire plugin task lock for ${taskId}`);
|
|
540
|
+
try {
|
|
541
|
+
return await callback();
|
|
542
|
+
} finally {
|
|
543
|
+
await state.releaseLock(lock);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/** Load the bounded completed-run projection exposed to plugin tasks. */
|
|
547
|
+
async function loadPluginRun(params) {
|
|
548
|
+
const record = await getTurnRecord(params.conversationId, params.sessionId);
|
|
549
|
+
if (!record) throw new Error("Completed plugin task session record is unavailable");
|
|
550
|
+
if (record.state !== "completed") throw new Error("Completed plugin task session record is not completed");
|
|
551
|
+
const conversationStore = getConversationStore();
|
|
552
|
+
const routing = await resolveConversationRouting({
|
|
553
|
+
conversationId: params.conversationId,
|
|
554
|
+
conversationStore
|
|
555
|
+
});
|
|
556
|
+
if (!routing) throw new Error(`Conversation ${params.conversationId} is missing durable routing metadata`);
|
|
557
|
+
const source = record.source ?? routing.source;
|
|
558
|
+
if (!source) throw new Error("Completed plugin task session record is missing Source");
|
|
559
|
+
const conversation = await conversationStore.get({ conversationId: params.conversationId });
|
|
560
|
+
const runActor = record.actor ?? record.actors[0] ?? (record.dispatchId ? (await getDispatchRecord(record.dispatchId))?.actor : void 0);
|
|
561
|
+
const actorUser = runActor ? (await readActorIdentity(runActor))?.user : void 0;
|
|
562
|
+
const runEntries = turnMessagesWithProvenance(record).map(({ message, provenance }) => runTranscriptEntry(message, provenance, runActor)).filter((entry) => Boolean(entry));
|
|
563
|
+
const runMessageTexts = new Set(runEntries.filter((entry) => entry.type === "message").map((entry) => entry.text));
|
|
564
|
+
const contextEntries = (await loadConversationContextTranscriptEntries(record, conversation?.location, conversation?.visibility, runActor)).filter((entry) => entry.type !== "message" || !runMessageTexts.has(entry.text));
|
|
565
|
+
return pluginRunContextSchema.parse({
|
|
566
|
+
...actorUser ? { actorUserId: actorUser.id } : void 0,
|
|
567
|
+
completedAtMs: record.updatedAtMs,
|
|
568
|
+
conversationId: record.conversationId,
|
|
569
|
+
destination: routing.destination,
|
|
570
|
+
...routing.location ? { locationId: routing.location.id } : void 0,
|
|
571
|
+
actors: record.actors,
|
|
572
|
+
...runActor ? { actor: runActor } : void 0,
|
|
573
|
+
runId: record.turnId,
|
|
574
|
+
source,
|
|
575
|
+
transcript: [...contextEntries, ...runEntries]
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
/** Build the plugin-facing context for one claimed task attempt. */
|
|
579
|
+
function taskPluginContext(plugin, message, options = {}) {
|
|
580
|
+
const pluginName = plugin.manifest.name;
|
|
581
|
+
const sessionParams = pluginTaskParamsSchema.parse(message.params);
|
|
582
|
+
return {
|
|
583
|
+
db: getDb(),
|
|
584
|
+
embedder: createPluginEmbedder(pluginName, { signal: options.signal }),
|
|
585
|
+
events: createPluginConversationEvents({
|
|
586
|
+
conversationId: sessionParams.conversationId,
|
|
587
|
+
operationId: pluginTaskId(message),
|
|
588
|
+
plugin,
|
|
589
|
+
turnId: sessionParams.sessionId
|
|
590
|
+
}),
|
|
591
|
+
id: pluginTaskId(message),
|
|
592
|
+
log: createPluginLogger(pluginName),
|
|
593
|
+
model: createPluginModel(pluginName, plugin.model, { signal: options.signal }),
|
|
594
|
+
name: message.name,
|
|
595
|
+
plugin: { name: pluginName },
|
|
596
|
+
run: { async load() {
|
|
597
|
+
return await loadPluginRun(sessionParams);
|
|
598
|
+
} },
|
|
599
|
+
state: createPluginState(pluginName)
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
function findPluginTask(message) {
|
|
603
|
+
const plugin = getPlugins().find((candidate) => candidate.manifest.name === message.plugin);
|
|
604
|
+
if (!plugin?.tasks || !Object.hasOwn(plugin.tasks, message.name)) return;
|
|
605
|
+
return {
|
|
606
|
+
plugin,
|
|
607
|
+
task: plugin.tasks[message.name]
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
/** Schedule all plugin tasks interested in a completed agent-run session. */
|
|
611
|
+
async function scheduleSessionCompletedPluginTasks(params, options = {}) {
|
|
612
|
+
const coreParams = pluginTaskParamsSchema.parse(params);
|
|
613
|
+
const taskRegistrations = getPlugins().flatMap((plugin) => Object.keys(plugin.tasks ?? {}).map((name) => ({
|
|
614
|
+
name,
|
|
615
|
+
plugin
|
|
616
|
+
})));
|
|
617
|
+
if (taskRegistrations.length === 0) return;
|
|
618
|
+
const record = await getTurnRecord(coreParams.conversationId, coreParams.sessionId);
|
|
619
|
+
if (!record || record.state !== "completed") throw new Error("Completed plugin task session record is not ready");
|
|
620
|
+
const send = options.send ?? sendVercelPluginTask;
|
|
621
|
+
const messages = taskRegistrations.map(({ name, plugin }) => ({
|
|
622
|
+
name,
|
|
623
|
+
params: coreParams,
|
|
624
|
+
plugin: plugin.manifest.name
|
|
625
|
+
}));
|
|
626
|
+
await Promise.all(messages.map(async (message) => {
|
|
627
|
+
await send(message);
|
|
628
|
+
}));
|
|
629
|
+
}
|
|
630
|
+
/** Execute one parsed plugin task request. */
|
|
631
|
+
async function processPluginTask(message, options = {}) {
|
|
632
|
+
await withPluginTaskLock(pluginTaskId(message), async () => {
|
|
633
|
+
const resolved = findPluginTask(message);
|
|
634
|
+
if (!resolved) throw new Error(`Plugin task "${message.plugin}.${message.name}" is not registered`);
|
|
635
|
+
await resolved.task.run(taskPluginContext(resolved.plugin, message, options));
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
//#endregion
|
|
639
|
+
export { markDispatchCompleted as _, claimDispatchMailboxAppend as a, getDispatchConversationId as c, getDispatchTurnId as d, getPluginDispatchProjection as f, markDispatchBlocked as g, markDispatchAwaitingResume as h, resolveTurnSessionRouting as i, getDispatchInputMessageId as l, listPendingDispatchMailboxAppends as m, scheduleSessionCompletedPluginTasks as n, confirmDispatchMailboxAppend as o, isTerminalDispatchStatus as p, task_runner_exports as r, createOrGetDispatch as s, processPluginTask as t, getDispatchRecord as u, markDispatchFailed as v, markDispatchRunning as y };
|