@standardagents/builder 0.38.2 → 0.39.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/built-in-routes.js +231 -73
- package/dist/built-in-routes.js.map +1 -1
- package/dist/{index-CF-lgN47.d.ts → index-yIcqf7DC.d.ts} +6 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +322 -148
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +17 -35
- package/dist/runtime.js +322 -148
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +5 -5
package/dist/runtime.js
CHANGED
|
@@ -1489,6 +1489,9 @@ function normalizeToolCallMessageSequence(messages) {
|
|
|
1489
1489
|
for (const message of messages) {
|
|
1490
1490
|
const isAssistantToolCallMessage = message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
|
1491
1491
|
if (!pending) {
|
|
1492
|
+
if (message.role === "tool") {
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1492
1495
|
if (!isAssistantToolCallMessage) {
|
|
1493
1496
|
normalized.push(message);
|
|
1494
1497
|
continue;
|
|
@@ -4274,6 +4277,24 @@ var init_ToolExecutor = __esm({
|
|
|
4274
4277
|
}
|
|
4275
4278
|
} catch {
|
|
4276
4279
|
}
|
|
4280
|
+
const aliasTarget = this.subagentAliasTarget(state, toolName);
|
|
4281
|
+
if (aliasTarget) {
|
|
4282
|
+
if (packageId) {
|
|
4283
|
+
try {
|
|
4284
|
+
const qualified = aliasTarget.includes("/") ? aliasTarget : `${packageId}/${aliasTarget}`;
|
|
4285
|
+
if (await state.thread.instance.loadAgent(qualified)) {
|
|
4286
|
+
return "agent";
|
|
4287
|
+
}
|
|
4288
|
+
} catch {
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
try {
|
|
4292
|
+
if (await state.thread.instance.loadAgent(aliasTarget)) {
|
|
4293
|
+
return "agent";
|
|
4294
|
+
}
|
|
4295
|
+
} catch {
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4277
4298
|
const isInToolsArray = (agentName) => {
|
|
4278
4299
|
const tools2 = state.prompt._tools || [];
|
|
4279
4300
|
return tools2.some((t) => typeof t === "string" ? t === agentName : t.name === agentName);
|
|
@@ -4789,15 +4810,20 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4789
4810
|
const builtinCreateAttachmentValue = createArgs?.attachments;
|
|
4790
4811
|
const builtinCreateInitialArguments = createArgs?.initialArguments ?? {};
|
|
4791
4812
|
const registryAgentName = targetAgentForCreate || call.function.name;
|
|
4813
|
+
const aliasConfig = this.resolveSubagentToolConfig(state, registryAgentName);
|
|
4814
|
+
const implementingAgentName = typeof aliasConfig.agent === "string" && aliasConfig.agent.trim().length > 0 ? aliasConfig.agent.trim() : registryAgentName;
|
|
4792
4815
|
const packageId = getPackageId(state);
|
|
4793
4816
|
let agentDef = null;
|
|
4794
|
-
let agentName =
|
|
4817
|
+
let agentName = implementingAgentName;
|
|
4795
4818
|
if (builtinSubagentAction === "create" && targetAgentForCreate) {
|
|
4796
4819
|
const availableSubagents = await this.getPromptSubagentNames(state);
|
|
4797
4820
|
if (!availableSubagents.includes(targetAgentForCreate)) {
|
|
4821
|
+
const configuredDirect = (state.prompt._tools || []).some(
|
|
4822
|
+
(t) => typeof t === "string" ? t === targetAgentForCreate : t?.name === targetAgentForCreate
|
|
4823
|
+
);
|
|
4798
4824
|
return {
|
|
4799
4825
|
status: "error",
|
|
4800
|
-
error: `Subagent "${targetAgentForCreate}" is not available for this prompt. Use one of: ${availableSubagents.join(", ") || "(none)"}.`
|
|
4826
|
+
error: configuredDirect ? `"${targetAgentForCreate}" is not a resumable subagent \u2014 call the ${targetAgentForCreate} tool directly; it runs to completion and returns its result in the tool response. subagent_create manages resumable subagents only: ${availableSubagents.join(", ") || "(none)"}.` : `Subagent "${targetAgentForCreate}" is not available for this prompt. Use one of: ${availableSubagents.join(", ") || "(none)"}.`
|
|
4801
4827
|
};
|
|
4802
4828
|
}
|
|
4803
4829
|
}
|
|
@@ -4838,7 +4864,7 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4838
4864
|
if (agentType === "ai_human") {
|
|
4839
4865
|
const parentToolConfigs = state.prompt._tools || [];
|
|
4840
4866
|
const toolConfig = parentToolConfigs.find(
|
|
4841
|
-
(t) => typeof t === "string" ? t === agentName : t.name === agentName
|
|
4867
|
+
(t) => typeof t === "string" ? t === registryAgentName || t === agentName : t.name === registryAgentName || t.name === agentName
|
|
4842
4868
|
);
|
|
4843
4869
|
const subpromptToolConfig = this.getSubpromptToolConfig(toolConfig);
|
|
4844
4870
|
const targetState = state.rootState || state;
|
|
@@ -5416,6 +5442,27 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5416
5442
|
}
|
|
5417
5443
|
return null;
|
|
5418
5444
|
}
|
|
5445
|
+
/**
|
|
5446
|
+
* The implementing agent behind an aliased subagent tool name, or null when
|
|
5447
|
+
* the name carries no alias (`agent` absent, empty, or equal to the name).
|
|
5448
|
+
*/
|
|
5449
|
+
static subagentAliasTarget(state, toolName) {
|
|
5450
|
+
for (const tool of state.prompt._tools || []) {
|
|
5451
|
+
if (!tool || typeof tool !== "object" || tool.name !== toolName) {
|
|
5452
|
+
continue;
|
|
5453
|
+
}
|
|
5454
|
+
const target = tool.agent;
|
|
5455
|
+
if (typeof target === "string" && target.trim().length > 0 && target.trim() !== toolName) {
|
|
5456
|
+
return target.trim();
|
|
5457
|
+
}
|
|
5458
|
+
}
|
|
5459
|
+
return null;
|
|
5460
|
+
}
|
|
5461
|
+
/**
|
|
5462
|
+
* Resolve the prompt's subagent tool config for an EXPOSED tool name.
|
|
5463
|
+
* Config entries are keyed by `name` (the model-facing tool name), which
|
|
5464
|
+
* may alias a differently-named implementing agent via `agent`.
|
|
5465
|
+
*/
|
|
5419
5466
|
static resolveSubagentToolConfig(state, agentName) {
|
|
5420
5467
|
const config = (state.prompt._tools || []).find(
|
|
5421
5468
|
(tool) => typeof tool === "string" ? tool === agentName : tool.name === agentName
|
|
@@ -7591,28 +7638,12 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7591
7638
|
state.promptPath = [sideAPrompt.name];
|
|
7592
7639
|
state.pendingImmediateAfterHandoff = true;
|
|
7593
7640
|
if (userMessageContent || userMessageAttachments) {
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
role: "user",
|
|
7599
|
-
content: userMessageContent || "",
|
|
7600
|
-
created_at: handoffTimestamp,
|
|
7601
|
-
attachments: userMessageAttachments
|
|
7602
|
-
};
|
|
7603
|
-
await state.storage.sql.exec(
|
|
7604
|
-
`INSERT INTO messages (id, role, content, attachments, created_at, prompt) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
7605
|
-
handoffMessage.id,
|
|
7606
|
-
handoffMessage.role,
|
|
7607
|
-
handoffMessage.content,
|
|
7608
|
-
handoffMessage.attachments || null,
|
|
7609
|
-
handoffMessage.created_at,
|
|
7641
|
+
await this.persistHandoffUserMessage(
|
|
7642
|
+
state,
|
|
7643
|
+
userMessageContent || "",
|
|
7644
|
+
userMessageAttachments,
|
|
7610
7645
|
sideAPrompt.name
|
|
7611
7646
|
);
|
|
7612
|
-
state.messageHistory.push(handoffMessage);
|
|
7613
|
-
if (state.emitMessage) {
|
|
7614
|
-
state.emitMessage(handoffMessage);
|
|
7615
|
-
}
|
|
7616
7647
|
}
|
|
7617
7648
|
state.pendingHandoff = void 0;
|
|
7618
7649
|
state.emitTelemetry?.({
|
|
@@ -7627,6 +7658,37 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7627
7658
|
throw error;
|
|
7628
7659
|
}
|
|
7629
7660
|
}
|
|
7661
|
+
/**
|
|
7662
|
+
* Persist the user message that rides an agent handoff, applying the
|
|
7663
|
+
* create-message lifecycle hooks like every other insertion path.
|
|
7664
|
+
*/
|
|
7665
|
+
static async persistHandoffUserMessage(state, content, attachments, promptName) {
|
|
7666
|
+
let handoffMessage = {
|
|
7667
|
+
id: crypto.randomUUID(),
|
|
7668
|
+
role: "user",
|
|
7669
|
+
content,
|
|
7670
|
+
created_at: Date.now() * 1e3,
|
|
7671
|
+
status: "completed",
|
|
7672
|
+
attachments: attachments ?? null
|
|
7673
|
+
};
|
|
7674
|
+
handoffMessage = await this.runBeforeCreateMessageHook(state, handoffMessage);
|
|
7675
|
+
await state.storage.sql.exec(
|
|
7676
|
+
`INSERT INTO messages (id, role, content, attachments, created_at, status, silent, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
7677
|
+
handoffMessage.id,
|
|
7678
|
+
handoffMessage.role,
|
|
7679
|
+
handoffMessage.content,
|
|
7680
|
+
handoffMessage.attachments || null,
|
|
7681
|
+
handoffMessage.created_at,
|
|
7682
|
+
handoffMessage.status ?? "completed",
|
|
7683
|
+
handoffMessage.silent ? 1 : 0,
|
|
7684
|
+
promptName
|
|
7685
|
+
);
|
|
7686
|
+
state.messageHistory.push(handoffMessage);
|
|
7687
|
+
await this.runAfterCreateMessageHook(state, handoffMessage);
|
|
7688
|
+
if (state.emitMessage) {
|
|
7689
|
+
state.emitMessage(handoffMessage);
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7630
7692
|
static isEnabledEnvFlag(value) {
|
|
7631
7693
|
if (value === null || value === void 0) return false;
|
|
7632
7694
|
const normalized = value.trim().toLowerCase();
|
|
@@ -8524,7 +8586,16 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8524
8586
|
role: "system",
|
|
8525
8587
|
content: systemPromptText
|
|
8526
8588
|
});
|
|
8527
|
-
const
|
|
8589
|
+
const historySnapshot = state.messageHistory.filter(
|
|
8590
|
+
(msg) => msg.status !== "pending"
|
|
8591
|
+
);
|
|
8592
|
+
const filteredHistory = await this.runFilterMessagesHook(
|
|
8593
|
+
state.thread.instance,
|
|
8594
|
+
state,
|
|
8595
|
+
historySnapshot
|
|
8596
|
+
);
|
|
8597
|
+
const contextHistory = this.filterOrphanedToolCalls(filteredHistory);
|
|
8598
|
+
const completedMessages = contextHistory.filter(
|
|
8528
8599
|
(msg) => msg.status !== "pending"
|
|
8529
8600
|
);
|
|
8530
8601
|
const recentMessageThreshold = state.prompt.recentImageThreshold ?? 10;
|
|
@@ -8962,7 +9033,8 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
8962
9033
|
}
|
|
8963
9034
|
if (foundToolNames.has(toolName)) continue;
|
|
8964
9035
|
try {
|
|
8965
|
-
const
|
|
9036
|
+
const implementingAgent = subagentConfig && typeof subagentConfig.agent === "string" && subagentConfig.agent.trim().length > 0 ? subagentConfig.agent.trim() : toolName;
|
|
9037
|
+
const agentDef = await state.thread.instance.loadAgent(implementingAgent);
|
|
8966
9038
|
if (agentDef && (agentDef.type === "ai_human" || agentDef.type === "dual_ai")) {
|
|
8967
9039
|
let parameters;
|
|
8968
9040
|
const sideAPromptName = agentDef.sideA?.prompt;
|
|
@@ -9176,12 +9248,14 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9176
9248
|
if (!toolName || toolName.startsWith("provider:") || seen.has(toolName)) {
|
|
9177
9249
|
continue;
|
|
9178
9250
|
}
|
|
9179
|
-
const
|
|
9251
|
+
const subagentConfigForLoad = this.isSubagentToolConfig(configEntry) ? configEntry : void 0;
|
|
9252
|
+
const implementingAgent = subagentConfigForLoad && typeof subagentConfigForLoad.agent === "string" && subagentConfigForLoad.agent.trim().length > 0 ? subagentConfigForLoad.agent.trim() : toolName;
|
|
9253
|
+
const agentDef = await this.tryLoadPromptToolAgent(state, implementingAgent, packageId);
|
|
9180
9254
|
if (!agentDef || agentDef.type !== "dual_ai") {
|
|
9181
9255
|
continue;
|
|
9182
9256
|
}
|
|
9183
9257
|
seen.add(toolName);
|
|
9184
|
-
const subagentConfig =
|
|
9258
|
+
const subagentConfig = subagentConfigForLoad;
|
|
9185
9259
|
const blocking = subagentConfig?.blocking ?? true;
|
|
9186
9260
|
const resumable = !!subagentConfig?.resumable && typeof subagentConfig.resumable === "object";
|
|
9187
9261
|
const receivesMessages = subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.receives_messages : "side_a";
|
|
@@ -9659,11 +9733,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9659
9733
|
* @param message - Message object to be created
|
|
9660
9734
|
* @returns Processed message (or original if hook doesn't exist/fails)
|
|
9661
9735
|
*/
|
|
9662
|
-
static async runBeforeCreateMessageHook(state, message) {
|
|
9736
|
+
static async runBeforeCreateMessageHook(state, message, threadStateOverride, options) {
|
|
9663
9737
|
const executors = await this.getHooksForType(state, "before_create_message");
|
|
9664
9738
|
if (executors.length === 0) return message;
|
|
9665
9739
|
let result = message;
|
|
9666
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9740
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9667
9741
|
for (const executor of executors) {
|
|
9668
9742
|
try {
|
|
9669
9743
|
const hooked = await executor(threadState, _FlowEngine.rowToHookMessage(result));
|
|
@@ -9673,6 +9747,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9673
9747
|
attachments: hooked.attachments === void 0 ? result.attachments : hooked.attachments === null ? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments)
|
|
9674
9748
|
};
|
|
9675
9749
|
} catch (error) {
|
|
9750
|
+
if (options?.propagateHookErrors) {
|
|
9751
|
+
throw error;
|
|
9752
|
+
}
|
|
9676
9753
|
console.error("[Hooks] \u2717 Error running before_create_message hook:", error);
|
|
9677
9754
|
}
|
|
9678
9755
|
}
|
|
@@ -9685,10 +9762,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9685
9762
|
* @param state - Flow state with execution context
|
|
9686
9763
|
* @param message - The created message object
|
|
9687
9764
|
*/
|
|
9688
|
-
static async runAfterCreateMessageHook(state, message) {
|
|
9765
|
+
static async runAfterCreateMessageHook(state, message, threadStateOverride) {
|
|
9689
9766
|
const executors = await this.getHooksForType(state, "after_create_message");
|
|
9690
9767
|
if (executors.length === 0) return;
|
|
9691
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9768
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9692
9769
|
for (const executor of executors) {
|
|
9693
9770
|
try {
|
|
9694
9771
|
await executor(threadState, _FlowEngine.rowToHookMessage(message));
|
|
@@ -10189,7 +10266,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10189
10266
|
}
|
|
10190
10267
|
existingPathMessages.add(content);
|
|
10191
10268
|
const attachmentsJson = JSON.stringify([ref]);
|
|
10192
|
-
|
|
10269
|
+
let silentMessage = {
|
|
10193
10270
|
id: crypto.randomUUID(),
|
|
10194
10271
|
role: sourceMessage.role,
|
|
10195
10272
|
content,
|
|
@@ -10200,6 +10277,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10200
10277
|
parent_id: parentId,
|
|
10201
10278
|
depth
|
|
10202
10279
|
};
|
|
10280
|
+
silentMessage = await this.runBeforeCreateMessageHook(state, silentMessage);
|
|
10203
10281
|
await state.storage.sql.exec(
|
|
10204
10282
|
`
|
|
10205
10283
|
INSERT INTO messages (
|
|
@@ -10210,15 +10288,16 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10210
10288
|
silentMessage.id,
|
|
10211
10289
|
silentMessage.role,
|
|
10212
10290
|
silentMessage.content,
|
|
10213
|
-
|
|
10214
|
-
1,
|
|
10291
|
+
silentMessage.attachments ?? null,
|
|
10292
|
+
silentMessage.silent ? 1 : 0,
|
|
10215
10293
|
silentMessage.created_at,
|
|
10216
|
-
silentMessage.status,
|
|
10294
|
+
silentMessage.status ?? "completed",
|
|
10217
10295
|
silentMessage.parent_id,
|
|
10218
10296
|
silentMessage.depth,
|
|
10219
10297
|
currentPrompt
|
|
10220
10298
|
);
|
|
10221
10299
|
state.messageHistory.push(silentMessage);
|
|
10300
|
+
await this.runAfterCreateMessageHook(state, silentMessage);
|
|
10222
10301
|
if (state.emitMessage) {
|
|
10223
10302
|
state.emitMessage(silentMessage);
|
|
10224
10303
|
}
|
|
@@ -10757,7 +10836,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10757
10836
|
*/
|
|
10758
10837
|
static async loadMessageHistory(state) {
|
|
10759
10838
|
const storage = state.storage;
|
|
10760
|
-
|
|
10839
|
+
state.thread;
|
|
10761
10840
|
const includeParentHistory = state.prompt.include_chat ?? true;
|
|
10762
10841
|
const includeToolCalls = state.prompt.include_past_tools ?? true;
|
|
10763
10842
|
try {
|
|
@@ -10793,8 +10872,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10793
10872
|
rows = cursor.toArray();
|
|
10794
10873
|
}
|
|
10795
10874
|
if (state.extraMessages && state.extraMessages.length > 0) {
|
|
10796
|
-
rows.
|
|
10797
|
-
rows.
|
|
10875
|
+
const persistedIds = new Set(rows.map((row) => row.id));
|
|
10876
|
+
rows.push(
|
|
10877
|
+
...state.extraMessages.filter((entry) => !persistedIds.has(entry.id))
|
|
10878
|
+
);
|
|
10879
|
+
rows.sort((a, b) => a.created_at - b.created_at);
|
|
10798
10880
|
}
|
|
10799
10881
|
const messages = rows.map((row) => ({
|
|
10800
10882
|
id: row.id,
|
|
@@ -10817,24 +10899,15 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10817
10899
|
reasoning_content: row.reasoning_content,
|
|
10818
10900
|
reasoning_details: row.reasoning_details
|
|
10819
10901
|
}));
|
|
10820
|
-
return
|
|
10821
|
-
thread.instance,
|
|
10822
|
-
state,
|
|
10823
|
-
this.filterOrphanedToolCalls(messages)
|
|
10824
|
-
);
|
|
10902
|
+
return messages;
|
|
10825
10903
|
} catch (error) {
|
|
10826
10904
|
console.error("Error loading message history:", error);
|
|
10827
10905
|
return [];
|
|
10828
10906
|
}
|
|
10829
10907
|
}
|
|
10830
10908
|
/**
|
|
10831
|
-
*
|
|
10832
|
-
*
|
|
10833
|
-
*
|
|
10834
|
-
* @param thread - Thread instance with hooks registry
|
|
10835
|
-
* @param state - Flow state for hook context
|
|
10836
|
-
* @param rows - SQL rows from messages table
|
|
10837
|
-
* @returns Processed rows (or original if hook doesn't exist/fails)
|
|
10909
|
+
* Build request-context rows from persisted history.
|
|
10910
|
+
* Mutations and synthetic messages stay in the request context.
|
|
10838
10911
|
*/
|
|
10839
10912
|
static async runFilterMessagesHook(thread, state, messages) {
|
|
10840
10913
|
const executors = await this.getHooksForType(state, "filter_messages");
|
|
@@ -10847,13 +10920,56 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10847
10920
|
for (const row of result) if (row.id) byId.set(row.id, row);
|
|
10848
10921
|
const hookView = result.map((row) => _FlowEngine.rowToHookMessage(row));
|
|
10849
10922
|
const kept = await executor(threadState, hookView);
|
|
10850
|
-
result = kept.map((
|
|
10923
|
+
result = kept.map((hookedMessage) => {
|
|
10924
|
+
const original = hookedMessage.id ? byId.get(hookedMessage.id) : void 0;
|
|
10925
|
+
if (original) {
|
|
10926
|
+
return _FlowEngine.applyHookMessageToRow(original, hookedMessage);
|
|
10927
|
+
}
|
|
10928
|
+
return _FlowEngine.hookMessageToContextRow(hookedMessage);
|
|
10929
|
+
});
|
|
10851
10930
|
} catch (error) {
|
|
10852
10931
|
console.error("[Hooks] \u2717 Error running filter_messages hook:", error);
|
|
10853
10932
|
}
|
|
10854
10933
|
}
|
|
10855
10934
|
return result;
|
|
10856
10935
|
}
|
|
10936
|
+
/**
|
|
10937
|
+
* Copy a persisted row and apply hook edits. The original live-history
|
|
10938
|
+
* object is left unchanged.
|
|
10939
|
+
*/
|
|
10940
|
+
static applyHookMessageToRow(original, hooked) {
|
|
10941
|
+
const attachments = hooked.attachments === void 0 ? original.attachments : hooked.attachments === null ? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments);
|
|
10942
|
+
return {
|
|
10943
|
+
...original,
|
|
10944
|
+
role: hooked.role ?? original.role,
|
|
10945
|
+
content: hooked.content !== void 0 ? hooked.content : original.content,
|
|
10946
|
+
name: hooked.name !== void 0 ? hooked.name : original.name,
|
|
10947
|
+
tool_calls: hooked.tool_calls !== void 0 ? hooked.tool_calls : original.tool_calls,
|
|
10948
|
+
tool_call_id: hooked.tool_call_id !== void 0 ? hooked.tool_call_id : original.tool_call_id,
|
|
10949
|
+
silent: hooked.silent !== void 0 ? hooked.silent : original.silent,
|
|
10950
|
+
attachments
|
|
10951
|
+
};
|
|
10952
|
+
}
|
|
10953
|
+
/**
|
|
10954
|
+
* Convert a synthetic hook message into a request-context-only builder row.
|
|
10955
|
+
*/
|
|
10956
|
+
static hookMessageToContextRow(hooked) {
|
|
10957
|
+
const attachments = hooked.attachments === void 0 || hooked.attachments === null ? hooked.attachments ?? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments);
|
|
10958
|
+
return {
|
|
10959
|
+
id: hooked.id || crypto.randomUUID(),
|
|
10960
|
+
role: hooked.role,
|
|
10961
|
+
content: hooked.content ?? null,
|
|
10962
|
+
name: hooked.name ?? null,
|
|
10963
|
+
tool_calls: typeof hooked.tool_calls === "string" ? hooked.tool_calls : null,
|
|
10964
|
+
tool_call_id: hooked.tool_call_id ?? null,
|
|
10965
|
+
created_at: hooked.created_at ?? Date.now() * TIMESTAMP_MULTIPLIER,
|
|
10966
|
+
parent_id: hooked.parent_id ?? null,
|
|
10967
|
+
depth: hooked.depth ?? 0,
|
|
10968
|
+
silent: hooked.silent ?? false,
|
|
10969
|
+
status: "completed",
|
|
10970
|
+
attachments
|
|
10971
|
+
};
|
|
10972
|
+
}
|
|
10857
10973
|
/**
|
|
10858
10974
|
* Log an error to the logs table (best-effort)
|
|
10859
10975
|
* Creates a log entry with error details but no associated message_id
|
|
@@ -10997,6 +11113,35 @@ ${errorStack}` : ""}`;
|
|
|
10997
11113
|
});
|
|
10998
11114
|
|
|
10999
11115
|
// src/agents/utilities.ts
|
|
11116
|
+
var utilities_exports = {};
|
|
11117
|
+
__export(utilities_exports, {
|
|
11118
|
+
cat: () => cat,
|
|
11119
|
+
emitThreadEvent: () => emitThreadEvent,
|
|
11120
|
+
exists: () => exists,
|
|
11121
|
+
find: () => find,
|
|
11122
|
+
forceTurn: () => forceTurn,
|
|
11123
|
+
getFileStats: () => getFileStats,
|
|
11124
|
+
getMessages: () => getMessages,
|
|
11125
|
+
getThumbnail: () => getThumbnail,
|
|
11126
|
+
grep: () => grep,
|
|
11127
|
+
head: () => head,
|
|
11128
|
+
injectMessage: () => injectMessage,
|
|
11129
|
+
linkFile: () => linkFile,
|
|
11130
|
+
mkdir: () => mkdir,
|
|
11131
|
+
move: () => move,
|
|
11132
|
+
queueTool: () => queueTool,
|
|
11133
|
+
readFile: () => readFile,
|
|
11134
|
+
readdir: () => readdir,
|
|
11135
|
+
reloadHistory: () => reloadHistory,
|
|
11136
|
+
rename: () => rename,
|
|
11137
|
+
rmdir: () => rmdir,
|
|
11138
|
+
stat: () => stat,
|
|
11139
|
+
tail: () => tail,
|
|
11140
|
+
unlink: () => unlink,
|
|
11141
|
+
updateThread: () => updateThread,
|
|
11142
|
+
writeFile: () => writeFile,
|
|
11143
|
+
writeImage: () => writeImage
|
|
11144
|
+
});
|
|
11000
11145
|
function queueTool(flow, toolName, args = {}) {
|
|
11001
11146
|
if (flow.currentToolUses !== void 0) {
|
|
11002
11147
|
if (!flow.currentToolUses.includes(toolName)) {
|
|
@@ -11024,7 +11169,7 @@ async function injectMessage(flow, options) {
|
|
|
11024
11169
|
const timestamp = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
11025
11170
|
const silent = options.silent ?? false;
|
|
11026
11171
|
const forceTopLevel = options.forceTopLevel ?? false;
|
|
11027
|
-
|
|
11172
|
+
let message = {
|
|
11028
11173
|
id: messageId,
|
|
11029
11174
|
role: options.role,
|
|
11030
11175
|
content: options.content,
|
|
@@ -11038,41 +11183,52 @@ async function injectMessage(flow, options) {
|
|
|
11038
11183
|
metadata: options.metadata
|
|
11039
11184
|
};
|
|
11040
11185
|
if (options.beforeMessageId) {
|
|
11041
|
-
const
|
|
11042
|
-
|
|
11043
|
-
options.beforeMessageId
|
|
11186
|
+
const liveTarget = flow.messageHistory.find(
|
|
11187
|
+
(entry) => entry.id === options.beforeMessageId
|
|
11044
11188
|
);
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11189
|
+
let targetCreatedAt = liveTarget?.created_at;
|
|
11190
|
+
if (targetCreatedAt === void 0) {
|
|
11191
|
+
const cursor = await flow.storage.sql.exec(
|
|
11192
|
+
`SELECT created_at FROM messages WHERE id = ?`,
|
|
11193
|
+
options.beforeMessageId
|
|
11050
11194
|
);
|
|
11195
|
+
const rows = cursor.toArray();
|
|
11196
|
+
const targetMessage = rows[0];
|
|
11197
|
+
if (!targetMessage) {
|
|
11198
|
+
throw new Error(
|
|
11199
|
+
`Message with id ${options.beforeMessageId} not found`
|
|
11200
|
+
);
|
|
11201
|
+
}
|
|
11202
|
+
targetCreatedAt = targetMessage.created_at;
|
|
11051
11203
|
}
|
|
11052
|
-
message.created_at =
|
|
11204
|
+
message.created_at = targetCreatedAt - 1;
|
|
11053
11205
|
}
|
|
11054
11206
|
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
11055
|
-
const
|
|
11207
|
+
const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
|
|
11208
|
+
message = await FlowEngine2.runBeforeCreateMessageHook(flow, message, void 0, {
|
|
11209
|
+
propagateHookErrors: true
|
|
11210
|
+
});
|
|
11211
|
+
const metadataJson = message.metadata === void 0 ? null : JSON.stringify(message.metadata);
|
|
11056
11212
|
await flow.storage.sql.exec(
|
|
11057
11213
|
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, metadata, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11058
|
-
|
|
11214
|
+
message.id,
|
|
11059
11215
|
message.role,
|
|
11060
11216
|
message.content,
|
|
11061
11217
|
message.name,
|
|
11062
11218
|
message.tool_call_id,
|
|
11063
11219
|
message.created_at,
|
|
11064
11220
|
message.status,
|
|
11065
|
-
silent ? 1 : 0,
|
|
11221
|
+
message.silent ? 1 : 0,
|
|
11066
11222
|
message.parent_id,
|
|
11067
11223
|
message.depth,
|
|
11068
11224
|
metadataJson,
|
|
11069
11225
|
currentPrompt
|
|
11070
11226
|
);
|
|
11071
|
-
|
|
11072
|
-
|
|
11073
|
-
|
|
11074
|
-
flow.messageHistory = await reloadHistory(flow);
|
|
11227
|
+
appendLiveExecutionHistory(flow, message, options.beforeMessageId);
|
|
11228
|
+
if (flow.prompt.include_chat === false || message.parent_id !== null || (message.depth ?? 0) > 0) {
|
|
11229
|
+
appendInjectedContextMessage(flow.extraMessages, message);
|
|
11075
11230
|
}
|
|
11231
|
+
await FlowEngine2.runAfterCreateMessageHook(flow, message);
|
|
11076
11232
|
if (flow.emitMessage) {
|
|
11077
11233
|
flow.emitMessage(message);
|
|
11078
11234
|
}
|
|
@@ -11081,6 +11237,42 @@ async function injectMessage(flow, options) {
|
|
|
11081
11237
|
}
|
|
11082
11238
|
return message;
|
|
11083
11239
|
}
|
|
11240
|
+
function appendLiveExecutionHistory(flow, message, beforeMessageId) {
|
|
11241
|
+
const history = flow.messageHistory;
|
|
11242
|
+
const existing = history.findIndex((entry) => entry.id === message.id);
|
|
11243
|
+
if (existing >= 0) {
|
|
11244
|
+
history.splice(existing, 1);
|
|
11245
|
+
}
|
|
11246
|
+
if (beforeMessageId) {
|
|
11247
|
+
const targetIndex = history.findIndex((entry) => entry.id === beforeMessageId);
|
|
11248
|
+
if (targetIndex >= 0) {
|
|
11249
|
+
history.splice(targetIndex, 0, message);
|
|
11250
|
+
return;
|
|
11251
|
+
}
|
|
11252
|
+
}
|
|
11253
|
+
const insertAt = history.findIndex(
|
|
11254
|
+
(entry) => entry.created_at > message.created_at
|
|
11255
|
+
);
|
|
11256
|
+
if (insertAt === -1) {
|
|
11257
|
+
history.push(message);
|
|
11258
|
+
return;
|
|
11259
|
+
}
|
|
11260
|
+
history.splice(insertAt, 0, message);
|
|
11261
|
+
}
|
|
11262
|
+
function appendInjectedContextMessage(extraMessages, message) {
|
|
11263
|
+
const existing = extraMessages.findIndex((entry) => entry.id === message.id);
|
|
11264
|
+
if (existing >= 0) {
|
|
11265
|
+
extraMessages.splice(existing, 1);
|
|
11266
|
+
}
|
|
11267
|
+
const insertAt = extraMessages.findIndex(
|
|
11268
|
+
(entry) => entry.created_at > message.created_at
|
|
11269
|
+
);
|
|
11270
|
+
if (insertAt === -1) {
|
|
11271
|
+
extraMessages.push(message);
|
|
11272
|
+
return;
|
|
11273
|
+
}
|
|
11274
|
+
extraMessages.splice(insertAt, 0, message);
|
|
11275
|
+
}
|
|
11084
11276
|
async function getMessages(flow, limit = 100, offset = 0, order = "asc") {
|
|
11085
11277
|
const orderClause = order === "desc" ? "DESC" : "ASC";
|
|
11086
11278
|
const cursor = await flow.storage.sql.exec(
|
|
@@ -21508,6 +21700,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
21508
21700
|
// src/durable-objects/DurableThread.ts
|
|
21509
21701
|
init_StreamManager();
|
|
21510
21702
|
init_LLMRequest();
|
|
21703
|
+
init_ThreadStateImpl();
|
|
21511
21704
|
|
|
21512
21705
|
// src/durable-objects/logDetailStream.ts
|
|
21513
21706
|
var LOG_DETAIL_HEAVY_FIELDS = [
|
|
@@ -22210,7 +22403,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22210
22403
|
side_b_session_fail_attachments_property: sideBSession.fail.attachmentsProperty,
|
|
22211
22404
|
side_b_session_status_tool: sideBSession.status.toolName,
|
|
22212
22405
|
side_b_session_status_message_property: sideBSession.status.messageProperty,
|
|
22213
|
-
side_b_session_status_attachments_property: sideBSession.status.attachmentsProperty
|
|
22406
|
+
side_b_session_status_attachments_property: sideBSession.status.attachmentsProperty,
|
|
22407
|
+
hooks: Array.isArray(agentDef.hooks) ? agentDef.hooks : void 0
|
|
22214
22408
|
};
|
|
22215
22409
|
}
|
|
22216
22410
|
/**
|
|
@@ -22880,6 +23074,29 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22880
23074
|
}
|
|
22881
23075
|
return projections;
|
|
22882
23076
|
}
|
|
23077
|
+
/**
|
|
23078
|
+
* Build hook resolution context and a genuine at-rest ThreadState.
|
|
23079
|
+
* Resolution failures abort insertion so lifecycle hooks cannot be bypassed.
|
|
23080
|
+
*/
|
|
23081
|
+
async buildAtRestHookState(threadId) {
|
|
23082
|
+
try {
|
|
23083
|
+
const metadata = await this.getThreadMetadata(threadId);
|
|
23084
|
+
const agentConfig = await this.loadAgentConfig(metadata.agent_id);
|
|
23085
|
+
const threadInstance = this;
|
|
23086
|
+
return {
|
|
23087
|
+
hookState: {
|
|
23088
|
+
agentConfig,
|
|
23089
|
+
thread: { instance: threadInstance, metadata }
|
|
23090
|
+
},
|
|
23091
|
+
threadState: ThreadStateImpl.fromThreadInstance(threadInstance, metadata)
|
|
23092
|
+
};
|
|
23093
|
+
} catch (error) {
|
|
23094
|
+
throw new Error(
|
|
23095
|
+
`Unable to resolve create-message hooks for ${threadId}`,
|
|
23096
|
+
{ cause: error }
|
|
23097
|
+
);
|
|
23098
|
+
}
|
|
23099
|
+
}
|
|
22883
23100
|
/**
|
|
22884
23101
|
* Inject a top-level message without starting a new execution.
|
|
22885
23102
|
*
|
|
@@ -22892,22 +23109,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22892
23109
|
const id = crypto.randomUUID();
|
|
22893
23110
|
const createdAt = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
22894
23111
|
const silent = message.silent === true;
|
|
22895
|
-
|
|
22896
|
-
await this.ctx.storage.sql.exec(
|
|
22897
|
-
`INSERT INTO messages (id, role, content, created_at, status, silent, parent_id, depth, metadata, prompt)
|
|
22898
|
-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
|
|
22899
|
-
id,
|
|
22900
|
-
message.role,
|
|
22901
|
-
message.content,
|
|
22902
|
-
createdAt,
|
|
22903
|
-
"completed",
|
|
22904
|
-
silent ? 1 : 0,
|
|
22905
|
-
null,
|
|
22906
|
-
0,
|
|
22907
|
-
metadataJson,
|
|
22908
|
-
null
|
|
22909
|
-
);
|
|
22910
|
-
const inserted = {
|
|
23112
|
+
let inserted = {
|
|
22911
23113
|
id,
|
|
22912
23114
|
role: message.role,
|
|
22913
23115
|
content: message.content,
|
|
@@ -22918,9 +23120,37 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22918
23120
|
depth: 0,
|
|
22919
23121
|
metadata: message.metadata
|
|
22920
23122
|
};
|
|
23123
|
+
const { hookState, threadState } = await this.buildAtRestHookState(threadId);
|
|
23124
|
+
const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
|
|
23125
|
+
inserted = await FlowEngine2.runBeforeCreateMessageHook(
|
|
23126
|
+
hookState,
|
|
23127
|
+
inserted,
|
|
23128
|
+
threadState,
|
|
23129
|
+
{ propagateHookErrors: true }
|
|
23130
|
+
);
|
|
23131
|
+
const metadataJson = inserted.metadata ? JSON.stringify(inserted.metadata) : null;
|
|
23132
|
+
await this.ctx.storage.sql.exec(
|
|
23133
|
+
`INSERT INTO messages (id, role, content, created_at, status, silent, parent_id, depth, metadata, prompt)
|
|
23134
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
|
|
23135
|
+
inserted.id,
|
|
23136
|
+
inserted.role,
|
|
23137
|
+
inserted.content,
|
|
23138
|
+
inserted.created_at,
|
|
23139
|
+
inserted.status ?? "completed",
|
|
23140
|
+
inserted.silent ? 1 : 0,
|
|
23141
|
+
inserted.parent_id ?? null,
|
|
23142
|
+
inserted.depth ?? 0,
|
|
23143
|
+
metadataJson,
|
|
23144
|
+
null
|
|
23145
|
+
);
|
|
23146
|
+
await FlowEngine2.runAfterCreateMessageHook(
|
|
23147
|
+
hookState,
|
|
23148
|
+
inserted,
|
|
23149
|
+
threadState
|
|
23150
|
+
);
|
|
22921
23151
|
this.broadcastMessage(inserted);
|
|
22922
23152
|
const record = inserted;
|
|
22923
|
-
const visibleUserInjection =
|
|
23153
|
+
const visibleUserInjection = inserted.role === "user" && !inserted.silent && typeof inserted.content === "string" && inserted.content.trim().length > 0 && !isRuntimeSubagentEnvelope(inserted.content);
|
|
22924
23154
|
if (visibleUserInjection || isVisibleTerminalAssistantMessage(record)) {
|
|
22925
23155
|
const stamp = this.recordRegistryActivity(
|
|
22926
23156
|
threadId,
|
|
@@ -29415,8 +29645,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
29415
29645
|
init_utilities();
|
|
29416
29646
|
|
|
29417
29647
|
// src/agents/FlowStateSdk.ts
|
|
29418
|
-
|
|
29419
|
-
var FlowStateSdk = class _FlowStateSdk {
|
|
29648
|
+
var FlowStateSdk = class {
|
|
29420
29649
|
/**
|
|
29421
29650
|
* Queue a new tool call to be executed in the current flow
|
|
29422
29651
|
*
|
|
@@ -29483,63 +29712,8 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
29483
29712
|
* ```
|
|
29484
29713
|
*/
|
|
29485
29714
|
static async injectMessage(flow, options) {
|
|
29486
|
-
const
|
|
29487
|
-
|
|
29488
|
-
const silent = options.silent ?? false;
|
|
29489
|
-
const forceTopLevel = options.forceTopLevel ?? false;
|
|
29490
|
-
const message = {
|
|
29491
|
-
id: messageId,
|
|
29492
|
-
role: options.role,
|
|
29493
|
-
content: options.content,
|
|
29494
|
-
name: options.name ?? null,
|
|
29495
|
-
tool_call_id: options.toolCallId ?? null,
|
|
29496
|
-
created_at: timestamp,
|
|
29497
|
-
status: "completed",
|
|
29498
|
-
silent,
|
|
29499
|
-
parent_id: forceTopLevel ? null : flow.parentMessageId ?? null,
|
|
29500
|
-
depth: forceTopLevel ? 0 : flow.depth
|
|
29501
|
-
};
|
|
29502
|
-
if (options.beforeMessageId) {
|
|
29503
|
-
const cursor = await flow.storage.sql.exec(
|
|
29504
|
-
`SELECT created_at FROM messages WHERE id = ?`,
|
|
29505
|
-
options.beforeMessageId
|
|
29506
|
-
);
|
|
29507
|
-
const rows = cursor.toArray();
|
|
29508
|
-
const targetMessage = rows[0];
|
|
29509
|
-
if (!targetMessage) {
|
|
29510
|
-
throw new Error(
|
|
29511
|
-
`Message with id ${options.beforeMessageId} not found`
|
|
29512
|
-
);
|
|
29513
|
-
}
|
|
29514
|
-
message.created_at = targetMessage.created_at - 1;
|
|
29515
|
-
}
|
|
29516
|
-
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
29517
|
-
await flow.storage.sql.exec(
|
|
29518
|
-
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
29519
|
-
messageId,
|
|
29520
|
-
message.role,
|
|
29521
|
-
message.content,
|
|
29522
|
-
message.name,
|
|
29523
|
-
message.tool_call_id,
|
|
29524
|
-
message.created_at,
|
|
29525
|
-
message.status,
|
|
29526
|
-
silent ? 1 : 0,
|
|
29527
|
-
message.parent_id,
|
|
29528
|
-
message.depth,
|
|
29529
|
-
currentPrompt
|
|
29530
|
-
);
|
|
29531
|
-
if (!silent) {
|
|
29532
|
-
flow.messageHistory.push(message);
|
|
29533
|
-
} else {
|
|
29534
|
-
flow.messageHistory = await _FlowStateSdk.reloadHistory(flow);
|
|
29535
|
-
}
|
|
29536
|
-
if (flow.emitMessage) {
|
|
29537
|
-
flow.emitMessage(message);
|
|
29538
|
-
}
|
|
29539
|
-
if (options.forceTurn) {
|
|
29540
|
-
_FlowStateSdk.forceTurn(flow, options.forceTurn);
|
|
29541
|
-
}
|
|
29542
|
-
return message;
|
|
29715
|
+
const { injectMessage: injectMessage2 } = await Promise.resolve().then(() => (init_utilities(), utilities_exports));
|
|
29716
|
+
return injectMessage2(flow, options);
|
|
29543
29717
|
}
|
|
29544
29718
|
/**
|
|
29545
29719
|
* Get messages from the thread history
|
|
@@ -29628,9 +29802,9 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
29628
29802
|
/**
|
|
29629
29803
|
* Reload message history from storage
|
|
29630
29804
|
*
|
|
29631
|
-
* Re-loads the complete message history from the thread's SQLite storage
|
|
29632
|
-
*
|
|
29633
|
-
*
|
|
29805
|
+
* Re-loads the complete message history from the thread's SQLite storage.
|
|
29806
|
+
* This is useful when you need to refresh the message history after making
|
|
29807
|
+
* changes (e.g., injecting messages).
|
|
29634
29808
|
*
|
|
29635
29809
|
* @param flow - The current FlowState
|
|
29636
29810
|
* @returns Array of messages (reloaded from storage)
|