@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/index.js
CHANGED
|
@@ -1498,6 +1498,9 @@ function normalizeToolCallMessageSequence(messages) {
|
|
|
1498
1498
|
for (const message of messages) {
|
|
1499
1499
|
const isAssistantToolCallMessage = message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0;
|
|
1500
1500
|
if (!pending) {
|
|
1501
|
+
if (message.role === "tool") {
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1501
1504
|
if (!isAssistantToolCallMessage) {
|
|
1502
1505
|
normalized.push(message);
|
|
1503
1506
|
continue;
|
|
@@ -4283,6 +4286,24 @@ var init_ToolExecutor = __esm({
|
|
|
4283
4286
|
}
|
|
4284
4287
|
} catch {
|
|
4285
4288
|
}
|
|
4289
|
+
const aliasTarget = this.subagentAliasTarget(state, toolName);
|
|
4290
|
+
if (aliasTarget) {
|
|
4291
|
+
if (packageId) {
|
|
4292
|
+
try {
|
|
4293
|
+
const qualified = aliasTarget.includes("/") ? aliasTarget : `${packageId}/${aliasTarget}`;
|
|
4294
|
+
if (await state.thread.instance.loadAgent(qualified)) {
|
|
4295
|
+
return "agent";
|
|
4296
|
+
}
|
|
4297
|
+
} catch {
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
try {
|
|
4301
|
+
if (await state.thread.instance.loadAgent(aliasTarget)) {
|
|
4302
|
+
return "agent";
|
|
4303
|
+
}
|
|
4304
|
+
} catch {
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4286
4307
|
const isInToolsArray = (agentName) => {
|
|
4287
4308
|
const tools2 = state.prompt._tools || [];
|
|
4288
4309
|
return tools2.some((t) => typeof t === "string" ? t === agentName : t.name === agentName);
|
|
@@ -4798,15 +4819,20 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4798
4819
|
const builtinCreateAttachmentValue = createArgs?.attachments;
|
|
4799
4820
|
const builtinCreateInitialArguments = createArgs?.initialArguments ?? {};
|
|
4800
4821
|
const registryAgentName = targetAgentForCreate || call.function.name;
|
|
4822
|
+
const aliasConfig = this.resolveSubagentToolConfig(state, registryAgentName);
|
|
4823
|
+
const implementingAgentName = typeof aliasConfig.agent === "string" && aliasConfig.agent.trim().length > 0 ? aliasConfig.agent.trim() : registryAgentName;
|
|
4801
4824
|
const packageId = getPackageId(state);
|
|
4802
4825
|
let agentDef = null;
|
|
4803
|
-
let agentName =
|
|
4826
|
+
let agentName = implementingAgentName;
|
|
4804
4827
|
if (builtinSubagentAction === "create" && targetAgentForCreate) {
|
|
4805
4828
|
const availableSubagents = await this.getPromptSubagentNames(state);
|
|
4806
4829
|
if (!availableSubagents.includes(targetAgentForCreate)) {
|
|
4830
|
+
const configuredDirect = (state.prompt._tools || []).some(
|
|
4831
|
+
(t) => typeof t === "string" ? t === targetAgentForCreate : t?.name === targetAgentForCreate
|
|
4832
|
+
);
|
|
4807
4833
|
return {
|
|
4808
4834
|
status: "error",
|
|
4809
|
-
error: `Subagent "${targetAgentForCreate}" is not available for this prompt. Use one of: ${availableSubagents.join(", ") || "(none)"}.`
|
|
4835
|
+
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)"}.`
|
|
4810
4836
|
};
|
|
4811
4837
|
}
|
|
4812
4838
|
}
|
|
@@ -4847,7 +4873,7 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4847
4873
|
if (agentType === "ai_human") {
|
|
4848
4874
|
const parentToolConfigs = state.prompt._tools || [];
|
|
4849
4875
|
const toolConfig = parentToolConfigs.find(
|
|
4850
|
-
(t) => typeof t === "string" ? t === agentName : t.name === agentName
|
|
4876
|
+
(t) => typeof t === "string" ? t === registryAgentName || t === agentName : t.name === registryAgentName || t.name === agentName
|
|
4851
4877
|
);
|
|
4852
4878
|
const subpromptToolConfig = this.getSubpromptToolConfig(toolConfig);
|
|
4853
4879
|
const targetState = state.rootState || state;
|
|
@@ -5425,6 +5451,27 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5425
5451
|
}
|
|
5426
5452
|
return null;
|
|
5427
5453
|
}
|
|
5454
|
+
/**
|
|
5455
|
+
* The implementing agent behind an aliased subagent tool name, or null when
|
|
5456
|
+
* the name carries no alias (`agent` absent, empty, or equal to the name).
|
|
5457
|
+
*/
|
|
5458
|
+
static subagentAliasTarget(state, toolName) {
|
|
5459
|
+
for (const tool of state.prompt._tools || []) {
|
|
5460
|
+
if (!tool || typeof tool !== "object" || tool.name !== toolName) {
|
|
5461
|
+
continue;
|
|
5462
|
+
}
|
|
5463
|
+
const target = tool.agent;
|
|
5464
|
+
if (typeof target === "string" && target.trim().length > 0 && target.trim() !== toolName) {
|
|
5465
|
+
return target.trim();
|
|
5466
|
+
}
|
|
5467
|
+
}
|
|
5468
|
+
return null;
|
|
5469
|
+
}
|
|
5470
|
+
/**
|
|
5471
|
+
* Resolve the prompt's subagent tool config for an EXPOSED tool name.
|
|
5472
|
+
* Config entries are keyed by `name` (the model-facing tool name), which
|
|
5473
|
+
* may alias a differently-named implementing agent via `agent`.
|
|
5474
|
+
*/
|
|
5428
5475
|
static resolveSubagentToolConfig(state, agentName) {
|
|
5429
5476
|
const config = (state.prompt._tools || []).find(
|
|
5430
5477
|
(tool) => typeof tool === "string" ? tool === agentName : tool.name === agentName
|
|
@@ -7600,28 +7647,12 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7600
7647
|
state.promptPath = [sideAPrompt.name];
|
|
7601
7648
|
state.pendingImmediateAfterHandoff = true;
|
|
7602
7649
|
if (userMessageContent || userMessageAttachments) {
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
role: "user",
|
|
7608
|
-
content: userMessageContent || "",
|
|
7609
|
-
created_at: handoffTimestamp,
|
|
7610
|
-
attachments: userMessageAttachments
|
|
7611
|
-
};
|
|
7612
|
-
await state.storage.sql.exec(
|
|
7613
|
-
`INSERT INTO messages (id, role, content, attachments, created_at, prompt) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
7614
|
-
handoffMessage.id,
|
|
7615
|
-
handoffMessage.role,
|
|
7616
|
-
handoffMessage.content,
|
|
7617
|
-
handoffMessage.attachments || null,
|
|
7618
|
-
handoffMessage.created_at,
|
|
7650
|
+
await this.persistHandoffUserMessage(
|
|
7651
|
+
state,
|
|
7652
|
+
userMessageContent || "",
|
|
7653
|
+
userMessageAttachments,
|
|
7619
7654
|
sideAPrompt.name
|
|
7620
7655
|
);
|
|
7621
|
-
state.messageHistory.push(handoffMessage);
|
|
7622
|
-
if (state.emitMessage) {
|
|
7623
|
-
state.emitMessage(handoffMessage);
|
|
7624
|
-
}
|
|
7625
7656
|
}
|
|
7626
7657
|
state.pendingHandoff = void 0;
|
|
7627
7658
|
state.emitTelemetry?.({
|
|
@@ -7636,6 +7667,37 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7636
7667
|
throw error;
|
|
7637
7668
|
}
|
|
7638
7669
|
}
|
|
7670
|
+
/**
|
|
7671
|
+
* Persist the user message that rides an agent handoff, applying the
|
|
7672
|
+
* create-message lifecycle hooks like every other insertion path.
|
|
7673
|
+
*/
|
|
7674
|
+
static async persistHandoffUserMessage(state, content, attachments, promptName) {
|
|
7675
|
+
let handoffMessage = {
|
|
7676
|
+
id: crypto.randomUUID(),
|
|
7677
|
+
role: "user",
|
|
7678
|
+
content,
|
|
7679
|
+
created_at: Date.now() * 1e3,
|
|
7680
|
+
status: "completed",
|
|
7681
|
+
attachments: attachments ?? null
|
|
7682
|
+
};
|
|
7683
|
+
handoffMessage = await this.runBeforeCreateMessageHook(state, handoffMessage);
|
|
7684
|
+
await state.storage.sql.exec(
|
|
7685
|
+
`INSERT INTO messages (id, role, content, attachments, created_at, status, silent, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
7686
|
+
handoffMessage.id,
|
|
7687
|
+
handoffMessage.role,
|
|
7688
|
+
handoffMessage.content,
|
|
7689
|
+
handoffMessage.attachments || null,
|
|
7690
|
+
handoffMessage.created_at,
|
|
7691
|
+
handoffMessage.status ?? "completed",
|
|
7692
|
+
handoffMessage.silent ? 1 : 0,
|
|
7693
|
+
promptName
|
|
7694
|
+
);
|
|
7695
|
+
state.messageHistory.push(handoffMessage);
|
|
7696
|
+
await this.runAfterCreateMessageHook(state, handoffMessage);
|
|
7697
|
+
if (state.emitMessage) {
|
|
7698
|
+
state.emitMessage(handoffMessage);
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7639
7701
|
static isEnabledEnvFlag(value) {
|
|
7640
7702
|
if (value === null || value === void 0) return false;
|
|
7641
7703
|
const normalized = value.trim().toLowerCase();
|
|
@@ -8533,7 +8595,16 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8533
8595
|
role: "system",
|
|
8534
8596
|
content: systemPromptText
|
|
8535
8597
|
});
|
|
8536
|
-
const
|
|
8598
|
+
const historySnapshot = state.messageHistory.filter(
|
|
8599
|
+
(msg) => msg.status !== "pending"
|
|
8600
|
+
);
|
|
8601
|
+
const filteredHistory = await this.runFilterMessagesHook(
|
|
8602
|
+
state.thread.instance,
|
|
8603
|
+
state,
|
|
8604
|
+
historySnapshot
|
|
8605
|
+
);
|
|
8606
|
+
const contextHistory = this.filterOrphanedToolCalls(filteredHistory);
|
|
8607
|
+
const completedMessages = contextHistory.filter(
|
|
8537
8608
|
(msg) => msg.status !== "pending"
|
|
8538
8609
|
);
|
|
8539
8610
|
const recentMessageThreshold = state.prompt.recentImageThreshold ?? 10;
|
|
@@ -8971,7 +9042,8 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
8971
9042
|
}
|
|
8972
9043
|
if (foundToolNames.has(toolName)) continue;
|
|
8973
9044
|
try {
|
|
8974
|
-
const
|
|
9045
|
+
const implementingAgent = subagentConfig && typeof subagentConfig.agent === "string" && subagentConfig.agent.trim().length > 0 ? subagentConfig.agent.trim() : toolName;
|
|
9046
|
+
const agentDef = await state.thread.instance.loadAgent(implementingAgent);
|
|
8975
9047
|
if (agentDef && (agentDef.type === "ai_human" || agentDef.type === "dual_ai")) {
|
|
8976
9048
|
let parameters;
|
|
8977
9049
|
const sideAPromptName = agentDef.sideA?.prompt;
|
|
@@ -9185,12 +9257,14 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9185
9257
|
if (!toolName || toolName.startsWith("provider:") || seen.has(toolName)) {
|
|
9186
9258
|
continue;
|
|
9187
9259
|
}
|
|
9188
|
-
const
|
|
9260
|
+
const subagentConfigForLoad = this.isSubagentToolConfig(configEntry) ? configEntry : void 0;
|
|
9261
|
+
const implementingAgent = subagentConfigForLoad && typeof subagentConfigForLoad.agent === "string" && subagentConfigForLoad.agent.trim().length > 0 ? subagentConfigForLoad.agent.trim() : toolName;
|
|
9262
|
+
const agentDef = await this.tryLoadPromptToolAgent(state, implementingAgent, packageId);
|
|
9189
9263
|
if (!agentDef || agentDef.type !== "dual_ai") {
|
|
9190
9264
|
continue;
|
|
9191
9265
|
}
|
|
9192
9266
|
seen.add(toolName);
|
|
9193
|
-
const subagentConfig =
|
|
9267
|
+
const subagentConfig = subagentConfigForLoad;
|
|
9194
9268
|
const blocking = subagentConfig?.blocking ?? true;
|
|
9195
9269
|
const resumable = !!subagentConfig?.resumable && typeof subagentConfig.resumable === "object";
|
|
9196
9270
|
const receivesMessages = subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.receives_messages : "side_a";
|
|
@@ -9668,11 +9742,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9668
9742
|
* @param message - Message object to be created
|
|
9669
9743
|
* @returns Processed message (or original if hook doesn't exist/fails)
|
|
9670
9744
|
*/
|
|
9671
|
-
static async runBeforeCreateMessageHook(state, message) {
|
|
9745
|
+
static async runBeforeCreateMessageHook(state, message, threadStateOverride, options) {
|
|
9672
9746
|
const executors = await this.getHooksForType(state, "before_create_message");
|
|
9673
9747
|
if (executors.length === 0) return message;
|
|
9674
9748
|
let result = message;
|
|
9675
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9749
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9676
9750
|
for (const executor of executors) {
|
|
9677
9751
|
try {
|
|
9678
9752
|
const hooked = await executor(threadState, _FlowEngine.rowToHookMessage(result));
|
|
@@ -9682,6 +9756,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9682
9756
|
attachments: hooked.attachments === void 0 ? result.attachments : hooked.attachments === null ? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments)
|
|
9683
9757
|
};
|
|
9684
9758
|
} catch (error) {
|
|
9759
|
+
if (options?.propagateHookErrors) {
|
|
9760
|
+
throw error;
|
|
9761
|
+
}
|
|
9685
9762
|
console.error("[Hooks] \u2717 Error running before_create_message hook:", error);
|
|
9686
9763
|
}
|
|
9687
9764
|
}
|
|
@@ -9694,10 +9771,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9694
9771
|
* @param state - Flow state with execution context
|
|
9695
9772
|
* @param message - The created message object
|
|
9696
9773
|
*/
|
|
9697
|
-
static async runAfterCreateMessageHook(state, message) {
|
|
9774
|
+
static async runAfterCreateMessageHook(state, message, threadStateOverride) {
|
|
9698
9775
|
const executors = await this.getHooksForType(state, "after_create_message");
|
|
9699
9776
|
if (executors.length === 0) return;
|
|
9700
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9777
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9701
9778
|
for (const executor of executors) {
|
|
9702
9779
|
try {
|
|
9703
9780
|
await executor(threadState, _FlowEngine.rowToHookMessage(message));
|
|
@@ -10198,7 +10275,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10198
10275
|
}
|
|
10199
10276
|
existingPathMessages.add(content);
|
|
10200
10277
|
const attachmentsJson = JSON.stringify([ref]);
|
|
10201
|
-
|
|
10278
|
+
let silentMessage = {
|
|
10202
10279
|
id: crypto.randomUUID(),
|
|
10203
10280
|
role: sourceMessage.role,
|
|
10204
10281
|
content,
|
|
@@ -10209,6 +10286,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10209
10286
|
parent_id: parentId,
|
|
10210
10287
|
depth
|
|
10211
10288
|
};
|
|
10289
|
+
silentMessage = await this.runBeforeCreateMessageHook(state, silentMessage);
|
|
10212
10290
|
await state.storage.sql.exec(
|
|
10213
10291
|
`
|
|
10214
10292
|
INSERT INTO messages (
|
|
@@ -10219,15 +10297,16 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10219
10297
|
silentMessage.id,
|
|
10220
10298
|
silentMessage.role,
|
|
10221
10299
|
silentMessage.content,
|
|
10222
|
-
|
|
10223
|
-
1,
|
|
10300
|
+
silentMessage.attachments ?? null,
|
|
10301
|
+
silentMessage.silent ? 1 : 0,
|
|
10224
10302
|
silentMessage.created_at,
|
|
10225
|
-
silentMessage.status,
|
|
10303
|
+
silentMessage.status ?? "completed",
|
|
10226
10304
|
silentMessage.parent_id,
|
|
10227
10305
|
silentMessage.depth,
|
|
10228
10306
|
currentPrompt
|
|
10229
10307
|
);
|
|
10230
10308
|
state.messageHistory.push(silentMessage);
|
|
10309
|
+
await this.runAfterCreateMessageHook(state, silentMessage);
|
|
10231
10310
|
if (state.emitMessage) {
|
|
10232
10311
|
state.emitMessage(silentMessage);
|
|
10233
10312
|
}
|
|
@@ -10766,7 +10845,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10766
10845
|
*/
|
|
10767
10846
|
static async loadMessageHistory(state) {
|
|
10768
10847
|
const storage = state.storage;
|
|
10769
|
-
|
|
10848
|
+
state.thread;
|
|
10770
10849
|
const includeParentHistory = state.prompt.include_chat ?? true;
|
|
10771
10850
|
const includeToolCalls = state.prompt.include_past_tools ?? true;
|
|
10772
10851
|
try {
|
|
@@ -10802,8 +10881,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10802
10881
|
rows = cursor.toArray();
|
|
10803
10882
|
}
|
|
10804
10883
|
if (state.extraMessages && state.extraMessages.length > 0) {
|
|
10805
|
-
rows.
|
|
10806
|
-
rows.
|
|
10884
|
+
const persistedIds = new Set(rows.map((row) => row.id));
|
|
10885
|
+
rows.push(
|
|
10886
|
+
...state.extraMessages.filter((entry) => !persistedIds.has(entry.id))
|
|
10887
|
+
);
|
|
10888
|
+
rows.sort((a, b) => a.created_at - b.created_at);
|
|
10807
10889
|
}
|
|
10808
10890
|
const messages = rows.map((row) => ({
|
|
10809
10891
|
id: row.id,
|
|
@@ -10826,24 +10908,15 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10826
10908
|
reasoning_content: row.reasoning_content,
|
|
10827
10909
|
reasoning_details: row.reasoning_details
|
|
10828
10910
|
}));
|
|
10829
|
-
return
|
|
10830
|
-
thread.instance,
|
|
10831
|
-
state,
|
|
10832
|
-
this.filterOrphanedToolCalls(messages)
|
|
10833
|
-
);
|
|
10911
|
+
return messages;
|
|
10834
10912
|
} catch (error) {
|
|
10835
10913
|
console.error("Error loading message history:", error);
|
|
10836
10914
|
return [];
|
|
10837
10915
|
}
|
|
10838
10916
|
}
|
|
10839
10917
|
/**
|
|
10840
|
-
*
|
|
10841
|
-
*
|
|
10842
|
-
*
|
|
10843
|
-
* @param thread - Thread instance with hooks registry
|
|
10844
|
-
* @param state - Flow state for hook context
|
|
10845
|
-
* @param rows - SQL rows from messages table
|
|
10846
|
-
* @returns Processed rows (or original if hook doesn't exist/fails)
|
|
10918
|
+
* Build request-context rows from persisted history.
|
|
10919
|
+
* Mutations and synthetic messages stay in the request context.
|
|
10847
10920
|
*/
|
|
10848
10921
|
static async runFilterMessagesHook(thread, state, messages) {
|
|
10849
10922
|
const executors = await this.getHooksForType(state, "filter_messages");
|
|
@@ -10856,13 +10929,56 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10856
10929
|
for (const row of result) if (row.id) byId.set(row.id, row);
|
|
10857
10930
|
const hookView = result.map((row) => _FlowEngine.rowToHookMessage(row));
|
|
10858
10931
|
const kept = await executor(threadState, hookView);
|
|
10859
|
-
result = kept.map((
|
|
10932
|
+
result = kept.map((hookedMessage) => {
|
|
10933
|
+
const original = hookedMessage.id ? byId.get(hookedMessage.id) : void 0;
|
|
10934
|
+
if (original) {
|
|
10935
|
+
return _FlowEngine.applyHookMessageToRow(original, hookedMessage);
|
|
10936
|
+
}
|
|
10937
|
+
return _FlowEngine.hookMessageToContextRow(hookedMessage);
|
|
10938
|
+
});
|
|
10860
10939
|
} catch (error) {
|
|
10861
10940
|
console.error("[Hooks] \u2717 Error running filter_messages hook:", error);
|
|
10862
10941
|
}
|
|
10863
10942
|
}
|
|
10864
10943
|
return result;
|
|
10865
10944
|
}
|
|
10945
|
+
/**
|
|
10946
|
+
* Copy a persisted row and apply hook edits. The original live-history
|
|
10947
|
+
* object is left unchanged.
|
|
10948
|
+
*/
|
|
10949
|
+
static applyHookMessageToRow(original, hooked) {
|
|
10950
|
+
const attachments = hooked.attachments === void 0 ? original.attachments : hooked.attachments === null ? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments);
|
|
10951
|
+
return {
|
|
10952
|
+
...original,
|
|
10953
|
+
role: hooked.role ?? original.role,
|
|
10954
|
+
content: hooked.content !== void 0 ? hooked.content : original.content,
|
|
10955
|
+
name: hooked.name !== void 0 ? hooked.name : original.name,
|
|
10956
|
+
tool_calls: hooked.tool_calls !== void 0 ? hooked.tool_calls : original.tool_calls,
|
|
10957
|
+
tool_call_id: hooked.tool_call_id !== void 0 ? hooked.tool_call_id : original.tool_call_id,
|
|
10958
|
+
silent: hooked.silent !== void 0 ? hooked.silent : original.silent,
|
|
10959
|
+
attachments
|
|
10960
|
+
};
|
|
10961
|
+
}
|
|
10962
|
+
/**
|
|
10963
|
+
* Convert a synthetic hook message into a request-context-only builder row.
|
|
10964
|
+
*/
|
|
10965
|
+
static hookMessageToContextRow(hooked) {
|
|
10966
|
+
const attachments = hooked.attachments === void 0 || hooked.attachments === null ? hooked.attachments ?? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments);
|
|
10967
|
+
return {
|
|
10968
|
+
id: hooked.id || crypto.randomUUID(),
|
|
10969
|
+
role: hooked.role,
|
|
10970
|
+
content: hooked.content ?? null,
|
|
10971
|
+
name: hooked.name ?? null,
|
|
10972
|
+
tool_calls: typeof hooked.tool_calls === "string" ? hooked.tool_calls : null,
|
|
10973
|
+
tool_call_id: hooked.tool_call_id ?? null,
|
|
10974
|
+
created_at: hooked.created_at ?? Date.now() * TIMESTAMP_MULTIPLIER,
|
|
10975
|
+
parent_id: hooked.parent_id ?? null,
|
|
10976
|
+
depth: hooked.depth ?? 0,
|
|
10977
|
+
silent: hooked.silent ?? false,
|
|
10978
|
+
status: "completed",
|
|
10979
|
+
attachments
|
|
10980
|
+
};
|
|
10981
|
+
}
|
|
10866
10982
|
/**
|
|
10867
10983
|
* Log an error to the logs table (best-effort)
|
|
10868
10984
|
* Creates a log entry with error details but no associated message_id
|
|
@@ -11006,6 +11122,35 @@ ${errorStack}` : ""}`;
|
|
|
11006
11122
|
});
|
|
11007
11123
|
|
|
11008
11124
|
// src/agents/utilities.ts
|
|
11125
|
+
var utilities_exports = {};
|
|
11126
|
+
__export(utilities_exports, {
|
|
11127
|
+
cat: () => cat,
|
|
11128
|
+
emitThreadEvent: () => emitThreadEvent,
|
|
11129
|
+
exists: () => exists,
|
|
11130
|
+
find: () => find,
|
|
11131
|
+
forceTurn: () => forceTurn,
|
|
11132
|
+
getFileStats: () => getFileStats,
|
|
11133
|
+
getMessages: () => getMessages,
|
|
11134
|
+
getThumbnail: () => getThumbnail,
|
|
11135
|
+
grep: () => grep,
|
|
11136
|
+
head: () => head,
|
|
11137
|
+
injectMessage: () => injectMessage,
|
|
11138
|
+
linkFile: () => linkFile,
|
|
11139
|
+
mkdir: () => mkdir,
|
|
11140
|
+
move: () => move,
|
|
11141
|
+
queueTool: () => queueTool,
|
|
11142
|
+
readFile: () => readFile,
|
|
11143
|
+
readdir: () => readdir,
|
|
11144
|
+
reloadHistory: () => reloadHistory,
|
|
11145
|
+
rename: () => rename,
|
|
11146
|
+
rmdir: () => rmdir,
|
|
11147
|
+
stat: () => stat,
|
|
11148
|
+
tail: () => tail,
|
|
11149
|
+
unlink: () => unlink,
|
|
11150
|
+
updateThread: () => updateThread,
|
|
11151
|
+
writeFile: () => writeFile,
|
|
11152
|
+
writeImage: () => writeImage
|
|
11153
|
+
});
|
|
11009
11154
|
function queueTool(flow, toolName, args = {}) {
|
|
11010
11155
|
if (flow.currentToolUses !== void 0) {
|
|
11011
11156
|
if (!flow.currentToolUses.includes(toolName)) {
|
|
@@ -11033,7 +11178,7 @@ async function injectMessage(flow, options) {
|
|
|
11033
11178
|
const timestamp = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
11034
11179
|
const silent = options.silent ?? false;
|
|
11035
11180
|
const forceTopLevel = options.forceTopLevel ?? false;
|
|
11036
|
-
|
|
11181
|
+
let message = {
|
|
11037
11182
|
id: messageId,
|
|
11038
11183
|
role: options.role,
|
|
11039
11184
|
content: options.content,
|
|
@@ -11047,41 +11192,52 @@ async function injectMessage(flow, options) {
|
|
|
11047
11192
|
metadata: options.metadata
|
|
11048
11193
|
};
|
|
11049
11194
|
if (options.beforeMessageId) {
|
|
11050
|
-
const
|
|
11051
|
-
|
|
11052
|
-
options.beforeMessageId
|
|
11195
|
+
const liveTarget = flow.messageHistory.find(
|
|
11196
|
+
(entry) => entry.id === options.beforeMessageId
|
|
11053
11197
|
);
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11198
|
+
let targetCreatedAt = liveTarget?.created_at;
|
|
11199
|
+
if (targetCreatedAt === void 0) {
|
|
11200
|
+
const cursor = await flow.storage.sql.exec(
|
|
11201
|
+
`SELECT created_at FROM messages WHERE id = ?`,
|
|
11202
|
+
options.beforeMessageId
|
|
11059
11203
|
);
|
|
11204
|
+
const rows = cursor.toArray();
|
|
11205
|
+
const targetMessage = rows[0];
|
|
11206
|
+
if (!targetMessage) {
|
|
11207
|
+
throw new Error(
|
|
11208
|
+
`Message with id ${options.beforeMessageId} not found`
|
|
11209
|
+
);
|
|
11210
|
+
}
|
|
11211
|
+
targetCreatedAt = targetMessage.created_at;
|
|
11060
11212
|
}
|
|
11061
|
-
message.created_at =
|
|
11213
|
+
message.created_at = targetCreatedAt - 1;
|
|
11062
11214
|
}
|
|
11063
11215
|
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
11064
|
-
const
|
|
11216
|
+
const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
|
|
11217
|
+
message = await FlowEngine2.runBeforeCreateMessageHook(flow, message, void 0, {
|
|
11218
|
+
propagateHookErrors: true
|
|
11219
|
+
});
|
|
11220
|
+
const metadataJson = message.metadata === void 0 ? null : JSON.stringify(message.metadata);
|
|
11065
11221
|
await flow.storage.sql.exec(
|
|
11066
11222
|
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, metadata, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11067
|
-
|
|
11223
|
+
message.id,
|
|
11068
11224
|
message.role,
|
|
11069
11225
|
message.content,
|
|
11070
11226
|
message.name,
|
|
11071
11227
|
message.tool_call_id,
|
|
11072
11228
|
message.created_at,
|
|
11073
11229
|
message.status,
|
|
11074
|
-
silent ? 1 : 0,
|
|
11230
|
+
message.silent ? 1 : 0,
|
|
11075
11231
|
message.parent_id,
|
|
11076
11232
|
message.depth,
|
|
11077
11233
|
metadataJson,
|
|
11078
11234
|
currentPrompt
|
|
11079
11235
|
);
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
flow.messageHistory = await reloadHistory(flow);
|
|
11236
|
+
appendLiveExecutionHistory(flow, message, options.beforeMessageId);
|
|
11237
|
+
if (flow.prompt.include_chat === false || message.parent_id !== null || (message.depth ?? 0) > 0) {
|
|
11238
|
+
appendInjectedContextMessage(flow.extraMessages, message);
|
|
11084
11239
|
}
|
|
11240
|
+
await FlowEngine2.runAfterCreateMessageHook(flow, message);
|
|
11085
11241
|
if (flow.emitMessage) {
|
|
11086
11242
|
flow.emitMessage(message);
|
|
11087
11243
|
}
|
|
@@ -11090,6 +11246,42 @@ async function injectMessage(flow, options) {
|
|
|
11090
11246
|
}
|
|
11091
11247
|
return message;
|
|
11092
11248
|
}
|
|
11249
|
+
function appendLiveExecutionHistory(flow, message, beforeMessageId) {
|
|
11250
|
+
const history = flow.messageHistory;
|
|
11251
|
+
const existing = history.findIndex((entry) => entry.id === message.id);
|
|
11252
|
+
if (existing >= 0) {
|
|
11253
|
+
history.splice(existing, 1);
|
|
11254
|
+
}
|
|
11255
|
+
if (beforeMessageId) {
|
|
11256
|
+
const targetIndex = history.findIndex((entry) => entry.id === beforeMessageId);
|
|
11257
|
+
if (targetIndex >= 0) {
|
|
11258
|
+
history.splice(targetIndex, 0, message);
|
|
11259
|
+
return;
|
|
11260
|
+
}
|
|
11261
|
+
}
|
|
11262
|
+
const insertAt = history.findIndex(
|
|
11263
|
+
(entry) => entry.created_at > message.created_at
|
|
11264
|
+
);
|
|
11265
|
+
if (insertAt === -1) {
|
|
11266
|
+
history.push(message);
|
|
11267
|
+
return;
|
|
11268
|
+
}
|
|
11269
|
+
history.splice(insertAt, 0, message);
|
|
11270
|
+
}
|
|
11271
|
+
function appendInjectedContextMessage(extraMessages, message) {
|
|
11272
|
+
const existing = extraMessages.findIndex((entry) => entry.id === message.id);
|
|
11273
|
+
if (existing >= 0) {
|
|
11274
|
+
extraMessages.splice(existing, 1);
|
|
11275
|
+
}
|
|
11276
|
+
const insertAt = extraMessages.findIndex(
|
|
11277
|
+
(entry) => entry.created_at > message.created_at
|
|
11278
|
+
);
|
|
11279
|
+
if (insertAt === -1) {
|
|
11280
|
+
extraMessages.push(message);
|
|
11281
|
+
return;
|
|
11282
|
+
}
|
|
11283
|
+
extraMessages.splice(insertAt, 0, message);
|
|
11284
|
+
}
|
|
11093
11285
|
async function getMessages(flow, limit = 100, offset = 0, order = "asc") {
|
|
11094
11286
|
const orderClause = order === "desc" ? "DESC" : "ASC";
|
|
11095
11287
|
const cursor = await flow.storage.sql.exec(
|
|
@@ -29983,6 +30175,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
29983
30175
|
// src/durable-objects/DurableThread.ts
|
|
29984
30176
|
init_StreamManager();
|
|
29985
30177
|
init_LLMRequest();
|
|
30178
|
+
init_ThreadStateImpl();
|
|
29986
30179
|
|
|
29987
30180
|
// src/durable-objects/logDetailStream.ts
|
|
29988
30181
|
var LOG_DETAIL_HEAVY_FIELDS = [
|
|
@@ -30685,7 +30878,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
30685
30878
|
side_b_session_fail_attachments_property: sideBSession.fail.attachmentsProperty,
|
|
30686
30879
|
side_b_session_status_tool: sideBSession.status.toolName,
|
|
30687
30880
|
side_b_session_status_message_property: sideBSession.status.messageProperty,
|
|
30688
|
-
side_b_session_status_attachments_property: sideBSession.status.attachmentsProperty
|
|
30881
|
+
side_b_session_status_attachments_property: sideBSession.status.attachmentsProperty,
|
|
30882
|
+
hooks: Array.isArray(agentDef.hooks) ? agentDef.hooks : void 0
|
|
30689
30883
|
};
|
|
30690
30884
|
}
|
|
30691
30885
|
/**
|
|
@@ -31355,6 +31549,29 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
31355
31549
|
}
|
|
31356
31550
|
return projections;
|
|
31357
31551
|
}
|
|
31552
|
+
/**
|
|
31553
|
+
* Build hook resolution context and a genuine at-rest ThreadState.
|
|
31554
|
+
* Resolution failures abort insertion so lifecycle hooks cannot be bypassed.
|
|
31555
|
+
*/
|
|
31556
|
+
async buildAtRestHookState(threadId) {
|
|
31557
|
+
try {
|
|
31558
|
+
const metadata = await this.getThreadMetadata(threadId);
|
|
31559
|
+
const agentConfig = await this.loadAgentConfig(metadata.agent_id);
|
|
31560
|
+
const threadInstance = this;
|
|
31561
|
+
return {
|
|
31562
|
+
hookState: {
|
|
31563
|
+
agentConfig,
|
|
31564
|
+
thread: { instance: threadInstance, metadata }
|
|
31565
|
+
},
|
|
31566
|
+
threadState: ThreadStateImpl.fromThreadInstance(threadInstance, metadata)
|
|
31567
|
+
};
|
|
31568
|
+
} catch (error) {
|
|
31569
|
+
throw new Error(
|
|
31570
|
+
`Unable to resolve create-message hooks for ${threadId}`,
|
|
31571
|
+
{ cause: error }
|
|
31572
|
+
);
|
|
31573
|
+
}
|
|
31574
|
+
}
|
|
31358
31575
|
/**
|
|
31359
31576
|
* Inject a top-level message without starting a new execution.
|
|
31360
31577
|
*
|
|
@@ -31367,22 +31584,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
31367
31584
|
const id = crypto.randomUUID();
|
|
31368
31585
|
const createdAt = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
31369
31586
|
const silent = message.silent === true;
|
|
31370
|
-
|
|
31371
|
-
await this.ctx.storage.sql.exec(
|
|
31372
|
-
`INSERT INTO messages (id, role, content, created_at, status, silent, parent_id, depth, metadata, prompt)
|
|
31373
|
-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
|
|
31374
|
-
id,
|
|
31375
|
-
message.role,
|
|
31376
|
-
message.content,
|
|
31377
|
-
createdAt,
|
|
31378
|
-
"completed",
|
|
31379
|
-
silent ? 1 : 0,
|
|
31380
|
-
null,
|
|
31381
|
-
0,
|
|
31382
|
-
metadataJson,
|
|
31383
|
-
null
|
|
31384
|
-
);
|
|
31385
|
-
const inserted = {
|
|
31587
|
+
let inserted = {
|
|
31386
31588
|
id,
|
|
31387
31589
|
role: message.role,
|
|
31388
31590
|
content: message.content,
|
|
@@ -31393,9 +31595,37 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
31393
31595
|
depth: 0,
|
|
31394
31596
|
metadata: message.metadata
|
|
31395
31597
|
};
|
|
31598
|
+
const { hookState, threadState } = await this.buildAtRestHookState(threadId);
|
|
31599
|
+
const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
|
|
31600
|
+
inserted = await FlowEngine2.runBeforeCreateMessageHook(
|
|
31601
|
+
hookState,
|
|
31602
|
+
inserted,
|
|
31603
|
+
threadState,
|
|
31604
|
+
{ propagateHookErrors: true }
|
|
31605
|
+
);
|
|
31606
|
+
const metadataJson = inserted.metadata ? JSON.stringify(inserted.metadata) : null;
|
|
31607
|
+
await this.ctx.storage.sql.exec(
|
|
31608
|
+
`INSERT INTO messages (id, role, content, created_at, status, silent, parent_id, depth, metadata, prompt)
|
|
31609
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
|
|
31610
|
+
inserted.id,
|
|
31611
|
+
inserted.role,
|
|
31612
|
+
inserted.content,
|
|
31613
|
+
inserted.created_at,
|
|
31614
|
+
inserted.status ?? "completed",
|
|
31615
|
+
inserted.silent ? 1 : 0,
|
|
31616
|
+
inserted.parent_id ?? null,
|
|
31617
|
+
inserted.depth ?? 0,
|
|
31618
|
+
metadataJson,
|
|
31619
|
+
null
|
|
31620
|
+
);
|
|
31621
|
+
await FlowEngine2.runAfterCreateMessageHook(
|
|
31622
|
+
hookState,
|
|
31623
|
+
inserted,
|
|
31624
|
+
threadState
|
|
31625
|
+
);
|
|
31396
31626
|
this.broadcastMessage(inserted);
|
|
31397
31627
|
const record = inserted;
|
|
31398
|
-
const visibleUserInjection =
|
|
31628
|
+
const visibleUserInjection = inserted.role === "user" && !inserted.silent && typeof inserted.content === "string" && inserted.content.trim().length > 0 && !isRuntimeSubagentEnvelope(inserted.content);
|
|
31399
31629
|
if (visibleUserInjection || isVisibleTerminalAssistantMessage(record)) {
|
|
31400
31630
|
const stamp = this.recordRegistryActivity(
|
|
31401
31631
|
threadId,
|
|
@@ -37890,8 +38120,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
37890
38120
|
init_utilities();
|
|
37891
38121
|
|
|
37892
38122
|
// src/agents/FlowStateSdk.ts
|
|
37893
|
-
|
|
37894
|
-
var FlowStateSdk = class _FlowStateSdk {
|
|
38123
|
+
var FlowStateSdk = class {
|
|
37895
38124
|
/**
|
|
37896
38125
|
* Queue a new tool call to be executed in the current flow
|
|
37897
38126
|
*
|
|
@@ -37958,63 +38187,8 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
37958
38187
|
* ```
|
|
37959
38188
|
*/
|
|
37960
38189
|
static async injectMessage(flow, options) {
|
|
37961
|
-
const
|
|
37962
|
-
|
|
37963
|
-
const silent = options.silent ?? false;
|
|
37964
|
-
const forceTopLevel = options.forceTopLevel ?? false;
|
|
37965
|
-
const message = {
|
|
37966
|
-
id: messageId,
|
|
37967
|
-
role: options.role,
|
|
37968
|
-
content: options.content,
|
|
37969
|
-
name: options.name ?? null,
|
|
37970
|
-
tool_call_id: options.toolCallId ?? null,
|
|
37971
|
-
created_at: timestamp,
|
|
37972
|
-
status: "completed",
|
|
37973
|
-
silent,
|
|
37974
|
-
parent_id: forceTopLevel ? null : flow.parentMessageId ?? null,
|
|
37975
|
-
depth: forceTopLevel ? 0 : flow.depth
|
|
37976
|
-
};
|
|
37977
|
-
if (options.beforeMessageId) {
|
|
37978
|
-
const cursor = await flow.storage.sql.exec(
|
|
37979
|
-
`SELECT created_at FROM messages WHERE id = ?`,
|
|
37980
|
-
options.beforeMessageId
|
|
37981
|
-
);
|
|
37982
|
-
const rows = cursor.toArray();
|
|
37983
|
-
const targetMessage = rows[0];
|
|
37984
|
-
if (!targetMessage) {
|
|
37985
|
-
throw new Error(
|
|
37986
|
-
`Message with id ${options.beforeMessageId} not found`
|
|
37987
|
-
);
|
|
37988
|
-
}
|
|
37989
|
-
message.created_at = targetMessage.created_at - 1;
|
|
37990
|
-
}
|
|
37991
|
-
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
37992
|
-
await flow.storage.sql.exec(
|
|
37993
|
-
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
37994
|
-
messageId,
|
|
37995
|
-
message.role,
|
|
37996
|
-
message.content,
|
|
37997
|
-
message.name,
|
|
37998
|
-
message.tool_call_id,
|
|
37999
|
-
message.created_at,
|
|
38000
|
-
message.status,
|
|
38001
|
-
silent ? 1 : 0,
|
|
38002
|
-
message.parent_id,
|
|
38003
|
-
message.depth,
|
|
38004
|
-
currentPrompt
|
|
38005
|
-
);
|
|
38006
|
-
if (!silent) {
|
|
38007
|
-
flow.messageHistory.push(message);
|
|
38008
|
-
} else {
|
|
38009
|
-
flow.messageHistory = await _FlowStateSdk.reloadHistory(flow);
|
|
38010
|
-
}
|
|
38011
|
-
if (flow.emitMessage) {
|
|
38012
|
-
flow.emitMessage(message);
|
|
38013
|
-
}
|
|
38014
|
-
if (options.forceTurn) {
|
|
38015
|
-
_FlowStateSdk.forceTurn(flow, options.forceTurn);
|
|
38016
|
-
}
|
|
38017
|
-
return message;
|
|
38190
|
+
const { injectMessage: injectMessage2 } = await Promise.resolve().then(() => (init_utilities(), utilities_exports));
|
|
38191
|
+
return injectMessage2(flow, options);
|
|
38018
38192
|
}
|
|
38019
38193
|
/**
|
|
38020
38194
|
* Get messages from the thread history
|
|
@@ -38103,9 +38277,9 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
38103
38277
|
/**
|
|
38104
38278
|
* Reload message history from storage
|
|
38105
38279
|
*
|
|
38106
|
-
* Re-loads the complete message history from the thread's SQLite storage
|
|
38107
|
-
*
|
|
38108
|
-
*
|
|
38280
|
+
* Re-loads the complete message history from the thread's SQLite storage.
|
|
38281
|
+
* This is useful when you need to refresh the message history after making
|
|
38282
|
+
* changes (e.g., injecting messages).
|
|
38109
38283
|
*
|
|
38110
38284
|
* @param flow - The current FlowState
|
|
38111
38285
|
* @returns Array of messages (reloaded from storage)
|