@otakumesi/heph 0.0.1
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/cli.d.mts +1 -0
- package/dist/cli.mjs +536 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/core.d.mts +2 -0
- package/dist/core.mjs +2 -0
- package/dist/hono.d.mts +30 -0
- package/dist/hono.d.mts.map +1 -0
- package/dist/hono.mjs +425 -0
- package/dist/hono.mjs.map +1 -0
- package/dist/index-CdsI9z7r.d.mts +1075 -0
- package/dist/index-CdsI9z7r.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/mcp.d.mts +2 -0
- package/dist/mcp.mjs +2 -0
- package/dist/skills-D1QE4Dtc.d.mts +13 -0
- package/dist/skills-D1QE4Dtc.d.mts.map +1 -0
- package/dist/skills-DLfYbSME.mjs +131 -0
- package/dist/skills-DLfYbSME.mjs.map +1 -0
- package/dist/skills.d.mts +2 -0
- package/dist/skills.mjs +2 -0
- package/dist/sqlite.d.mts +138 -0
- package/dist/sqlite.d.mts.map +1 -0
- package/dist/sqlite.mjs +1140 -0
- package/dist/sqlite.mjs.map +1 -0
- package/dist/src-DeheByi4.mjs +2677 -0
- package/dist/src-DeheByi4.mjs.map +1 -0
- package/dist/worker.d.mts +15 -0
- package/dist/worker.d.mts.map +1 -0
- package/dist/worker.mjs +18 -0
- package/dist/worker.mjs.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,2677 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../core/src/errors.ts
|
|
3
|
+
var HephError = class extends Error {
|
|
4
|
+
code;
|
|
5
|
+
title;
|
|
6
|
+
details;
|
|
7
|
+
status;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super(options.message ?? options.title, hasCause(options) ? { cause: options.cause } : void 0);
|
|
10
|
+
this.name = "HephError";
|
|
11
|
+
this.code = options.code;
|
|
12
|
+
this.title = options.title;
|
|
13
|
+
if (options.details !== void 0) this.details = options.details;
|
|
14
|
+
if (options.status !== void 0) this.status = options.status;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function isHephError(error) {
|
|
18
|
+
return error instanceof HephError;
|
|
19
|
+
}
|
|
20
|
+
function toErrorDetails(error) {
|
|
21
|
+
if (error instanceof Error) return {
|
|
22
|
+
name: error.name,
|
|
23
|
+
message: error.message
|
|
24
|
+
};
|
|
25
|
+
return { message: String(error) };
|
|
26
|
+
}
|
|
27
|
+
function hasCause(options) {
|
|
28
|
+
return "cause" in options;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region ../core/src/context.ts
|
|
32
|
+
var ContextRenderer = class {
|
|
33
|
+
render(options) {
|
|
34
|
+
const slotValues = /* @__PURE__ */ new Map();
|
|
35
|
+
const manifestBlocks = [];
|
|
36
|
+
for (const block of options.blocks) {
|
|
37
|
+
const slot = options.template.slots[block.key];
|
|
38
|
+
const originalTokens = estimateTokens(block.content);
|
|
39
|
+
const truncatedContent = slot?.maxTokens ? truncateToTokens(block.content, slot.maxTokens) : block.content;
|
|
40
|
+
const tokens = estimateTokens(truncatedContent);
|
|
41
|
+
const existing = slotValues.get(block.key);
|
|
42
|
+
slotValues.set(block.key, existing ? `${existing}\n\n${truncatedContent}` : truncatedContent);
|
|
43
|
+
manifestBlocks.push({
|
|
44
|
+
key: block.key,
|
|
45
|
+
type: block.type,
|
|
46
|
+
tokens,
|
|
47
|
+
sourceRefs: block.sourceRefs ?? [],
|
|
48
|
+
truncated: tokens < originalTokens
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const [key, slot] of Object.entries(options.template.slots)) {
|
|
52
|
+
const value = slotValues.get(key);
|
|
53
|
+
if (slot.required && isBlank(value)) throw new HephError({
|
|
54
|
+
code: "HEPH2001",
|
|
55
|
+
title: "Required context slot is missing",
|
|
56
|
+
message: `Context template ${options.template.id} requires slot ${key}.`,
|
|
57
|
+
status: 422,
|
|
58
|
+
details: {
|
|
59
|
+
templateId: options.template.id,
|
|
60
|
+
slot: key
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const messages = options.template.messages.map((message) => ({
|
|
65
|
+
role: message.role,
|
|
66
|
+
content: interpolate(message.content, {
|
|
67
|
+
input: options.input,
|
|
68
|
+
runtime: options.runtime ?? {},
|
|
69
|
+
slots: slotValues
|
|
70
|
+
}).trim()
|
|
71
|
+
}));
|
|
72
|
+
return {
|
|
73
|
+
messages,
|
|
74
|
+
manifest: {
|
|
75
|
+
runId: options.runId,
|
|
76
|
+
contextTemplateId: options.template.id,
|
|
77
|
+
contextTemplateVersion: options.template.version,
|
|
78
|
+
blocks: manifestBlocks,
|
|
79
|
+
totalTokens: messages.reduce((sum, message) => sum + estimateTokens(message.content), 0),
|
|
80
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const defaultContextTemplate = {
|
|
86
|
+
id: "default",
|
|
87
|
+
version: "0.1.0",
|
|
88
|
+
slots: {
|
|
89
|
+
runtimePolicy: { required: true },
|
|
90
|
+
agentIdentity: { required: true },
|
|
91
|
+
developerRules: { maxTokens: 1200 },
|
|
92
|
+
currentTask: {
|
|
93
|
+
required: true,
|
|
94
|
+
maxTokens: 1200
|
|
95
|
+
},
|
|
96
|
+
sessionState: {
|
|
97
|
+
required: true,
|
|
98
|
+
maxTokens: 1500
|
|
99
|
+
},
|
|
100
|
+
openTasks: { maxTokens: 1e3 },
|
|
101
|
+
pendingApprovals: { maxTokens: 800 },
|
|
102
|
+
skills: { maxTokens: 2e3 },
|
|
103
|
+
memories: { maxTokens: 2e3 },
|
|
104
|
+
condensedHistory: { maxTokens: 2e3 },
|
|
105
|
+
recentMessages: { maxTokens: 3e3 },
|
|
106
|
+
domainContext: { maxTokens: 2500 },
|
|
107
|
+
workspaceContext: { maxTokens: 2500 },
|
|
108
|
+
artifacts: { maxTokens: 1500 },
|
|
109
|
+
teamContext: { maxTokens: 1500 },
|
|
110
|
+
toolManifest: {
|
|
111
|
+
required: true,
|
|
112
|
+
maxTokens: 2500
|
|
113
|
+
},
|
|
114
|
+
outputContract: { maxTokens: 1e3 }
|
|
115
|
+
},
|
|
116
|
+
messages: [
|
|
117
|
+
{
|
|
118
|
+
role: "system",
|
|
119
|
+
content: `
|
|
120
|
+
{{ runtimePolicy }}
|
|
121
|
+
|
|
122
|
+
{{ agentIdentity }}
|
|
123
|
+
`
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
role: "developer",
|
|
127
|
+
content: `
|
|
128
|
+
Developer rules:
|
|
129
|
+
{{ developerRules }}
|
|
130
|
+
|
|
131
|
+
Tool and safety policy:
|
|
132
|
+
{{ runtime.toolPolicy }}
|
|
133
|
+
|
|
134
|
+
Output contract:
|
|
135
|
+
{{ outputContract }}
|
|
136
|
+
`
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
role: "user",
|
|
140
|
+
content: `
|
|
141
|
+
Current task:
|
|
142
|
+
{{ currentTask }}
|
|
143
|
+
|
|
144
|
+
Current session state:
|
|
145
|
+
{{ sessionState }}
|
|
146
|
+
|
|
147
|
+
Open tasks:
|
|
148
|
+
{{ openTasks }}
|
|
149
|
+
|
|
150
|
+
Pending approvals or blocked actions:
|
|
151
|
+
{{ pendingApprovals }}
|
|
152
|
+
|
|
153
|
+
Active skills:
|
|
154
|
+
{{ skills }}
|
|
155
|
+
|
|
156
|
+
Relevant memory:
|
|
157
|
+
{{ memories }}
|
|
158
|
+
|
|
159
|
+
Condensed prior history:
|
|
160
|
+
{{ condensedHistory }}
|
|
161
|
+
|
|
162
|
+
Recent conversation:
|
|
163
|
+
{{ recentMessages }}
|
|
164
|
+
|
|
165
|
+
Domain context:
|
|
166
|
+
{{ domainContext }}
|
|
167
|
+
|
|
168
|
+
Workspace context:
|
|
169
|
+
{{ workspaceContext }}
|
|
170
|
+
|
|
171
|
+
Relevant artifacts:
|
|
172
|
+
{{ artifacts }}
|
|
173
|
+
|
|
174
|
+
Team context:
|
|
175
|
+
{{ teamContext }}
|
|
176
|
+
|
|
177
|
+
Available tools for this Run:
|
|
178
|
+
{{ toolManifest }}
|
|
179
|
+
|
|
180
|
+
User input:
|
|
181
|
+
{{ input }}
|
|
182
|
+
`
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
function estimateTokens(content) {
|
|
187
|
+
if (!content) return 0;
|
|
188
|
+
return Math.max(1, Math.ceil(content.length / 4));
|
|
189
|
+
}
|
|
190
|
+
function truncateToTokens(content, maxTokens) {
|
|
191
|
+
const maxChars = Math.max(0, maxTokens * 4);
|
|
192
|
+
if (content.length <= maxChars) return content;
|
|
193
|
+
return `${content.slice(0, Math.max(0, maxChars - 16)).trimEnd()}\n[truncated]`;
|
|
194
|
+
}
|
|
195
|
+
function interpolate(template, values) {
|
|
196
|
+
return template.replaceAll(/\{\{\s*([\w.]+)\s*\}\}/g, (_match, key) => {
|
|
197
|
+
if (key === "input") return values.input;
|
|
198
|
+
if (key.startsWith("runtime.")) return values.runtime[key.slice(8)] ?? "";
|
|
199
|
+
return values.slots.get(key) ?? "";
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function isBlank(value) {
|
|
203
|
+
return value === void 0 || value.trim().length === 0;
|
|
204
|
+
}
|
|
205
|
+
function messagesToText(messages) {
|
|
206
|
+
return messages.map((message) => `${message.role}: ${message.content}`).join("\n\n");
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region ../core/src/definitions.ts
|
|
210
|
+
function defineAgent(definition) {
|
|
211
|
+
return {
|
|
212
|
+
id: definition.id,
|
|
213
|
+
version: definition.version ?? null,
|
|
214
|
+
instructions: definition.instructions,
|
|
215
|
+
model: definition.model ?? null,
|
|
216
|
+
tools: definition.tools ?? [],
|
|
217
|
+
mcp: normalizeMcpPolicy(definition.mcp, definition.allowAllMcpTools),
|
|
218
|
+
skills: normalizeSkillPolicy(definition.skills),
|
|
219
|
+
contextProviders: [...definition.contextProviders ?? [], ...definition.context ?? []],
|
|
220
|
+
contextTemplate: definition.contextTemplate ?? null,
|
|
221
|
+
metadata: definition.metadata ?? {}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function normalizeMcpPolicy(policy, allowAllTools) {
|
|
225
|
+
if (policy === void 0 || policy === null) return null;
|
|
226
|
+
if (Array.isArray(policy)) {
|
|
227
|
+
const normalized = { allowCapabilities: policy };
|
|
228
|
+
if (allowAllTools !== void 0) normalized.allowAllTools = allowAllTools;
|
|
229
|
+
return normalized;
|
|
230
|
+
}
|
|
231
|
+
if (allowAllTools !== void 0) return {
|
|
232
|
+
...policy,
|
|
233
|
+
allowAllTools
|
|
234
|
+
};
|
|
235
|
+
return policy;
|
|
236
|
+
}
|
|
237
|
+
function normalizeSkillPolicy(policy) {
|
|
238
|
+
if (policy === void 0 || policy === null) return null;
|
|
239
|
+
if (policy === "all") return { allow: "all" };
|
|
240
|
+
if (Array.isArray(policy)) return { allow: policy };
|
|
241
|
+
return policy;
|
|
242
|
+
}
|
|
243
|
+
function defineContextProvider(definition) {
|
|
244
|
+
return {
|
|
245
|
+
id: definition.id,
|
|
246
|
+
load: definition.load
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function defineContextTemplate(template) {
|
|
250
|
+
return template;
|
|
251
|
+
}
|
|
252
|
+
function defineTool(definition) {
|
|
253
|
+
const jsonSchema = toJsonSchema(definition.id, definition.inputSchema);
|
|
254
|
+
const tool = {
|
|
255
|
+
id: definition.id,
|
|
256
|
+
description: definition.description,
|
|
257
|
+
inputSchema: definition.inputSchema,
|
|
258
|
+
jsonSchema,
|
|
259
|
+
sideEffect: definition.sideEffect ?? false,
|
|
260
|
+
requiresApproval: definition.requiresApproval ?? false,
|
|
261
|
+
execute: definition.execute
|
|
262
|
+
};
|
|
263
|
+
if (definition.concurrencyKey !== void 0) tool.concurrencyKey = definition.concurrencyKey;
|
|
264
|
+
return tool;
|
|
265
|
+
}
|
|
266
|
+
const AgentSpec = { define: defineAgent };
|
|
267
|
+
const ContextProvider = { define: defineContextProvider };
|
|
268
|
+
const ContextTemplate = { define: defineContextTemplate };
|
|
269
|
+
const Tool = { define: defineTool };
|
|
270
|
+
function toJsonSchema(toolId, schema) {
|
|
271
|
+
try {
|
|
272
|
+
return z.toJSONSchema(schema);
|
|
273
|
+
} catch (cause) {
|
|
274
|
+
throw new HephError({
|
|
275
|
+
code: "HEPH3001",
|
|
276
|
+
title: "Tool schema is not JSON Schema representable",
|
|
277
|
+
message: `Tool ${toolId} uses a Zod schema that cannot be exposed to the model.`,
|
|
278
|
+
status: 422,
|
|
279
|
+
details: { toolId },
|
|
280
|
+
cause
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region ../core/src/executor.ts
|
|
286
|
+
var MinimalRunExecutor = class {
|
|
287
|
+
async execute(ctx) {
|
|
288
|
+
await ctx.emit({
|
|
289
|
+
type: "turn.started",
|
|
290
|
+
payload: { executor: "minimal" }
|
|
291
|
+
});
|
|
292
|
+
const text = runInputText$1(ctx.run.input);
|
|
293
|
+
const response = text ? `Minimal executor received: ${text}` : "Minimal executor completed the run.";
|
|
294
|
+
await ctx.emit({
|
|
295
|
+
type: "message.started",
|
|
296
|
+
payload: { role: "assistant" }
|
|
297
|
+
});
|
|
298
|
+
await ctx.emit({
|
|
299
|
+
type: "message.delta",
|
|
300
|
+
payload: { text: response }
|
|
301
|
+
});
|
|
302
|
+
const message = await ctx.appendMessage({
|
|
303
|
+
role: "assistant",
|
|
304
|
+
content: response,
|
|
305
|
+
sourceRunId: ctx.run.id,
|
|
306
|
+
metadata: { executor: "minimal" }
|
|
307
|
+
});
|
|
308
|
+
await ctx.emit({
|
|
309
|
+
type: "message.completed",
|
|
310
|
+
payload: {
|
|
311
|
+
messageId: message.id,
|
|
312
|
+
role: message.role,
|
|
313
|
+
content: message.content
|
|
314
|
+
},
|
|
315
|
+
sourceRefs: [{
|
|
316
|
+
type: "message",
|
|
317
|
+
id: message.id
|
|
318
|
+
}]
|
|
319
|
+
});
|
|
320
|
+
await ctx.emit({
|
|
321
|
+
type: "turn.completed",
|
|
322
|
+
payload: { executor: "minimal" }
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
function runInputText$1(input) {
|
|
327
|
+
return "text" in input ? input.text : "";
|
|
328
|
+
}
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region ../core/src/ids.ts
|
|
331
|
+
let fallbackCounter = 0;
|
|
332
|
+
function createId(prefix) {
|
|
333
|
+
const randomId = globalThis.crypto?.randomUUID?.();
|
|
334
|
+
if (randomId) return `${prefix}${randomId.replaceAll("-", "")}`;
|
|
335
|
+
fallbackCounter += 1;
|
|
336
|
+
return `${prefix}${Date.now().toString(36)}${fallbackCounter.toString(36)}`;
|
|
337
|
+
}
|
|
338
|
+
function createAgentSessionId() {
|
|
339
|
+
return createId("agent_");
|
|
340
|
+
}
|
|
341
|
+
function createRunId() {
|
|
342
|
+
return createId("run_");
|
|
343
|
+
}
|
|
344
|
+
function createMessageId() {
|
|
345
|
+
return createId("msg_");
|
|
346
|
+
}
|
|
347
|
+
function createRunEventId() {
|
|
348
|
+
return createId("evt_");
|
|
349
|
+
}
|
|
350
|
+
function createMemoryId() {
|
|
351
|
+
return createId("mem_");
|
|
352
|
+
}
|
|
353
|
+
function createInboxEventId() {
|
|
354
|
+
return createId("inbox_");
|
|
355
|
+
}
|
|
356
|
+
function createDeferredToolOperationId() {
|
|
357
|
+
return createId("op_");
|
|
358
|
+
}
|
|
359
|
+
function createMcpBindingId() {
|
|
360
|
+
return createId("mcpbind_");
|
|
361
|
+
}
|
|
362
|
+
function createSkillBindingId() {
|
|
363
|
+
return createId("skillbind_");
|
|
364
|
+
}
|
|
365
|
+
function createApprovalRequestId() {
|
|
366
|
+
return createId("approval_");
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region ../core/src/providers.ts
|
|
370
|
+
function recentMessages(options = {}) {
|
|
371
|
+
const limit = options.limit ?? 20;
|
|
372
|
+
return defineContextProvider({
|
|
373
|
+
id: "recent-messages",
|
|
374
|
+
async load(ctx) {
|
|
375
|
+
const messages = await ctx.stores.messages.listMessages(ctx.agent.id, { limit });
|
|
376
|
+
if (messages.length === 0) return null;
|
|
377
|
+
return {
|
|
378
|
+
key: "recentMessages",
|
|
379
|
+
type: "message_history",
|
|
380
|
+
content: formatMessages(messages),
|
|
381
|
+
sourceRefs: messages.map((message) => ({
|
|
382
|
+
type: "message",
|
|
383
|
+
id: message.id
|
|
384
|
+
}))
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function threadState() {
|
|
390
|
+
return defineContextProvider({
|
|
391
|
+
id: "thread-state",
|
|
392
|
+
async load(ctx) {
|
|
393
|
+
return {
|
|
394
|
+
key: "sessionState",
|
|
395
|
+
type: "state",
|
|
396
|
+
content: JSON.stringify(ctx.agent.state, null, 2)
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function memorySearch(options = {}) {
|
|
402
|
+
const topK = options.topK ?? 8;
|
|
403
|
+
return defineContextProvider({
|
|
404
|
+
id: "memory-search",
|
|
405
|
+
async load(ctx) {
|
|
406
|
+
const query = "text" in ctx.input ? ctx.input.text : void 0;
|
|
407
|
+
const searchInput = {
|
|
408
|
+
scopes: options.scopes ?? defaultMemoryScopes(ctx.agent.id, ctx.spec.id, ctx.auth?.userId),
|
|
409
|
+
topK
|
|
410
|
+
};
|
|
411
|
+
const memories = await ctx.stores.memory.searchMemory(query === void 0 ? searchInput : {
|
|
412
|
+
...searchInput,
|
|
413
|
+
query
|
|
414
|
+
});
|
|
415
|
+
if (memories.length === 0) return null;
|
|
416
|
+
return {
|
|
417
|
+
key: "memories",
|
|
418
|
+
type: "memory",
|
|
419
|
+
content: memories.map((memory) => {
|
|
420
|
+
const sourceRefs = memory.sourceRefs.map((ref) => `${ref.type}:${ref.id}`).join(", ");
|
|
421
|
+
return `- [${memory.kind}] ${memory.content} (sourceRefs: ${sourceRefs})`;
|
|
422
|
+
}).join("\n"),
|
|
423
|
+
sourceRefs: memories.map((memory) => ({
|
|
424
|
+
type: "memory",
|
|
425
|
+
id: memory.id
|
|
426
|
+
}))
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
function formatMessages(messages) {
|
|
432
|
+
return messages.map((message) => `${message.role}: ${message.content}`).join("\n");
|
|
433
|
+
}
|
|
434
|
+
function defaultMemoryScopes(sessionId, agentSpecId, userId) {
|
|
435
|
+
const scopes = [{
|
|
436
|
+
type: "session",
|
|
437
|
+
id: sessionId
|
|
438
|
+
}, {
|
|
439
|
+
type: "agent",
|
|
440
|
+
id: agentSpecId
|
|
441
|
+
}];
|
|
442
|
+
if (userId) scopes.push({
|
|
443
|
+
type: "user",
|
|
444
|
+
id: userId
|
|
445
|
+
});
|
|
446
|
+
return scopes;
|
|
447
|
+
}
|
|
448
|
+
function block(block) {
|
|
449
|
+
return block;
|
|
450
|
+
}
|
|
451
|
+
//#endregion
|
|
452
|
+
//#region ../core/src/queue.ts
|
|
453
|
+
var InProcessQueue = class {
|
|
454
|
+
concurrency;
|
|
455
|
+
onError;
|
|
456
|
+
jobs = [];
|
|
457
|
+
activeAgents = /* @__PURE__ */ new Set();
|
|
458
|
+
idleResolvers = /* @__PURE__ */ new Set();
|
|
459
|
+
activeCount = 0;
|
|
460
|
+
scheduled = false;
|
|
461
|
+
handler = null;
|
|
462
|
+
constructor(options = {}) {
|
|
463
|
+
this.concurrency = options.concurrency ?? 4;
|
|
464
|
+
this.onError = options.onError ?? ((error, job) => {
|
|
465
|
+
console.error("Unhandled Heph in-process queue error", {
|
|
466
|
+
error,
|
|
467
|
+
job
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
async startConsumer(handler) {
|
|
472
|
+
this.handler = handler;
|
|
473
|
+
this.schedule();
|
|
474
|
+
}
|
|
475
|
+
async enqueue(job) {
|
|
476
|
+
this.jobs.push(job);
|
|
477
|
+
this.schedule();
|
|
478
|
+
}
|
|
479
|
+
async onIdle() {
|
|
480
|
+
if (this.isIdle()) return;
|
|
481
|
+
await new Promise((resolve) => {
|
|
482
|
+
this.idleResolvers.add(resolve);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
schedule() {
|
|
486
|
+
if (this.scheduled) return;
|
|
487
|
+
this.scheduled = true;
|
|
488
|
+
queueMicrotask(() => {
|
|
489
|
+
this.scheduled = false;
|
|
490
|
+
this.pump();
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
pump() {
|
|
494
|
+
if (!this.handler) {
|
|
495
|
+
this.resolveIdleIfNeeded();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
while (this.activeCount < this.concurrency) {
|
|
499
|
+
const index = this.jobs.findIndex((job) => !this.activeAgents.has(job.agentId));
|
|
500
|
+
if (index === -1) break;
|
|
501
|
+
const [job] = this.jobs.splice(index, 1);
|
|
502
|
+
if (!job) break;
|
|
503
|
+
this.activeCount += 1;
|
|
504
|
+
this.activeAgents.add(job.agentId);
|
|
505
|
+
this.handler(job).catch((error) => {
|
|
506
|
+
this.onError(error, job);
|
|
507
|
+
}).finally(() => {
|
|
508
|
+
this.activeCount -= 1;
|
|
509
|
+
this.activeAgents.delete(job.agentId);
|
|
510
|
+
this.resolveIdleIfNeeded();
|
|
511
|
+
this.schedule();
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
this.resolveIdleIfNeeded();
|
|
515
|
+
}
|
|
516
|
+
isIdle() {
|
|
517
|
+
return this.jobs.length === 0 && this.activeCount === 0;
|
|
518
|
+
}
|
|
519
|
+
resolveIdleIfNeeded() {
|
|
520
|
+
if (!this.isIdle()) return;
|
|
521
|
+
for (const resolve of this.idleResolvers) resolve();
|
|
522
|
+
this.idleResolvers.clear();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
//#endregion
|
|
526
|
+
//#region ../core/src/skills.ts
|
|
527
|
+
function createInMemorySkillCatalog(skills) {
|
|
528
|
+
const byId = /* @__PURE__ */ new Map();
|
|
529
|
+
for (const skill of skills) byId.set(skill.id, cloneSkillPackage(skill));
|
|
530
|
+
return {
|
|
531
|
+
async getSkill(id) {
|
|
532
|
+
const skill = byId.get(id);
|
|
533
|
+
return skill ? cloneSkillPackage(skill) : null;
|
|
534
|
+
},
|
|
535
|
+
async listSkills() {
|
|
536
|
+
return Array.from(byId.values()).sort((a, b) => a.id.localeCompare(b.id)).map(cloneSkillPackage);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function cloneSkillPackage(skill) {
|
|
541
|
+
return {
|
|
542
|
+
...skill,
|
|
543
|
+
source: { ...skill.source },
|
|
544
|
+
references: skill.references.map((ref) => ({
|
|
545
|
+
...ref,
|
|
546
|
+
metadata: { ...ref.metadata }
|
|
547
|
+
})),
|
|
548
|
+
assets: skill.assets.map((ref) => ({
|
|
549
|
+
...ref,
|
|
550
|
+
metadata: { ...ref.metadata }
|
|
551
|
+
})),
|
|
552
|
+
templates: skill.templates.map((ref) => ({
|
|
553
|
+
...ref,
|
|
554
|
+
metadata: { ...ref.metadata }
|
|
555
|
+
})),
|
|
556
|
+
metadata: { ...skill.metadata },
|
|
557
|
+
loadedAt: new Date(skill.loadedAt)
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region ../core/src/stores.ts
|
|
562
|
+
var InMemoryHephStore = class {
|
|
563
|
+
state = this;
|
|
564
|
+
messages = this;
|
|
565
|
+
inbox = this;
|
|
566
|
+
events = this;
|
|
567
|
+
memory = this;
|
|
568
|
+
mcpBindings = this;
|
|
569
|
+
skillBindings = this;
|
|
570
|
+
approvals = this;
|
|
571
|
+
deferredToolOperations = this;
|
|
572
|
+
agentSessions = /* @__PURE__ */ new Map();
|
|
573
|
+
runs = /* @__PURE__ */ new Map();
|
|
574
|
+
messageList = [];
|
|
575
|
+
inboxList = [];
|
|
576
|
+
inboxEvents = /* @__PURE__ */ new Map();
|
|
577
|
+
eventList = [];
|
|
578
|
+
eventSeqByRun = /* @__PURE__ */ new Map();
|
|
579
|
+
memoryItems = /* @__PURE__ */ new Map();
|
|
580
|
+
mcpBindingList = [];
|
|
581
|
+
mcpBindingsById = /* @__PURE__ */ new Map();
|
|
582
|
+
skillBindingList = [];
|
|
583
|
+
skillBindingsById = /* @__PURE__ */ new Map();
|
|
584
|
+
approvalRequests = /* @__PURE__ */ new Map();
|
|
585
|
+
deferredOperations = /* @__PURE__ */ new Map();
|
|
586
|
+
async createAgentSession(input) {
|
|
587
|
+
const now = /* @__PURE__ */ new Date();
|
|
588
|
+
const agent = {
|
|
589
|
+
id: input.id ?? createAgentSessionId(),
|
|
590
|
+
agentSpecId: input.agentSpecId,
|
|
591
|
+
agentSpecVersion: input.agentSpecVersion ?? null,
|
|
592
|
+
state: input.state ?? {},
|
|
593
|
+
activeRunId: null,
|
|
594
|
+
auth: input.auth ?? null,
|
|
595
|
+
metadata: input.metadata ?? {},
|
|
596
|
+
createdAt: now,
|
|
597
|
+
updatedAt: now
|
|
598
|
+
};
|
|
599
|
+
this.agentSessions.set(agent.id, cloneAgentSession(agent));
|
|
600
|
+
return cloneAgentSession(agent);
|
|
601
|
+
}
|
|
602
|
+
async getAgentSession(id) {
|
|
603
|
+
const agent = this.agentSessions.get(id);
|
|
604
|
+
return agent ? cloneAgentSession(agent) : null;
|
|
605
|
+
}
|
|
606
|
+
async updateAgentSession(id, patch) {
|
|
607
|
+
const existing = this.agentSessions.get(id);
|
|
608
|
+
if (!existing) throw notFound("AgentSession not found", { agentId: id });
|
|
609
|
+
const updated = {
|
|
610
|
+
...existing,
|
|
611
|
+
...patch,
|
|
612
|
+
id,
|
|
613
|
+
createdAt: existing.createdAt,
|
|
614
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
615
|
+
};
|
|
616
|
+
this.agentSessions.set(id, cloneAgentSession(updated));
|
|
617
|
+
return cloneAgentSession(updated);
|
|
618
|
+
}
|
|
619
|
+
async createRun(input) {
|
|
620
|
+
const now = /* @__PURE__ */ new Date();
|
|
621
|
+
const run = {
|
|
622
|
+
id: input.id ?? createRunId(),
|
|
623
|
+
agentId: input.agentId,
|
|
624
|
+
agentSpecId: input.agentSpecId,
|
|
625
|
+
agentSpecVersion: input.agentSpecVersion ?? null,
|
|
626
|
+
status: input.status,
|
|
627
|
+
input: input.input,
|
|
628
|
+
auth: input.auth ?? null,
|
|
629
|
+
contextManifest: null,
|
|
630
|
+
skillManifest: null,
|
|
631
|
+
toolManifest: null,
|
|
632
|
+
error: null,
|
|
633
|
+
metadata: input.metadata ?? {},
|
|
634
|
+
queuedAt: now,
|
|
635
|
+
startedAt: null,
|
|
636
|
+
completedAt: null,
|
|
637
|
+
createdAt: now,
|
|
638
|
+
updatedAt: now
|
|
639
|
+
};
|
|
640
|
+
this.runs.set(run.id, cloneRun(run));
|
|
641
|
+
return cloneRun(run);
|
|
642
|
+
}
|
|
643
|
+
async getRun(id) {
|
|
644
|
+
const run = this.runs.get(id);
|
|
645
|
+
return run ? cloneRun(run) : null;
|
|
646
|
+
}
|
|
647
|
+
async updateRun(id, patch) {
|
|
648
|
+
const existing = this.runs.get(id);
|
|
649
|
+
if (!existing) throw notFound("Run not found", { runId: id });
|
|
650
|
+
const updated = {
|
|
651
|
+
...existing,
|
|
652
|
+
...patch,
|
|
653
|
+
id,
|
|
654
|
+
createdAt: existing.createdAt,
|
|
655
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
656
|
+
};
|
|
657
|
+
this.runs.set(id, cloneRun(updated));
|
|
658
|
+
return cloneRun(updated);
|
|
659
|
+
}
|
|
660
|
+
async listRunsByAgent(agentId) {
|
|
661
|
+
return Array.from(this.runs.values()).filter((run) => run.agentId === agentId).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).map(cloneRun);
|
|
662
|
+
}
|
|
663
|
+
async appendMessage(input) {
|
|
664
|
+
const message = {
|
|
665
|
+
id: input.id ?? createMessageId(),
|
|
666
|
+
agentId: input.agentId,
|
|
667
|
+
role: input.role,
|
|
668
|
+
content: input.content,
|
|
669
|
+
sourceRunId: input.sourceRunId ?? null,
|
|
670
|
+
auth: input.auth ?? null,
|
|
671
|
+
metadata: input.metadata ?? {},
|
|
672
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
673
|
+
};
|
|
674
|
+
this.messageList.push(cloneMessage(message));
|
|
675
|
+
return cloneMessage(message);
|
|
676
|
+
}
|
|
677
|
+
async listMessages(agentId, options = {}) {
|
|
678
|
+
const messages = this.messageList.filter((message) => message.agentId === agentId).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
679
|
+
return (options.limit === void 0 ? messages : messages.slice(Math.max(0, messages.length - options.limit))).map(cloneMessage);
|
|
680
|
+
}
|
|
681
|
+
async appendInboxEvent(input) {
|
|
682
|
+
const now = /* @__PURE__ */ new Date();
|
|
683
|
+
const event = {
|
|
684
|
+
id: input.id ?? createInboxEventId(),
|
|
685
|
+
agentId: input.agentId,
|
|
686
|
+
type: input.input.type,
|
|
687
|
+
input: clonePlain(input.input),
|
|
688
|
+
status: "pending",
|
|
689
|
+
runId: null,
|
|
690
|
+
auth: input.auth ?? null,
|
|
691
|
+
metadata: input.metadata ?? {},
|
|
692
|
+
createdAt: now,
|
|
693
|
+
updatedAt: now,
|
|
694
|
+
claimedAt: null,
|
|
695
|
+
processedAt: null,
|
|
696
|
+
failedAt: null,
|
|
697
|
+
error: null
|
|
698
|
+
};
|
|
699
|
+
this.inboxList.push(cloneInboxEvent(event));
|
|
700
|
+
this.inboxEvents.set(event.id, cloneInboxEvent(event));
|
|
701
|
+
return cloneInboxEvent(event);
|
|
702
|
+
}
|
|
703
|
+
async getInboxEvent(id) {
|
|
704
|
+
const event = this.inboxEvents.get(id);
|
|
705
|
+
return event ? cloneInboxEvent(event) : null;
|
|
706
|
+
}
|
|
707
|
+
async listInboxEvents(agentId, options = {}) {
|
|
708
|
+
const events = this.inboxList.filter((event) => event.agentId === agentId).filter((event) => options.status === void 0 || event.status === options.status).filter((event) => options.types === void 0 || options.types.includes(event.type)).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
709
|
+
return (options.limit === void 0 ? events : events.slice(0, options.limit)).map(cloneInboxEvent);
|
|
710
|
+
}
|
|
711
|
+
async claimPendingInboxEvents(agentId, options = {}) {
|
|
712
|
+
const now = /* @__PURE__ */ new Date();
|
|
713
|
+
const pending = this.inboxList.filter((event) => event.agentId === agentId && event.status === "pending").filter((event) => options.types === void 0 || options.types.includes(event.type)).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
714
|
+
return (options.limit === void 0 ? pending : pending.slice(0, options.limit)).map((event) => {
|
|
715
|
+
return cloneInboxEvent(this.replaceInboxEvent({
|
|
716
|
+
...event,
|
|
717
|
+
status: "processing",
|
|
718
|
+
claimedAt: now,
|
|
719
|
+
updatedAt: now
|
|
720
|
+
}));
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
async markInboxEventsProcessed(ids, runId) {
|
|
724
|
+
const now = /* @__PURE__ */ new Date();
|
|
725
|
+
return ids.map((id) => cloneInboxEvent(this.replaceInboxEvent({
|
|
726
|
+
...this.getInboxEventOrThrow(id),
|
|
727
|
+
status: "processed",
|
|
728
|
+
runId,
|
|
729
|
+
processedAt: now,
|
|
730
|
+
updatedAt: now,
|
|
731
|
+
error: null
|
|
732
|
+
})));
|
|
733
|
+
}
|
|
734
|
+
async markInboxEventsFailed(ids, error) {
|
|
735
|
+
const now = /* @__PURE__ */ new Date();
|
|
736
|
+
return ids.map((id) => cloneInboxEvent(this.replaceInboxEvent({
|
|
737
|
+
...this.getInboxEventOrThrow(id),
|
|
738
|
+
status: "failed",
|
|
739
|
+
failedAt: now,
|
|
740
|
+
updatedAt: now,
|
|
741
|
+
error
|
|
742
|
+
})));
|
|
743
|
+
}
|
|
744
|
+
async appendRunEvent(input) {
|
|
745
|
+
const seq = (this.eventSeqByRun.get(input.runId) ?? 0) + 1;
|
|
746
|
+
this.eventSeqByRun.set(input.runId, seq);
|
|
747
|
+
const event = {
|
|
748
|
+
id: input.id ?? createRunEventId(),
|
|
749
|
+
runId: input.runId,
|
|
750
|
+
seq,
|
|
751
|
+
type: input.type,
|
|
752
|
+
payload: input.payload ?? {},
|
|
753
|
+
sourceRefs: input.sourceRefs ?? [],
|
|
754
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
755
|
+
};
|
|
756
|
+
this.eventList.push(cloneRunEvent(event));
|
|
757
|
+
return cloneRunEvent(event);
|
|
758
|
+
}
|
|
759
|
+
async listRunEvents(runId, options = {}) {
|
|
760
|
+
const after = options.after ?? 0;
|
|
761
|
+
const events = this.eventList.filter((event) => event.runId === runId && event.seq > after).sort((a, b) => a.seq - b.seq);
|
|
762
|
+
return (options.limit === void 0 ? events : events.slice(0, options.limit)).map(cloneRunEvent);
|
|
763
|
+
}
|
|
764
|
+
async putMemory(input) {
|
|
765
|
+
const now = /* @__PURE__ */ new Date();
|
|
766
|
+
const existing = input.id ? this.memoryItems.get(input.id) : void 0;
|
|
767
|
+
const item = {
|
|
768
|
+
id: input.id ?? createMemoryId(),
|
|
769
|
+
scope: input.scope,
|
|
770
|
+
kind: input.kind,
|
|
771
|
+
content: input.content,
|
|
772
|
+
sourceRefs: input.sourceRefs,
|
|
773
|
+
importance: input.importance ?? null,
|
|
774
|
+
confidence: input.confidence ?? null,
|
|
775
|
+
embeddingRef: input.embeddingRef ?? null,
|
|
776
|
+
expiresAt: input.expiresAt ?? null,
|
|
777
|
+
createdAt: existing?.createdAt ?? now,
|
|
778
|
+
updatedAt: now
|
|
779
|
+
};
|
|
780
|
+
this.memoryItems.set(item.id, cloneMemoryItem(item));
|
|
781
|
+
return cloneMemoryItem(item);
|
|
782
|
+
}
|
|
783
|
+
async searchMemory(input) {
|
|
784
|
+
const now = Date.now();
|
|
785
|
+
const query = input.query?.trim().toLowerCase();
|
|
786
|
+
const topK = input.topK ?? 8;
|
|
787
|
+
const scopes = input.scopes ?? [];
|
|
788
|
+
return Array.from(this.memoryItems.values()).filter((item) => item.expiresAt === null || item.expiresAt.getTime() > now).filter((item) => scopes.length === 0 || scopes.some((scope) => sameScope(scope, item.scope))).map((item) => ({
|
|
789
|
+
item,
|
|
790
|
+
score: scoreMemory(item, query)
|
|
791
|
+
})).filter(({ score }) => score > 0 || !query).sort((a, b) => b.score - a.score || b.item.updatedAt.getTime() - a.item.updatedAt.getTime()).slice(0, topK).map(({ item }) => cloneMemoryItem(item));
|
|
792
|
+
}
|
|
793
|
+
async createMcpBinding(input) {
|
|
794
|
+
const now = /* @__PURE__ */ new Date();
|
|
795
|
+
const binding = {
|
|
796
|
+
id: input.id ?? createMcpBindingId(),
|
|
797
|
+
agentId: input.agentId,
|
|
798
|
+
capabilityId: input.capabilityId,
|
|
799
|
+
accountRef: input.accountRef ?? null,
|
|
800
|
+
allowTools: clonePlain(input.allowTools),
|
|
801
|
+
status: "active",
|
|
802
|
+
metadata: input.metadata ?? {},
|
|
803
|
+
createdAt: now,
|
|
804
|
+
updatedAt: now,
|
|
805
|
+
removedAt: null
|
|
806
|
+
};
|
|
807
|
+
this.mcpBindingList.push(cloneMcpBinding(binding));
|
|
808
|
+
this.mcpBindingsById.set(binding.id, cloneMcpBinding(binding));
|
|
809
|
+
return cloneMcpBinding(binding);
|
|
810
|
+
}
|
|
811
|
+
async getMcpBinding(id) {
|
|
812
|
+
const binding = this.mcpBindingsById.get(id);
|
|
813
|
+
return binding ? cloneMcpBinding(binding) : null;
|
|
814
|
+
}
|
|
815
|
+
async listMcpBindings(agentId, options = {}) {
|
|
816
|
+
const status = options.status ?? "active";
|
|
817
|
+
return this.mcpBindingList.filter((binding) => binding.agentId === agentId).filter((binding) => status === "all" || binding.status === status).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).map(cloneMcpBinding);
|
|
818
|
+
}
|
|
819
|
+
async removeMcpBinding(id) {
|
|
820
|
+
const existing = this.mcpBindingsById.get(id);
|
|
821
|
+
if (!existing) throw notFound("McpBinding not found", { bindingId: id });
|
|
822
|
+
const now = /* @__PURE__ */ new Date();
|
|
823
|
+
const updated = {
|
|
824
|
+
...existing,
|
|
825
|
+
status: "removed",
|
|
826
|
+
updatedAt: now,
|
|
827
|
+
removedAt: existing.removedAt ?? now
|
|
828
|
+
};
|
|
829
|
+
this.replaceMcpBinding(updated);
|
|
830
|
+
return cloneMcpBinding(updated);
|
|
831
|
+
}
|
|
832
|
+
async createSkillBinding(input) {
|
|
833
|
+
const now = /* @__PURE__ */ new Date();
|
|
834
|
+
const binding = {
|
|
835
|
+
id: input.id ?? createSkillBindingId(),
|
|
836
|
+
agentId: input.agentId,
|
|
837
|
+
skillId: input.skillId,
|
|
838
|
+
name: input.name,
|
|
839
|
+
version: input.version ?? null,
|
|
840
|
+
source: { ...input.source },
|
|
841
|
+
allowReferences: input.allowReferences === void 0 ? [] : clonePlain(input.allowReferences),
|
|
842
|
+
status: "active",
|
|
843
|
+
metadata: input.metadata ?? {},
|
|
844
|
+
createdAt: now,
|
|
845
|
+
updatedAt: now,
|
|
846
|
+
removedAt: null
|
|
847
|
+
};
|
|
848
|
+
this.skillBindingList.push(cloneSkillBinding(binding));
|
|
849
|
+
this.skillBindingsById.set(binding.id, cloneSkillBinding(binding));
|
|
850
|
+
return cloneSkillBinding(binding);
|
|
851
|
+
}
|
|
852
|
+
async getSkillBinding(id) {
|
|
853
|
+
const binding = this.skillBindingsById.get(id);
|
|
854
|
+
return binding ? cloneSkillBinding(binding) : null;
|
|
855
|
+
}
|
|
856
|
+
async listSkillBindings(agentId, options = {}) {
|
|
857
|
+
const status = options.status ?? "active";
|
|
858
|
+
return this.skillBindingList.filter((binding) => binding.agentId === agentId).filter((binding) => status === "all" || binding.status === status).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).map(cloneSkillBinding);
|
|
859
|
+
}
|
|
860
|
+
async removeSkillBinding(id) {
|
|
861
|
+
const existing = this.skillBindingsById.get(id);
|
|
862
|
+
if (!existing) throw notFound("SkillBinding not found", { bindingId: id });
|
|
863
|
+
const now = /* @__PURE__ */ new Date();
|
|
864
|
+
const updated = {
|
|
865
|
+
...existing,
|
|
866
|
+
status: "removed",
|
|
867
|
+
updatedAt: now,
|
|
868
|
+
removedAt: existing.removedAt ?? now
|
|
869
|
+
};
|
|
870
|
+
this.replaceSkillBinding(updated);
|
|
871
|
+
return cloneSkillBinding(updated);
|
|
872
|
+
}
|
|
873
|
+
async createApprovalRequest(input) {
|
|
874
|
+
const now = /* @__PURE__ */ new Date();
|
|
875
|
+
const request = {
|
|
876
|
+
id: input.id ?? createApprovalRequestId(),
|
|
877
|
+
agentId: input.agentId,
|
|
878
|
+
runId: input.runId,
|
|
879
|
+
toolId: input.toolId,
|
|
880
|
+
input: clonePlain(input.input),
|
|
881
|
+
status: "pending",
|
|
882
|
+
requestedBy: input.requestedBy ?? null,
|
|
883
|
+
decidedBy: null,
|
|
884
|
+
metadata: input.metadata ?? {},
|
|
885
|
+
createdAt: now,
|
|
886
|
+
updatedAt: now,
|
|
887
|
+
decidedAt: null
|
|
888
|
+
};
|
|
889
|
+
this.approvalRequests.set(request.id, cloneApprovalRequest(request));
|
|
890
|
+
return cloneApprovalRequest(request);
|
|
891
|
+
}
|
|
892
|
+
async getApprovalRequest(id) {
|
|
893
|
+
const request = this.approvalRequests.get(id);
|
|
894
|
+
return request ? cloneApprovalRequest(request) : null;
|
|
895
|
+
}
|
|
896
|
+
async listApprovalRequests(runId, options = {}) {
|
|
897
|
+
const status = options.status ?? "all";
|
|
898
|
+
return Array.from(this.approvalRequests.values()).filter((request) => request.runId === runId).filter((request) => status === "all" || request.status === status).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime()).map(cloneApprovalRequest);
|
|
899
|
+
}
|
|
900
|
+
async decideApprovalRequest(input) {
|
|
901
|
+
const existing = this.approvalRequests.get(input.id);
|
|
902
|
+
if (!existing) throw notFound("ApprovalRequest not found", { approvalRequestId: input.id });
|
|
903
|
+
const now = /* @__PURE__ */ new Date();
|
|
904
|
+
const updated = {
|
|
905
|
+
...existing,
|
|
906
|
+
status: input.decision,
|
|
907
|
+
decidedBy: input.decidedBy ?? null,
|
|
908
|
+
metadata: {
|
|
909
|
+
...existing.metadata,
|
|
910
|
+
...input.metadata ?? {}
|
|
911
|
+
},
|
|
912
|
+
updatedAt: now,
|
|
913
|
+
decidedAt: now
|
|
914
|
+
};
|
|
915
|
+
this.approvalRequests.set(input.id, cloneApprovalRequest(updated));
|
|
916
|
+
return cloneApprovalRequest(updated);
|
|
917
|
+
}
|
|
918
|
+
async createDeferredToolOperation(input) {
|
|
919
|
+
const now = /* @__PURE__ */ new Date();
|
|
920
|
+
const operation = {
|
|
921
|
+
id: input.id ?? createDeferredToolOperationId(),
|
|
922
|
+
agentId: input.agentId,
|
|
923
|
+
runId: input.runId,
|
|
924
|
+
toolId: input.toolId,
|
|
925
|
+
toolCallId: input.toolCallId ?? null,
|
|
926
|
+
status: "pending",
|
|
927
|
+
resumePolicy: input.resumePolicy ?? "auto",
|
|
928
|
+
auth: input.auth ?? null,
|
|
929
|
+
result: null,
|
|
930
|
+
error: null,
|
|
931
|
+
metadata: input.metadata ?? {},
|
|
932
|
+
createdAt: now,
|
|
933
|
+
updatedAt: now,
|
|
934
|
+
completedAt: null
|
|
935
|
+
};
|
|
936
|
+
this.deferredOperations.set(operation.id, cloneDeferredToolOperation(operation));
|
|
937
|
+
return cloneDeferredToolOperation(operation);
|
|
938
|
+
}
|
|
939
|
+
async getDeferredToolOperation(id) {
|
|
940
|
+
const operation = this.deferredOperations.get(id);
|
|
941
|
+
return operation ? cloneDeferredToolOperation(operation) : null;
|
|
942
|
+
}
|
|
943
|
+
async completeDeferredToolOperation(input) {
|
|
944
|
+
const existing = this.deferredOperations.get(input.id);
|
|
945
|
+
if (!existing) throw notFound("DeferredToolOperation not found", { operationId: input.id });
|
|
946
|
+
if (existing.status !== "pending") return cloneDeferredToolOperation(existing);
|
|
947
|
+
const now = /* @__PURE__ */ new Date();
|
|
948
|
+
const updated = {
|
|
949
|
+
...existing,
|
|
950
|
+
status: input.status,
|
|
951
|
+
result: input.result ?? null,
|
|
952
|
+
error: input.error ?? null,
|
|
953
|
+
metadata: {
|
|
954
|
+
...existing.metadata,
|
|
955
|
+
...input.metadata ?? {}
|
|
956
|
+
},
|
|
957
|
+
updatedAt: now,
|
|
958
|
+
completedAt: now
|
|
959
|
+
};
|
|
960
|
+
this.deferredOperations.set(updated.id, cloneDeferredToolOperation(updated));
|
|
961
|
+
return cloneDeferredToolOperation(updated);
|
|
962
|
+
}
|
|
963
|
+
replaceInboxEvent(updated) {
|
|
964
|
+
const index = this.inboxList.findIndex((event) => event.id === updated.id);
|
|
965
|
+
if (index === -1) throw notFound("InboxEvent not found", { inboxEventId: updated.id });
|
|
966
|
+
this.inboxList[index] = cloneInboxEvent(updated);
|
|
967
|
+
this.inboxEvents.set(updated.id, cloneInboxEvent(updated));
|
|
968
|
+
return cloneInboxEvent(updated);
|
|
969
|
+
}
|
|
970
|
+
getInboxEventOrThrow(id) {
|
|
971
|
+
const event = this.inboxEvents.get(id);
|
|
972
|
+
if (!event) throw notFound("InboxEvent not found", { inboxEventId: id });
|
|
973
|
+
return cloneInboxEvent(event);
|
|
974
|
+
}
|
|
975
|
+
replaceMcpBinding(updated) {
|
|
976
|
+
const index = this.mcpBindingList.findIndex((binding) => binding.id === updated.id);
|
|
977
|
+
if (index === -1) throw notFound("McpBinding not found", { bindingId: updated.id });
|
|
978
|
+
this.mcpBindingList[index] = cloneMcpBinding(updated);
|
|
979
|
+
this.mcpBindingsById.set(updated.id, cloneMcpBinding(updated));
|
|
980
|
+
return cloneMcpBinding(updated);
|
|
981
|
+
}
|
|
982
|
+
replaceSkillBinding(updated) {
|
|
983
|
+
const index = this.skillBindingList.findIndex((binding) => binding.id === updated.id);
|
|
984
|
+
if (index === -1) throw notFound("SkillBinding not found", { bindingId: updated.id });
|
|
985
|
+
this.skillBindingList[index] = cloneSkillBinding(updated);
|
|
986
|
+
this.skillBindingsById.set(updated.id, cloneSkillBinding(updated));
|
|
987
|
+
return cloneSkillBinding(updated);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
function scoreMemory(item, query) {
|
|
991
|
+
const importance = item.importance ?? .5;
|
|
992
|
+
const confidence = item.confidence ?? .5;
|
|
993
|
+
const content = item.content.toLowerCase();
|
|
994
|
+
const queryScore = query && content.includes(query) ? 2 : 0;
|
|
995
|
+
return importance + confidence + queryScore;
|
|
996
|
+
}
|
|
997
|
+
function sameScope(a, b) {
|
|
998
|
+
return a.type === b.type && a.id === b.id;
|
|
999
|
+
}
|
|
1000
|
+
function notFound(message, details) {
|
|
1001
|
+
return new HephError({
|
|
1002
|
+
code: "HEPH5001",
|
|
1003
|
+
title: message,
|
|
1004
|
+
message,
|
|
1005
|
+
status: 404,
|
|
1006
|
+
details
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
function cloneAgentSession(agent) {
|
|
1010
|
+
return {
|
|
1011
|
+
...agent,
|
|
1012
|
+
state: { ...agent.state },
|
|
1013
|
+
metadata: { ...agent.metadata },
|
|
1014
|
+
auth: agent.auth ? { ...agent.auth } : null,
|
|
1015
|
+
createdAt: new Date(agent.createdAt),
|
|
1016
|
+
updatedAt: new Date(agent.updatedAt)
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function cloneRun(run) {
|
|
1020
|
+
return {
|
|
1021
|
+
...run,
|
|
1022
|
+
input: clonePlain(run.input),
|
|
1023
|
+
auth: run.auth ? { ...run.auth } : null,
|
|
1024
|
+
contextManifest: run.contextManifest ? clonePlain(run.contextManifest) : null,
|
|
1025
|
+
skillManifest: run.skillManifest ? clonePlain(run.skillManifest) : null,
|
|
1026
|
+
toolManifest: run.toolManifest ? clonePlain(run.toolManifest) : null,
|
|
1027
|
+
error: run.error ? clonePlain(run.error) : null,
|
|
1028
|
+
metadata: { ...run.metadata },
|
|
1029
|
+
queuedAt: new Date(run.queuedAt),
|
|
1030
|
+
startedAt: run.startedAt ? new Date(run.startedAt) : null,
|
|
1031
|
+
completedAt: run.completedAt ? new Date(run.completedAt) : null,
|
|
1032
|
+
createdAt: new Date(run.createdAt),
|
|
1033
|
+
updatedAt: new Date(run.updatedAt)
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
function cloneMessage(message) {
|
|
1037
|
+
return {
|
|
1038
|
+
...message,
|
|
1039
|
+
auth: message.auth ? { ...message.auth } : null,
|
|
1040
|
+
metadata: { ...message.metadata },
|
|
1041
|
+
createdAt: new Date(message.createdAt)
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
function cloneInboxEvent(event) {
|
|
1045
|
+
return {
|
|
1046
|
+
...event,
|
|
1047
|
+
input: clonePlain(event.input),
|
|
1048
|
+
auth: event.auth ? { ...event.auth } : null,
|
|
1049
|
+
metadata: { ...event.metadata },
|
|
1050
|
+
createdAt: new Date(event.createdAt),
|
|
1051
|
+
updatedAt: new Date(event.updatedAt),
|
|
1052
|
+
claimedAt: event.claimedAt ? new Date(event.claimedAt) : null,
|
|
1053
|
+
processedAt: event.processedAt ? new Date(event.processedAt) : null,
|
|
1054
|
+
failedAt: event.failedAt ? new Date(event.failedAt) : null,
|
|
1055
|
+
error: event.error ? clonePlain(event.error) : null
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
function cloneRunEvent(event) {
|
|
1059
|
+
return {
|
|
1060
|
+
...event,
|
|
1061
|
+
payload: clonePlain(event.payload),
|
|
1062
|
+
sourceRefs: event.sourceRefs.map((ref) => ({ ...ref })),
|
|
1063
|
+
createdAt: new Date(event.createdAt)
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
function cloneMemoryItem(item) {
|
|
1067
|
+
return {
|
|
1068
|
+
...item,
|
|
1069
|
+
scope: { ...item.scope },
|
|
1070
|
+
sourceRefs: item.sourceRefs.map((ref) => ({ ...ref })),
|
|
1071
|
+
expiresAt: item.expiresAt ? new Date(item.expiresAt) : null,
|
|
1072
|
+
createdAt: new Date(item.createdAt),
|
|
1073
|
+
updatedAt: new Date(item.updatedAt)
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
function cloneMcpBinding(binding) {
|
|
1077
|
+
return {
|
|
1078
|
+
...binding,
|
|
1079
|
+
allowTools: clonePlain(binding.allowTools),
|
|
1080
|
+
metadata: { ...binding.metadata },
|
|
1081
|
+
createdAt: new Date(binding.createdAt),
|
|
1082
|
+
updatedAt: new Date(binding.updatedAt),
|
|
1083
|
+
removedAt: binding.removedAt ? new Date(binding.removedAt) : null
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
function cloneSkillBinding(binding) {
|
|
1087
|
+
return {
|
|
1088
|
+
...binding,
|
|
1089
|
+
source: { ...binding.source },
|
|
1090
|
+
allowReferences: clonePlain(binding.allowReferences),
|
|
1091
|
+
metadata: { ...binding.metadata },
|
|
1092
|
+
createdAt: new Date(binding.createdAt),
|
|
1093
|
+
updatedAt: new Date(binding.updatedAt),
|
|
1094
|
+
removedAt: binding.removedAt ? new Date(binding.removedAt) : null
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
function cloneApprovalRequest(request) {
|
|
1098
|
+
return {
|
|
1099
|
+
...request,
|
|
1100
|
+
input: clonePlain(request.input),
|
|
1101
|
+
requestedBy: request.requestedBy ? { ...request.requestedBy } : null,
|
|
1102
|
+
decidedBy: request.decidedBy ? { ...request.decidedBy } : null,
|
|
1103
|
+
metadata: { ...request.metadata },
|
|
1104
|
+
createdAt: new Date(request.createdAt),
|
|
1105
|
+
updatedAt: new Date(request.updatedAt),
|
|
1106
|
+
decidedAt: request.decidedAt ? new Date(request.decidedAt) : null
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function cloneDeferredToolOperation(operation) {
|
|
1110
|
+
return {
|
|
1111
|
+
...operation,
|
|
1112
|
+
auth: operation.auth ? { ...operation.auth } : null,
|
|
1113
|
+
result: clonePlain(operation.result),
|
|
1114
|
+
error: operation.error ? clonePlain(operation.error) : null,
|
|
1115
|
+
metadata: { ...operation.metadata },
|
|
1116
|
+
createdAt: new Date(operation.createdAt),
|
|
1117
|
+
updatedAt: new Date(operation.updatedAt),
|
|
1118
|
+
completedAt: operation.completedAt ? new Date(operation.completedAt) : null
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
function clonePlain(value) {
|
|
1122
|
+
return structuredClone(value);
|
|
1123
|
+
}
|
|
1124
|
+
//#endregion
|
|
1125
|
+
//#region ../core/src/runtime.ts
|
|
1126
|
+
var StreamableHttpMcpToolExecutor = class {
|
|
1127
|
+
async callTool(ctx) {
|
|
1128
|
+
const credentials = await ctx.resolved.resolveCredentials?.({
|
|
1129
|
+
auth: ctx.auth,
|
|
1130
|
+
agent: ctx.agent,
|
|
1131
|
+
run: ctx.run,
|
|
1132
|
+
binding: ctx.binding,
|
|
1133
|
+
app: ctx.app
|
|
1134
|
+
});
|
|
1135
|
+
const headers = new Headers({
|
|
1136
|
+
"Content-Type": "application/json",
|
|
1137
|
+
Accept: "application/json, text/event-stream"
|
|
1138
|
+
});
|
|
1139
|
+
for (const [key, value] of Object.entries(credentials?.headers ?? {})) headers.set(key, value);
|
|
1140
|
+
const rpcId = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}_${Math.random()}`;
|
|
1141
|
+
const requestInit = {
|
|
1142
|
+
method: "POST",
|
|
1143
|
+
headers,
|
|
1144
|
+
body: JSON.stringify({
|
|
1145
|
+
jsonrpc: "2.0",
|
|
1146
|
+
id: rpcId,
|
|
1147
|
+
method: "tools/call",
|
|
1148
|
+
params: {
|
|
1149
|
+
name: ctx.manifestTool.remoteToolName,
|
|
1150
|
+
arguments: ctx.input ?? {}
|
|
1151
|
+
}
|
|
1152
|
+
})
|
|
1153
|
+
};
|
|
1154
|
+
if (ctx.signal !== void 0) requestInit.signal = ctx.signal;
|
|
1155
|
+
const response = await fetch(ctx.resolved.endpoint, requestInit);
|
|
1156
|
+
const rawBody = await response.text();
|
|
1157
|
+
const parsed = parseMcpResponseBody(rawBody, response.headers.get("Content-Type"));
|
|
1158
|
+
if (!response.ok) throw new HephError({
|
|
1159
|
+
code: "HEPH7002",
|
|
1160
|
+
title: "MCP tool call failed",
|
|
1161
|
+
message: `MCP server returned HTTP ${response.status}.`,
|
|
1162
|
+
status: 503,
|
|
1163
|
+
details: {
|
|
1164
|
+
toolId: ctx.manifestTool.id,
|
|
1165
|
+
bindingId: ctx.binding.id,
|
|
1166
|
+
status: response.status,
|
|
1167
|
+
body: parsed ?? rawBody
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
if (isJsonRpcError(parsed)) throw new HephError({
|
|
1171
|
+
code: "HEPH7002",
|
|
1172
|
+
title: "MCP tool call failed",
|
|
1173
|
+
message: "MCP server returned a JSON-RPC error.",
|
|
1174
|
+
status: 503,
|
|
1175
|
+
details: {
|
|
1176
|
+
toolId: ctx.manifestTool.id,
|
|
1177
|
+
bindingId: ctx.binding.id,
|
|
1178
|
+
error: parsed.error
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
if (isRecord(parsed) && "result" in parsed) return parsed.result;
|
|
1182
|
+
return parsed;
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
function createHeph(options) {
|
|
1186
|
+
const stores = options.stores ?? new InMemoryHephStore();
|
|
1187
|
+
const queue = options.queue ?? new InProcessQueue({ concurrency: options.execution?.concurrency ?? 4 });
|
|
1188
|
+
const executor = options.executor ?? new MinimalRunExecutor();
|
|
1189
|
+
const resolver = normalizeAgentSpecResolver(options.agents);
|
|
1190
|
+
const mcpResolver = options.mcp?.resolver ?? null;
|
|
1191
|
+
const mcpToolExecutor = options.mcp?.toolExecutor ?? new StreamableHttpMcpToolExecutor();
|
|
1192
|
+
const skillCatalog = options.skills?.catalog ?? createInMemorySkillCatalog([]);
|
|
1193
|
+
const renderer = new ContextRenderer();
|
|
1194
|
+
const app = options.app ?? {};
|
|
1195
|
+
const abortControllers = /* @__PURE__ */ new Map();
|
|
1196
|
+
const executionMode = options.execution?.mode ?? "single-process";
|
|
1197
|
+
const reducerOptions = {
|
|
1198
|
+
maxEventsPerRun: normalizeMaxEventsPerRun(options.inbox?.maxEventsPerRun),
|
|
1199
|
+
textSeparator: options.inbox?.textSeparator ?? "\n\n--- next message ---\n\n"
|
|
1200
|
+
};
|
|
1201
|
+
let consumerStarted = false;
|
|
1202
|
+
const runtime = {
|
|
1203
|
+
stores,
|
|
1204
|
+
queue,
|
|
1205
|
+
agents: {
|
|
1206
|
+
async create(input) {
|
|
1207
|
+
const spec = await resolveSpecOrThrow(resolver, input.spec, input.auth ?? null);
|
|
1208
|
+
const skillPackages = await resolveSkillPackagesForSession(spec, input.skills ?? []);
|
|
1209
|
+
const agent = await stores.state.createAgentSession({
|
|
1210
|
+
agentSpecId: spec.id,
|
|
1211
|
+
agentSpecVersion: spec.version,
|
|
1212
|
+
state: input.state,
|
|
1213
|
+
auth: input.auth ?? null,
|
|
1214
|
+
metadata: input.metadata
|
|
1215
|
+
});
|
|
1216
|
+
for (const skillPackage of skillPackages) await stores.skillBindings.createSkillBinding({
|
|
1217
|
+
agentId: agent.id,
|
|
1218
|
+
skillId: skillPackage.id,
|
|
1219
|
+
name: skillPackage.name,
|
|
1220
|
+
version: skillPackage.version,
|
|
1221
|
+
source: skillPackage.source,
|
|
1222
|
+
allowReferences: [],
|
|
1223
|
+
metadata: { description: skillPackage.description }
|
|
1224
|
+
});
|
|
1225
|
+
return agent;
|
|
1226
|
+
},
|
|
1227
|
+
async createAndRun(input) {
|
|
1228
|
+
const agent = await runtime.agents.create(input);
|
|
1229
|
+
const runInput = normalizeRunInput(input.input);
|
|
1230
|
+
const appended = await appendRunInputToInbox({
|
|
1231
|
+
agentId: agent.id,
|
|
1232
|
+
input: runInput,
|
|
1233
|
+
auth: input.auth ?? null,
|
|
1234
|
+
metadata: input.metadata,
|
|
1235
|
+
messageMetadata: {
|
|
1236
|
+
...input.metadata ?? {},
|
|
1237
|
+
runInput: true
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
const run = await scheduleAgent(agent.id);
|
|
1241
|
+
if (!run) throw new HephError({
|
|
1242
|
+
code: "HEPH4002",
|
|
1243
|
+
title: "Run was not scheduled",
|
|
1244
|
+
message: `AgentSession ${agent.id} did not produce a Run from its initial input.`,
|
|
1245
|
+
status: 409,
|
|
1246
|
+
details: {
|
|
1247
|
+
agentId: agent.id,
|
|
1248
|
+
inboxEventId: appended.inboxEvent.id
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
return {
|
|
1252
|
+
agent,
|
|
1253
|
+
run,
|
|
1254
|
+
message: appended.message,
|
|
1255
|
+
inboxEvent: appended.inboxEvent,
|
|
1256
|
+
agent_id: agent.id,
|
|
1257
|
+
agent_spec_id: agent.agentSpecId,
|
|
1258
|
+
run_id: run.id
|
|
1259
|
+
};
|
|
1260
|
+
},
|
|
1261
|
+
async appendMessage(input) {
|
|
1262
|
+
await getAgentOrThrow(stores, input.agentId);
|
|
1263
|
+
const appended = await appendRunInputToInbox({
|
|
1264
|
+
agentId: input.agentId,
|
|
1265
|
+
input: {
|
|
1266
|
+
type: input.type ?? "user.message",
|
|
1267
|
+
text: input.content
|
|
1268
|
+
},
|
|
1269
|
+
auth: input.auth ?? null,
|
|
1270
|
+
metadata: input.metadata,
|
|
1271
|
+
messageMetadata: input.metadata
|
|
1272
|
+
});
|
|
1273
|
+
const shouldSchedule = input.schedule ?? true;
|
|
1274
|
+
if (!appended.message) throw new HephError({
|
|
1275
|
+
code: "HEPH4004",
|
|
1276
|
+
title: "Message was not stored",
|
|
1277
|
+
message: "The user message input did not produce a MessageStore record.",
|
|
1278
|
+
status: 500,
|
|
1279
|
+
details: {
|
|
1280
|
+
agentId: input.agentId,
|
|
1281
|
+
inboxEventId: appended.inboxEvent.id
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
const inboxEvent = shouldSchedule ? await scheduleAfterAppend(input.agentId, appended.inboxEvent) : appended.inboxEvent;
|
|
1285
|
+
return {
|
|
1286
|
+
message: appended.message,
|
|
1287
|
+
inboxEvent,
|
|
1288
|
+
message_id: appended.message.id,
|
|
1289
|
+
inbox_event_id: inboxEvent.id,
|
|
1290
|
+
scheduled: shouldSchedule
|
|
1291
|
+
};
|
|
1292
|
+
},
|
|
1293
|
+
schedule(agentId) {
|
|
1294
|
+
return scheduleAgent(agentId);
|
|
1295
|
+
},
|
|
1296
|
+
get(agentId) {
|
|
1297
|
+
return stores.state.getAgentSession(agentId);
|
|
1298
|
+
},
|
|
1299
|
+
async addMcpBinding(input) {
|
|
1300
|
+
const agent = await getAgentOrThrow(stores, input.agentId);
|
|
1301
|
+
const spec = await resolveSpecOrThrow(resolver, agent.agentSpecId, input.auth ?? agent.auth);
|
|
1302
|
+
const bindingId = createMcpBindingId();
|
|
1303
|
+
const now = /* @__PURE__ */ new Date();
|
|
1304
|
+
const draft = {
|
|
1305
|
+
id: bindingId,
|
|
1306
|
+
agentId: agent.id,
|
|
1307
|
+
capabilityId: input.capabilityId,
|
|
1308
|
+
accountRef: input.accountRef ?? null,
|
|
1309
|
+
allowTools: Array.isArray(input.allowTools) ? [...input.allowTools] : input.allowTools,
|
|
1310
|
+
status: "active",
|
|
1311
|
+
metadata: input.metadata ?? {},
|
|
1312
|
+
createdAt: now,
|
|
1313
|
+
updatedAt: now,
|
|
1314
|
+
removedAt: null
|
|
1315
|
+
};
|
|
1316
|
+
enforceMcpPolicy(spec, draft);
|
|
1317
|
+
validateMcpCatalog(draft, await resolveMcpBindingOrThrow({
|
|
1318
|
+
resolver: mcpResolver,
|
|
1319
|
+
auth: input.auth ?? agent.auth,
|
|
1320
|
+
agent,
|
|
1321
|
+
binding: draft,
|
|
1322
|
+
app
|
|
1323
|
+
}));
|
|
1324
|
+
return stores.mcpBindings.createMcpBinding({
|
|
1325
|
+
id: bindingId,
|
|
1326
|
+
agentId: agent.id,
|
|
1327
|
+
capabilityId: input.capabilityId,
|
|
1328
|
+
accountRef: input.accountRef ?? null,
|
|
1329
|
+
allowTools: Array.isArray(input.allowTools) ? [...input.allowTools] : input.allowTools,
|
|
1330
|
+
metadata: input.metadata
|
|
1331
|
+
});
|
|
1332
|
+
},
|
|
1333
|
+
async listMcpBindings(agentId) {
|
|
1334
|
+
await getAgentOrThrow(stores, agentId);
|
|
1335
|
+
return stores.mcpBindings.listMcpBindings(agentId);
|
|
1336
|
+
},
|
|
1337
|
+
async removeMcpBinding(input) {
|
|
1338
|
+
const agent = await getAgentOrThrow(stores, input.agentId);
|
|
1339
|
+
const binding = await stores.mcpBindings.getMcpBinding(input.bindingId);
|
|
1340
|
+
if (!binding || binding.agentId !== agent.id) throw new HephError({
|
|
1341
|
+
code: "HEPH5001",
|
|
1342
|
+
title: "McpBinding not found",
|
|
1343
|
+
message: `McpBinding ${input.bindingId} was not found.`,
|
|
1344
|
+
status: 404,
|
|
1345
|
+
details: {
|
|
1346
|
+
agentId: input.agentId,
|
|
1347
|
+
bindingId: input.bindingId
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1350
|
+
return stores.mcpBindings.removeMcpBinding(input.bindingId);
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1353
|
+
runs: {
|
|
1354
|
+
async create(input) {
|
|
1355
|
+
const agent = await getAgentOrThrow(stores, input.agentId);
|
|
1356
|
+
return createRunForAgent({
|
|
1357
|
+
agent,
|
|
1358
|
+
input: normalizeRunInput(input.input),
|
|
1359
|
+
auth: input.auth ?? agent.auth,
|
|
1360
|
+
metadata: input.metadata,
|
|
1361
|
+
enqueue: input.enqueue ?? true
|
|
1362
|
+
});
|
|
1363
|
+
},
|
|
1364
|
+
get(runId) {
|
|
1365
|
+
return stores.state.getRun(runId);
|
|
1366
|
+
},
|
|
1367
|
+
async cancel(runId) {
|
|
1368
|
+
return cancelRun(runId);
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1371
|
+
messages: {
|
|
1372
|
+
append(input) {
|
|
1373
|
+
return stores.messages.appendMessage({
|
|
1374
|
+
agentId: input.agentId,
|
|
1375
|
+
role: input.role,
|
|
1376
|
+
content: input.content,
|
|
1377
|
+
auth: input.auth ?? null,
|
|
1378
|
+
metadata: input.metadata
|
|
1379
|
+
});
|
|
1380
|
+
},
|
|
1381
|
+
list(agentId, listOptions) {
|
|
1382
|
+
return stores.messages.listMessages(agentId, listOptions);
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
approvals: {
|
|
1386
|
+
get(approvalRequestId) {
|
|
1387
|
+
return stores.approvals.getApprovalRequest(approvalRequestId);
|
|
1388
|
+
},
|
|
1389
|
+
list(runId) {
|
|
1390
|
+
return stores.approvals.listApprovalRequests(runId);
|
|
1391
|
+
},
|
|
1392
|
+
async decide(input) {
|
|
1393
|
+
const request = await stores.approvals.decideApprovalRequest({
|
|
1394
|
+
id: input.approvalRequestId,
|
|
1395
|
+
decision: input.decision,
|
|
1396
|
+
decidedBy: input.auth ?? null,
|
|
1397
|
+
metadata: input.metadata
|
|
1398
|
+
});
|
|
1399
|
+
await stores.events.appendRunEvent({
|
|
1400
|
+
runId: request.runId,
|
|
1401
|
+
type: input.decision === "granted" ? "approval.granted" : "approval.rejected",
|
|
1402
|
+
payload: {
|
|
1403
|
+
approvalRequestId: request.id,
|
|
1404
|
+
toolId: request.toolId
|
|
1405
|
+
},
|
|
1406
|
+
sourceRefs: [{
|
|
1407
|
+
type: "approval_request",
|
|
1408
|
+
id: request.id
|
|
1409
|
+
}]
|
|
1410
|
+
});
|
|
1411
|
+
return request;
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1414
|
+
tools: {
|
|
1415
|
+
call(runId, input) {
|
|
1416
|
+
return callTool(runId, input);
|
|
1417
|
+
},
|
|
1418
|
+
tryCall(runId, input) {
|
|
1419
|
+
return tryCallTool(runId, input);
|
|
1420
|
+
}
|
|
1421
|
+
},
|
|
1422
|
+
operations: {
|
|
1423
|
+
deferToolResult(input) {
|
|
1424
|
+
return deferToolResult(input);
|
|
1425
|
+
},
|
|
1426
|
+
get(operationId) {
|
|
1427
|
+
return stores.deferredToolOperations.getDeferredToolOperation(operationId);
|
|
1428
|
+
},
|
|
1429
|
+
complete(input) {
|
|
1430
|
+
return completeDeferredToolResult(input);
|
|
1431
|
+
}
|
|
1432
|
+
},
|
|
1433
|
+
renderRunContext(runId) {
|
|
1434
|
+
return renderRunContext(runId);
|
|
1435
|
+
},
|
|
1436
|
+
handleJob(job) {
|
|
1437
|
+
return handleJob(job);
|
|
1438
|
+
},
|
|
1439
|
+
async startWorker() {
|
|
1440
|
+
if (consumerStarted) return;
|
|
1441
|
+
if (!queue.startConsumer) throw new HephError({
|
|
1442
|
+
code: "HEPH4003",
|
|
1443
|
+
title: "Queue consumer is not available",
|
|
1444
|
+
message: "This QueueAdapter does not expose startConsumer(). Use handleJob() or an adapter-specific batch handler.",
|
|
1445
|
+
status: 422
|
|
1446
|
+
});
|
|
1447
|
+
consumerStarted = true;
|
|
1448
|
+
await queue.startConsumer((job) => handleJob(job));
|
|
1449
|
+
},
|
|
1450
|
+
async drain() {
|
|
1451
|
+
await queue.onIdle?.();
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
if (options.execution?.autoStartConsumer ?? executionMode === "single-process") runtime.startWorker();
|
|
1455
|
+
return runtime;
|
|
1456
|
+
async function handleJob(job) {
|
|
1457
|
+
switch (job.type) {
|
|
1458
|
+
case "schedule_agent":
|
|
1459
|
+
await scheduleAgent(job.agentId);
|
|
1460
|
+
return;
|
|
1461
|
+
case "execute_run":
|
|
1462
|
+
case "resume_run":
|
|
1463
|
+
await executeRun(job.runId);
|
|
1464
|
+
return;
|
|
1465
|
+
case "cancel_run":
|
|
1466
|
+
await cancelRun(job.runId);
|
|
1467
|
+
return;
|
|
1468
|
+
case "ingest_memory": return;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
async function appendRunInputToInbox(input) {
|
|
1472
|
+
const normalized = normalizeRunInput(input.input);
|
|
1473
|
+
const message = "text" in normalized ? await stores.messages.appendMessage({
|
|
1474
|
+
agentId: input.agentId,
|
|
1475
|
+
role: "user",
|
|
1476
|
+
content: normalized.text,
|
|
1477
|
+
auth: input.auth,
|
|
1478
|
+
metadata: input.messageMetadata
|
|
1479
|
+
}) : null;
|
|
1480
|
+
const runInput = message ? addMessageIdToRunInput(normalized, message.id) : normalized;
|
|
1481
|
+
return {
|
|
1482
|
+
runInput,
|
|
1483
|
+
message,
|
|
1484
|
+
inboxEvent: await stores.inbox.appendInboxEvent({
|
|
1485
|
+
agentId: input.agentId,
|
|
1486
|
+
input: runInput,
|
|
1487
|
+
auth: input.auth,
|
|
1488
|
+
metadata: input.metadata
|
|
1489
|
+
})
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1492
|
+
async function scheduleAfterAppend(agentId, inboxEvent) {
|
|
1493
|
+
if (inboxEvent.type === "steering.message") {
|
|
1494
|
+
await scheduleAgent(agentId);
|
|
1495
|
+
return await stores.inbox.getInboxEvent(inboxEvent.id) ?? inboxEvent;
|
|
1496
|
+
}
|
|
1497
|
+
await queue.enqueue({
|
|
1498
|
+
type: "schedule_agent",
|
|
1499
|
+
agentId
|
|
1500
|
+
});
|
|
1501
|
+
return inboxEvent;
|
|
1502
|
+
}
|
|
1503
|
+
async function scheduleAgent(agentId) {
|
|
1504
|
+
let agent = await getAgentOrThrow(stores, agentId);
|
|
1505
|
+
if (agent.activeRunId) {
|
|
1506
|
+
const activeRun = await stores.state.getRun(agent.activeRunId);
|
|
1507
|
+
if (activeRun && !isTerminalRun(activeRun)) {
|
|
1508
|
+
await processPendingCancellationEvents(agent, activeRun);
|
|
1509
|
+
await processPendingSteeringEvents(agent, activeRun);
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
agent = await stores.state.updateAgentSession(agent.id, { activeRunId: null });
|
|
1513
|
+
}
|
|
1514
|
+
const nextPending = await stores.inbox.listInboxEvents(agent.id, {
|
|
1515
|
+
status: "pending",
|
|
1516
|
+
limit: 1
|
|
1517
|
+
});
|
|
1518
|
+
if (nextPending.length === 0) return null;
|
|
1519
|
+
const claimOptions = { types: [nextPending[0].type] };
|
|
1520
|
+
if (reducerOptions.maxEventsPerRun !== void 0) claimOptions.limit = reducerOptions.maxEventsPerRun;
|
|
1521
|
+
const claimed = await stores.inbox.claimPendingInboxEvents(agent.id, claimOptions);
|
|
1522
|
+
if (claimed.length === 0) return null;
|
|
1523
|
+
try {
|
|
1524
|
+
const inboxEventIds = claimed.map((event) => event.id);
|
|
1525
|
+
const run = await createRunForAgent({
|
|
1526
|
+
agent,
|
|
1527
|
+
input: reduceInboxEvents(claimed, reducerOptions.textSeparator),
|
|
1528
|
+
auth: firstAuth(claimed) ?? agent.auth,
|
|
1529
|
+
metadata: {
|
|
1530
|
+
inboxEventIds,
|
|
1531
|
+
inboxEventCount: claimed.length
|
|
1532
|
+
},
|
|
1533
|
+
sourceRefs: toInboxSourceRefs(claimed),
|
|
1534
|
+
enqueue: false
|
|
1535
|
+
});
|
|
1536
|
+
await stores.inbox.markInboxEventsProcessed(inboxEventIds, run.id);
|
|
1537
|
+
await queue.enqueue({
|
|
1538
|
+
type: "execute_run",
|
|
1539
|
+
agentId: agent.id,
|
|
1540
|
+
runId: run.id
|
|
1541
|
+
});
|
|
1542
|
+
return run;
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
await stores.inbox.markInboxEventsFailed(claimed.map((event) => event.id), toRunError(error));
|
|
1545
|
+
throw error;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
async function processPendingCancellationEvents(agent, activeRun) {
|
|
1549
|
+
const cancellationEvents = await stores.inbox.claimPendingInboxEvents(agent.id, { types: ["run.cancel_requested"] });
|
|
1550
|
+
if (cancellationEvents.length === 0) return;
|
|
1551
|
+
const cancelled = await cancelRun(activeRun.id, { sourceRefs: toInboxSourceRefs(cancellationEvents) });
|
|
1552
|
+
await stores.inbox.markInboxEventsProcessed(cancellationEvents.map((event) => event.id), cancelled.id);
|
|
1553
|
+
}
|
|
1554
|
+
async function processPendingSteeringEvents(agent, activeRun) {
|
|
1555
|
+
const steeringEvents = await stores.inbox.claimPendingInboxEvents(agent.id, { types: ["steering.message"] });
|
|
1556
|
+
for (const event of steeringEvents) await stores.events.appendRunEvent({
|
|
1557
|
+
runId: activeRun.id,
|
|
1558
|
+
type: "run.steering_received",
|
|
1559
|
+
payload: {
|
|
1560
|
+
agentId: agent.id,
|
|
1561
|
+
inboxEventId: event.id,
|
|
1562
|
+
input: event.input
|
|
1563
|
+
},
|
|
1564
|
+
sourceRefs: toInboxSourceRefs([event])
|
|
1565
|
+
});
|
|
1566
|
+
if (steeringEvents.length > 0) await stores.inbox.markInboxEventsProcessed(steeringEvents.map((event) => event.id), activeRun.id);
|
|
1567
|
+
}
|
|
1568
|
+
async function createRunForAgent(input) {
|
|
1569
|
+
const spec = await resolveSpecOrThrow(resolver, input.agent.agentSpecId, input.auth ?? input.agent.auth);
|
|
1570
|
+
const run = await stores.state.createRun({
|
|
1571
|
+
agentId: input.agent.id,
|
|
1572
|
+
agentSpecId: spec.id,
|
|
1573
|
+
agentSpecVersion: spec.version,
|
|
1574
|
+
status: "queued",
|
|
1575
|
+
input: input.input,
|
|
1576
|
+
auth: input.auth,
|
|
1577
|
+
metadata: input.metadata
|
|
1578
|
+
});
|
|
1579
|
+
await stores.state.updateAgentSession(input.agent.id, { activeRunId: run.id });
|
|
1580
|
+
await stores.events.appendRunEvent({
|
|
1581
|
+
runId: run.id,
|
|
1582
|
+
type: "run.queued",
|
|
1583
|
+
payload: {
|
|
1584
|
+
agentId: input.agent.id,
|
|
1585
|
+
agentSpecId: spec.id
|
|
1586
|
+
},
|
|
1587
|
+
sourceRefs: input.sourceRefs
|
|
1588
|
+
});
|
|
1589
|
+
if (input.enqueue) await queue.enqueue({
|
|
1590
|
+
type: "execute_run",
|
|
1591
|
+
agentId: input.agent.id,
|
|
1592
|
+
runId: run.id
|
|
1593
|
+
});
|
|
1594
|
+
return run;
|
|
1595
|
+
}
|
|
1596
|
+
async function cancelRun(runId, options = {}) {
|
|
1597
|
+
const run = await getRunOrThrow(stores, runId);
|
|
1598
|
+
if (isTerminalRun(run)) return run;
|
|
1599
|
+
abortControllers.get(run.id)?.abort();
|
|
1600
|
+
await stores.events.appendRunEvent({
|
|
1601
|
+
runId: run.id,
|
|
1602
|
+
type: "run.cancel_requested",
|
|
1603
|
+
payload: {},
|
|
1604
|
+
sourceRefs: options.sourceRefs
|
|
1605
|
+
});
|
|
1606
|
+
const cancelled = await stores.state.updateRun(run.id, {
|
|
1607
|
+
status: "cancelled",
|
|
1608
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1609
|
+
});
|
|
1610
|
+
await stores.events.appendRunEvent({
|
|
1611
|
+
runId: run.id,
|
|
1612
|
+
type: "run.cancelled",
|
|
1613
|
+
payload: {}
|
|
1614
|
+
});
|
|
1615
|
+
const agent = await stores.state.getAgentSession(run.agentId);
|
|
1616
|
+
if (agent?.activeRunId === run.id) await stores.state.updateAgentSession(agent.id, { activeRunId: null });
|
|
1617
|
+
await enqueueScheduleIfPending(run.agentId);
|
|
1618
|
+
return cancelled;
|
|
1619
|
+
}
|
|
1620
|
+
async function executeRun(runId) {
|
|
1621
|
+
const initialRun = await getRunOrThrow(stores, runId);
|
|
1622
|
+
if (isTerminalRun(initialRun)) return;
|
|
1623
|
+
const agent = await getAgentOrThrow(stores, initialRun.agentId);
|
|
1624
|
+
const spec = await resolveSpecOrThrow(resolver, initialRun.agentSpecId, initialRun.auth ?? agent.auth);
|
|
1625
|
+
const controller = new AbortController();
|
|
1626
|
+
abortControllers.set(initialRun.id, controller);
|
|
1627
|
+
try {
|
|
1628
|
+
const skillManifest = await createSkillManifestForRun(agent, initialRun);
|
|
1629
|
+
const runWithSkillManifest = await stores.state.updateRun(initialRun.id, { skillManifest });
|
|
1630
|
+
await stores.events.appendRunEvent({
|
|
1631
|
+
runId: runWithSkillManifest.id,
|
|
1632
|
+
type: "skill_manifest.created",
|
|
1633
|
+
payload: { skillCount: skillManifest.skills.length },
|
|
1634
|
+
sourceRefs: skillManifest.skills.map((skill) => ({
|
|
1635
|
+
type: "skill_binding",
|
|
1636
|
+
id: skill.bindingId
|
|
1637
|
+
}))
|
|
1638
|
+
});
|
|
1639
|
+
const toolManifest = await createToolManifestForRun(agent, spec, runWithSkillManifest);
|
|
1640
|
+
const runWithToolManifest = await stores.state.updateRun(runWithSkillManifest.id, { toolManifest });
|
|
1641
|
+
await stores.events.appendRunEvent({
|
|
1642
|
+
runId: runWithToolManifest.id,
|
|
1643
|
+
type: "tool_manifest.created",
|
|
1644
|
+
payload: {
|
|
1645
|
+
toolCount: toolManifest.tools.length,
|
|
1646
|
+
localToolCount: toolManifest.tools.filter((tool) => tool.source === "local").length,
|
|
1647
|
+
mcpToolCount: toolManifest.tools.filter((tool) => tool.source === "mcp").length
|
|
1648
|
+
},
|
|
1649
|
+
sourceRefs: toolManifest.tools.flatMap((tool) => tool.source === "mcp" ? [{
|
|
1650
|
+
type: "mcp_binding",
|
|
1651
|
+
id: tool.bindingId
|
|
1652
|
+
}] : [])
|
|
1653
|
+
});
|
|
1654
|
+
const running = await stores.state.updateRun(runWithToolManifest.id, {
|
|
1655
|
+
status: "running",
|
|
1656
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
1657
|
+
});
|
|
1658
|
+
await stores.events.appendRunEvent({
|
|
1659
|
+
runId: running.id,
|
|
1660
|
+
type: "run.started",
|
|
1661
|
+
payload: {
|
|
1662
|
+
agentId: agent.id,
|
|
1663
|
+
agentSpecId: spec.id
|
|
1664
|
+
}
|
|
1665
|
+
});
|
|
1666
|
+
const renderedContext = await renderRunContext(running.id);
|
|
1667
|
+
const runWithContext = await stores.state.updateRun(running.id, { contextManifest: renderedContext.manifest });
|
|
1668
|
+
const callToolForRun = (input) => callTool(runWithContext.id, {
|
|
1669
|
+
...input,
|
|
1670
|
+
auth: input.auth ?? runWithContext.auth,
|
|
1671
|
+
signal: input.signal ?? controller.signal
|
|
1672
|
+
});
|
|
1673
|
+
const tryCallToolForRun = (input) => tryCallTool(runWithContext.id, {
|
|
1674
|
+
...input,
|
|
1675
|
+
auth: input.auth ?? runWithContext.auth,
|
|
1676
|
+
signal: input.signal ?? controller.signal
|
|
1677
|
+
});
|
|
1678
|
+
await executor.execute({
|
|
1679
|
+
auth: runWithContext.auth,
|
|
1680
|
+
agent,
|
|
1681
|
+
spec,
|
|
1682
|
+
run: runWithContext,
|
|
1683
|
+
renderedContext,
|
|
1684
|
+
stores,
|
|
1685
|
+
app,
|
|
1686
|
+
signal: controller.signal,
|
|
1687
|
+
emit(event) {
|
|
1688
|
+
return stores.events.appendRunEvent({
|
|
1689
|
+
...event,
|
|
1690
|
+
runId: runWithContext.id
|
|
1691
|
+
}).then(() => void 0);
|
|
1692
|
+
},
|
|
1693
|
+
appendMessage(message) {
|
|
1694
|
+
return stores.messages.appendMessage({
|
|
1695
|
+
...message,
|
|
1696
|
+
agentId: agent.id,
|
|
1697
|
+
auth: runWithContext.auth
|
|
1698
|
+
});
|
|
1699
|
+
},
|
|
1700
|
+
tools: {
|
|
1701
|
+
call: callToolForRun,
|
|
1702
|
+
tryCall: tryCallToolForRun
|
|
1703
|
+
},
|
|
1704
|
+
callTool: callToolForRun,
|
|
1705
|
+
tryCallTool: tryCallToolForRun,
|
|
1706
|
+
deferToolResult(input) {
|
|
1707
|
+
return deferToolResult({
|
|
1708
|
+
...input,
|
|
1709
|
+
runId: input.runId ?? runWithContext.id,
|
|
1710
|
+
auth: input.auth ?? runWithContext.auth
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
const current = await getRunOrThrow(stores, running.id);
|
|
1715
|
+
if (current.status === "running") {
|
|
1716
|
+
await stores.state.updateRun(current.id, {
|
|
1717
|
+
status: "completed",
|
|
1718
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1719
|
+
});
|
|
1720
|
+
await stores.events.appendRunEvent({
|
|
1721
|
+
runId: current.id,
|
|
1722
|
+
type: "run.completed",
|
|
1723
|
+
payload: {}
|
|
1724
|
+
});
|
|
1725
|
+
await clearActiveRunIfCurrent(agent.id, current.id);
|
|
1726
|
+
await enqueueScheduleIfPending(agent.id);
|
|
1727
|
+
}
|
|
1728
|
+
} catch (error) {
|
|
1729
|
+
if ((await stores.state.getRun(initialRun.id))?.status === "cancelled") return;
|
|
1730
|
+
const runError = {
|
|
1731
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1732
|
+
details: toErrorDetails(error)
|
|
1733
|
+
};
|
|
1734
|
+
if (error instanceof HephError) Object.assign(runError, { code: error.code });
|
|
1735
|
+
await stores.state.updateRun(initialRun.id, {
|
|
1736
|
+
status: "failed",
|
|
1737
|
+
completedAt: /* @__PURE__ */ new Date(),
|
|
1738
|
+
error: runError
|
|
1739
|
+
});
|
|
1740
|
+
await stores.events.appendRunEvent({
|
|
1741
|
+
runId: initialRun.id,
|
|
1742
|
+
type: "run.failed",
|
|
1743
|
+
payload: toErrorDetails(error)
|
|
1744
|
+
});
|
|
1745
|
+
await clearActiveRunIfCurrent(agent.id, initialRun.id);
|
|
1746
|
+
await enqueueScheduleIfPending(agent.id);
|
|
1747
|
+
} finally {
|
|
1748
|
+
abortControllers.delete(initialRun.id);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
async function deferToolResult(input) {
|
|
1752
|
+
const run = await getRunOrThrow(stores, input.runId);
|
|
1753
|
+
const agent = await getAgentOrThrow(stores, run.agentId);
|
|
1754
|
+
const operation = await stores.deferredToolOperations.createDeferredToolOperation({
|
|
1755
|
+
agentId: agent.id,
|
|
1756
|
+
runId: run.id,
|
|
1757
|
+
toolId: input.toolId,
|
|
1758
|
+
auth: input.auth ?? run.auth ?? agent.auth,
|
|
1759
|
+
...input.operationId !== void 0 ? { id: input.operationId } : {},
|
|
1760
|
+
...input.toolCallId !== void 0 ? { toolCallId: input.toolCallId } : {},
|
|
1761
|
+
...input.resumePolicy !== void 0 ? { resumePolicy: input.resumePolicy } : {},
|
|
1762
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {}
|
|
1763
|
+
});
|
|
1764
|
+
await stores.events.appendRunEvent({
|
|
1765
|
+
runId: run.id,
|
|
1766
|
+
type: "tool.deferred",
|
|
1767
|
+
payload: {
|
|
1768
|
+
operationId: operation.id,
|
|
1769
|
+
toolId: operation.toolId,
|
|
1770
|
+
toolCallId: operation.toolCallId,
|
|
1771
|
+
resumePolicy: operation.resumePolicy
|
|
1772
|
+
},
|
|
1773
|
+
sourceRefs: [{
|
|
1774
|
+
type: "deferred_tool_operation",
|
|
1775
|
+
id: operation.id
|
|
1776
|
+
}]
|
|
1777
|
+
});
|
|
1778
|
+
return operation;
|
|
1779
|
+
}
|
|
1780
|
+
async function completeDeferredToolResult(input) {
|
|
1781
|
+
if (!await stores.deferredToolOperations.getDeferredToolOperation(input.operationId)) throw new HephError({
|
|
1782
|
+
code: "HEPH3005",
|
|
1783
|
+
title: "DeferredToolOperation not found",
|
|
1784
|
+
message: `DeferredToolOperation ${input.operationId} was not found.`,
|
|
1785
|
+
status: 404,
|
|
1786
|
+
details: { operationId: input.operationId }
|
|
1787
|
+
});
|
|
1788
|
+
const status = input.status ?? (input.error ? "failed" : "completed");
|
|
1789
|
+
const operation = await stores.deferredToolOperations.completeDeferredToolOperation({
|
|
1790
|
+
id: input.operationId,
|
|
1791
|
+
status,
|
|
1792
|
+
result: input.result,
|
|
1793
|
+
error: input.error,
|
|
1794
|
+
metadata: input.metadata
|
|
1795
|
+
});
|
|
1796
|
+
const message = await stores.messages.appendMessage({
|
|
1797
|
+
agentId: operation.agentId,
|
|
1798
|
+
role: "tool",
|
|
1799
|
+
content: input.content ?? renderDeferredToolResultContent(operation),
|
|
1800
|
+
sourceRunId: operation.runId,
|
|
1801
|
+
auth: input.auth ?? operation.auth,
|
|
1802
|
+
metadata: {
|
|
1803
|
+
type: "tool_result",
|
|
1804
|
+
deferredToolOperationId: operation.id,
|
|
1805
|
+
toolId: operation.toolId,
|
|
1806
|
+
toolCallId: operation.toolCallId,
|
|
1807
|
+
status: operation.status,
|
|
1808
|
+
...input.metadata ?? {}
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
const eventType = status === "completed" ? "deferred_tool.completed" : "deferred_tool.failed";
|
|
1812
|
+
await stores.events.appendRunEvent({
|
|
1813
|
+
runId: operation.runId,
|
|
1814
|
+
type: eventType,
|
|
1815
|
+
payload: {
|
|
1816
|
+
operationId: operation.id,
|
|
1817
|
+
toolId: operation.toolId,
|
|
1818
|
+
toolCallId: operation.toolCallId,
|
|
1819
|
+
status: operation.status,
|
|
1820
|
+
messageId: message.id,
|
|
1821
|
+
result: operation.result,
|
|
1822
|
+
error: operation.error
|
|
1823
|
+
},
|
|
1824
|
+
sourceRefs: [{
|
|
1825
|
+
type: "deferred_tool_operation",
|
|
1826
|
+
id: operation.id
|
|
1827
|
+
}, {
|
|
1828
|
+
type: "message",
|
|
1829
|
+
id: message.id
|
|
1830
|
+
}]
|
|
1831
|
+
});
|
|
1832
|
+
if (!(input.schedule ?? operation.resumePolicy === "auto")) return {
|
|
1833
|
+
operation,
|
|
1834
|
+
message,
|
|
1835
|
+
inboxEvent: null,
|
|
1836
|
+
scheduled: false
|
|
1837
|
+
};
|
|
1838
|
+
const inboxEvent = await stores.inbox.appendInboxEvent({
|
|
1839
|
+
agentId: operation.agentId,
|
|
1840
|
+
input: {
|
|
1841
|
+
type: "system.event",
|
|
1842
|
+
payload: {
|
|
1843
|
+
event: "deferred_tool.completed",
|
|
1844
|
+
operationId: operation.id,
|
|
1845
|
+
runId: operation.runId,
|
|
1846
|
+
toolId: operation.toolId,
|
|
1847
|
+
toolCallId: operation.toolCallId,
|
|
1848
|
+
status: operation.status
|
|
1849
|
+
},
|
|
1850
|
+
messageIds: [message.id]
|
|
1851
|
+
},
|
|
1852
|
+
auth: input.auth ?? operation.auth,
|
|
1853
|
+
metadata: {
|
|
1854
|
+
deferredToolOperationId: operation.id,
|
|
1855
|
+
toolId: operation.toolId,
|
|
1856
|
+
status: operation.status
|
|
1857
|
+
}
|
|
1858
|
+
});
|
|
1859
|
+
await queue.enqueue({
|
|
1860
|
+
type: "schedule_agent",
|
|
1861
|
+
agentId: operation.agentId
|
|
1862
|
+
});
|
|
1863
|
+
return {
|
|
1864
|
+
operation,
|
|
1865
|
+
message,
|
|
1866
|
+
inboxEvent,
|
|
1867
|
+
scheduled: true
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
async function enqueueScheduleIfPending(agentId) {
|
|
1871
|
+
if ((await stores.inbox.listInboxEvents(agentId, {
|
|
1872
|
+
status: "pending",
|
|
1873
|
+
limit: 1
|
|
1874
|
+
})).length > 0) await queue.enqueue({
|
|
1875
|
+
type: "schedule_agent",
|
|
1876
|
+
agentId
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
async function clearActiveRunIfCurrent(agentId, runId) {
|
|
1880
|
+
if ((await stores.state.getAgentSession(agentId))?.activeRunId === runId) await stores.state.updateAgentSession(agentId, { activeRunId: null });
|
|
1881
|
+
}
|
|
1882
|
+
async function resolveSkillPackagesForSession(spec, skillIds) {
|
|
1883
|
+
const uniqueSkillIds = unique(skillIds);
|
|
1884
|
+
if (uniqueSkillIds.length === 0) return [];
|
|
1885
|
+
const packages = [];
|
|
1886
|
+
for (const skillId of uniqueSkillIds) {
|
|
1887
|
+
enforceSkillPolicy(spec, skillId);
|
|
1888
|
+
const skillPackage = await skillCatalog.getSkill(skillId);
|
|
1889
|
+
if (!skillPackage) throw new HephError({
|
|
1890
|
+
code: "HEPH8003",
|
|
1891
|
+
title: "Skill not found",
|
|
1892
|
+
message: `Skill ${skillId} was not found in the configured SkillCatalog.`,
|
|
1893
|
+
status: 422,
|
|
1894
|
+
details: {
|
|
1895
|
+
agentSpecId: spec.id,
|
|
1896
|
+
skillId
|
|
1897
|
+
}
|
|
1898
|
+
});
|
|
1899
|
+
packages.push(skillPackage);
|
|
1900
|
+
}
|
|
1901
|
+
return packages;
|
|
1902
|
+
}
|
|
1903
|
+
async function createSkillManifestForRun(agent, run) {
|
|
1904
|
+
const bindings = await stores.skillBindings.listSkillBindings(agent.id);
|
|
1905
|
+
const skills = [];
|
|
1906
|
+
for (const binding of bindings) {
|
|
1907
|
+
const skillPackage = await skillCatalog.getSkill(binding.skillId);
|
|
1908
|
+
if (!skillPackage) throw new HephError({
|
|
1909
|
+
code: "HEPH8003",
|
|
1910
|
+
title: "Skill not found",
|
|
1911
|
+
message: `Skill ${binding.skillId} was not found in the configured SkillCatalog.`,
|
|
1912
|
+
status: 422,
|
|
1913
|
+
details: {
|
|
1914
|
+
agentId: agent.id,
|
|
1915
|
+
bindingId: binding.id,
|
|
1916
|
+
skillId: binding.skillId
|
|
1917
|
+
}
|
|
1918
|
+
});
|
|
1919
|
+
skills.push({
|
|
1920
|
+
bindingId: binding.id,
|
|
1921
|
+
skillId: binding.skillId,
|
|
1922
|
+
name: skillPackage.name,
|
|
1923
|
+
version: skillPackage.version,
|
|
1924
|
+
description: skillPackage.description,
|
|
1925
|
+
instructions: skillPackage.instructions,
|
|
1926
|
+
descriptionHash: await sha256Text(skillPackage.description),
|
|
1927
|
+
instructionHash: await sha256Text(skillPackage.instructions),
|
|
1928
|
+
source: { ...binding.source },
|
|
1929
|
+
availableReferences: filterSkillReferences(skillPackage.references, binding.allowReferences),
|
|
1930
|
+
availableAssets: skillPackage.assets.map(cloneSkillResourceRef),
|
|
1931
|
+
availableTemplates: skillPackage.templates.map(cloneSkillResourceRef),
|
|
1932
|
+
metadata: {
|
|
1933
|
+
...skillPackage.metadata,
|
|
1934
|
+
...binding.metadata
|
|
1935
|
+
}
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
return {
|
|
1939
|
+
runId: run.id,
|
|
1940
|
+
skills,
|
|
1941
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
async function createToolManifestForRun(agent, spec, run) {
|
|
1945
|
+
const tools = spec.tools.map(toLocalManifestTool);
|
|
1946
|
+
const bindings = await stores.mcpBindings.listMcpBindings(agent.id);
|
|
1947
|
+
for (const binding of bindings) {
|
|
1948
|
+
enforceMcpPolicy(spec, binding);
|
|
1949
|
+
const resolved = await resolveMcpBindingOrThrow({
|
|
1950
|
+
resolver: mcpResolver,
|
|
1951
|
+
auth: run.auth ?? agent.auth,
|
|
1952
|
+
agent,
|
|
1953
|
+
binding,
|
|
1954
|
+
app
|
|
1955
|
+
});
|
|
1956
|
+
validateMcpCatalog(binding, resolved);
|
|
1957
|
+
tools.push(...filterMcpCatalog(binding, resolved).map((tool) => toMcpManifestTool(binding, tool)));
|
|
1958
|
+
}
|
|
1959
|
+
return {
|
|
1960
|
+
runId: run.id,
|
|
1961
|
+
tools,
|
|
1962
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1965
|
+
async function callTool(runId, input) {
|
|
1966
|
+
const run = await getRunOrThrow(stores, runId);
|
|
1967
|
+
if (run.status !== "running" && run.status !== "paused") throw new HephError({
|
|
1968
|
+
code: "HEPH3004",
|
|
1969
|
+
title: "Tool call is not allowed for this Run status",
|
|
1970
|
+
message: `Run ${run.id} is ${run.status}; tool calls require running or paused.`,
|
|
1971
|
+
status: 409,
|
|
1972
|
+
details: {
|
|
1973
|
+
runId: run.id,
|
|
1974
|
+
status: run.status,
|
|
1975
|
+
toolId: input.toolId
|
|
1976
|
+
}
|
|
1977
|
+
});
|
|
1978
|
+
if (!run.toolManifest) throw new HephError({
|
|
1979
|
+
code: "HEPH3003",
|
|
1980
|
+
title: "ToolManifest is not ready",
|
|
1981
|
+
message: `Run ${run.id} is ${run.status} but has no Run-scoped ToolManifest.`,
|
|
1982
|
+
status: 500,
|
|
1983
|
+
details: {
|
|
1984
|
+
runId: run.id,
|
|
1985
|
+
status: run.status,
|
|
1986
|
+
toolId: input.toolId
|
|
1987
|
+
}
|
|
1988
|
+
});
|
|
1989
|
+
const manifestTool = run.toolManifest.tools.find((tool) => tool.id === input.toolId);
|
|
1990
|
+
if (!manifestTool) throw new HephError({
|
|
1991
|
+
code: "HEPH3005",
|
|
1992
|
+
title: "Tool is not available for this Run",
|
|
1993
|
+
message: `Tool ${input.toolId} is not present in Run ${run.id}'s ToolManifest.`,
|
|
1994
|
+
status: 404,
|
|
1995
|
+
details: {
|
|
1996
|
+
runId: run.id,
|
|
1997
|
+
toolId: input.toolId
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
const agent = await getAgentOrThrow(stores, run.agentId);
|
|
2001
|
+
const spec = await resolveSpecOrThrow(resolver, run.agentSpecId, input.auth ?? run.auth ?? agent.auth);
|
|
2002
|
+
const auth = input.auth ?? run.auth;
|
|
2003
|
+
const toolInput = input.input ?? {};
|
|
2004
|
+
await ensureToolApproval({
|
|
2005
|
+
run,
|
|
2006
|
+
agent,
|
|
2007
|
+
manifestTool,
|
|
2008
|
+
input: toolInput,
|
|
2009
|
+
auth,
|
|
2010
|
+
approvalRequestId: input.approvalRequestId
|
|
2011
|
+
});
|
|
2012
|
+
await stores.events.appendRunEvent({
|
|
2013
|
+
runId: run.id,
|
|
2014
|
+
type: "tool.started",
|
|
2015
|
+
payload: {
|
|
2016
|
+
toolId: manifestTool.id,
|
|
2017
|
+
displayName: manifestTool.displayName,
|
|
2018
|
+
source: manifestTool.source,
|
|
2019
|
+
input: toolInput
|
|
2020
|
+
},
|
|
2021
|
+
sourceRefs: toolSourceRefs(manifestTool, input.approvalRequestId)
|
|
2022
|
+
});
|
|
2023
|
+
try {
|
|
2024
|
+
const result = manifestTool.source === "local" ? await callLocalTool({
|
|
2025
|
+
spec,
|
|
2026
|
+
manifestTool,
|
|
2027
|
+
input: toolInput,
|
|
2028
|
+
auth,
|
|
2029
|
+
agent,
|
|
2030
|
+
run,
|
|
2031
|
+
signal: input.signal ?? new AbortController().signal
|
|
2032
|
+
}) : await callMcpTool({
|
|
2033
|
+
manifestTool,
|
|
2034
|
+
input: toolInput,
|
|
2035
|
+
auth,
|
|
2036
|
+
agent,
|
|
2037
|
+
run,
|
|
2038
|
+
signal: input.signal
|
|
2039
|
+
});
|
|
2040
|
+
await stores.events.appendRunEvent({
|
|
2041
|
+
runId: run.id,
|
|
2042
|
+
type: "tool.completed",
|
|
2043
|
+
payload: {
|
|
2044
|
+
toolId: manifestTool.id,
|
|
2045
|
+
source: manifestTool.source,
|
|
2046
|
+
result
|
|
2047
|
+
},
|
|
2048
|
+
sourceRefs: toolSourceRefs(manifestTool, input.approvalRequestId)
|
|
2049
|
+
});
|
|
2050
|
+
return {
|
|
2051
|
+
toolId: manifestTool.id,
|
|
2052
|
+
result,
|
|
2053
|
+
ok: true
|
|
2054
|
+
};
|
|
2055
|
+
} catch (error) {
|
|
2056
|
+
await stores.events.appendRunEvent({
|
|
2057
|
+
runId: run.id,
|
|
2058
|
+
type: "tool.failed",
|
|
2059
|
+
payload: {
|
|
2060
|
+
toolId: manifestTool.id,
|
|
2061
|
+
source: manifestTool.source,
|
|
2062
|
+
error: toErrorDetails(error)
|
|
2063
|
+
},
|
|
2064
|
+
sourceRefs: toolSourceRefs(manifestTool, input.approvalRequestId)
|
|
2065
|
+
});
|
|
2066
|
+
throw error;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
async function tryCallTool(runId, input) {
|
|
2070
|
+
try {
|
|
2071
|
+
return {
|
|
2072
|
+
...await callTool(runId, input),
|
|
2073
|
+
ok: true
|
|
2074
|
+
};
|
|
2075
|
+
} catch (error) {
|
|
2076
|
+
if (shouldRethrowToolCallAttemptError(error)) throw error;
|
|
2077
|
+
return {
|
|
2078
|
+
toolId: input.toolId,
|
|
2079
|
+
ok: false,
|
|
2080
|
+
error: toRunError(error)
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
async function ensureToolApproval(input) {
|
|
2085
|
+
if (!(input.manifestTool.requiresApproval || input.manifestTool.sideEffect !== false)) return;
|
|
2086
|
+
if (input.approvalRequestId) {
|
|
2087
|
+
const request = await stores.approvals.getApprovalRequest(input.approvalRequestId);
|
|
2088
|
+
if (request && request.runId === input.run.id && request.toolId === input.manifestTool.id && request.status === "granted") return;
|
|
2089
|
+
throw new HephError({
|
|
2090
|
+
code: "HEPH3002",
|
|
2091
|
+
title: "Approval required",
|
|
2092
|
+
message: `Tool ${input.manifestTool.id} requires a granted approval request.`,
|
|
2093
|
+
status: 409,
|
|
2094
|
+
details: {
|
|
2095
|
+
approvalRequestId: input.approvalRequestId,
|
|
2096
|
+
runId: input.run.id,
|
|
2097
|
+
toolId: input.manifestTool.id,
|
|
2098
|
+
approvalStatus: request?.status ?? null
|
|
2099
|
+
}
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
const approval = await stores.approvals.createApprovalRequest({
|
|
2103
|
+
agentId: input.agent.id,
|
|
2104
|
+
runId: input.run.id,
|
|
2105
|
+
toolId: input.manifestTool.id,
|
|
2106
|
+
input: input.input,
|
|
2107
|
+
requestedBy: input.auth,
|
|
2108
|
+
metadata: {
|
|
2109
|
+
toolSource: input.manifestTool.source,
|
|
2110
|
+
displayName: input.manifestTool.displayName
|
|
2111
|
+
}
|
|
2112
|
+
});
|
|
2113
|
+
if (input.run.status === "running") {
|
|
2114
|
+
await stores.state.updateRun(input.run.id, { status: "paused" });
|
|
2115
|
+
await stores.events.appendRunEvent({
|
|
2116
|
+
runId: input.run.id,
|
|
2117
|
+
type: "run.paused",
|
|
2118
|
+
payload: {
|
|
2119
|
+
reason: "approval_required",
|
|
2120
|
+
approvalRequestId: approval.id,
|
|
2121
|
+
toolId: input.manifestTool.id
|
|
2122
|
+
},
|
|
2123
|
+
sourceRefs: [{
|
|
2124
|
+
type: "approval_request",
|
|
2125
|
+
id: approval.id
|
|
2126
|
+
}]
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
await stores.events.appendRunEvent({
|
|
2130
|
+
runId: input.run.id,
|
|
2131
|
+
type: "approval.requested",
|
|
2132
|
+
payload: {
|
|
2133
|
+
approvalRequestId: approval.id,
|
|
2134
|
+
toolId: input.manifestTool.id,
|
|
2135
|
+
displayName: input.manifestTool.displayName
|
|
2136
|
+
},
|
|
2137
|
+
sourceRefs: [...toolSourceRefs(input.manifestTool), {
|
|
2138
|
+
type: "approval_request",
|
|
2139
|
+
id: approval.id
|
|
2140
|
+
}]
|
|
2141
|
+
});
|
|
2142
|
+
throw new HephError({
|
|
2143
|
+
code: "HEPH3002",
|
|
2144
|
+
title: "Approval required",
|
|
2145
|
+
message: `Tool ${input.manifestTool.id} requires approval before execution.`,
|
|
2146
|
+
status: 409,
|
|
2147
|
+
details: {
|
|
2148
|
+
approvalRequestId: approval.id,
|
|
2149
|
+
runId: input.run.id,
|
|
2150
|
+
toolId: input.manifestTool.id
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
async function callLocalTool(input) {
|
|
2155
|
+
const tool = input.spec.tools.find((candidate) => candidate.id === input.manifestTool.id);
|
|
2156
|
+
if (!tool) throw new HephError({
|
|
2157
|
+
code: "HEPH3005",
|
|
2158
|
+
title: "Local tool is not registered",
|
|
2159
|
+
message: `Local tool ${input.manifestTool.id} is not registered on AgentSpec ${input.spec.id}.`,
|
|
2160
|
+
status: 500,
|
|
2161
|
+
details: {
|
|
2162
|
+
toolId: input.manifestTool.id,
|
|
2163
|
+
agentSpecId: input.spec.id
|
|
2164
|
+
}
|
|
2165
|
+
});
|
|
2166
|
+
const parsedInput = tool.inputSchema.parse(input.input);
|
|
2167
|
+
return tool.execute(parsedInput, {
|
|
2168
|
+
auth: input.auth,
|
|
2169
|
+
agent: input.agent,
|
|
2170
|
+
run: input.run,
|
|
2171
|
+
app,
|
|
2172
|
+
signal: input.signal
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
async function callMcpTool(input) {
|
|
2176
|
+
const binding = await stores.mcpBindings.getMcpBinding(input.manifestTool.bindingId);
|
|
2177
|
+
if (!binding) throw new HephError({
|
|
2178
|
+
code: "HEPH7001",
|
|
2179
|
+
title: "MCP binding not found",
|
|
2180
|
+
message: `MCP binding ${input.manifestTool.bindingId} was not found.`,
|
|
2181
|
+
status: 500,
|
|
2182
|
+
details: {
|
|
2183
|
+
bindingId: input.manifestTool.bindingId,
|
|
2184
|
+
toolId: input.manifestTool.id
|
|
2185
|
+
}
|
|
2186
|
+
});
|
|
2187
|
+
const resolved = await resolveMcpBindingOrThrow({
|
|
2188
|
+
resolver: mcpResolver,
|
|
2189
|
+
auth: input.auth,
|
|
2190
|
+
agent: input.agent,
|
|
2191
|
+
binding,
|
|
2192
|
+
app
|
|
2193
|
+
});
|
|
2194
|
+
return mcpToolExecutor.callTool({
|
|
2195
|
+
auth: input.auth,
|
|
2196
|
+
agent: input.agent,
|
|
2197
|
+
run: input.run,
|
|
2198
|
+
binding,
|
|
2199
|
+
manifestTool: input.manifestTool,
|
|
2200
|
+
resolved,
|
|
2201
|
+
input: input.input,
|
|
2202
|
+
app,
|
|
2203
|
+
signal: input.signal
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
async function renderRunContext(runId) {
|
|
2207
|
+
const run = await getRunOrThrow(stores, runId);
|
|
2208
|
+
const agent = await getAgentOrThrow(stores, run.agentId);
|
|
2209
|
+
const spec = await resolveSpecOrThrow(resolver, run.agentSpecId, run.auth ?? agent.auth);
|
|
2210
|
+
const providerBlocks = await loadProviderBlocks(spec.contextProviders, {
|
|
2211
|
+
auth: run.auth,
|
|
2212
|
+
agent,
|
|
2213
|
+
run,
|
|
2214
|
+
spec,
|
|
2215
|
+
input: run.input,
|
|
2216
|
+
stores,
|
|
2217
|
+
app
|
|
2218
|
+
});
|
|
2219
|
+
const builtInBlocks = createBuiltInBlocks({
|
|
2220
|
+
agent,
|
|
2221
|
+
spec,
|
|
2222
|
+
run,
|
|
2223
|
+
runtimePolicy: options.runtimePolicy ?? "Follow the active platform, security, tenant-boundary, and tool policies supplied by the runtime.",
|
|
2224
|
+
toolPolicy: options.toolPolicy ?? "Use only the tools listed in the Run-scoped ToolManifest."
|
|
2225
|
+
});
|
|
2226
|
+
const rendered = renderer.render({
|
|
2227
|
+
template: spec.contextTemplate ?? defaultContextTemplate,
|
|
2228
|
+
blocks: [...builtInBlocks, ...providerBlocks],
|
|
2229
|
+
runId: run.id,
|
|
2230
|
+
input: runInputText(run.input),
|
|
2231
|
+
runtime: { toolPolicy: options.toolPolicy ?? "Use only the tools listed in the Run-scoped ToolManifest." }
|
|
2232
|
+
});
|
|
2233
|
+
await stores.events.appendRunEvent({
|
|
2234
|
+
runId: run.id,
|
|
2235
|
+
type: "context.rendered",
|
|
2236
|
+
payload: {
|
|
2237
|
+
contextTemplateId: rendered.manifest.contextTemplateId,
|
|
2238
|
+
contextTemplateVersion: rendered.manifest.contextTemplateVersion,
|
|
2239
|
+
totalTokens: rendered.manifest.totalTokens,
|
|
2240
|
+
blocks: rendered.manifest.blocks.map((block) => ({
|
|
2241
|
+
key: block.key,
|
|
2242
|
+
type: block.type,
|
|
2243
|
+
tokens: block.tokens,
|
|
2244
|
+
truncated: block.truncated
|
|
2245
|
+
}))
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
return rendered;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
function normalizeAgentSpecResolver(registration) {
|
|
2252
|
+
if (isAgentSpecResolver(registration)) return registration;
|
|
2253
|
+
const specs = /* @__PURE__ */ new Map();
|
|
2254
|
+
if (Array.isArray(registration)) for (const spec of registration) specs.set(spec.id, spec);
|
|
2255
|
+
else for (const [id, spec] of Object.entries(registration)) specs.set(id, spec);
|
|
2256
|
+
return { async resolve(id) {
|
|
2257
|
+
return specs.get(id) ?? null;
|
|
2258
|
+
} };
|
|
2259
|
+
}
|
|
2260
|
+
function isAgentSpecResolver(registration) {
|
|
2261
|
+
return typeof registration.resolve === "function";
|
|
2262
|
+
}
|
|
2263
|
+
async function resolveSpecOrThrow(resolver, id, auth) {
|
|
2264
|
+
const spec = await resolver.resolve(id, { auth });
|
|
2265
|
+
if (!spec) throw new HephError({
|
|
2266
|
+
code: "HEPH1001",
|
|
2267
|
+
title: "Agent spec not found",
|
|
2268
|
+
message: `Agent spec ${id} was not found.`,
|
|
2269
|
+
status: 404,
|
|
2270
|
+
details: { agentSpecId: id }
|
|
2271
|
+
});
|
|
2272
|
+
return spec;
|
|
2273
|
+
}
|
|
2274
|
+
async function getAgentOrThrow(stores, agentId) {
|
|
2275
|
+
const agent = await stores.state.getAgentSession(agentId);
|
|
2276
|
+
if (!agent) throw new HephError({
|
|
2277
|
+
code: "HEPH5001",
|
|
2278
|
+
title: "AgentSession not found",
|
|
2279
|
+
message: `AgentSession ${agentId} was not found.`,
|
|
2280
|
+
status: 404,
|
|
2281
|
+
details: { agentId }
|
|
2282
|
+
});
|
|
2283
|
+
return agent;
|
|
2284
|
+
}
|
|
2285
|
+
async function getRunOrThrow(stores, runId) {
|
|
2286
|
+
const run = await stores.state.getRun(runId);
|
|
2287
|
+
if (!run) throw new HephError({
|
|
2288
|
+
code: "HEPH4001",
|
|
2289
|
+
title: "Run not found",
|
|
2290
|
+
message: `Run ${runId} was not found.`,
|
|
2291
|
+
status: 404,
|
|
2292
|
+
details: { runId }
|
|
2293
|
+
});
|
|
2294
|
+
return run;
|
|
2295
|
+
}
|
|
2296
|
+
async function loadProviderBlocks(providers, ctx) {
|
|
2297
|
+
const blocks = [];
|
|
2298
|
+
for (const provider of providers) {
|
|
2299
|
+
const loaded = await provider.load(ctx);
|
|
2300
|
+
if (!loaded) continue;
|
|
2301
|
+
if (Array.isArray(loaded)) blocks.push(...loaded);
|
|
2302
|
+
else blocks.push(loaded);
|
|
2303
|
+
}
|
|
2304
|
+
return blocks;
|
|
2305
|
+
}
|
|
2306
|
+
function enforceMcpPolicy(spec, binding) {
|
|
2307
|
+
if (!spec.mcp) throw new HephError({
|
|
2308
|
+
code: "HEPH7001",
|
|
2309
|
+
title: "MCP is disabled for this AgentSpec",
|
|
2310
|
+
message: `AgentSpec ${spec.id} does not allow dynamic MCP bindings.`,
|
|
2311
|
+
status: 422,
|
|
2312
|
+
details: {
|
|
2313
|
+
agentSpecId: spec.id,
|
|
2314
|
+
capabilityId: binding.capabilityId
|
|
2315
|
+
}
|
|
2316
|
+
});
|
|
2317
|
+
if (!spec.mcp.allowCapabilities.includes(binding.capabilityId)) throw new HephError({
|
|
2318
|
+
code: "HEPH7001",
|
|
2319
|
+
title: "MCP capability is not allowed",
|
|
2320
|
+
message: `AgentSpec ${spec.id} does not allow MCP capability ${binding.capabilityId}.`,
|
|
2321
|
+
status: 422,
|
|
2322
|
+
details: {
|
|
2323
|
+
agentSpecId: spec.id,
|
|
2324
|
+
capabilityId: binding.capabilityId
|
|
2325
|
+
}
|
|
2326
|
+
});
|
|
2327
|
+
if (binding.allowTools === "all" && spec.mcp.allowAllTools !== true) throw new HephError({
|
|
2328
|
+
code: "HEPH7001",
|
|
2329
|
+
title: "MCP allowTools all is not allowed",
|
|
2330
|
+
message: `AgentSpec ${spec.id} must opt in before an MCP binding can expose all tools.`,
|
|
2331
|
+
status: 422,
|
|
2332
|
+
details: {
|
|
2333
|
+
agentSpecId: spec.id,
|
|
2334
|
+
capabilityId: binding.capabilityId
|
|
2335
|
+
}
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2338
|
+
function enforceSkillPolicy(spec, skillId) {
|
|
2339
|
+
if (!spec.skills) throw new HephError({
|
|
2340
|
+
code: "HEPH8004",
|
|
2341
|
+
title: "Skills are disabled for this AgentSpec",
|
|
2342
|
+
message: `AgentSpec ${spec.id} does not allow session skill activation.`,
|
|
2343
|
+
status: 422,
|
|
2344
|
+
details: {
|
|
2345
|
+
agentSpecId: spec.id,
|
|
2346
|
+
skillId
|
|
2347
|
+
}
|
|
2348
|
+
});
|
|
2349
|
+
if (spec.skills.allow !== "all" && !spec.skills.allow.includes(skillId)) throw new HephError({
|
|
2350
|
+
code: "HEPH8004",
|
|
2351
|
+
title: "Skill is not allowed",
|
|
2352
|
+
message: `AgentSpec ${spec.id} does not allow skill ${skillId}.`,
|
|
2353
|
+
status: 422,
|
|
2354
|
+
details: {
|
|
2355
|
+
agentSpecId: spec.id,
|
|
2356
|
+
skillId
|
|
2357
|
+
}
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
async function resolveMcpBindingOrThrow(input) {
|
|
2361
|
+
if (!input.resolver) throw new HephError({
|
|
2362
|
+
code: "HEPH7001",
|
|
2363
|
+
title: "MCP binding resolver is not configured",
|
|
2364
|
+
message: "createHeph({ mcp: { resolver } }) is required before MCP bindings can be resolved.",
|
|
2365
|
+
status: 422,
|
|
2366
|
+
details: {
|
|
2367
|
+
bindingId: input.binding.id,
|
|
2368
|
+
capabilityId: input.binding.capabilityId
|
|
2369
|
+
}
|
|
2370
|
+
});
|
|
2371
|
+
const resolved = await input.resolver.resolve({
|
|
2372
|
+
auth: input.auth,
|
|
2373
|
+
agent: input.agent,
|
|
2374
|
+
binding: input.binding,
|
|
2375
|
+
app: input.app
|
|
2376
|
+
});
|
|
2377
|
+
if (resolved.transport !== "streamable_http") throw new HephError({
|
|
2378
|
+
code: "HEPH7001",
|
|
2379
|
+
title: "Unsupported MCP transport",
|
|
2380
|
+
message: "The MCP MVP supports only Streamable HTTP bindings.",
|
|
2381
|
+
status: 422,
|
|
2382
|
+
details: {
|
|
2383
|
+
bindingId: input.binding.id,
|
|
2384
|
+
transport: resolved.transport
|
|
2385
|
+
}
|
|
2386
|
+
});
|
|
2387
|
+
if (!resolved.endpoint.trim()) throw new HephError({
|
|
2388
|
+
code: "HEPH7001",
|
|
2389
|
+
title: "MCP endpoint is missing",
|
|
2390
|
+
message: "Resolved MCP bindings must include a Streamable HTTP endpoint.",
|
|
2391
|
+
status: 422,
|
|
2392
|
+
details: { bindingId: input.binding.id }
|
|
2393
|
+
});
|
|
2394
|
+
return resolved;
|
|
2395
|
+
}
|
|
2396
|
+
function validateMcpCatalog(binding, resolved) {
|
|
2397
|
+
const toolNames = new Set(resolved.tools.map((tool) => tool.name));
|
|
2398
|
+
if (resolved.tools.filter((tool) => !tool.name.trim()).length > 0) throw new HephError({
|
|
2399
|
+
code: "HEPH7001",
|
|
2400
|
+
title: "MCP tool catalog is invalid",
|
|
2401
|
+
message: "MCP tool catalog entries must include non-empty tool names.",
|
|
2402
|
+
status: 422,
|
|
2403
|
+
details: {
|
|
2404
|
+
bindingId: binding.id,
|
|
2405
|
+
capabilityId: binding.capabilityId
|
|
2406
|
+
}
|
|
2407
|
+
});
|
|
2408
|
+
if (binding.allowTools !== "all") {
|
|
2409
|
+
const unknownTools = binding.allowTools.filter((toolName) => !toolNames.has(toolName));
|
|
2410
|
+
if (unknownTools.length > 0) throw new HephError({
|
|
2411
|
+
code: "HEPH7001",
|
|
2412
|
+
title: "MCP allowTools contains unknown tools",
|
|
2413
|
+
message: "MCP binding allowTools must name tools present in the resolved catalog.",
|
|
2414
|
+
status: 422,
|
|
2415
|
+
details: {
|
|
2416
|
+
bindingId: binding.id,
|
|
2417
|
+
capabilityId: binding.capabilityId,
|
|
2418
|
+
unknownTools
|
|
2419
|
+
}
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
function filterMcpCatalog(binding, resolved) {
|
|
2424
|
+
if (binding.allowTools === "all") return resolved.tools;
|
|
2425
|
+
const allowSet = new Set(binding.allowTools);
|
|
2426
|
+
return resolved.tools.filter((tool) => allowSet.has(tool.name));
|
|
2427
|
+
}
|
|
2428
|
+
function toolSourceRefs(tool, approvalRequestId) {
|
|
2429
|
+
const refs = tool.source === "mcp" ? [{
|
|
2430
|
+
type: "mcp_binding",
|
|
2431
|
+
id: tool.bindingId
|
|
2432
|
+
}] : [];
|
|
2433
|
+
if (approvalRequestId) refs.push({
|
|
2434
|
+
type: "approval_request",
|
|
2435
|
+
id: approvalRequestId
|
|
2436
|
+
});
|
|
2437
|
+
return refs;
|
|
2438
|
+
}
|
|
2439
|
+
function createBuiltInBlocks(input) {
|
|
2440
|
+
return [
|
|
2441
|
+
{
|
|
2442
|
+
key: "runtimePolicy",
|
|
2443
|
+
type: "policy",
|
|
2444
|
+
content: input.runtimePolicy
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
key: "agentIdentity",
|
|
2448
|
+
type: "agent_identity",
|
|
2449
|
+
content: input.spec.instructions
|
|
2450
|
+
},
|
|
2451
|
+
{
|
|
2452
|
+
key: "currentTask",
|
|
2453
|
+
type: "input",
|
|
2454
|
+
content: runInputText(input.run.input)
|
|
2455
|
+
},
|
|
2456
|
+
{
|
|
2457
|
+
key: "sessionState",
|
|
2458
|
+
type: "state",
|
|
2459
|
+
content: JSON.stringify(input.agent.state, null, 2)
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
key: "skills",
|
|
2463
|
+
type: "skill",
|
|
2464
|
+
content: formatSkillsBlock(input.run.skillManifest),
|
|
2465
|
+
sourceRefs: input.run.skillManifest?.skills.map((skill) => ({
|
|
2466
|
+
type: "skill_binding",
|
|
2467
|
+
id: skill.bindingId
|
|
2468
|
+
})) ?? []
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
key: "toolManifest",
|
|
2472
|
+
type: "tool_manifest",
|
|
2473
|
+
content: JSON.stringify(input.run.toolManifest ?? createLocalToolManifest(input.run.id, input.spec.tools), null, 2)
|
|
2474
|
+
}
|
|
2475
|
+
];
|
|
2476
|
+
}
|
|
2477
|
+
function createLocalToolManifest(runId, tools) {
|
|
2478
|
+
return {
|
|
2479
|
+
runId,
|
|
2480
|
+
tools: tools.map(toLocalManifestTool),
|
|
2481
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
function toLocalManifestTool(tool) {
|
|
2485
|
+
return {
|
|
2486
|
+
id: tool.id,
|
|
2487
|
+
displayName: tool.id,
|
|
2488
|
+
source: "local",
|
|
2489
|
+
localToolId: tool.id,
|
|
2490
|
+
description: tool.description,
|
|
2491
|
+
inputSchema: tool.jsonSchema,
|
|
2492
|
+
sideEffect: tool.sideEffect,
|
|
2493
|
+
requiresApproval: tool.requiresApproval,
|
|
2494
|
+
metadata: {}
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
function toMcpManifestTool(binding, tool) {
|
|
2498
|
+
const sideEffect = tool.sideEffect ?? null;
|
|
2499
|
+
return {
|
|
2500
|
+
id: `mcp.${binding.id}.${tool.name}`,
|
|
2501
|
+
displayName: `${binding.capabilityId}.${tool.name}`,
|
|
2502
|
+
source: "mcp",
|
|
2503
|
+
bindingId: binding.id,
|
|
2504
|
+
capabilityId: binding.capabilityId,
|
|
2505
|
+
remoteToolName: tool.name,
|
|
2506
|
+
transport: "streamable_http",
|
|
2507
|
+
description: tool.description ?? "",
|
|
2508
|
+
inputSchema: tool.inputSchema ?? {
|
|
2509
|
+
type: "object",
|
|
2510
|
+
additionalProperties: true
|
|
2511
|
+
},
|
|
2512
|
+
sideEffect,
|
|
2513
|
+
requiresApproval: tool.requiresApproval ?? sideEffect !== false,
|
|
2514
|
+
metadata: tool.metadata ?? {}
|
|
2515
|
+
};
|
|
2516
|
+
}
|
|
2517
|
+
function normalizeRunInput(input) {
|
|
2518
|
+
if (typeof input === "string") return {
|
|
2519
|
+
type: "user.message",
|
|
2520
|
+
text: input
|
|
2521
|
+
};
|
|
2522
|
+
return input;
|
|
2523
|
+
}
|
|
2524
|
+
function renderDeferredToolResultContent(operation) {
|
|
2525
|
+
const lines = [`Deferred tool operation ${operation.id} ${operation.status}.`];
|
|
2526
|
+
lines.push(`- toolId: ${operation.toolId}`);
|
|
2527
|
+
lines.push(`- runId: ${operation.runId}`);
|
|
2528
|
+
if (operation.toolCallId) lines.push(`- toolCallId: ${operation.toolCallId}`);
|
|
2529
|
+
if (operation.error) lines.push(`- error: ${operation.error.message}`);
|
|
2530
|
+
if (operation.result !== null && operation.result !== void 0) lines.push(`- result: ${JSON.stringify(operation.result)}`);
|
|
2531
|
+
return lines.join("\n");
|
|
2532
|
+
}
|
|
2533
|
+
function addMessageIdToRunInput(input, messageId) {
|
|
2534
|
+
return {
|
|
2535
|
+
...input,
|
|
2536
|
+
messageIds: [...input.messageIds ?? [], messageId]
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
function reduceInboxEvents(events, textSeparator) {
|
|
2540
|
+
const messageIds = unique(events.flatMap((event) => event.input.messageIds ?? []));
|
|
2541
|
+
const textEvents = events.filter((event) => "text" in event.input);
|
|
2542
|
+
if (textEvents.length === events.length) {
|
|
2543
|
+
const first = textEvents[0];
|
|
2544
|
+
return {
|
|
2545
|
+
type: first?.input.type === "steering.message" || first?.input.type === "follow_up.message" ? first.input.type : "user.message",
|
|
2546
|
+
text: textEvents.map((event) => "text" in event.input ? event.input.text : "").join(textSeparator),
|
|
2547
|
+
messageIds,
|
|
2548
|
+
payload: {
|
|
2549
|
+
inboxEventIds: events.map((event) => event.id),
|
|
2550
|
+
reducedInboxEvents: events.map(toReducedInboxEvent)
|
|
2551
|
+
}
|
|
2552
|
+
};
|
|
2553
|
+
}
|
|
2554
|
+
if (events.length === 1) return {
|
|
2555
|
+
...events[0].input,
|
|
2556
|
+
messageIds,
|
|
2557
|
+
payload: {
|
|
2558
|
+
...typeof events[0].input.payload === "object" && events[0].input.payload !== null ? events[0].input.payload : {},
|
|
2559
|
+
reducedInboxEvents: events.map(toReducedInboxEvent)
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
return {
|
|
2563
|
+
type: "system.event",
|
|
2564
|
+
messageIds,
|
|
2565
|
+
payload: {
|
|
2566
|
+
inboxEvents: events.map((event) => ({
|
|
2567
|
+
id: event.id,
|
|
2568
|
+
type: event.type,
|
|
2569
|
+
input: event.input
|
|
2570
|
+
})),
|
|
2571
|
+
reducedInboxEvents: events.map(toReducedInboxEvent)
|
|
2572
|
+
}
|
|
2573
|
+
};
|
|
2574
|
+
}
|
|
2575
|
+
function normalizeMaxEventsPerRun(value) {
|
|
2576
|
+
if (value === null) return;
|
|
2577
|
+
if (value === void 0) return 20;
|
|
2578
|
+
if (!Number.isFinite(value) || value < 1) throw new HephError({
|
|
2579
|
+
code: "HEPH4006",
|
|
2580
|
+
title: "Invalid inbox reducer configuration",
|
|
2581
|
+
message: "inbox.maxEventsPerRun must be a positive number or null.",
|
|
2582
|
+
status: 422,
|
|
2583
|
+
details: { maxEventsPerRun: value }
|
|
2584
|
+
});
|
|
2585
|
+
return Math.floor(value);
|
|
2586
|
+
}
|
|
2587
|
+
function toReducedInboxEvent(event) {
|
|
2588
|
+
const input = event.input;
|
|
2589
|
+
return {
|
|
2590
|
+
inboxEventId: event.id,
|
|
2591
|
+
type: event.type,
|
|
2592
|
+
messageIds: input.messageIds ?? [],
|
|
2593
|
+
text: "text" in input ? input.text : null
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
function firstAuth(events) {
|
|
2597
|
+
return events.find((event) => event.auth !== null)?.auth ?? null;
|
|
2598
|
+
}
|
|
2599
|
+
function toInboxSourceRefs(events) {
|
|
2600
|
+
return events.map((event) => ({
|
|
2601
|
+
type: "inbox_event",
|
|
2602
|
+
id: event.id
|
|
2603
|
+
}));
|
|
2604
|
+
}
|
|
2605
|
+
function toRunError(error) {
|
|
2606
|
+
const runError = {
|
|
2607
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2608
|
+
details: toErrorDetails(error)
|
|
2609
|
+
};
|
|
2610
|
+
if (error instanceof HephError) runError.code = error.code;
|
|
2611
|
+
return runError;
|
|
2612
|
+
}
|
|
2613
|
+
function shouldRethrowToolCallAttemptError(error) {
|
|
2614
|
+
if (!(error instanceof HephError)) return false;
|
|
2615
|
+
return error.code === "HEPH3002" || error.code === "HEPH3003" || error.code === "HEPH3004";
|
|
2616
|
+
}
|
|
2617
|
+
function isTerminalRun(run) {
|
|
2618
|
+
return run.status === "completed" || run.status === "failed" || run.status === "cancelled";
|
|
2619
|
+
}
|
|
2620
|
+
function unique(values) {
|
|
2621
|
+
return Array.from(new Set(values));
|
|
2622
|
+
}
|
|
2623
|
+
function runInputText(input) {
|
|
2624
|
+
return "text" in input ? input.text : JSON.stringify(input.payload ?? {});
|
|
2625
|
+
}
|
|
2626
|
+
function formatSkillsBlock(manifest) {
|
|
2627
|
+
if (!manifest || manifest.skills.length === 0) return "";
|
|
2628
|
+
return manifest.skills.map((skill) => {
|
|
2629
|
+
const version = skill.version ? `@${skill.version}` : "";
|
|
2630
|
+
const referenceLines = skill.availableReferences.length === 0 ? "" : `\nAvailable references:\n${skill.availableReferences.map((ref) => `- ${ref.id}: ${ref.pathOrRef}`).join("\n")}`;
|
|
2631
|
+
return `# ${skill.name}${version}\n\nDescription: ${skill.description}\n\nInstructions:\n${skill.instructions}${referenceLines}`;
|
|
2632
|
+
}).join("\n\n---\n\n");
|
|
2633
|
+
}
|
|
2634
|
+
function filterSkillReferences(references, allowReferences) {
|
|
2635
|
+
if (allowReferences === "all") return references.map(cloneSkillResourceRef);
|
|
2636
|
+
const allowSet = new Set(allowReferences);
|
|
2637
|
+
return references.filter((reference) => allowSet.has(reference.id)).map(cloneSkillResourceRef);
|
|
2638
|
+
}
|
|
2639
|
+
function cloneSkillResourceRef(ref) {
|
|
2640
|
+
return {
|
|
2641
|
+
...ref,
|
|
2642
|
+
metadata: { ...ref.metadata }
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
async function sha256Text(value) {
|
|
2646
|
+
const bytes = new TextEncoder().encode(value);
|
|
2647
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
2648
|
+
return `sha256:${Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
2649
|
+
}
|
|
2650
|
+
function parseMcpResponseBody(body, contentType) {
|
|
2651
|
+
const trimmed = body.trim();
|
|
2652
|
+
if (!trimmed) return null;
|
|
2653
|
+
if (contentType?.includes("text/event-stream")) {
|
|
2654
|
+
const lastData = trimmed.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter((line) => line && line !== "[DONE]").at(-1);
|
|
2655
|
+
if (!lastData) return null;
|
|
2656
|
+
try {
|
|
2657
|
+
return JSON.parse(lastData);
|
|
2658
|
+
} catch {
|
|
2659
|
+
return lastData;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
try {
|
|
2663
|
+
return JSON.parse(trimmed);
|
|
2664
|
+
} catch {
|
|
2665
|
+
return trimmed;
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
function isJsonRpcError(value) {
|
|
2669
|
+
return isRecord(value) && "error" in value && value.error !== void 0 && value.error !== null;
|
|
2670
|
+
}
|
|
2671
|
+
function isRecord(value) {
|
|
2672
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2673
|
+
}
|
|
2674
|
+
//#endregion
|
|
2675
|
+
export { ContextRenderer as A, ContextProvider as C, defineContextProvider as D, defineAgent as E, isHephError as F, toErrorDetails as I, estimateTokens as M, messagesToText as N, defineContextTemplate as O, HephError as P, AgentSpec as S, Tool as T, createMessageId as _, InProcessQueue as a, createSkillBindingId as b, recentMessages as c, createApprovalRequestId as d, createDeferredToolOperationId as f, createMemoryId as g, createMcpBindingId as h, createInMemorySkillCatalog as i, defaultContextTemplate as j, defineTool as k, threadState as l, createInboxEventId as m, createHeph as n, block as o, createId as p, InMemoryHephStore as r, memorySearch as s, StreamableHttpMcpToolExecutor as t, createAgentSessionId as u, createRunEventId as v, ContextTemplate as w, MinimalRunExecutor as x, createRunId as y };
|
|
2676
|
+
|
|
2677
|
+
//# sourceMappingURL=src-DeheByi4.mjs.map
|