@standardagents/builder 0.39.0 → 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 +178 -67
- package/dist/built-in-routes.js.map +1 -1
- package/dist/index.js +269 -142
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +15 -33
- package/dist/runtime.js +269 -142
- package/dist/runtime.js.map +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;
|
|
@@ -7635,28 +7638,12 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7635
7638
|
state.promptPath = [sideAPrompt.name];
|
|
7636
7639
|
state.pendingImmediateAfterHandoff = true;
|
|
7637
7640
|
if (userMessageContent || userMessageAttachments) {
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
role: "user",
|
|
7643
|
-
content: userMessageContent || "",
|
|
7644
|
-
created_at: handoffTimestamp,
|
|
7645
|
-
attachments: userMessageAttachments
|
|
7646
|
-
};
|
|
7647
|
-
await state.storage.sql.exec(
|
|
7648
|
-
`INSERT INTO messages (id, role, content, attachments, created_at, prompt) VALUES (?, ?, ?, ?, ?, ?)`,
|
|
7649
|
-
handoffMessage.id,
|
|
7650
|
-
handoffMessage.role,
|
|
7651
|
-
handoffMessage.content,
|
|
7652
|
-
handoffMessage.attachments || null,
|
|
7653
|
-
handoffMessage.created_at,
|
|
7641
|
+
await this.persistHandoffUserMessage(
|
|
7642
|
+
state,
|
|
7643
|
+
userMessageContent || "",
|
|
7644
|
+
userMessageAttachments,
|
|
7654
7645
|
sideAPrompt.name
|
|
7655
7646
|
);
|
|
7656
|
-
state.messageHistory.push(handoffMessage);
|
|
7657
|
-
if (state.emitMessage) {
|
|
7658
|
-
state.emitMessage(handoffMessage);
|
|
7659
|
-
}
|
|
7660
7647
|
}
|
|
7661
7648
|
state.pendingHandoff = void 0;
|
|
7662
7649
|
state.emitTelemetry?.({
|
|
@@ -7671,6 +7658,37 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
7671
7658
|
throw error;
|
|
7672
7659
|
}
|
|
7673
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
|
+
}
|
|
7674
7692
|
static isEnabledEnvFlag(value) {
|
|
7675
7693
|
if (value === null || value === void 0) return false;
|
|
7676
7694
|
const normalized = value.trim().toLowerCase();
|
|
@@ -8568,7 +8586,16 @@ This usually points to something I can't fix from here \u2014 for example the wo
|
|
|
8568
8586
|
role: "system",
|
|
8569
8587
|
content: systemPromptText
|
|
8570
8588
|
});
|
|
8571
|
-
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(
|
|
8572
8599
|
(msg) => msg.status !== "pending"
|
|
8573
8600
|
);
|
|
8574
8601
|
const recentMessageThreshold = state.prompt.recentImageThreshold ?? 10;
|
|
@@ -9706,11 +9733,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9706
9733
|
* @param message - Message object to be created
|
|
9707
9734
|
* @returns Processed message (or original if hook doesn't exist/fails)
|
|
9708
9735
|
*/
|
|
9709
|
-
static async runBeforeCreateMessageHook(state, message) {
|
|
9736
|
+
static async runBeforeCreateMessageHook(state, message, threadStateOverride, options) {
|
|
9710
9737
|
const executors = await this.getHooksForType(state, "before_create_message");
|
|
9711
9738
|
if (executors.length === 0) return message;
|
|
9712
9739
|
let result = message;
|
|
9713
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9740
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9714
9741
|
for (const executor of executors) {
|
|
9715
9742
|
try {
|
|
9716
9743
|
const hooked = await executor(threadState, _FlowEngine.rowToHookMessage(result));
|
|
@@ -9720,6 +9747,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9720
9747
|
attachments: hooked.attachments === void 0 ? result.attachments : hooked.attachments === null ? null : typeof hooked.attachments === "string" ? hooked.attachments : JSON.stringify(hooked.attachments)
|
|
9721
9748
|
};
|
|
9722
9749
|
} catch (error) {
|
|
9750
|
+
if (options?.propagateHookErrors) {
|
|
9751
|
+
throw error;
|
|
9752
|
+
}
|
|
9723
9753
|
console.error("[Hooks] \u2717 Error running before_create_message hook:", error);
|
|
9724
9754
|
}
|
|
9725
9755
|
}
|
|
@@ -9732,10 +9762,10 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
9732
9762
|
* @param state - Flow state with execution context
|
|
9733
9763
|
* @param message - The created message object
|
|
9734
9764
|
*/
|
|
9735
|
-
static async runAfterCreateMessageHook(state, message) {
|
|
9765
|
+
static async runAfterCreateMessageHook(state, message, threadStateOverride) {
|
|
9736
9766
|
const executors = await this.getHooksForType(state, "after_create_message");
|
|
9737
9767
|
if (executors.length === 0) return;
|
|
9738
|
-
const threadState = ThreadStateImpl.fromFlowState(state);
|
|
9768
|
+
const threadState = threadStateOverride ?? ThreadStateImpl.fromFlowState(state);
|
|
9739
9769
|
for (const executor of executors) {
|
|
9740
9770
|
try {
|
|
9741
9771
|
await executor(threadState, _FlowEngine.rowToHookMessage(message));
|
|
@@ -10236,7 +10266,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10236
10266
|
}
|
|
10237
10267
|
existingPathMessages.add(content);
|
|
10238
10268
|
const attachmentsJson = JSON.stringify([ref]);
|
|
10239
|
-
|
|
10269
|
+
let silentMessage = {
|
|
10240
10270
|
id: crypto.randomUUID(),
|
|
10241
10271
|
role: sourceMessage.role,
|
|
10242
10272
|
content,
|
|
@@ -10247,6 +10277,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10247
10277
|
parent_id: parentId,
|
|
10248
10278
|
depth
|
|
10249
10279
|
};
|
|
10280
|
+
silentMessage = await this.runBeforeCreateMessageHook(state, silentMessage);
|
|
10250
10281
|
await state.storage.sql.exec(
|
|
10251
10282
|
`
|
|
10252
10283
|
INSERT INTO messages (
|
|
@@ -10257,15 +10288,16 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10257
10288
|
silentMessage.id,
|
|
10258
10289
|
silentMessage.role,
|
|
10259
10290
|
silentMessage.content,
|
|
10260
|
-
|
|
10261
|
-
1,
|
|
10291
|
+
silentMessage.attachments ?? null,
|
|
10292
|
+
silentMessage.silent ? 1 : 0,
|
|
10262
10293
|
silentMessage.created_at,
|
|
10263
|
-
silentMessage.status,
|
|
10294
|
+
silentMessage.status ?? "completed",
|
|
10264
10295
|
silentMessage.parent_id,
|
|
10265
10296
|
silentMessage.depth,
|
|
10266
10297
|
currentPrompt
|
|
10267
10298
|
);
|
|
10268
10299
|
state.messageHistory.push(silentMessage);
|
|
10300
|
+
await this.runAfterCreateMessageHook(state, silentMessage);
|
|
10269
10301
|
if (state.emitMessage) {
|
|
10270
10302
|
state.emitMessage(silentMessage);
|
|
10271
10303
|
}
|
|
@@ -10804,7 +10836,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10804
10836
|
*/
|
|
10805
10837
|
static async loadMessageHistory(state) {
|
|
10806
10838
|
const storage = state.storage;
|
|
10807
|
-
|
|
10839
|
+
state.thread;
|
|
10808
10840
|
const includeParentHistory = state.prompt.include_chat ?? true;
|
|
10809
10841
|
const includeToolCalls = state.prompt.include_past_tools ?? true;
|
|
10810
10842
|
try {
|
|
@@ -10840,8 +10872,11 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10840
10872
|
rows = cursor.toArray();
|
|
10841
10873
|
}
|
|
10842
10874
|
if (state.extraMessages && state.extraMessages.length > 0) {
|
|
10843
|
-
rows.
|
|
10844
|
-
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);
|
|
10845
10880
|
}
|
|
10846
10881
|
const messages = rows.map((row) => ({
|
|
10847
10882
|
id: row.id,
|
|
@@ -10864,24 +10899,15 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10864
10899
|
reasoning_content: row.reasoning_content,
|
|
10865
10900
|
reasoning_details: row.reasoning_details
|
|
10866
10901
|
}));
|
|
10867
|
-
return
|
|
10868
|
-
thread.instance,
|
|
10869
|
-
state,
|
|
10870
|
-
this.filterOrphanedToolCalls(messages)
|
|
10871
|
-
);
|
|
10902
|
+
return messages;
|
|
10872
10903
|
} catch (error) {
|
|
10873
10904
|
console.error("Error loading message history:", error);
|
|
10874
10905
|
return [];
|
|
10875
10906
|
}
|
|
10876
10907
|
}
|
|
10877
10908
|
/**
|
|
10878
|
-
*
|
|
10879
|
-
*
|
|
10880
|
-
*
|
|
10881
|
-
* @param thread - Thread instance with hooks registry
|
|
10882
|
-
* @param state - Flow state for hook context
|
|
10883
|
-
* @param rows - SQL rows from messages table
|
|
10884
|
-
* @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.
|
|
10885
10911
|
*/
|
|
10886
10912
|
static async runFilterMessagesHook(thread, state, messages) {
|
|
10887
10913
|
const executors = await this.getHooksForType(state, "filter_messages");
|
|
@@ -10894,13 +10920,56 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10894
10920
|
for (const row of result) if (row.id) byId.set(row.id, row);
|
|
10895
10921
|
const hookView = result.map((row) => _FlowEngine.rowToHookMessage(row));
|
|
10896
10922
|
const kept = await executor(threadState, hookView);
|
|
10897
|
-
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
|
+
});
|
|
10898
10930
|
} catch (error) {
|
|
10899
10931
|
console.error("[Hooks] \u2717 Error running filter_messages hook:", error);
|
|
10900
10932
|
}
|
|
10901
10933
|
}
|
|
10902
10934
|
return result;
|
|
10903
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
|
+
}
|
|
10904
10973
|
/**
|
|
10905
10974
|
* Log an error to the logs table (best-effort)
|
|
10906
10975
|
* Creates a log entry with error details but no associated message_id
|
|
@@ -11044,6 +11113,35 @@ ${errorStack}` : ""}`;
|
|
|
11044
11113
|
});
|
|
11045
11114
|
|
|
11046
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
|
+
});
|
|
11047
11145
|
function queueTool(flow, toolName, args = {}) {
|
|
11048
11146
|
if (flow.currentToolUses !== void 0) {
|
|
11049
11147
|
if (!flow.currentToolUses.includes(toolName)) {
|
|
@@ -11071,7 +11169,7 @@ async function injectMessage(flow, options) {
|
|
|
11071
11169
|
const timestamp = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
11072
11170
|
const silent = options.silent ?? false;
|
|
11073
11171
|
const forceTopLevel = options.forceTopLevel ?? false;
|
|
11074
|
-
|
|
11172
|
+
let message = {
|
|
11075
11173
|
id: messageId,
|
|
11076
11174
|
role: options.role,
|
|
11077
11175
|
content: options.content,
|
|
@@ -11085,41 +11183,52 @@ async function injectMessage(flow, options) {
|
|
|
11085
11183
|
metadata: options.metadata
|
|
11086
11184
|
};
|
|
11087
11185
|
if (options.beforeMessageId) {
|
|
11088
|
-
const
|
|
11089
|
-
|
|
11090
|
-
options.beforeMessageId
|
|
11186
|
+
const liveTarget = flow.messageHistory.find(
|
|
11187
|
+
(entry) => entry.id === options.beforeMessageId
|
|
11091
11188
|
);
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
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
|
|
11097
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;
|
|
11098
11203
|
}
|
|
11099
|
-
message.created_at =
|
|
11204
|
+
message.created_at = targetCreatedAt - 1;
|
|
11100
11205
|
}
|
|
11101
11206
|
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
11102
|
-
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);
|
|
11103
11212
|
await flow.storage.sql.exec(
|
|
11104
11213
|
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, metadata, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11105
|
-
|
|
11214
|
+
message.id,
|
|
11106
11215
|
message.role,
|
|
11107
11216
|
message.content,
|
|
11108
11217
|
message.name,
|
|
11109
11218
|
message.tool_call_id,
|
|
11110
11219
|
message.created_at,
|
|
11111
11220
|
message.status,
|
|
11112
|
-
silent ? 1 : 0,
|
|
11221
|
+
message.silent ? 1 : 0,
|
|
11113
11222
|
message.parent_id,
|
|
11114
11223
|
message.depth,
|
|
11115
11224
|
metadataJson,
|
|
11116
11225
|
currentPrompt
|
|
11117
11226
|
);
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
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);
|
|
11122
11230
|
}
|
|
11231
|
+
await FlowEngine2.runAfterCreateMessageHook(flow, message);
|
|
11123
11232
|
if (flow.emitMessage) {
|
|
11124
11233
|
flow.emitMessage(message);
|
|
11125
11234
|
}
|
|
@@ -11128,6 +11237,42 @@ async function injectMessage(flow, options) {
|
|
|
11128
11237
|
}
|
|
11129
11238
|
return message;
|
|
11130
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
|
+
}
|
|
11131
11276
|
async function getMessages(flow, limit = 100, offset = 0, order = "asc") {
|
|
11132
11277
|
const orderClause = order === "desc" ? "DESC" : "ASC";
|
|
11133
11278
|
const cursor = await flow.storage.sql.exec(
|
|
@@ -21555,6 +21700,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
21555
21700
|
// src/durable-objects/DurableThread.ts
|
|
21556
21701
|
init_StreamManager();
|
|
21557
21702
|
init_LLMRequest();
|
|
21703
|
+
init_ThreadStateImpl();
|
|
21558
21704
|
|
|
21559
21705
|
// src/durable-objects/logDetailStream.ts
|
|
21560
21706
|
var LOG_DETAIL_HEAVY_FIELDS = [
|
|
@@ -22257,7 +22403,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22257
22403
|
side_b_session_fail_attachments_property: sideBSession.fail.attachmentsProperty,
|
|
22258
22404
|
side_b_session_status_tool: sideBSession.status.toolName,
|
|
22259
22405
|
side_b_session_status_message_property: sideBSession.status.messageProperty,
|
|
22260
|
-
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
|
|
22261
22408
|
};
|
|
22262
22409
|
}
|
|
22263
22410
|
/**
|
|
@@ -22927,6 +23074,29 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22927
23074
|
}
|
|
22928
23075
|
return projections;
|
|
22929
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
|
+
}
|
|
22930
23100
|
/**
|
|
22931
23101
|
* Inject a top-level message without starting a new execution.
|
|
22932
23102
|
*
|
|
@@ -22939,22 +23109,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22939
23109
|
const id = crypto.randomUUID();
|
|
22940
23110
|
const createdAt = Date.now() * TIMESTAMP_MULTIPLIER;
|
|
22941
23111
|
const silent = message.silent === true;
|
|
22942
|
-
|
|
22943
|
-
await this.ctx.storage.sql.exec(
|
|
22944
|
-
`INSERT INTO messages (id, role, content, created_at, status, silent, parent_id, depth, metadata, prompt)
|
|
22945
|
-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)`,
|
|
22946
|
-
id,
|
|
22947
|
-
message.role,
|
|
22948
|
-
message.content,
|
|
22949
|
-
createdAt,
|
|
22950
|
-
"completed",
|
|
22951
|
-
silent ? 1 : 0,
|
|
22952
|
-
null,
|
|
22953
|
-
0,
|
|
22954
|
-
metadataJson,
|
|
22955
|
-
null
|
|
22956
|
-
);
|
|
22957
|
-
const inserted = {
|
|
23112
|
+
let inserted = {
|
|
22958
23113
|
id,
|
|
22959
23114
|
role: message.role,
|
|
22960
23115
|
content: message.content,
|
|
@@ -22965,9 +23120,37 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22965
23120
|
depth: 0,
|
|
22966
23121
|
metadata: message.metadata
|
|
22967
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
|
+
);
|
|
22968
23151
|
this.broadcastMessage(inserted);
|
|
22969
23152
|
const record = inserted;
|
|
22970
|
-
const visibleUserInjection =
|
|
23153
|
+
const visibleUserInjection = inserted.role === "user" && !inserted.silent && typeof inserted.content === "string" && inserted.content.trim().length > 0 && !isRuntimeSubagentEnvelope(inserted.content);
|
|
22971
23154
|
if (visibleUserInjection || isVisibleTerminalAssistantMessage(record)) {
|
|
22972
23155
|
const stamp = this.recordRegistryActivity(
|
|
22973
23156
|
threadId,
|
|
@@ -29462,8 +29645,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
29462
29645
|
init_utilities();
|
|
29463
29646
|
|
|
29464
29647
|
// src/agents/FlowStateSdk.ts
|
|
29465
|
-
|
|
29466
|
-
var FlowStateSdk = class _FlowStateSdk {
|
|
29648
|
+
var FlowStateSdk = class {
|
|
29467
29649
|
/**
|
|
29468
29650
|
* Queue a new tool call to be executed in the current flow
|
|
29469
29651
|
*
|
|
@@ -29530,63 +29712,8 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
29530
29712
|
* ```
|
|
29531
29713
|
*/
|
|
29532
29714
|
static async injectMessage(flow, options) {
|
|
29533
|
-
const
|
|
29534
|
-
|
|
29535
|
-
const silent = options.silent ?? false;
|
|
29536
|
-
const forceTopLevel = options.forceTopLevel ?? false;
|
|
29537
|
-
const message = {
|
|
29538
|
-
id: messageId,
|
|
29539
|
-
role: options.role,
|
|
29540
|
-
content: options.content,
|
|
29541
|
-
name: options.name ?? null,
|
|
29542
|
-
tool_call_id: options.toolCallId ?? null,
|
|
29543
|
-
created_at: timestamp,
|
|
29544
|
-
status: "completed",
|
|
29545
|
-
silent,
|
|
29546
|
-
parent_id: forceTopLevel ? null : flow.parentMessageId ?? null,
|
|
29547
|
-
depth: forceTopLevel ? 0 : flow.depth
|
|
29548
|
-
};
|
|
29549
|
-
if (options.beforeMessageId) {
|
|
29550
|
-
const cursor = await flow.storage.sql.exec(
|
|
29551
|
-
`SELECT created_at FROM messages WHERE id = ?`,
|
|
29552
|
-
options.beforeMessageId
|
|
29553
|
-
);
|
|
29554
|
-
const rows = cursor.toArray();
|
|
29555
|
-
const targetMessage = rows[0];
|
|
29556
|
-
if (!targetMessage) {
|
|
29557
|
-
throw new Error(
|
|
29558
|
-
`Message with id ${options.beforeMessageId} not found`
|
|
29559
|
-
);
|
|
29560
|
-
}
|
|
29561
|
-
message.created_at = targetMessage.created_at - 1;
|
|
29562
|
-
}
|
|
29563
|
-
const currentPrompt = flow.promptPath.length > 0 ? flow.promptPath[flow.promptPath.length - 1] : null;
|
|
29564
|
-
await flow.storage.sql.exec(
|
|
29565
|
-
`INSERT INTO messages (id, role, content, name, tool_call_id, created_at, status, silent, parent_id, depth, prompt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
29566
|
-
messageId,
|
|
29567
|
-
message.role,
|
|
29568
|
-
message.content,
|
|
29569
|
-
message.name,
|
|
29570
|
-
message.tool_call_id,
|
|
29571
|
-
message.created_at,
|
|
29572
|
-
message.status,
|
|
29573
|
-
silent ? 1 : 0,
|
|
29574
|
-
message.parent_id,
|
|
29575
|
-
message.depth,
|
|
29576
|
-
currentPrompt
|
|
29577
|
-
);
|
|
29578
|
-
if (!silent) {
|
|
29579
|
-
flow.messageHistory.push(message);
|
|
29580
|
-
} else {
|
|
29581
|
-
flow.messageHistory = await _FlowStateSdk.reloadHistory(flow);
|
|
29582
|
-
}
|
|
29583
|
-
if (flow.emitMessage) {
|
|
29584
|
-
flow.emitMessage(message);
|
|
29585
|
-
}
|
|
29586
|
-
if (options.forceTurn) {
|
|
29587
|
-
_FlowStateSdk.forceTurn(flow, options.forceTurn);
|
|
29588
|
-
}
|
|
29589
|
-
return message;
|
|
29715
|
+
const { injectMessage: injectMessage2 } = await Promise.resolve().then(() => (init_utilities(), utilities_exports));
|
|
29716
|
+
return injectMessage2(flow, options);
|
|
29590
29717
|
}
|
|
29591
29718
|
/**
|
|
29592
29719
|
* Get messages from the thread history
|
|
@@ -29675,9 +29802,9 @@ var FlowStateSdk = class _FlowStateSdk {
|
|
|
29675
29802
|
/**
|
|
29676
29803
|
* Reload message history from storage
|
|
29677
29804
|
*
|
|
29678
|
-
* Re-loads the complete message history from the thread's SQLite storage
|
|
29679
|
-
*
|
|
29680
|
-
*
|
|
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).
|
|
29681
29808
|
*
|
|
29682
29809
|
* @param flow - The current FlowState
|
|
29683
29810
|
* @returns Array of messages (reloaded from storage)
|