memeloop 0.0.1 → 0.1.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.
Files changed (228) hide show
  1. package/README.md +63 -0
  2. package/dist/browser.cjs +1413 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +3066 -0
  5. package/dist/browser.d.ts +3066 -0
  6. package/dist/browser.js +43 -0
  7. package/dist/chunk-2C6BJZI3.js +382 -0
  8. package/dist/chunk-2C6BJZI3.js.map +1 -0
  9. package/dist/chunk-426CJUZP.js +630 -0
  10. package/dist/chunk-426CJUZP.js.map +1 -0
  11. package/dist/chunk-7ZDTB4VZ.js +63 -0
  12. package/dist/chunk-7ZDTB4VZ.js.map +1 -0
  13. package/dist/chunk-AZFYDWIN.js +98 -0
  14. package/dist/chunk-AZFYDWIN.js.map +1 -0
  15. package/dist/chunk-BGPU4RR7.js +367 -0
  16. package/dist/chunk-BGPU4RR7.js.map +1 -0
  17. package/dist/chunk-CCEFAOSH.js +496 -0
  18. package/dist/chunk-CCEFAOSH.js.map +1 -0
  19. package/dist/chunk-FWSY5HOA.js +63 -0
  20. package/dist/chunk-FWSY5HOA.js.map +1 -0
  21. package/dist/chunk-GYIOMQMY.js +8726 -0
  22. package/dist/chunk-GYIOMQMY.js.map +1 -0
  23. package/dist/chunk-K6P63KD4.js +68 -0
  24. package/dist/chunk-K6P63KD4.js.map +1 -0
  25. package/dist/chunk-KFS2EJT6.js +42 -0
  26. package/dist/chunk-KFS2EJT6.js.map +1 -0
  27. package/dist/chunk-MAJWHAKR.js +3637 -0
  28. package/dist/chunk-MAJWHAKR.js.map +1 -0
  29. package/dist/chunk-MRKY4HGF.js +205 -0
  30. package/dist/chunk-MRKY4HGF.js.map +1 -0
  31. package/dist/chunk-T7FSXWFR.js +2744 -0
  32. package/dist/chunk-T7FSXWFR.js.map +1 -0
  33. package/dist/chunk-VZKQX5PP.js +1 -0
  34. package/dist/chunk-VZKQX5PP.js.map +1 -0
  35. package/dist/chunk-WAI6BODI.js +175 -0
  36. package/dist/chunk-WAI6BODI.js.map +1 -0
  37. package/dist/chunk-YMNXDNDW.js +798 -0
  38. package/dist/chunk-YMNXDNDW.js.map +1 -0
  39. package/dist/conversation.cjs +208 -0
  40. package/dist/conversation.cjs.map +1 -0
  41. package/dist/conversation.d.cts +100 -0
  42. package/dist/conversation.d.ts +100 -0
  43. package/dist/conversation.js +21 -0
  44. package/dist/conversation.js.map +1 -0
  45. package/dist/device-network-portable.cjs +702 -0
  46. package/dist/device-network-portable.cjs.map +1 -0
  47. package/dist/device-network-portable.d.cts +110 -0
  48. package/dist/device-network-portable.d.ts +110 -0
  49. package/dist/device-network-portable.js +53 -0
  50. package/dist/device-network-portable.js.map +1 -0
  51. package/dist/device-network.cjs +906 -0
  52. package/dist/device-network.cjs.map +1 -0
  53. package/dist/device-network.d.cts +6 -0
  54. package/dist/device-network.d.ts +6 -0
  55. package/dist/device-network.js +59 -0
  56. package/dist/device-network.js.map +1 -0
  57. package/dist/fetchProvider-WWnWnQFP.d.ts +91 -0
  58. package/dist/fetchProvider-toTHy5Nu.d.cts +91 -0
  59. package/dist/index.cjs +28051 -5459
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +94 -1320
  62. package/dist/index.d.ts +94 -1320
  63. package/dist/index.js +10616 -2420
  64. package/dist/index.js.map +1 -1
  65. package/dist/interface-IrKBFtL1.d.cts +493 -0
  66. package/dist/interface-IrKBFtL1.d.ts +493 -0
  67. package/dist/llm-providers.cjs +43 -8
  68. package/dist/llm-providers.cjs.map +1 -1
  69. package/dist/llm-providers.d.cts +2 -1
  70. package/dist/llm-providers.d.ts +2 -1
  71. package/dist/llm-providers.js +4 -2
  72. package/dist/llm-providers.js.map +1 -1
  73. package/dist/loop-api.cjs +5227 -2010
  74. package/dist/loop-api.cjs.map +1 -1
  75. package/dist/loop-api.d.cts +11 -5
  76. package/dist/loop-api.d.ts +11 -5
  77. package/dist/loop-api.js +86 -49
  78. package/dist/mobile.cjs +2711 -0
  79. package/dist/mobile.cjs.map +1 -0
  80. package/dist/mobile.d.cts +6 -0
  81. package/dist/mobile.d.ts +6 -0
  82. package/dist/mobile.js +22 -0
  83. package/dist/mobile.js.map +1 -0
  84. package/dist/orchestration-portable-BHB_YrNN.d.ts +2192 -0
  85. package/dist/orchestration-portable-mvYBvGBb.d.cts +2192 -0
  86. package/dist/orchestration-portable.cjs +9553 -0
  87. package/dist/orchestration-portable.cjs.map +1 -0
  88. package/dist/orchestration-portable.d.cts +5 -0
  89. package/dist/orchestration-portable.d.ts +5 -0
  90. package/dist/orchestration-portable.js +290 -0
  91. package/dist/orchestration-portable.js.map +1 -0
  92. package/dist/pairingInvite-BXPWY3aM.d.cts +149 -0
  93. package/dist/pairingInvite-Cuz0wuq9.d.ts +149 -0
  94. package/dist/promptConcat-0WNFTg4l.d.ts +516 -0
  95. package/dist/promptConcat-D6wr5V-V.d.cts +516 -0
  96. package/dist/providerRegistry-Bi6pAvSj.d.ts +86 -0
  97. package/dist/providerRegistry-CPsktuiX.d.cts +86 -0
  98. package/dist/registry-D0kbxksn.d.cts +393 -0
  99. package/dist/registry-DDbvhlhs.d.ts +393 -0
  100. package/dist/remoteClient-B_spK019.d.ts +87 -0
  101. package/dist/remoteClient-CBggnRy3.d.cts +87 -0
  102. package/dist/runtime-PGWR6FIV.js +18 -0
  103. package/dist/runtime-PGWR6FIV.js.map +1 -0
  104. package/dist/scriptDeploymentPipeline-CXJcC82H.d.ts +2464 -0
  105. package/dist/scriptDeploymentPipeline-yG1ZhVVI.d.cts +2464 -0
  106. package/dist/syncCloudDevices-BEqwgrhD.d.ts +49 -0
  107. package/dist/syncCloudDevices-Ds_Kcgrv.d.cts +49 -0
  108. package/dist/types-7pYti-k9.d.cts +255 -0
  109. package/dist/types-CdFVSntj.d.ts +255 -0
  110. package/package.json +110 -35
  111. package/dist/anthropic.cjs +0 -72
  112. package/dist/anthropic.cjs.map +0 -1
  113. package/dist/anthropic.d.cts +0 -21
  114. package/dist/anthropic.d.ts +0 -21
  115. package/dist/anthropic.js +0 -21
  116. package/dist/anthropic.js.map +0 -1
  117. package/dist/azure.cjs +0 -72
  118. package/dist/azure.cjs.map +0 -1
  119. package/dist/azure.d.cts +0 -21
  120. package/dist/azure.d.ts +0 -21
  121. package/dist/azure.js +0 -21
  122. package/dist/azure.js.map +0 -1
  123. package/dist/chunk-3CN7DFBL.js +0 -4894
  124. package/dist/chunk-3CN7DFBL.js.map +0 -1
  125. package/dist/chunk-4AZ4D7U5.js +0 -32
  126. package/dist/chunk-4AZ4D7U5.js.map +0 -1
  127. package/dist/chunk-6ON4XSOV.js +0 -63
  128. package/dist/chunk-6ON4XSOV.js.map +0 -1
  129. package/dist/chunk-DJQNGIXX.js +0 -4793
  130. package/dist/chunk-DJQNGIXX.js.map +0 -1
  131. package/dist/chunk-FKQP6AOQ.js +0 -32
  132. package/dist/chunk-FKQP6AOQ.js.map +0 -1
  133. package/dist/chunk-OVJ7JJBA.js +0 -35
  134. package/dist/chunk-OVJ7JJBA.js.map +0 -1
  135. package/dist/chunk-P4UZ7IXC.js +0 -42
  136. package/dist/chunk-YHJ2AEFR.js +0 -4933
  137. package/dist/chunk-YHJ2AEFR.js.map +0 -1
  138. package/dist/chunk-YVK7RYRO.js +0 -4973
  139. package/dist/chunk-YVK7RYRO.js.map +0 -1
  140. package/dist/code-assistant.json +0 -114
  141. package/dist/cohere.cjs +0 -72
  142. package/dist/cohere.cjs.map +0 -1
  143. package/dist/cohere.d.cts +0 -21
  144. package/dist/cohere.d.ts +0 -21
  145. package/dist/cohere.js +0 -21
  146. package/dist/cohere.js.map +0 -1
  147. package/dist/deepseek.cjs +0 -72
  148. package/dist/deepseek.cjs.map +0 -1
  149. package/dist/deepseek.d.cts +0 -21
  150. package/dist/deepseek.d.ts +0 -21
  151. package/dist/deepseek.js +0 -21
  152. package/dist/deepseek.js.map +0 -1
  153. package/dist/dist-65U7OYRG.js +0 -1257
  154. package/dist/dist-65U7OYRG.js.map +0 -1
  155. package/dist/fetchProvider-Cu4WkU5O.d.cts +0 -819
  156. package/dist/fetchProvider-Cu4WkU5O.d.ts +0 -819
  157. package/dist/frontend-ui-ux.json +0 -105
  158. package/dist/general-assistant.json +0 -95
  159. package/dist/git-master.json +0 -51
  160. package/dist/google-vertex.cjs +0 -72
  161. package/dist/google-vertex.cjs.map +0 -1
  162. package/dist/google-vertex.d.cts +0 -21
  163. package/dist/google-vertex.d.ts +0 -21
  164. package/dist/google-vertex.js +0 -21
  165. package/dist/google-vertex.js.map +0 -1
  166. package/dist/google.cjs +0 -72
  167. package/dist/google.cjs.map +0 -1
  168. package/dist/google.d.cts +0 -21
  169. package/dist/google.d.ts +0 -21
  170. package/dist/google.js +0 -21
  171. package/dist/google.js.map +0 -1
  172. package/dist/groq.cjs +0 -72
  173. package/dist/groq.cjs.map +0 -1
  174. package/dist/groq.d.cts +0 -21
  175. package/dist/groq.d.ts +0 -21
  176. package/dist/groq.js +0 -21
  177. package/dist/groq.js.map +0 -1
  178. package/dist/index.d.mts +0 -3203
  179. package/dist/index.mjs +0 -7064
  180. package/dist/index.mjs.map +0 -1
  181. package/dist/mistral.cjs +0 -72
  182. package/dist/mistral.cjs.map +0 -1
  183. package/dist/mistral.d.cts +0 -21
  184. package/dist/mistral.d.ts +0 -21
  185. package/dist/mistral.js +0 -21
  186. package/dist/mistral.js.map +0 -1
  187. package/dist/multipart-parser-EJCXIUHC.js +0 -372
  188. package/dist/multipart-parser-EJCXIUHC.js.map +0 -1
  189. package/dist/openai.cjs +0 -72
  190. package/dist/openai.cjs.map +0 -1
  191. package/dist/openai.d.cts +0 -21
  192. package/dist/openai.d.ts +0 -21
  193. package/dist/openai.js +0 -21
  194. package/dist/openai.js.map +0 -1
  195. package/dist/perplexity.cjs +0 -72
  196. package/dist/perplexity.cjs.map +0 -1
  197. package/dist/perplexity.d.cts +0 -21
  198. package/dist/perplexity.d.ts +0 -21
  199. package/dist/perplexity.js +0 -21
  200. package/dist/perplexity.js.map +0 -1
  201. package/dist/playwright.json +0 -52
  202. package/dist/promptConcat-BJdazTg5.d.cts +0 -1832
  203. package/dist/promptConcat-BJdazTg5.d.ts +0 -1832
  204. package/dist/promptConcat-CAkpni_8.d.cts +0 -1834
  205. package/dist/promptConcat-CAkpni_8.d.ts +0 -1834
  206. package/dist/promptConcat-CfH5-GAE.d.cts +0 -1036
  207. package/dist/promptConcat-ChcAZOOL.d.ts +0 -1036
  208. package/dist/promptConcat-G5TnJVRy.d.cts +0 -1800
  209. package/dist/promptConcat-G5TnJVRy.d.ts +0 -1800
  210. package/dist/promptConcat-L72eowzp.d.ts +0 -1090
  211. package/dist/promptConcat-eLHdN7K8.d.cts +0 -1090
  212. package/dist/src-VTSXKG72.js +0 -1409
  213. package/dist/src-VTSXKG72.js.map +0 -1
  214. package/dist/togetherai.cjs +0 -72
  215. package/dist/togetherai.cjs.map +0 -1
  216. package/dist/togetherai.d.cts +0 -21
  217. package/dist/togetherai.d.ts +0 -21
  218. package/dist/togetherai.js +0 -21
  219. package/dist/togetherai.js.map +0 -1
  220. package/dist/types-B0Jm2l38.d.cts +0 -767
  221. package/dist/types-B0Jm2l38.d.ts +0 -767
  222. package/dist/xai.cjs +0 -72
  223. package/dist/xai.cjs.map +0 -1
  224. package/dist/xai.d.cts +0 -21
  225. package/dist/xai.d.ts +0 -21
  226. package/dist/xai.js +0 -21
  227. package/dist/xai.js.map +0 -1
  228. /package/dist/{chunk-P4UZ7IXC.js.map → browser.js.map} +0 -0
@@ -0,0 +1,2711 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/mobile.ts
31
+ var mobile_exports = {};
32
+ __export(mobile_exports, {
33
+ createFetchLLMProvider: () => createFetchLLMProvider,
34
+ getBuiltinLoopProfile: () => getBuiltinLoopProfile,
35
+ getBuiltinLoopProfiles: () => getBuiltinLoopProfiles,
36
+ resolveAgentToolLoopTerminalState: () => resolveAgentToolLoopTerminalState,
37
+ runAgentToolLoopTurn: () => runAgentToolLoopTurn
38
+ });
39
+ module.exports = __toCommonJS(mobile_exports);
40
+
41
+ // src/llm/fetchProvider.ts
42
+ var import_ai = require("ai");
43
+ function createFetchLLMProvider(config) {
44
+ return {
45
+ name: config.name,
46
+ ...config.modelId !== void 0 ? { modelId: config.modelId } : {},
47
+ // Store the factory so hosts can introspect or extend
48
+ model: config.createModel,
49
+ async chat(request) {
50
+ const body = typeof request === "object" && request !== null ? request : {};
51
+ const model = config.createModel(body.model);
52
+ const specificationVersion = model?.specificationVersion;
53
+ if (model === null || typeof model !== "object" || !["v2", "v3", "v4"].includes(String(specificationVersion))) {
54
+ throw new Error(
55
+ `LLM provider '${config.name}' returned an incompatible AI SDK model for '${typeof body.model === "string" ? body.model : config.modelId ?? "default"}' (expected specificationVersion v2, v3, or v4; received ${String(specificationVersion)})`
56
+ );
57
+ }
58
+ const systemMessages = (body.messages ?? []).filter((message) => message.role === "system").map((message) => message.content);
59
+ const messages = (body.messages ?? []).filter((message) => message.role !== "system").map((message) => {
60
+ const role = message.role === "tool" ? "user" : message.role;
61
+ return {
62
+ role,
63
+ content: message.content
64
+ };
65
+ });
66
+ const system = body.system ?? (systemMessages.length > 0 ? systemMessages.join("\n\n") : void 0);
67
+ const temperature = body.temperature;
68
+ const abortSignal = body.abortSignal;
69
+ const maxOutputTokens = body.max_tokens;
70
+ if (body.stream !== false) {
71
+ let streamingError;
72
+ const result2 = (0, import_ai.streamText)({
73
+ model,
74
+ instructions: system,
75
+ messages,
76
+ maxOutputTokens,
77
+ temperature,
78
+ abortSignal,
79
+ onError: ({ error }) => {
80
+ streamingError = error;
81
+ }
82
+ });
83
+ return (async function* () {
84
+ for await (const chunk of result2.textStream) {
85
+ yield chunk;
86
+ }
87
+ if (streamingError !== void 0) {
88
+ throw streamingError instanceof Error ? streamingError : new Error("The model stream failed", { cause: streamingError });
89
+ }
90
+ })();
91
+ }
92
+ const result = await (0, import_ai.generateText)({
93
+ model,
94
+ instructions: system,
95
+ messages,
96
+ maxOutputTokens,
97
+ temperature,
98
+ abortSignal
99
+ });
100
+ return result.text;
101
+ }
102
+ };
103
+ }
104
+
105
+ // src/conversation/parts.ts
106
+ function tryParseJson(value) {
107
+ try {
108
+ return JSON.parse(value);
109
+ } catch {
110
+ return void 0;
111
+ }
112
+ }
113
+ function parseLegacyToolResultContent(content) {
114
+ const match = /(?:<functions_result>\s*)?Tool:\s*(.+?)\nParameters:\s*(.+?)\n(Error|Result):\s*([\s\S]*?)\s*(?:<\/functions_result>|$)/su.exec(content.trim());
115
+ if (!match) return null;
116
+ const [, rawToolName, rawParameters, kind, rawBody] = match;
117
+ const parsedParameters = tryParseJson(rawParameters.trim());
118
+ const result = rawBody.trim();
119
+ return {
120
+ type: "tool-result",
121
+ toolName: rawToolName.trim(),
122
+ parameters: parsedParameters,
123
+ result,
124
+ isError: kind === "Error",
125
+ payload: tryParseJson(result)
126
+ };
127
+ }
128
+ function isTextPart(part) {
129
+ return part.type === "text";
130
+ }
131
+ function isReasoningPart(part) {
132
+ return part.type === "reasoning";
133
+ }
134
+ function isToolCallPart(part) {
135
+ return part.type === "tool-call";
136
+ }
137
+ function isAttachmentPart(part) {
138
+ return part.type === "attachment";
139
+ }
140
+ function isToolResultPart(part) {
141
+ return part.type === "tool-result";
142
+ }
143
+ function buildToolResultSummary(part) {
144
+ const prefix = part.isError ? "Error" : "Result";
145
+ const suffix = part.result.trim();
146
+ if (suffix.length === 0) return `${prefix} from ${part.toolName}`;
147
+ return `${prefix} from ${part.toolName}: ${suffix}`;
148
+ }
149
+ function projectChatMessageParts(parts) {
150
+ const text = parts.filter(isTextPart).map((part) => part.text.trim()).filter(Boolean);
151
+ const reasoning = parts.filter(isReasoningPart).map((part) => part.text.trim()).filter(Boolean);
152
+ const toolCalls = parts.filter(isToolCallPart).map((part) => ({ id: part.toolCallId, toolName: part.toolName, arguments: part.arguments }));
153
+ const attachments = parts.filter(isAttachmentPart).map((part) => part.attachment);
154
+ const toolResults = parts.filter(isToolResultPart);
155
+ let content = text.join("\n\n");
156
+ if (content.length === 0 && toolResults.length > 0) {
157
+ content = toolResults.map(buildToolResultSummary).join("\n\n");
158
+ }
159
+ if (content.length === 0 && toolCalls.length > 0) {
160
+ content = toolCalls.map((part) => `Tool call: ${part.toolName}`).join("\n\n");
161
+ }
162
+ return {
163
+ content,
164
+ reasoning_content: reasoning.length > 0 ? reasoning.join("\n\n") : void 0,
165
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
166
+ attachments: attachments.length > 0 ? attachments : void 0
167
+ };
168
+ }
169
+ function buildLegacyChatMessageParts(input) {
170
+ const parts = [];
171
+ if (input.role !== "tool" && typeof input.content === "string" && input.content.trim().length > 0) {
172
+ parts.push({ type: "text", text: input.content });
173
+ }
174
+ if (typeof input.reasoning_content === "string" && input.reasoning_content.trim().length > 0) {
175
+ parts.push({ type: "reasoning", text: input.reasoning_content });
176
+ }
177
+ if (input.toolCalls) {
178
+ for (const toolCall of input.toolCalls) {
179
+ parts.push({
180
+ type: "tool-call",
181
+ toolCallId: toolCall.id,
182
+ toolName: toolCall.toolName,
183
+ arguments: toolCall.arguments
184
+ });
185
+ }
186
+ }
187
+ if (input.attachments) {
188
+ for (const attachment of input.attachments) {
189
+ parts.push({ type: "attachment", attachment });
190
+ }
191
+ }
192
+ if (input.role === "tool") {
193
+ const metadata = input.metadata ?? {};
194
+ const parsed = typeof input.content === "string" ? parseLegacyToolResultContent(input.content) : null;
195
+ const toolName = typeof metadata.toolId === "string" && metadata.toolId.length > 0 ? metadata.toolId : parsed?.toolName ?? "tool";
196
+ const result = parsed?.result ?? (typeof input.content === "string" ? input.content : "");
197
+ const payload = parsed?.payload ?? tryParseJson(result);
198
+ parts.push({
199
+ type: "tool-result",
200
+ toolName,
201
+ parameters: metadata.toolParameters ?? parsed?.parameters,
202
+ result,
203
+ isError: metadata.isError === true || parsed?.isError === true,
204
+ payload,
205
+ detailRef: input.detailRef
206
+ });
207
+ }
208
+ return parts;
209
+ }
210
+ function getChatMessageParts(message) {
211
+ return message.parts ?? buildLegacyChatMessageParts(message);
212
+ }
213
+
214
+ // src/conversation/factory.ts
215
+ function createChatMessage(input) {
216
+ const now = Date.now();
217
+ const parts = input.parts ?? buildLegacyChatMessageParts({
218
+ role: input.role,
219
+ content: input.content,
220
+ reasoning_content: input.reasoning_content,
221
+ toolCalls: input.toolCalls,
222
+ attachments: input.attachments,
223
+ detailRef: input.detailRef,
224
+ metadata: input.metadata
225
+ });
226
+ const projection = projectChatMessageParts(parts);
227
+ return {
228
+ messageId: input.messageId,
229
+ conversationId: input.conversationId,
230
+ originNodeId: input.originNodeId ?? "unknown",
231
+ timestamp: now,
232
+ lamportClock: input.lamportClock ?? now,
233
+ role: input.role,
234
+ parts: parts.length > 0 ? parts : void 0,
235
+ content: input.content ?? projection.content,
236
+ contentType: input.contentType ?? "text/plain",
237
+ metadata: input.metadata,
238
+ duration: input.duration,
239
+ toolCalls: input.toolCalls ?? projection.toolCalls,
240
+ reasoning_content: input.reasoning_content ?? projection.reasoning_content,
241
+ hidden: input.hidden,
242
+ attachments: input.attachments ?? projection.attachments,
243
+ detailRef: input.detailRef
244
+ };
245
+ }
246
+
247
+ // src/tools/pluginRegistry.ts
248
+ var defaultPluginRegistry = /* @__PURE__ */ new Map();
249
+ var activeOverride = null;
250
+ function getActivePluginRegistry() {
251
+ return activeOverride ?? defaultPluginRegistry;
252
+ }
253
+ function createHookSlot() {
254
+ const handlers = [];
255
+ return {
256
+ handlers,
257
+ tapAsync(_name, function_) {
258
+ handlers.push(function_);
259
+ },
260
+ async promise(context) {
261
+ for (const function_ of handlers) {
262
+ await new Promise((resolve) => {
263
+ function_(context, resolve);
264
+ });
265
+ }
266
+ }
267
+ };
268
+ }
269
+ function createAgentFrameworkHooks() {
270
+ return {
271
+ processPrompts: createHookSlot(),
272
+ finalizePrompts: createHookSlot(),
273
+ postProcess: createHookSlot(),
274
+ userMessageReceived: createHookSlot(),
275
+ agentStatusChanged: createHookSlot(),
276
+ toolExecuted: createHookSlot(),
277
+ responseUpdate: createHookSlot(),
278
+ responseComplete: createHookSlot()
279
+ };
280
+ }
281
+ var hookHandlers = {};
282
+ async function runProcessPromptsHooks(_hooks, context) {
283
+ const slot = _hooks.processPrompts;
284
+ const fns = slot?.handlers ?? hookHandlers.processPrompts ?? [];
285
+ for (const function_ of fns) {
286
+ await new Promise((resolve) => {
287
+ function_(context, resolve);
288
+ });
289
+ }
290
+ return context;
291
+ }
292
+ async function runResponseCompleteHooks(hooks, context) {
293
+ await hooks.responseComplete.promise(context);
294
+ }
295
+ async function runPostProcessHooks(hooks, context) {
296
+ await hooks.postProcess.promise(context);
297
+ }
298
+ function resolvePromptPluginMap(context) {
299
+ const fromTools = context.tools?.getPromptPlugins?.();
300
+ if (fromTools) return fromTools;
301
+ return getActivePluginRegistry();
302
+ }
303
+ async function createHooksWithPlugins(agentFrameworkConfig, options) {
304
+ const reg = options?.pluginRegistry ?? getActivePluginRegistry();
305
+ const hooks = createAgentFrameworkHooks();
306
+ if (agentFrameworkConfig.plugins) {
307
+ for (const pluginConfig of agentFrameworkConfig.plugins) {
308
+ const { toolId } = pluginConfig;
309
+ const plugin = reg.get(toolId);
310
+ if (plugin) {
311
+ plugin(hooks);
312
+ }
313
+ }
314
+ }
315
+ return {
316
+ hooks,
317
+ pluginConfigs: agentFrameworkConfig.plugins ?? []
318
+ };
319
+ }
320
+
321
+ // src/promptUtilities/responseConcat.ts
322
+ function cloneResponses(responses) {
323
+ return structuredClone(responses);
324
+ }
325
+ async function responseConcat(agentFrameworkConfig, llmResponse, agentFrameworkContext, messages) {
326
+ const responses = Array.isArray(agentFrameworkConfig?.response) ? cloneResponses(agentFrameworkConfig.response) : [];
327
+ const toolConfigs = (Array.isArray(agentFrameworkConfig.plugins) ? agentFrameworkConfig.plugins : []).filter((t) => t.enabled !== false);
328
+ const hooks = createAgentFrameworkHooks();
329
+ const pluginMap = resolvePromptPluginMap(agentFrameworkContext);
330
+ for (const tool of toolConfigs) {
331
+ const builtInTool = pluginMap.get(tool.toolId);
332
+ if (builtInTool) {
333
+ builtInTool(hooks);
334
+ }
335
+ }
336
+ let yieldNextRoundTo;
337
+ let toolCallInfo;
338
+ for (const tool of toolConfigs) {
339
+ const responseContext = {
340
+ agentFrameworkContext,
341
+ messages,
342
+ prompts: [],
343
+ toolConfig: tool,
344
+ llmResponse,
345
+ responses,
346
+ metadata: {},
347
+ actions: {}
348
+ };
349
+ await runPostProcessHooks(hooks, responseContext);
350
+ if (responseContext.actions?.yieldNextRoundTo) {
351
+ yieldNextRoundTo = responseContext.actions.yieldNextRoundTo;
352
+ if (responseContext.actions.toolCalling) {
353
+ toolCallInfo = responseContext.actions.toolCalling;
354
+ }
355
+ }
356
+ }
357
+ const processedResponse = flattenResponses(responses);
358
+ return {
359
+ processedResponse: processedResponse || llmResponse,
360
+ yieldNextRoundTo,
361
+ toolCallInfo
362
+ };
363
+ }
364
+ function flattenResponses(responses) {
365
+ if (responses.length === 0) {
366
+ return "";
367
+ }
368
+ return responses.filter((response) => response.enabled !== false).map((response) => response.text || "").join("\n\n").trim();
369
+ }
370
+
371
+ // src/promptUtilities/responsePatternUtility.ts
372
+ var import_json5 = __toESM(require("json5"), 1);
373
+ var MAX_FALLBACK_INPUT_LENGTH = 1e3;
374
+ var TOOL_PARAMETER_PARSE_ERROR_KEY = "__memeloopToolParameterParseError";
375
+ function parseToolParameters(parametersText) {
376
+ if (!parametersText || !parametersText.trim()) {
377
+ return {};
378
+ }
379
+ const trimmedText = parametersText.trim();
380
+ try {
381
+ return JSON.parse(trimmedText);
382
+ } catch {
383
+ }
384
+ try {
385
+ return import_json5.default.parse(trimmedText);
386
+ } catch {
387
+ }
388
+ return {
389
+ [TOOL_PARAMETER_PARSE_ERROR_KEY]: `Invalid tool arguments JSON. Return one valid JSON object inside the tool tag. Received: ${trimmedText.substring(0, MAX_FALLBACK_INPUT_LENGTH)}`
390
+ };
391
+ }
392
+ function extractFunctionCallsParameters(text) {
393
+ const parameters = {};
394
+ const parameterRegex = /<parameter\s+name="([^"]+)"[^>]*>([^<]*)<\/parameter>/g;
395
+ let m;
396
+ while ((m = parameterRegex.exec(text)) !== null) {
397
+ parameters[m[1]] = m[2].trim();
398
+ }
399
+ return parameters;
400
+ }
401
+ var toolPatterns = [
402
+ {
403
+ name: "tool_use",
404
+ pattern: /<tool_use\s+name="([^"]+)"[^>]*>(.*?)<\/tool_use>/gis,
405
+ extractToolId: (match) => match[1],
406
+ extractParams: (match) => match[2],
407
+ extractOriginalText: (match) => match[0]
408
+ },
409
+ {
410
+ name: "function_call",
411
+ pattern: /<function_call\s+name="([^"]+)"[^>]*>(.*?)<\/function_call>/gis,
412
+ extractToolId: (match) => match[1],
413
+ extractParams: (match) => match[2],
414
+ extractOriginalText: (match) => match[0]
415
+ },
416
+ {
417
+ name: "function_calls_invoke",
418
+ pattern: /<invoke\s+name="([^"]+)"[^>]*>(.*?)<\/invoke>/gis,
419
+ extractToolId: (match) => match[1],
420
+ extractParams: (match) => JSON.stringify(extractFunctionCallsParameters(match[2])),
421
+ extractOriginalText: (match) => match[0]
422
+ }
423
+ ];
424
+ function matchAllToolCallings(responseText) {
425
+ const calls = [];
426
+ const parallel = /<parallel_tool_calls>/i.test(responseText);
427
+ try {
428
+ for (const toolPattern of toolPatterns) {
429
+ toolPattern.pattern.lastIndex = 0;
430
+ let match;
431
+ while ((match = toolPattern.pattern.exec(responseText)) !== null) {
432
+ calls.push({
433
+ found: true,
434
+ toolId: toolPattern.extractToolId(match),
435
+ parameters: parseToolParameters(toolPattern.extractParams(match)),
436
+ originalText: toolPattern.extractOriginalText(match)
437
+ });
438
+ }
439
+ }
440
+ } catch {
441
+ }
442
+ return { calls, parallel };
443
+ }
444
+
445
+ // src/storage/nextLamport.ts
446
+ async function nextLamportClockForConversation(storage, conversationId) {
447
+ if (typeof storage.getMaxLamportClockForConversation === "function") {
448
+ const max2 = await storage.getMaxLamportClockForConversation(conversationId);
449
+ return max2 + 1;
450
+ }
451
+ const msgs = await storage.getMessages(conversationId, { mode: "full-content" });
452
+ let max = 0;
453
+ for (const m of msgs) {
454
+ if (typeof m.lamportClock === "number" && m.lamportClock > max) {
455
+ max = m.lamportClock;
456
+ }
457
+ }
458
+ return max + 1;
459
+ }
460
+
461
+ // src/loopAPI/hooks/registry.ts
462
+ var HookRegistry = class {
463
+ hookRegistry = /* @__PURE__ */ new Map();
464
+ hookOrder = /* @__PURE__ */ new Map();
465
+ /**
466
+ * Register a hook handler for a specific lifecycle event.
467
+ */
468
+ registerHook(type, handler, name) {
469
+ const key = name ?? `hook:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;
470
+ const handlers = this.hookOrder.get(type) ?? [];
471
+ handlers.push(handler);
472
+ this.hookOrder.set(type, handlers);
473
+ const map = this.hookRegistry.get(type) ?? /* @__PURE__ */ new Map();
474
+ map.set(key, handler);
475
+ this.hookRegistry.set(type, map);
476
+ }
477
+ /**
478
+ * Unregister a specific hook handler by name.
479
+ */
480
+ unregisterHook(type, name) {
481
+ const map = this.hookRegistry.get(type);
482
+ if (!map) return false;
483
+ const deleted = map.delete(name);
484
+ if (deleted) {
485
+ this.hookOrder.set(type, Array.from(map.values()));
486
+ }
487
+ return deleted;
488
+ }
489
+ /**
490
+ * Execute all registered hooks for a given type in registration order.
491
+ */
492
+ async executeHooks(type, context, data) {
493
+ const handlers = this.hookOrder.get(type);
494
+ if (!handlers || handlers.length === 0) {
495
+ return { allowed: true };
496
+ }
497
+ let currentData = data;
498
+ let mergedModified;
499
+ let permissionAction;
500
+ for (const handler of handlers) {
501
+ try {
502
+ const result = await handler(context, currentData);
503
+ if (result.modified) {
504
+ mergedModified = { ...mergedModified ?? {}, ...result.modified };
505
+ currentData = { ...currentData, ...result.modified };
506
+ }
507
+ if (result.permissionAction && result.permissionAction !== "allow") {
508
+ permissionAction = result.permissionAction;
509
+ }
510
+ if (!result.allowed) {
511
+ return {
512
+ ...result,
513
+ modified: mergedModified ?? result.modified,
514
+ permissionAction: permissionAction ?? result.permissionAction
515
+ };
516
+ }
517
+ } catch (error) {
518
+ return {
519
+ allowed: false,
520
+ reason: error instanceof Error ? error.message : "Hook execution failed",
521
+ modified: mergedModified,
522
+ permissionAction
523
+ };
524
+ }
525
+ }
526
+ const finalResult = { allowed: true };
527
+ if (mergedModified) finalResult.modified = mergedModified;
528
+ if (permissionAction) finalResult.permissionAction = permissionAction;
529
+ return finalResult;
530
+ }
531
+ /**
532
+ * Check if any hooks are registered for a given type.
533
+ */
534
+ hasHooks(type) {
535
+ const map = this.hookRegistry.get(type);
536
+ return map != null && map.size > 0;
537
+ }
538
+ /**
539
+ * Remove all registered hooks of all types.
540
+ */
541
+ clearHooks() {
542
+ this.hookRegistry.clear();
543
+ this.hookOrder.clear();
544
+ }
545
+ /**
546
+ * List all hook types that have at least one registered handler.
547
+ */
548
+ listRegisteredHookTypes() {
549
+ const types = [];
550
+ for (const [type, map] of this.hookRegistry) {
551
+ if (map.size > 0) {
552
+ types.push(type);
553
+ }
554
+ }
555
+ return types;
556
+ }
557
+ /**
558
+ * Get the count of registered handlers for a hook type.
559
+ */
560
+ getHookCount(type) {
561
+ const map = this.hookRegistry.get(type);
562
+ return map?.size ?? 0;
563
+ }
564
+ };
565
+ var defaultHookRegistry = new HookRegistry();
566
+ async function executeHooks(type, context, data) {
567
+ return defaultHookRegistry.executeHooks(type, context, data);
568
+ }
569
+ function hasHooks(type) {
570
+ return defaultHookRegistry.hasHooks(type);
571
+ }
572
+
573
+ // src/loopAPI/agent-tool-loop/compaction.ts
574
+ function countTurns(messages) {
575
+ let turns = 0;
576
+ for (const message of messages) {
577
+ if (message.role === "user") {
578
+ turns++;
579
+ }
580
+ }
581
+ return turns;
582
+ }
583
+ function estimateTokens(messages) {
584
+ let total = 0;
585
+ for (const message of messages) {
586
+ const content = typeof message.content === "string" ? message.content : JSON.stringify(message.content);
587
+ total += content.length / 3.5;
588
+ }
589
+ return Math.ceil(total);
590
+ }
591
+ function buildTruncationSummary(dropped, totalDropped) {
592
+ const turns = countTurns(dropped);
593
+ const oldest = dropped[0];
594
+ const newest = dropped[dropped.length - 1];
595
+ const oldestTime = oldest?.timestamp ? new Date(oldest.timestamp).toISOString() : "unknown";
596
+ const newestTime = newest?.timestamp ? new Date(newest.timestamp).toISOString() : "unknown";
597
+ return `[context-summary] ${totalDropped} earlier messages (${turns} turns, ${oldestTime} \u2192 ${newestTime}) were compacted. Key topics: see recent messages below.`;
598
+ }
599
+ function createSummaryMessage(conversationId, summaryText, baseMessage) {
600
+ return {
601
+ messageId: `${conversationId}:compacted:${Date.now().toString(36)}`,
602
+ conversationId,
603
+ originNodeId: baseMessage.originNodeId,
604
+ timestamp: Date.now(),
605
+ lamportClock: -1,
606
+ // Will be replaced by AgentToolLoop
607
+ role: "assistant",
608
+ content: summaryText,
609
+ metadata: { compacted: true }
610
+ };
611
+ }
612
+ function compactMessages(messages, options = {}) {
613
+ const recentTurnsToKeep = options.recentTurnsToKeep ?? 4;
614
+ if (messages.length <= recentTurnsToKeep * 2) {
615
+ return { messages, compacted: false, droppedCount: 0, summaryText: "" };
616
+ }
617
+ const userIndices = [];
618
+ for (let index = 0; index < messages.length; index++) {
619
+ if (messages[index].role === "user") {
620
+ userIndices.push(index);
621
+ }
622
+ }
623
+ if (userIndices.length <= recentTurnsToKeep) {
624
+ return { messages, compacted: false, droppedCount: 0, summaryText: "" };
625
+ }
626
+ const keepStartIndex = userIndices[userIndices.length - recentTurnsToKeep];
627
+ const dropped = messages.slice(0, keepStartIndex);
628
+ const kept = messages.slice(keepStartIndex);
629
+ if (dropped.length === 0) {
630
+ return { messages, compacted: false, droppedCount: 0, summaryText: "" };
631
+ }
632
+ const conversationId = messages[0]?.conversationId ?? "unknown";
633
+ const summaryText = buildTruncationSummary(dropped, dropped.length);
634
+ const summaryMessage = createSummaryMessage(conversationId, summaryText, messages[0]);
635
+ const compacted = [summaryMessage, ...kept];
636
+ return {
637
+ messages: compacted,
638
+ compacted: true,
639
+ droppedCount: dropped.length,
640
+ summaryText
641
+ };
642
+ }
643
+ function shouldCompact(messages, threshold) {
644
+ const t = threshold ?? 50;
645
+ return messages.length > t;
646
+ }
647
+ async function autoCompact(messages, options = {}) {
648
+ const recentTurnsToKeep = options.recentTurnsToKeep ?? 4;
649
+ if (options.maxTokens && options.maxTokens > 0) {
650
+ const currentTokens = estimateTokens(messages);
651
+ if (currentTokens <= options.maxTokens) {
652
+ return { messages, compacted: false, droppedCount: 0, summaryText: "" };
653
+ }
654
+ }
655
+ if (options.useLlmSummary !== false && options.llmProvider?.model != null) {
656
+ try {
657
+ const result = await llmCompact(messages, options.llmProvider, recentTurnsToKeep);
658
+ if (result) return result;
659
+ } catch {
660
+ }
661
+ }
662
+ return compactMessages(messages, { ...options });
663
+ }
664
+ async function llmCompact(messages, llmProvider, recentTurnsToKeep) {
665
+ const userIndices = [];
666
+ for (let index = 0; index < messages.length; index++) {
667
+ if (messages[index].role === "user") {
668
+ userIndices.push(index);
669
+ }
670
+ }
671
+ if (userIndices.length <= recentTurnsToKeep) {
672
+ return null;
673
+ }
674
+ const keepStartIndex = userIndices[userIndices.length - recentTurnsToKeep];
675
+ const toSummarize = messages.slice(0, keepStartIndex);
676
+ const kept = messages.slice(keepStartIndex);
677
+ if (toSummarize.length === 0) return null;
678
+ const conversationId = messages[0]?.conversationId ?? "unknown";
679
+ const conversationText = toSummarize.map((m) => {
680
+ const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
681
+ const toolId = typeof m.metadata?.toolId === "string" ? m.metadata.toolId : "unknown";
682
+ const roleLabel = m.role === "tool" ? `[tool: ${toolId}]` : `[${m.role}]`;
683
+ if (m.role === "tool" && content.length > 500) {
684
+ return `${roleLabel} ${content.slice(0, 500)}... (truncated)`;
685
+ }
686
+ return `${roleLabel} ${content}`;
687
+ }).join("\n\n");
688
+ const prompt = `Summarize the following conversation excerpt. Be concise but capture key decisions, action items, tool calls, and important context. Focus on information useful for continuing the conversation.
689
+
690
+ <conversation>
691
+ ${conversationText.slice(0, 8e3)}
692
+ </conversation>
693
+
694
+ Provide a brief summary (3-5 paragraphs) of the key points.`;
695
+ try {
696
+ const summaryText = await generateSummary(llmProvider, prompt);
697
+ if (!summaryText || summaryText.length < 10) return null;
698
+ const summaryMessage = createSummaryMessage(
699
+ conversationId,
700
+ `[context-summary] ${summaryText}`,
701
+ messages[0]
702
+ );
703
+ return {
704
+ messages: [summaryMessage, ...kept],
705
+ compacted: true,
706
+ droppedCount: toSummarize.length,
707
+ summaryText
708
+ };
709
+ } catch {
710
+ return null;
711
+ }
712
+ }
713
+ async function generateSummary(llmProvider, prompt) {
714
+ if (typeof llmProvider.chat !== "function") return null;
715
+ const raw = llmProvider.chat({ messages: [{ role: "user", content: prompt }] });
716
+ let resolved = raw;
717
+ if (resolved != null && typeof resolved.then === "function") {
718
+ resolved = await resolved;
719
+ }
720
+ if (resolved != null && typeof resolved[Symbol.asyncIterator] === "function") {
721
+ let text = "";
722
+ for await (const chunk of resolved) {
723
+ text += chunkToText(chunk);
724
+ }
725
+ return text || null;
726
+ }
727
+ if (typeof resolved === "string") return resolved;
728
+ return null;
729
+ }
730
+ function chunkToText(chunk) {
731
+ if (typeof chunk === "string") return chunk;
732
+ if (chunk != null && typeof chunk === "object" && "content" in chunk) {
733
+ const content = chunk.content;
734
+ return typeof content === "string" ? content : JSON.stringify(content);
735
+ }
736
+ return JSON.stringify(chunk);
737
+ }
738
+
739
+ // src/loopAPI/agent-tool-loop/historyCompaction.ts
740
+ function compactHistory(history, options) {
741
+ const maxMessages = options?.contextCompaction?.maxMessages ?? 0;
742
+ if (maxMessages <= 0 || history.length <= maxMessages) return history;
743
+ const dropped = history.length - maxMessages;
744
+ const tail = history.slice(-maxMessages);
745
+ const summaryMessage = {
746
+ ...tail[0],
747
+ messageId: `${tail[0]?.conversationId ?? "unknown"}:summary:${Date.now().toString(36)}`,
748
+ role: "assistant",
749
+ content: `[context-summary] ${dropped} earlier messages were compacted.`
750
+ };
751
+ if (options?.contextCompaction?.replayLastUserMessage === false) return tail;
752
+ const lastUser = [...history].reverse().find((message) => message.role === "user");
753
+ if (!lastUser) return [summaryMessage, ...tail];
754
+ if (tail.some((message) => message.messageId === lastUser.messageId)) return tail;
755
+ return [summaryMessage, lastUser, ...tail];
756
+ }
757
+ function asChatMessages(value) {
758
+ if (!Array.isArray(value)) return void 0;
759
+ if (!value.every((message) => message != null && typeof message === "object")) return void 0;
760
+ return value;
761
+ }
762
+ function buildCompactedStep(conversationId, iteration, droppedCount, summaryText) {
763
+ return {
764
+ type: "thinking",
765
+ data: {
766
+ status: "compacted",
767
+ conversationId,
768
+ droppedCount: typeof droppedCount === "number" ? droppedCount : 0,
769
+ summaryText: typeof summaryText === "string" ? summaryText : "",
770
+ iteration
771
+ }
772
+ };
773
+ }
774
+ async function persistSummaryMessage(context, conversationId, summaryMessage) {
775
+ if (!summaryMessage) return;
776
+ const lamportSummary = await nextLamportClockForConversation(context.storage, conversationId);
777
+ await context.storage.appendMessage({
778
+ ...summaryMessage,
779
+ lamportClock: lamportSummary
780
+ });
781
+ }
782
+ async function maybeApplyContextCompactionHook(options) {
783
+ const { context, conversationId, iteration, history, agentToolLoopOptions } = options;
784
+ if (!hasHooks("ContextCompaction")) {
785
+ return { handled: false, history, steps: [] };
786
+ }
787
+ const hookResult = await executeHooks("ContextCompaction", context, {
788
+ conversationId,
789
+ iteration,
790
+ history,
791
+ autoCompact: agentToolLoopOptions?.autoCompact,
792
+ contextCompaction: agentToolLoopOptions?.contextCompaction
793
+ });
794
+ const modified = hookResult.modified;
795
+ const modifiedHistory = asChatMessages(modified?.history);
796
+ const nextHistory = modifiedHistory ?? history;
797
+ const skipDefault = !hookResult.allowed || modifiedHistory != null || modified?.skipDefault === true;
798
+ if (!skipDefault) {
799
+ return { handled: false, history: nextHistory, steps: [] };
800
+ }
801
+ const steps = modified?.compacted === true ? [buildCompactedStep(conversationId, iteration, modified.droppedCount, modified.summaryText)] : [];
802
+ if (modified?.persistSummaryMessage === true) {
803
+ await persistSummaryMessage(context, conversationId, nextHistory[0]);
804
+ }
805
+ return { handled: true, history: nextHistory, steps };
806
+ }
807
+ async function applyBuiltInAutoCompact(options) {
808
+ const { context, conversationId, iteration, agentToolLoopOptions } = options;
809
+ let history = options.history;
810
+ const autoCompactOptions = agentToolLoopOptions?.autoCompact;
811
+ if (!autoCompactOptions) {
812
+ return { history, steps: [] };
813
+ }
814
+ const threshold = autoCompactOptions.threshold ?? 50;
815
+ if (!shouldCompact(history, threshold)) {
816
+ return { history, steps: [] };
817
+ }
818
+ try {
819
+ const result = await autoCompact(history, {
820
+ recentTurnsToKeep: autoCompactOptions.recentTurnsToKeep ?? 4,
821
+ maxTokens: autoCompactOptions.maxTokens ?? 0,
822
+ llmProvider: context.llmProvider
823
+ });
824
+ if (!result.compacted) {
825
+ return { history, steps: [] };
826
+ }
827
+ history = result.messages;
828
+ await persistSummaryMessage(context, conversationId, result.messages[0]);
829
+ return {
830
+ history,
831
+ steps: [
832
+ buildCompactedStep(conversationId, iteration, result.droppedCount, result.summaryText)
833
+ ]
834
+ };
835
+ } catch (error) {
836
+ if (context.logger?.warn) {
837
+ context.logger.warn("[agentToolLoop] auto-compact failed:", error);
838
+ } else {
839
+ console.warn("[agentToolLoop] auto-compact failed:", error);
840
+ }
841
+ return { history, steps: [] };
842
+ }
843
+ }
844
+ async function prepareIterationHistory(options) {
845
+ const { agentToolLoopOptions } = options;
846
+ const hookResult = await maybeApplyContextCompactionHook({
847
+ ...options,
848
+ history: options.rawHistory
849
+ });
850
+ if (hookResult.handled) {
851
+ return hookResult;
852
+ }
853
+ const autoCompactResult = await applyBuiltInAutoCompact({
854
+ ...options,
855
+ history: hookResult.history
856
+ });
857
+ return {
858
+ history: compactHistory(autoCompactResult.history, agentToolLoopOptions),
859
+ steps: autoCompactResult.steps
860
+ };
861
+ }
862
+
863
+ // src/loopAPI/agent-tool-loop/llmStream.ts
864
+ function isAsyncIterable(value) {
865
+ return value != null && typeof value[Symbol.asyncIterator] === "function";
866
+ }
867
+ function chunkToText2(chunk) {
868
+ if (typeof chunk === "string") return chunk;
869
+ if (chunk != null && typeof chunk === "object" && "content" in chunk) {
870
+ const content = chunk.content;
871
+ return typeof content === "string" ? content : JSON.stringify(content);
872
+ }
873
+ return JSON.stringify(chunk);
874
+ }
875
+ async function* streamLlm(context, request) {
876
+ const chatFunction = context.llmProvider.chat;
877
+ if (typeof chatFunction !== "function") {
878
+ throw new Error(
879
+ "LLM provider does not support legacy chat() method. Use AI SDK's streamText instead."
880
+ );
881
+ }
882
+ const raw = chatFunction(request);
883
+ let resolved = raw;
884
+ if (resolved != null && typeof resolved.then === "function") {
885
+ resolved = await resolved;
886
+ }
887
+ if (isAsyncIterable(resolved)) {
888
+ for await (const chunk of resolved) {
889
+ yield chunk;
890
+ }
891
+ return;
892
+ }
893
+ yield resolved;
894
+ }
895
+
896
+ // src/promptUtilities/promptConcat.ts
897
+ function collectPromptSourcePaths(prompts, basePath = "agentFrameworkConfig.prompts") {
898
+ const out = {};
899
+ function walk(nodes, prefix) {
900
+ nodes.forEach((n, index) => {
901
+ const p = `${prefix}.${index}`;
902
+ if (n.id) {
903
+ out[n.id] = p;
904
+ }
905
+ if (n.children?.length) {
906
+ walk(n.children, `${p}.children`);
907
+ }
908
+ });
909
+ }
910
+ walk(prompts, basePath);
911
+ return out;
912
+ }
913
+ var logger = {
914
+ debug: (..._arguments) => {
915
+ },
916
+ info: (..._arguments) => {
917
+ },
918
+ warn: (..._arguments) => {
919
+ },
920
+ error: (..._arguments) => {
921
+ }
922
+ };
923
+ function flattenPrompts(prompts) {
924
+ const result = [];
925
+ function processPrompt(prompt) {
926
+ let text = prompt.text ?? "";
927
+ if (prompt.children) {
928
+ for (const child of prompt.children) {
929
+ if (!child.role) {
930
+ text += processPrompt(child);
931
+ }
932
+ }
933
+ }
934
+ return text;
935
+ }
936
+ function collectRolePrompts(nodes) {
937
+ for (const prompt of nodes) {
938
+ if (prompt.enabled === false) continue;
939
+ const content = processPrompt(prompt);
940
+ if (content.trim() || prompt.role) {
941
+ result.push({
942
+ role: prompt.role ?? "system",
943
+ content: content.trim()
944
+ });
945
+ }
946
+ if (prompt.children) {
947
+ collectRolePrompts(prompt.children);
948
+ }
949
+ }
950
+ }
951
+ collectRolePrompts(prompts);
952
+ return result;
953
+ }
954
+ async function* promptConcatStream(agentConfig, messages, agentFrameworkContext, options) {
955
+ const frameworkConfig = agentConfig.agentFrameworkConfig;
956
+ const promptConfigs = frameworkConfig?.prompts ?? [];
957
+ const plugins = frameworkConfig?.plugins ?? [];
958
+ const hooks = createAgentFrameworkHooks();
959
+ const pluginMap = resolvePromptPluginMap(agentFrameworkContext);
960
+ for (const plugin of plugins) {
961
+ const entry = pluginMap.get(plugin.toolId);
962
+ if (entry) entry(hooks);
963
+ }
964
+ let processedContext = { prompts: promptConfigs };
965
+ for (let index = 0; index < plugins.length; index++) {
966
+ const plugin = plugins[index];
967
+ processedContext = await runProcessPromptsHooks(hooks, {
968
+ prompts: processedContext.prompts,
969
+ messages,
970
+ toolConfig: plugin,
971
+ pluginIndex: index,
972
+ agentFrameworkContext
973
+ });
974
+ }
975
+ const processed = processedContext.prompts;
976
+ const flat = flattenPrompts(processed);
977
+ const last = messages[messages.length - 1];
978
+ if (last && last.role === "user") {
979
+ const content = last.content;
980
+ const fileMeta = last.metadata?.file;
981
+ if (fileMeta?.path && options?.readAttachmentFile) {
982
+ try {
983
+ const buf = await options.readAttachmentFile(fileMeta.path);
984
+ flat.push({
985
+ role: "user",
986
+ content: [
987
+ { type: "image", image: buf },
988
+ { type: "text", text: content }
989
+ ]
990
+ });
991
+ } catch (error) {
992
+ logger.error("failed to read attached file", { error, path: fileMeta.path });
993
+ }
994
+ } else if (fileMeta?.path && !options?.readAttachmentFile) {
995
+ flat.push({
996
+ role: "user",
997
+ content: `[attached path: ${fileMeta.path}]
998
+ ${content}`
999
+ });
1000
+ } else {
1001
+ flat.push({ role: "user", content });
1002
+ }
1003
+ }
1004
+ const state = {
1005
+ processedPrompts: processed,
1006
+ flatPrompts: flat,
1007
+ step: "complete",
1008
+ isComplete: true,
1009
+ sourcePaths: collectPromptSourcePaths(processed)
1010
+ };
1011
+ yield state;
1012
+ return state;
1013
+ }
1014
+
1015
+ // src/promptUtilities/utilities.ts
1016
+ function filterOldMessagesByDuration(messages, maxAgeMs, now = Date.now()) {
1017
+ if (maxAgeMs <= 0) return messages;
1018
+ const cutoff = now - maxAgeMs;
1019
+ return messages.filter((m) => typeof m.timestamp === "number" && m.timestamp >= cutoff);
1020
+ }
1021
+
1022
+ // src/loopAPI/agent-tool-loop/toolResultMessage.ts
1023
+ function formatToolResultMessage(toolName, parameters, body, isError) {
1024
+ return `<functions_result>
1025
+ Tool: ${toolName}
1026
+ Parameters: ${JSON.stringify(parameters)}
1027
+ ${isError ? "Error" : "Result"}: ${body}
1028
+ </functions_result>`;
1029
+ }
1030
+
1031
+ // src/loopAPI/agent-tool-loop/modelMessages.ts
1032
+ function chatMessageToModelMessage(message) {
1033
+ const role = message.role === "agent" || message.role === "error" ? "assistant" : message.role === "tool" ? "tool" : message.role === "user" ? "user" : "assistant";
1034
+ if (role === "tool") {
1035
+ const toolResults = getChatMessageParts(message).filter(isToolResultPart);
1036
+ if (toolResults.length > 0) {
1037
+ return {
1038
+ role,
1039
+ content: toolResults.map(
1040
+ (part) => formatToolResultMessage(
1041
+ part.toolName,
1042
+ part.parameters && typeof part.parameters === "object" ? part.parameters : {},
1043
+ part.result,
1044
+ part.isError === true
1045
+ )
1046
+ ).join("\n\n")
1047
+ };
1048
+ }
1049
+ }
1050
+ return {
1051
+ role,
1052
+ content: message.content
1053
+ };
1054
+ }
1055
+ async function resolveAgentDefinitionModel(context, definitionId) {
1056
+ if (context.resolveAgentDefinition) {
1057
+ return context.resolveAgentDefinition(definitionId);
1058
+ }
1059
+ return context.storage.getAgentDefinition(definitionId);
1060
+ }
1061
+ async function inferDefinitionId(storage, conversationId) {
1062
+ try {
1063
+ const meta = await storage.getConversationMeta(conversationId);
1064
+ if (meta?.definitionId) return meta.definitionId;
1065
+ } catch {
1066
+ }
1067
+ const parts = conversationId.split(":");
1068
+ if (parts.length >= 2) {
1069
+ return parts.slice(0, -1).join(":");
1070
+ }
1071
+ return conversationId;
1072
+ }
1073
+ async function buildLlmMessages(context, conversationId, history) {
1074
+ const definitionId = await inferDefinitionId(context.storage, conversationId);
1075
+ const definition = await resolveAgentDefinitionModel(context, definitionId);
1076
+ const fw = definition?.agentFrameworkConfig;
1077
+ const maxHistoryAgeMs = context.agentToolLoop?.maxHistoryAgeMs ?? 0;
1078
+ const historyForPrompt = maxHistoryAgeMs > 0 ? filterOldMessagesByDuration(history, maxHistoryAgeMs) : history;
1079
+ if (fw?.prompts && Array.isArray(fw.prompts) && fw.prompts.length > 0) {
1080
+ const readAttachmentFile = context.agentToolLoop?.readAttachmentFile;
1081
+ const gen = promptConcatStream(
1082
+ {
1083
+ agentFrameworkConfig: {
1084
+ prompts: fw.prompts,
1085
+ plugins: fw.plugins ?? [],
1086
+ response: []
1087
+ }
1088
+ },
1089
+ historyForPrompt,
1090
+ context,
1091
+ readAttachmentFile ? { readAttachmentFile } : void 0
1092
+ );
1093
+ let lastFlat = [];
1094
+ for await (const state of gen) {
1095
+ lastFlat = state.flatPrompts;
1096
+ }
1097
+ const withoutTrailingUser = lastFlat.length > 0 && lastFlat[lastFlat.length - 1]?.role === "user" ? lastFlat.slice(0, -1) : lastFlat;
1098
+ return [...withoutTrailingUser, ...historyForPrompt.map(chatMessageToModelMessage)];
1099
+ }
1100
+ const systemText = typeof definition?.systemPrompt === "string" ? definition.systemPrompt.trim() : "";
1101
+ if (systemText.length > 0) {
1102
+ return [
1103
+ { role: "system", content: systemText },
1104
+ ...historyForPrompt.map(chatMessageToModelMessage)
1105
+ ];
1106
+ }
1107
+ return historyForPrompt.map(chatMessageToModelMessage);
1108
+ }
1109
+
1110
+ // src/orchestration/drivers/unknownEffect.ts
1111
+ var DEFAULT_MAX_ATTEMPTS = 3;
1112
+ function attemptsOf(operation) {
1113
+ return operation.status?.attempts ?? 0;
1114
+ }
1115
+ function maxAttemptsOf(operation) {
1116
+ return operation.spec.retry?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
1117
+ }
1118
+ function reconcileUnknownEffect(operation, evidence) {
1119
+ if (evidence.resultObserved) {
1120
+ return { action: "succeeded", reason: "result was observed before the disconnect; only the ack was lost" };
1121
+ }
1122
+ if (operation.spec.retry?.nonRetryable) {
1123
+ return { action: "manual-intervention", reason: "operation is marked nonRetryable and its effect is unknown" };
1124
+ }
1125
+ const attempts = attemptsOf(operation);
1126
+ const maxAttempts = maxAttemptsOf(operation);
1127
+ const withinBudget = attempts < maxAttempts;
1128
+ if (operation.spec.effect === "read") {
1129
+ if (withinBudget) {
1130
+ return { action: "retry", reason: `read effect has no side effects (attempt ${attempts + 1}/${maxAttempts})` };
1131
+ }
1132
+ return { action: "verification-required", reason: `read retry budget exhausted (${attempts}/${maxAttempts})` };
1133
+ }
1134
+ if (operation.spec.idempotencyKey) {
1135
+ if (withinBudget) {
1136
+ return {
1137
+ action: "retry",
1138
+ reason: `idempotencyKey deduplicates repeated delivery (attempt ${attempts + 1}/${maxAttempts})`
1139
+ };
1140
+ }
1141
+ return {
1142
+ action: "verification-required",
1143
+ reason: `idempotent retry budget exhausted (${attempts}/${maxAttempts}); verify before further attempts`
1144
+ };
1145
+ }
1146
+ return {
1147
+ action: "verification-required",
1148
+ reason: `effect '${operation.spec.effect}' without idempotencyKey must be verified before any retry`
1149
+ };
1150
+ }
1151
+
1152
+ // src/orchestration/errors.ts
1153
+ var OrchestrationError = class extends Error {
1154
+ code;
1155
+ retryable;
1156
+ retryAfterMs;
1157
+ reason;
1158
+ details;
1159
+ constructor(data) {
1160
+ super(data.message);
1161
+ this.name = "OrchestrationError";
1162
+ this.code = data.code;
1163
+ this.retryable = data.retryable;
1164
+ this.retryAfterMs = data.retryAfterMs;
1165
+ this.reason = data.reason;
1166
+ this.details = data.details;
1167
+ }
1168
+ toJSON() {
1169
+ return {
1170
+ code: this.code,
1171
+ message: this.message,
1172
+ retryable: this.retryable,
1173
+ retryAfterMs: this.retryAfterMs,
1174
+ reason: this.reason,
1175
+ details: this.details
1176
+ };
1177
+ }
1178
+ };
1179
+
1180
+ // src/orchestration/resources.ts
1181
+ var TOOL_OPERATION_API_VERSION = "execution.memeloop.io/v1alpha1";
1182
+ var TOOL_OPERATION_KIND = "ToolOperation";
1183
+ function createToolOperationManifest(name, spec) {
1184
+ return {
1185
+ apiVersion: TOOL_OPERATION_API_VERSION,
1186
+ kind: TOOL_OPERATION_KIND,
1187
+ metadata: { name },
1188
+ spec
1189
+ };
1190
+ }
1191
+
1192
+ // src/tools/structuredToolResult.ts
1193
+ var MEMELOOP_STRUCTURED_TOOL_KEY = "__memeloopToolResult";
1194
+ function truncateToolSummary(s, max = 2e3) {
1195
+ if (s.length <= max) return s;
1196
+ return `${s.slice(0, max - 3)}...`;
1197
+ }
1198
+ function extractMemeloopStructuredToolPayload(raw) {
1199
+ if (raw === null || typeof raw !== "object") return null;
1200
+ const o = raw;
1201
+ const payload = o[MEMELOOP_STRUCTURED_TOOL_KEY];
1202
+ if (payload === null || typeof payload !== "object") return null;
1203
+ const p = payload;
1204
+ if (typeof p.summary !== "string" || p.summary.length === 0) return null;
1205
+ const awaitSessionId = typeof p.awaitSessionId === "string" && p.awaitSessionId.length > 0 ? p.awaitSessionId : void 0;
1206
+ return {
1207
+ summary: p.summary,
1208
+ detailRef: p.detailRef,
1209
+ awaitSessionId
1210
+ };
1211
+ }
1212
+
1213
+ // src/loopAPI/agent-tool-loop/toolCallRunner.ts
1214
+ var TOOL_OPERATION_DEFAULT_TIMEOUT_MS = 6e4;
1215
+ var TOOL_OPERATION_POLL_INTERVAL_MS = 250;
1216
+ var toolOperationCounter = 0;
1217
+ var toolResultMessageCounter = 0;
1218
+ function isTerminalToolOperationPhase(phase) {
1219
+ return phase === "Completed" || phase === "Failed" || phase === "Cancelled";
1220
+ }
1221
+ function stableStringify(value) {
1222
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
1223
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
1224
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`);
1225
+ return `{${entries.join(",")}}`;
1226
+ }
1227
+ function fnv1aHex(input) {
1228
+ let hash = 2166136261;
1229
+ for (let index = 0; index < input.length; index += 1) {
1230
+ hash = Math.imul(hash ^ input.charCodeAt(index), 16777619) >>> 0;
1231
+ }
1232
+ return hash.toString(16).padStart(8, "0");
1233
+ }
1234
+ function isTransientGetError(error) {
1235
+ return error instanceof OrchestrationError && (error.code === "UNAVAILABLE" || error.code === "TIMEOUT" || error.code === "INTERNAL");
1236
+ }
1237
+ async function waitForToolOperationTerminal(client, reference, timeoutMs, applied) {
1238
+ const deadline = Date.now() + timeoutMs;
1239
+ let last = applied ?? null;
1240
+ while (Date.now() < deadline) {
1241
+ let resource;
1242
+ try {
1243
+ resource = await client.get(reference);
1244
+ } catch (error) {
1245
+ if (!isTransientGetError(error)) throw error;
1246
+ const basis = last ?? applied;
1247
+ if (!basis) throw error;
1248
+ const decision = reconcileUnknownEffect(basis, { resultObserved: false });
1249
+ if (decision.action === "retry") {
1250
+ } else {
1251
+ throw new Error(
1252
+ `ToolOperation ${reference.name ?? "<unknown>"} effect unknown after transport failure: ${decision.action} \u2014 ${decision.reason}`
1253
+ );
1254
+ }
1255
+ }
1256
+ if (resource) {
1257
+ last = resource;
1258
+ if (isTerminalToolOperationPhase(last.status?.phase)) {
1259
+ return last;
1260
+ }
1261
+ }
1262
+ await new Promise((resolve) => {
1263
+ setTimeout(resolve, TOOL_OPERATION_POLL_INTERVAL_MS);
1264
+ });
1265
+ }
1266
+ if (last) {
1267
+ return last;
1268
+ }
1269
+ throw new Error(`ToolOperation ${reference.name ?? "<unknown>"} was not observed before timeout`);
1270
+ }
1271
+ function toolOperationRow(resource) {
1272
+ const status = resource.status;
1273
+ if (status?.phase === "Completed") {
1274
+ const value = status.result?.value;
1275
+ if (value != null && typeof value === "object") {
1276
+ const structured = extractMemeloopStructuredToolPayload(value);
1277
+ if (structured) {
1278
+ return {
1279
+ text: structured.summary,
1280
+ isError: false,
1281
+ detailRef: structured.detailRef,
1282
+ awaitSessionId: structured.awaitSessionId
1283
+ };
1284
+ }
1285
+ if ("error" in value && typeof value.error === "string") {
1286
+ return { text: value.error, isError: true };
1287
+ }
1288
+ if ("result" in value && value.result != null) {
1289
+ return {
1290
+ text: typeof value.result === "string" ? value.result : JSON.stringify(value.result),
1291
+ payload: typeof value.result === "string" ? void 0 : value.result,
1292
+ isError: false
1293
+ };
1294
+ }
1295
+ }
1296
+ return { text: typeof value === "string" ? value : JSON.stringify(value), isError: false };
1297
+ }
1298
+ if (status?.phase === "Failed" || status?.phase === "Cancelled") {
1299
+ return {
1300
+ text: status.result?.error?.message ?? `ToolOperation ${status.phase}`,
1301
+ isError: true
1302
+ };
1303
+ }
1304
+ return {
1305
+ text: `ToolOperation did not reach a terminal phase (last phase: ${status?.phase ?? "unknown"})`,
1306
+ isError: true
1307
+ };
1308
+ }
1309
+ async function executeToolOperation(context, conversationId, call, occurrence) {
1310
+ const client = context.orchestration;
1311
+ if (!client) return null;
1312
+ try {
1313
+ const caps = await client.getCapabilities();
1314
+ if (!caps.resourceKinds.includes(TOOL_OPERATION_KIND) || !caps.operations.includes("apply") || !caps.operations.includes("get")) {
1315
+ return null;
1316
+ }
1317
+ } catch {
1318
+ return null;
1319
+ }
1320
+ const timeoutMs = context.agentToolLoop?.toolOperationTimeoutMs ?? TOOL_OPERATION_DEFAULT_TIMEOUT_MS;
1321
+ const idempotencyKey = `${conversationId}:${fnv1aHex(stableStringify({
1322
+ toolId: call.toolId,
1323
+ parameters: call.parameters
1324
+ }))}:${occurrence}`;
1325
+ toolOperationCounter += 1;
1326
+ const operation = createToolOperationManifest(
1327
+ `${call.toolId}-${Date.now().toString(36)}-${toolOperationCounter.toString(36)}`,
1328
+ {
1329
+ toolRef: { kind: "BuiltinTool", name: call.toolId },
1330
+ effect: context.tools.getToolEffect?.(call.toolId) ?? "execute",
1331
+ arguments: call.parameters,
1332
+ idempotencyKey,
1333
+ timeoutMs,
1334
+ policy: { auditLevel: "metadata" }
1335
+ }
1336
+ );
1337
+ try {
1338
+ const applied = await client.apply(operation);
1339
+ if (applied.apiVersion !== TOOL_OPERATION_API_VERSION || applied.kind !== TOOL_OPERATION_KIND) {
1340
+ return { text: "ToolOperation apply returned an unexpected resource kind", isError: true };
1341
+ }
1342
+ let resource = applied;
1343
+ if (!isTerminalToolOperationPhase(resource.status?.phase)) {
1344
+ const reference = {
1345
+ apiVersion: applied.apiVersion,
1346
+ kind: applied.kind,
1347
+ name: applied.metadata.name,
1348
+ namespace: applied.metadata.namespace
1349
+ };
1350
+ resource = await waitForToolOperationTerminal(client, reference, timeoutMs, resource);
1351
+ }
1352
+ return toolOperationRow(resource);
1353
+ } catch (error) {
1354
+ const message = error instanceof Error ? error.message : String(error);
1355
+ return { text: `ToolOperation execution error: ${message}`, isError: true };
1356
+ }
1357
+ }
1358
+ async function executeRegistryTool(context, toolId, parameters) {
1359
+ const normalizedId = toolId.includes("-") ? toolId.replace(/-([a-z])/g, (_m, c) => c.toUpperCase()) : toolId;
1360
+ const impl = context.tools.getTool(toolId) ?? context.tools.getTool(normalizedId);
1361
+ if (typeof impl !== "function") {
1362
+ return {
1363
+ text: `No tool registered for "${toolId}".`,
1364
+ isError: true
1365
+ };
1366
+ }
1367
+ try {
1368
+ const raw = await impl(parameters);
1369
+ if (raw != null && typeof raw === "object") {
1370
+ const o = raw;
1371
+ if (typeof o.error === "string" && o.error.length > 0) {
1372
+ return { text: o.error, isError: true };
1373
+ }
1374
+ if ("result" in o) {
1375
+ return {
1376
+ text: typeof o.result === "string" ? o.result : JSON.stringify(o.result),
1377
+ payload: typeof o.result === "string" ? void 0 : o.result,
1378
+ isError: false
1379
+ };
1380
+ }
1381
+ const structured = extractMemeloopStructuredToolPayload(raw);
1382
+ if (structured) {
1383
+ return {
1384
+ text: structured.summary,
1385
+ isError: false,
1386
+ detailRef: structured.detailRef,
1387
+ awaitSessionId: structured.awaitSessionId
1388
+ };
1389
+ }
1390
+ }
1391
+ return { text: typeof raw === "string" ? raw : JSON.stringify(raw), isError: false };
1392
+ } catch (error) {
1393
+ const message = error instanceof Error ? error.message : String(error);
1394
+ if (context.logger?.warn) {
1395
+ context.logger.warn("[agentToolLoop] tool execution error", toolId, message);
1396
+ } else {
1397
+ console.warn("[agentToolLoop] tool execution error", toolId, message);
1398
+ }
1399
+ return { text: message, isError: true };
1400
+ }
1401
+ }
1402
+ async function executeWithGuards(context, options, conversationId, recentToolCalls, call) {
1403
+ const parameterParseError = call.parameters[TOOL_PARAMETER_PARSE_ERROR_KEY];
1404
+ if (typeof parameterParseError === "string") {
1405
+ return { text: parameterParseError, isError: true };
1406
+ }
1407
+ const signature = `${call.toolId}:${JSON.stringify(call.parameters)}`;
1408
+ recentToolCalls.push(signature);
1409
+ const threshold = Math.max(2, options?.doomLoopThreshold ?? 3);
1410
+ const last = recentToolCalls.slice(-threshold);
1411
+ if (last.length === threshold && last.every((x) => x === signature)) {
1412
+ return { text: "Blocked by doom-loop guard", isError: true };
1413
+ }
1414
+ const occurrence = recentToolCalls.filter((entry) => entry === signature).length;
1415
+ const row = await executeToolOperation(context, conversationId, call, occurrence) ?? await executeRegistryTool(context, call.toolId, call.parameters);
1416
+ if (hasHooks("PostToolUse")) {
1417
+ await executeHooks("PostToolUse", context, {
1418
+ toolId: call.toolId,
1419
+ parameters: call.parameters,
1420
+ result: row.text,
1421
+ isError: row.isError,
1422
+ conversationId
1423
+ });
1424
+ }
1425
+ return row;
1426
+ }
1427
+ async function persistToolResult(context, conversationId, call, row) {
1428
+ toolResultMessageCounter += 1;
1429
+ const lamportTool = await nextLamportClockForConversation(context.storage, conversationId);
1430
+ await context.storage.appendMessage(createChatMessage({
1431
+ // Counter suffix keeps message identity unique for identical calls within
1432
+ // the same millisecond (parallel tools or fast consecutive rounds).
1433
+ messageId: `${conversationId}:t:${call.toolId}:${Date.now().toString(36)}:${toolResultMessageCounter.toString(36)}`,
1434
+ conversationId,
1435
+ originNodeId: "local",
1436
+ lamportClock: lamportTool,
1437
+ role: "tool",
1438
+ parts: [{
1439
+ type: "tool-result",
1440
+ toolName: call.toolId,
1441
+ parameters: call.parameters,
1442
+ result: row.text,
1443
+ isError: row.isError,
1444
+ payload: row.payload,
1445
+ detailRef: row.detailRef
1446
+ }],
1447
+ detailRef: row.detailRef,
1448
+ metadata: {
1449
+ isToolResult: true,
1450
+ isError: row.isError,
1451
+ toolId: call.toolId,
1452
+ toolParameters: call.parameters
1453
+ }
1454
+ }));
1455
+ }
1456
+ async function persistTerminalAwaitCompletion(context, options, conversationId, call, row) {
1457
+ const sid = row.awaitSessionId;
1458
+ const wait = options?.waitForTerminalSession;
1459
+ if (!sid || !wait || row.isError) return;
1460
+ const done = await wait(sid);
1461
+ const lamportTool = await nextLamportClockForConversation(context.storage, conversationId);
1462
+ const body = truncateToolSummary(
1463
+ `[terminal.await done] session=${sid}
1464
+ exitCode: ${done.exitCode ?? "null"}
1465
+ ---
1466
+ ${done.truncatedOutput}`
1467
+ );
1468
+ await context.storage.appendMessage(createChatMessage({
1469
+ messageId: `${conversationId}:t:${call.toolId}:await:${Date.now().toString(36)}:${toolResultMessageCounter.toString(36)}`,
1470
+ conversationId,
1471
+ originNodeId: "local",
1472
+ lamportClock: lamportTool,
1473
+ role: "tool",
1474
+ parts: [{
1475
+ type: "tool-result",
1476
+ toolName: call.toolId,
1477
+ parameters: call.parameters,
1478
+ result: body,
1479
+ detailRef: row.detailRef ? { ...row.detailRef, exitCode: done.exitCode ?? row.detailRef.exitCode } : void 0
1480
+ }],
1481
+ detailRef: row.detailRef ? { ...row.detailRef, exitCode: done.exitCode ?? row.detailRef.exitCode } : void 0,
1482
+ metadata: {
1483
+ isToolResult: true,
1484
+ toolId: call.toolId,
1485
+ toolParameters: call.parameters,
1486
+ awaitSessionId: sid
1487
+ }
1488
+ }));
1489
+ }
1490
+ function toolStep(row, parallel) {
1491
+ return {
1492
+ type: "tool",
1493
+ data: {
1494
+ toolId: row.call.toolId,
1495
+ parameters: row.call.parameters,
1496
+ parallel,
1497
+ result: row.text,
1498
+ isError: row.isError
1499
+ }
1500
+ };
1501
+ }
1502
+ async function* runRegistryToolCalls(options) {
1503
+ const { context, agentToolLoopOptions, conversationId, calls, parallel, recentToolCalls } = options;
1504
+ if (parallel) {
1505
+ const results = await Promise.all(
1506
+ calls.map(
1507
+ async (call) => ({
1508
+ call,
1509
+ ...await executeWithGuards(
1510
+ context,
1511
+ agentToolLoopOptions,
1512
+ conversationId,
1513
+ recentToolCalls,
1514
+ call
1515
+ )
1516
+ })
1517
+ )
1518
+ );
1519
+ for (const row of results) {
1520
+ yield toolStep(row, true);
1521
+ }
1522
+ for (const row of results) {
1523
+ await persistToolResult(context, conversationId, row.call, row);
1524
+ }
1525
+ for (const row of results) {
1526
+ await persistTerminalAwaitCompletion(
1527
+ context,
1528
+ agentToolLoopOptions,
1529
+ conversationId,
1530
+ row.call,
1531
+ row
1532
+ );
1533
+ }
1534
+ return;
1535
+ }
1536
+ for (const call of calls) {
1537
+ const row = await executeWithGuards(
1538
+ context,
1539
+ agentToolLoopOptions,
1540
+ conversationId,
1541
+ recentToolCalls,
1542
+ call
1543
+ );
1544
+ yield toolStep({ call, ...row }, false);
1545
+ await persistToolResult(context, conversationId, call, row);
1546
+ await persistTerminalAwaitCompletion(context, agentToolLoopOptions, conversationId, call, row);
1547
+ }
1548
+ }
1549
+
1550
+ // src/permission/engine.ts
1551
+ function matchPattern(toolName, pattern) {
1552
+ if (pattern === toolName) return true;
1553
+ if (pattern === "*") return true;
1554
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, ".*");
1555
+ return new RegExp(`^${escaped}$`).test(toolName);
1556
+ }
1557
+ function mergePermissionSets(sets) {
1558
+ const merged = /* @__PURE__ */ new Map();
1559
+ merged.set("allow", /* @__PURE__ */ new Map());
1560
+ merged.set("deny", /* @__PURE__ */ new Map());
1561
+ merged.set("ask", /* @__PURE__ */ new Map());
1562
+ for (const set of sets) {
1563
+ for (const rule of set.rules) {
1564
+ for (const [action, map] of merged) {
1565
+ if (action !== rule.action) {
1566
+ map.delete(rule.toolPattern);
1567
+ }
1568
+ }
1569
+ merged.get(rule.action).set(rule.toolPattern, rule.action);
1570
+ }
1571
+ }
1572
+ return {
1573
+ allow: [...merged.get("allow").keys()],
1574
+ deny: [...merged.get("deny").keys()],
1575
+ ask: [...merged.get("ask").keys()]
1576
+ };
1577
+ }
1578
+ function checkPermission(toolName, merged) {
1579
+ const isWildcard = (p) => p.includes("*");
1580
+ for (const pattern of merged.deny) {
1581
+ if (!isWildcard(pattern) && matchPattern(toolName, pattern)) return "deny";
1582
+ }
1583
+ for (const pattern of merged.ask) {
1584
+ if (!isWildcard(pattern) && matchPattern(toolName, pattern)) return "ask";
1585
+ }
1586
+ for (const pattern of merged.allow) {
1587
+ if (!isWildcard(pattern) && matchPattern(toolName, pattern)) return "allow";
1588
+ }
1589
+ for (const pattern of merged.deny) {
1590
+ if (isWildcard(pattern) && matchPattern(toolName, pattern)) return "deny";
1591
+ }
1592
+ for (const pattern of merged.ask) {
1593
+ if (isWildcard(pattern) && matchPattern(toolName, pattern)) return "ask";
1594
+ }
1595
+ for (const pattern of merged.allow) {
1596
+ if (isWildcard(pattern) && matchPattern(toolName, pattern)) return "allow";
1597
+ }
1598
+ const hasAnyRules = merged.allow.length > 0 || merged.deny.length > 0 || merged.ask.length > 0;
1599
+ return hasAnyRules ? "deny" : "allow";
1600
+ }
1601
+
1602
+ // src/orchestration/security/admission.ts
1603
+ function defaultPermissionActionForTrustClass(trustClass) {
1604
+ return trustClass === "restricted" || trustClass === "quarantine" ? "deny" : "allow";
1605
+ }
1606
+
1607
+ // src/tools/approval.ts
1608
+ var pendingApprovals = /* @__PURE__ */ new Map();
1609
+ var approvalListeners = /* @__PURE__ */ new Set();
1610
+ function requestApproval(request, timeoutMs = 6e4) {
1611
+ return new Promise((resolve) => {
1612
+ pendingApprovals.set(request.approvalId, { request, resolve });
1613
+ for (const listener of approvalListeners) {
1614
+ try {
1615
+ listener(request);
1616
+ } catch {
1617
+ }
1618
+ }
1619
+ if (timeoutMs > 0) {
1620
+ setTimeout(() => {
1621
+ if (pendingApprovals.has(request.approvalId)) {
1622
+ pendingApprovals.delete(request.approvalId);
1623
+ resolve("deny");
1624
+ }
1625
+ }, timeoutMs);
1626
+ }
1627
+ });
1628
+ }
1629
+
1630
+ // src/loopAPI/agent-tool-loop/toolUseGate.ts
1631
+ function buildLayeredPermissions(options, definitionId, userSet) {
1632
+ const globalPerms = options?.toolPermissions;
1633
+ const sets = [];
1634
+ if (globalPerms?.default) {
1635
+ sets.push({
1636
+ source: "default",
1637
+ rules: [{ toolPattern: "*", action: globalPerms.default }]
1638
+ });
1639
+ }
1640
+ const scoped = globalPerms?.perAgent?.[definitionId];
1641
+ if (scoped) {
1642
+ if (scoped.default) {
1643
+ sets.push({
1644
+ source: `agent:${definitionId}:default`,
1645
+ rules: [{ toolPattern: "*", action: scoped.default }]
1646
+ });
1647
+ }
1648
+ if (scoped.rules && scoped.rules.length > 0) {
1649
+ sets.push({
1650
+ source: `agent:${definitionId}`,
1651
+ rules: scoped.rules.map((r) => ({ toolPattern: r.pattern, action: r.action }))
1652
+ });
1653
+ }
1654
+ }
1655
+ if (userSet && userSet.rules.length > 0) {
1656
+ sets.push(userSet);
1657
+ }
1658
+ if (globalPerms?.rules && globalPerms.rules.length > 0) {
1659
+ sets.push({
1660
+ source: "session",
1661
+ rules: globalPerms.rules.map((r) => ({ toolPattern: r.pattern, action: r.action }))
1662
+ });
1663
+ }
1664
+ if (!sets.some((s) => s.rules.some((r) => r.toolPattern === "*"))) {
1665
+ sets.unshift({
1666
+ source: "implied-default",
1667
+ rules: [{ toolPattern: "*", action: defaultPermissionActionForTrustClass(options?.trustClass) }]
1668
+ });
1669
+ }
1670
+ return mergePermissionSets(sets);
1671
+ }
1672
+ function createPermissionPreToolUseHook(options, definitionId, userSet) {
1673
+ const mergedPermissions = buildLayeredPermissions(options, definitionId, userSet);
1674
+ return async (_context, data) => {
1675
+ const toolId = typeof data.toolId === "string" ? data.toolId : "";
1676
+ const action = checkPermission(toolId, mergedPermissions);
1677
+ if (action === "allow") {
1678
+ return { allowed: true, permissionAction: "allow" };
1679
+ }
1680
+ return {
1681
+ allowed: true,
1682
+ permissionAction: action,
1683
+ reason: action === "deny" ? "Denied by tool permission" : void 0
1684
+ };
1685
+ };
1686
+ }
1687
+ function applyModifiedCall(call, modified) {
1688
+ if (!modified) return call;
1689
+ const toolId = typeof modified.toolId === "string" ? modified.toolId : call.toolId;
1690
+ const parameters = modified.parameters != null && typeof modified.parameters === "object" ? modified.parameters : call.parameters;
1691
+ return { ...call, toolId, parameters };
1692
+ }
1693
+ function normalizePreToolUseResult(result) {
1694
+ if (!result.allowed) {
1695
+ return { action: "deny", reason: result.reason ?? "Blocked by PreToolUse hook" };
1696
+ }
1697
+ if (result.permissionAction === "ask" || result.permissionAction === "deny") {
1698
+ return { action: result.permissionAction, reason: result.reason };
1699
+ }
1700
+ return { action: "allow", reason: result.reason };
1701
+ }
1702
+ async function persistDeniedToolResult(context, conversationId, call, errorText) {
1703
+ const lamportTool = await nextLamportClockForConversation(context.storage, conversationId);
1704
+ await context.storage.appendMessage(createChatMessage({
1705
+ messageId: `${conversationId}:t:${call.toolId}:${Date.now().toString(36)}`,
1706
+ conversationId,
1707
+ originNodeId: "local",
1708
+ lamportClock: lamportTool,
1709
+ role: "tool",
1710
+ parts: [{
1711
+ type: "tool-result",
1712
+ toolName: call.toolId,
1713
+ parameters: call.parameters,
1714
+ result: errorText,
1715
+ isError: true
1716
+ }],
1717
+ metadata: {
1718
+ isToolResult: true,
1719
+ isError: true,
1720
+ toolId: call.toolId,
1721
+ toolParameters: call.parameters
1722
+ }
1723
+ }));
1724
+ }
1725
+ async function* resolveAskAction(conversationId, call) {
1726
+ yield {
1727
+ type: "permission_request",
1728
+ data: { tool: call.toolId, args: call.parameters }
1729
+ };
1730
+ const decision = await requestApproval(
1731
+ {
1732
+ approvalId: `${conversationId}:${Date.now().toString(36)}:${call.toolId}`,
1733
+ agentId: conversationId,
1734
+ toolName: call.toolId,
1735
+ parameters: call.parameters,
1736
+ created: /* @__PURE__ */ new Date()
1737
+ },
1738
+ 6e4
1739
+ );
1740
+ return decision === "allow" ? "allow" : "deny";
1741
+ }
1742
+ async function runPreToolUseHook(context, data) {
1743
+ if (!hasHooks("PreToolUse")) return { allowed: true };
1744
+ return executeHooks("PreToolUse", context, data);
1745
+ }
1746
+ async function* gateToolCallsWithPreToolUse(context, options, definitionId, conversationId, calls) {
1747
+ const permissionHook = createPermissionPreToolUseHook(options, definitionId);
1748
+ const allowedCalls = [];
1749
+ for (const originalCall of calls) {
1750
+ let call = originalCall;
1751
+ const permissionResult = await permissionHook(context, {
1752
+ toolId: call.toolId,
1753
+ parameters: call.parameters,
1754
+ conversationId
1755
+ });
1756
+ call = applyModifiedCall(call, permissionResult.modified);
1757
+ let { action, reason } = normalizePreToolUseResult(permissionResult);
1758
+ if (action === "ask") {
1759
+ action = yield* resolveAskAction(conversationId, call);
1760
+ reason = action === "deny" ? "Tool approval denied or timed out" : reason;
1761
+ }
1762
+ if (action === "deny") {
1763
+ const errorText = reason ?? "Denied by tool permission";
1764
+ yield {
1765
+ type: "tool",
1766
+ data: {
1767
+ toolId: call.toolId,
1768
+ parameters: call.parameters,
1769
+ parallel: false,
1770
+ result: errorText,
1771
+ isError: true
1772
+ }
1773
+ };
1774
+ await persistDeniedToolResult(context, conversationId, call, errorText);
1775
+ continue;
1776
+ }
1777
+ const hookResult = await runPreToolUseHook(context, {
1778
+ toolId: call.toolId,
1779
+ parameters: call.parameters,
1780
+ conversationId
1781
+ });
1782
+ call = applyModifiedCall(call, hookResult.modified);
1783
+ ({ action, reason } = normalizePreToolUseResult(hookResult));
1784
+ if (action === "ask") {
1785
+ action = yield* resolveAskAction(conversationId, call);
1786
+ reason = action === "deny" ? "Tool approval denied or timed out" : reason;
1787
+ }
1788
+ if (action === "deny") {
1789
+ const errorText = reason ?? "Blocked by PreToolUse hook";
1790
+ yield {
1791
+ type: "tool",
1792
+ data: {
1793
+ toolId: call.toolId,
1794
+ parameters: call.parameters,
1795
+ parallel: false,
1796
+ result: errorText,
1797
+ isError: true
1798
+ }
1799
+ };
1800
+ await persistDeniedToolResult(context, conversationId, call, errorText);
1801
+ continue;
1802
+ }
1803
+ allowedCalls.push(call);
1804
+ }
1805
+ return allowedCalls;
1806
+ }
1807
+
1808
+ // src/loopAPI/agent-tool-loop/turnPrimitives.ts
1809
+ var DEFAULT_MAX_ITERATIONS = 256;
1810
+ function toolCallHandledInAgentMessages(agentMessages, assistantContent, call) {
1811
+ let assistantIndex = -1;
1812
+ for (let index = agentMessages.length - 1; index >= 0; index -= 1) {
1813
+ const message = agentMessages[index];
1814
+ if (message.role === "assistant" && message.content === assistantContent) {
1815
+ assistantIndex = index;
1816
+ break;
1817
+ }
1818
+ }
1819
+ if (assistantIndex < 0) return false;
1820
+ const after = agentMessages.slice(assistantIndex + 1);
1821
+ return after.some(
1822
+ (message) => message.role === "tool" && (message.metadata?.toolId === call.toolId || typeof message.content === "string" && message.content.includes(`Tool: ${call.toolId}`))
1823
+ );
1824
+ }
1825
+ function resolveMaxIterations(context) {
1826
+ const configured = context.agentToolLoop?.maxIterations;
1827
+ return configured != null && configured > 0 ? configured : DEFAULT_MAX_ITERATIONS;
1828
+ }
1829
+ function pluginToolCallSignature(calls) {
1830
+ return calls.map((call) => `${call.toolId}:${JSON.stringify(call.parameters)}`).join("|");
1831
+ }
1832
+ async function blockRepeatedPluginToolCalls(context, input, state, calls, hookContext) {
1833
+ if (calls.length === 0) return { blocked: false };
1834
+ const signature = pluginToolCallSignature(calls);
1835
+ state.recentToolCalls.push(signature);
1836
+ const threshold = Math.max(2, context.agentToolLoop?.doomLoopThreshold ?? 3);
1837
+ const last = state.recentToolCalls.slice(-threshold);
1838
+ if (last.length !== threshold || !last.every((entry) => entry === signature)) {
1839
+ return { blocked: false };
1840
+ }
1841
+ const message = `Blocked by doom-loop guard: the model repeated the same tool call ${threshold} times. Change the arguments or approach before trying again.`;
1842
+ const firstCall = calls[0];
1843
+ const lamportClock = await nextLamportClockForConversation(
1844
+ context.storage,
1845
+ input.conversationId
1846
+ );
1847
+ const toolMessage = createChatMessage({
1848
+ messageId: `${input.conversationId}:t:doom-loop:${state.iteration}:${Date.now().toString(36)}`,
1849
+ conversationId: input.conversationId,
1850
+ originNodeId: "local",
1851
+ lamportClock,
1852
+ role: "tool",
1853
+ parts: [{
1854
+ type: "tool-result",
1855
+ toolName: firstCall.toolId,
1856
+ parameters: firstCall.parameters,
1857
+ result: message,
1858
+ isError: true
1859
+ }],
1860
+ metadata: {
1861
+ isToolResult: true,
1862
+ isError: true,
1863
+ toolId: firstCall.toolId,
1864
+ toolParameters: firstCall.parameters,
1865
+ doomLoopBlocked: true
1866
+ }
1867
+ });
1868
+ hookContext.agent.messages.push(toolMessage);
1869
+ await context.storage.appendMessage(toolMessage);
1870
+ return { blocked: true, message };
1871
+ }
1872
+ function createAgentToolLoopState(context) {
1873
+ return {
1874
+ iteration: 0,
1875
+ maxIterations: resolveMaxIterations(context),
1876
+ recentToolCalls: [],
1877
+ agentStarted: false,
1878
+ agentStopped: false
1879
+ };
1880
+ }
1881
+ function markAgentToolLoopStop(state, reason) {
1882
+ state.stopReason ??= reason;
1883
+ }
1884
+ function finishAgentToolLoopThinking(state, reason, data) {
1885
+ markAgentToolLoopStop(state, reason);
1886
+ return { type: "thinking", data };
1887
+ }
1888
+ async function startAgentToolLoopTurn(context, input, state) {
1889
+ const now = Date.now();
1890
+ const lamportClock = await nextLamportClockForConversation(
1891
+ context.storage,
1892
+ input.conversationId
1893
+ );
1894
+ const hostUserMessage = input.userMessage;
1895
+ const userMessage = context.normalizeMessage?.({
1896
+ ...hostUserMessage,
1897
+ messageId: hostUserMessage?.messageId ?? `${input.conversationId}:${now.toString(36)}`,
1898
+ conversationId: input.conversationId,
1899
+ originNodeId: hostUserMessage?.originNodeId ?? "local",
1900
+ timestamp: hostUserMessage?.timestamp ?? now,
1901
+ lamportClock: hostUserMessage?.lamportClock ?? lamportClock,
1902
+ role: "user",
1903
+ content: hostUserMessage?.content ?? input.message
1904
+ }) ?? {
1905
+ ...hostUserMessage,
1906
+ messageId: hostUserMessage?.messageId ?? `${input.conversationId}:${now.toString(36)}`,
1907
+ conversationId: input.conversationId,
1908
+ originNodeId: hostUserMessage?.originNodeId ?? "local",
1909
+ timestamp: hostUserMessage?.timestamp ?? now,
1910
+ lamportClock: hostUserMessage?.lamportClock ?? lamportClock,
1911
+ role: "user",
1912
+ content: hostUserMessage?.content ?? input.message
1913
+ };
1914
+ if (input.resumeSession && input.resumeSession.length > 0) {
1915
+ await context.storage.insertMessagesIfAbsent(input.resumeSession);
1916
+ }
1917
+ await context.storage.appendMessage(userMessage);
1918
+ if (hasHooks("UserPromptSubmit")) {
1919
+ const hookResult = await executeHooks("UserPromptSubmit", context, {
1920
+ message: input.message,
1921
+ conversationId: input.conversationId
1922
+ });
1923
+ if (!hookResult.allowed) {
1924
+ return {
1925
+ action: "stop",
1926
+ step: {
1927
+ type: "thinking",
1928
+ data: {
1929
+ status: "blocked",
1930
+ conversationId: input.conversationId,
1931
+ reason: hookResult.reason ?? "Blocked by UserPromptSubmit hook"
1932
+ }
1933
+ }
1934
+ };
1935
+ }
1936
+ }
1937
+ const initialDefinitionId = await inferDefinitionId(context.storage, input.conversationId);
1938
+ if (hasHooks("AgentStart")) {
1939
+ const hookResult = await executeHooks("AgentStart", context, {
1940
+ conversationId: input.conversationId,
1941
+ definitionId: initialDefinitionId
1942
+ });
1943
+ if (!hookResult.allowed) {
1944
+ return {
1945
+ action: "stop",
1946
+ step: {
1947
+ type: "thinking",
1948
+ data: {
1949
+ status: "blocked",
1950
+ conversationId: input.conversationId,
1951
+ reason: hookResult.reason ?? "Blocked by AgentStart hook"
1952
+ }
1953
+ }
1954
+ };
1955
+ }
1956
+ }
1957
+ state.agentStarted = true;
1958
+ return { action: "continue" };
1959
+ }
1960
+ async function* runAgentToolLoopIteration(context, input, state) {
1961
+ const options = context.agentToolLoop ?? {};
1962
+ const enableToolLoop = options.enableToolLoop !== false;
1963
+ const fallbackRegistry = options.fallbackRegistryTools !== false;
1964
+ const checkpointOptions = options.sessionCheckpoint;
1965
+ if (state.iteration >= state.maxIterations) {
1966
+ yield finishAgentToolLoopThinking(state, "max-iterations", {
1967
+ status: "max-iterations",
1968
+ conversationId: input.conversationId,
1969
+ maxIterations: state.maxIterations
1970
+ });
1971
+ return { action: "stop", reason: "max-iterations" };
1972
+ }
1973
+ state.iteration += 1;
1974
+ const iteration = state.iteration;
1975
+ if (options.isCancelled?.(input.conversationId)) {
1976
+ yield finishAgentToolLoopThinking(state, "cancelled", {
1977
+ status: "cancelled",
1978
+ conversationId: input.conversationId
1979
+ });
1980
+ return { action: "stop", reason: "cancelled" };
1981
+ }
1982
+ const rawHistory = await context.storage.getMessages(input.conversationId, {
1983
+ mode: "full-content"
1984
+ });
1985
+ const { history, steps: compactionSteps } = await prepareIterationHistory({
1986
+ context,
1987
+ conversationId: input.conversationId,
1988
+ iteration,
1989
+ rawHistory,
1990
+ agentToolLoopOptions: options
1991
+ });
1992
+ for (const step of compactionSteps) {
1993
+ yield step;
1994
+ }
1995
+ const runtimeAgent = context.resolveAgentRuntimeView ? await context.resolveAgentRuntimeView(input.conversationId, history) : { id: input.conversationId, messages: history };
1996
+ const hookContext = {
1997
+ ...context,
1998
+ agent: runtimeAgent,
1999
+ persistAgentMessage: async (message) => {
2000
+ await context.storage.appendMessage(message);
2001
+ }
2002
+ };
2003
+ yield {
2004
+ type: "thinking",
2005
+ data: {
2006
+ status: "calling-llm",
2007
+ conversationId: input.conversationId,
2008
+ messageCount: history.length,
2009
+ iteration
2010
+ }
2011
+ };
2012
+ const messages = await buildLlmMessages(hookContext, input.conversationId, history);
2013
+ const request = { conversationId: input.conversationId, messages };
2014
+ const assistantMessageId = `${input.conversationId}:a:${iteration}:${Date.now().toString(36)}`;
2015
+ const assistantLamportClock = await nextLamportClockForConversation(
2016
+ context.storage,
2017
+ input.conversationId
2018
+ );
2019
+ const buildAssistantMessage = (content) => context.normalizeMessage?.({
2020
+ messageId: assistantMessageId,
2021
+ conversationId: input.conversationId,
2022
+ originNodeId: "local",
2023
+ timestamp: Date.now(),
2024
+ lamportClock: assistantLamportClock,
2025
+ role: "assistant",
2026
+ content
2027
+ }) ?? {
2028
+ messageId: assistantMessageId,
2029
+ conversationId: input.conversationId,
2030
+ originNodeId: "local",
2031
+ timestamp: Date.now(),
2032
+ lamportClock: assistantLamportClock,
2033
+ role: "assistant",
2034
+ content
2035
+ };
2036
+ const updateAssistantView = (message) => {
2037
+ const existingIndex = hookContext.agent.messages.findIndex(
2038
+ (item) => item.messageId === message.messageId
2039
+ );
2040
+ if (existingIndex >= 0) {
2041
+ hookContext.agent.messages[existingIndex] = message;
2042
+ } else {
2043
+ hookContext.agent.messages.push(message);
2044
+ }
2045
+ };
2046
+ let assistantText = "";
2047
+ for await (const chunk of streamLlm(context, request)) {
2048
+ assistantText += chunkToText2(chunk);
2049
+ const transientAssistantMessage = buildAssistantMessage(assistantText);
2050
+ updateAssistantView(transientAssistantMessage);
2051
+ try {
2052
+ await context.onTransientMessage?.(transientAssistantMessage);
2053
+ } catch (error) {
2054
+ context.logger?.warn?.("[agentToolLoop] transient message subscriber failed:", error);
2055
+ }
2056
+ yield { type: "message", data: chunk };
2057
+ }
2058
+ const definitionId = await inferDefinitionId(context.storage, input.conversationId);
2059
+ const agentDefinition = await resolveAgentDefinitionModel(context, definitionId);
2060
+ const frameworkConfig = agentDefinition?.agentFrameworkConfig;
2061
+ const hasPlugins = Boolean(
2062
+ frameworkConfig?.plugins && Array.isArray(frameworkConfig.plugins) && frameworkConfig.plugins.length > 0
2063
+ );
2064
+ const assistantMessage = buildAssistantMessage(assistantText);
2065
+ updateAssistantView(assistantMessage);
2066
+ await hookContext.persistAgentMessage?.(assistantMessage);
2067
+ const { calls, parallel } = matchAllToolCallings(assistantText);
2068
+ if (hasPlugins && frameworkConfig) {
2069
+ const doomLoop = await blockRepeatedPluginToolCalls(
2070
+ context,
2071
+ input,
2072
+ state,
2073
+ calls,
2074
+ hookContext
2075
+ );
2076
+ if (doomLoop.blocked) {
2077
+ yield {
2078
+ type: "tool",
2079
+ data: {
2080
+ toolId: calls[0].toolId,
2081
+ parameters: calls[0].parameters,
2082
+ parallel,
2083
+ result: doomLoop.message,
2084
+ isError: true
2085
+ }
2086
+ };
2087
+ yield finishAgentToolLoopThinking(state, "error", {
2088
+ status: "blocked",
2089
+ conversationId: input.conversationId,
2090
+ reason: doomLoop.message
2091
+ });
2092
+ return { action: "stop", reason: "error" };
2093
+ }
2094
+ const { hooks } = await createHooksWithPlugins(
2095
+ frameworkConfig,
2096
+ {
2097
+ pluginRegistry: resolvePromptPluginMap(context)
2098
+ }
2099
+ );
2100
+ const responseCompletePayload = {
2101
+ agentFrameworkContext: hookContext,
2102
+ response: { status: "done", content: assistantText },
2103
+ agentFrameworkConfig: frameworkConfig,
2104
+ requestId: void 0,
2105
+ toolConfig: { id: "_memeloop", toolId: "_memeloop" },
2106
+ actions: {}
2107
+ };
2108
+ await runResponseCompleteHooks(hooks, responseCompletePayload);
2109
+ await context.storage.insertMessagesIfAbsent(hookContext.agent.messages);
2110
+ const postProcess = await responseConcat(
2111
+ frameworkConfig,
2112
+ assistantText,
2113
+ hookContext,
2114
+ hookContext.agent.messages
2115
+ );
2116
+ const yieldTarget = responseCompletePayload.actions?.yieldNextRoundTo ?? postProcess.yieldNextRoundTo;
2117
+ if (yieldTarget === "human") {
2118
+ yield finishAgentToolLoopThinking(state, "completed", {
2119
+ status: "input-required",
2120
+ conversationId: input.conversationId
2121
+ });
2122
+ return { action: "stop", reason: "completed" };
2123
+ }
2124
+ if (yieldTarget === "self") {
2125
+ return { action: "continue" };
2126
+ }
2127
+ }
2128
+ if (calls.length === 0) {
2129
+ markAgentToolLoopStop(state, "completed");
2130
+ return { action: "stop", reason: "completed" };
2131
+ }
2132
+ if (!enableToolLoop) {
2133
+ markAgentToolLoopStop(state, "completed");
2134
+ return { action: "stop", reason: "completed" };
2135
+ }
2136
+ const pending = calls.filter(
2137
+ (call) => !toolCallHandledInAgentMessages(hookContext.agent.messages, assistantText, call)
2138
+ );
2139
+ if (pending.length === 0) {
2140
+ if (hasPlugins && calls.length > 0) {
2141
+ return { action: "continue" };
2142
+ }
2143
+ markAgentToolLoopStop(state, "completed");
2144
+ return { action: "stop", reason: "completed" };
2145
+ }
2146
+ if (!fallbackRegistry && hasPlugins) {
2147
+ return { action: "continue" };
2148
+ }
2149
+ const allowedCalls = yield* gateToolCallsWithPreToolUse(
2150
+ context,
2151
+ options,
2152
+ definitionId,
2153
+ input.conversationId,
2154
+ pending
2155
+ );
2156
+ if (allowedCalls.length === 0) {
2157
+ return { action: "continue" };
2158
+ }
2159
+ yield* runRegistryToolCalls({
2160
+ context,
2161
+ agentToolLoopOptions: options,
2162
+ conversationId: input.conversationId,
2163
+ calls: allowedCalls,
2164
+ parallel,
2165
+ recentToolCalls: state.recentToolCalls
2166
+ });
2167
+ if (checkpointOptions?.enabled) {
2168
+ const checkpointStore = checkpointOptions.store;
2169
+ if (!checkpointStore) {
2170
+ if (context.logger?.warn) {
2171
+ context.logger.warn("[agentToolLoop] checkpoint enabled without a checkpoint store");
2172
+ } else {
2173
+ console.warn("[agentToolLoop] checkpoint enabled without a checkpoint store");
2174
+ }
2175
+ return { action: "continue" };
2176
+ }
2177
+ try {
2178
+ const allMessages = await context.storage.getMessages(input.conversationId, {
2179
+ mode: "full-content"
2180
+ });
2181
+ await checkpointStore.saveCheckpoint(input.conversationId, allMessages);
2182
+ } catch (error) {
2183
+ if (context.logger?.warn) {
2184
+ context.logger.warn("[agentToolLoop] checkpoint save failed:", error);
2185
+ } else {
2186
+ console.warn("[agentToolLoop] checkpoint save failed:", error);
2187
+ }
2188
+ }
2189
+ }
2190
+ return { action: "continue" };
2191
+ }
2192
+ async function stopAgentToolLoopTurn(context, input, state, reason) {
2193
+ if (reason) markAgentToolLoopStop(state, reason);
2194
+ if (state.agentStarted && !state.agentStopped && state.stopReason && hasHooks("AgentStop")) {
2195
+ state.agentStopped = true;
2196
+ await executeHooks("AgentStop", context, {
2197
+ conversationId: input.conversationId,
2198
+ reason: state.stopReason
2199
+ });
2200
+ }
2201
+ }
2202
+
2203
+ // src/loopAPI/agent-tool-loop/directRunner.ts
2204
+ function createAgentToolLoopRunner(context) {
2205
+ return async function* agentToolLoopRunner(input) {
2206
+ const state = createAgentToolLoopState(context);
2207
+ try {
2208
+ const start = await startAgentToolLoopTurn(context, input, state);
2209
+ if (start.step) yield start.step;
2210
+ if (start.action === "stop") return;
2211
+ while (true) {
2212
+ const result = yield* runAgentToolLoopIteration(context, input, state);
2213
+ if (result.action === "stop") return;
2214
+ }
2215
+ } catch (error) {
2216
+ await stopAgentToolLoopTurn(context, input, state, "error");
2217
+ throw error;
2218
+ } finally {
2219
+ await stopAgentToolLoopTurn(context, input, state);
2220
+ }
2221
+ };
2222
+ }
2223
+
2224
+ // src/loopAPI/agent-tool-loop/runner.ts
2225
+ function resolveAgentToolLoopTerminalState(step, current) {
2226
+ if (step.type !== "thinking") return current;
2227
+ const data = step.data;
2228
+ if (data.status === "input-required") return "input-required";
2229
+ if (data.status === "cancelled") return "canceled";
2230
+ if (data.status === "max-iterations") return "completed";
2231
+ if (data.status === "blocked") return "failed";
2232
+ if (data.status === "calling-llm") return "working";
2233
+ return current;
2234
+ }
2235
+ async function runAgentToolLoopTurn(context, input, callbacks = {}) {
2236
+ const agentToolLoop = callbacks.agentToolLoop ?? createAgentToolLoopRunner(context);
2237
+ let terminalState = "completed";
2238
+ let stepCount = 0;
2239
+ for await (const step of agentToolLoop(input)) {
2240
+ stepCount += 1;
2241
+ terminalState = resolveAgentToolLoopTerminalState(step, terminalState);
2242
+ await callbacks.onStep?.(step);
2243
+ if (step.type === "thinking" && step.data && typeof step.data === "object") {
2244
+ const data = step.data;
2245
+ const status = data.status;
2246
+ if (typeof status === "string") {
2247
+ await callbacks.onProgress?.(status, data, step);
2248
+ }
2249
+ }
2250
+ }
2251
+ return {
2252
+ state: terminalState === "working" || terminalState === "submitted" ? "completed" : terminalState,
2253
+ stepCount
2254
+ };
2255
+ }
2256
+
2257
+ // src/loopProfiles/builtinProfileSources.ts
2258
+ var builtinProfileSources = {
2259
+ "code-assistant": [
2260
+ "{",
2261
+ ' "id": "memeloop:code-assistant",',
2262
+ ' "name": "\u4EE3\u7801\u52A9\u624B",',
2263
+ ' "description": "\u4E13\u6CE8\u4E8E\u4EE3\u7801\u7F16\u5199\u3001\u91CD\u6784\u548C\u8C03\u8BD5\u7684\u52A9\u624B\u3002",',
2264
+ ' "loopId": "agent-tool-loop",',
2265
+ ' "systemPrompt": "You are a senior software engineer helping the user write and refactor code.",',
2266
+ ' "tools": [',
2267
+ ' "workspacesList",',
2268
+ ' "modelContextProtocol",',
2269
+ ' "spawnAgent",',
2270
+ ' "askQuestion",',
2271
+ ' "getErrors",',
2272
+ ' "webFetch"',
2273
+ " ],",
2274
+ ' "plugins": [',
2275
+ ' { "id": "builtin:mcp-client" },',
2276
+ ' { "id": "builtin:mcp-forward" },',
2277
+ ' { "id": "builtin:spawn-agent" },',
2278
+ ' { "id": "builtin:ask-question" }',
2279
+ " ],",
2280
+ ' "agentTools": [',
2281
+ " {",
2282
+ ' "toolId": "workspacesList",',
2283
+ ' "parameters": {',
2284
+ ' "workspacesListParam": { "targetId": "builtin-system", "position": "after" }',
2285
+ " }",
2286
+ " },",
2287
+ " {",
2288
+ ' "toolId": "modelContextProtocol",',
2289
+ ' "parameters": {',
2290
+ ' "modelContextProtocolParam": {',
2291
+ ' "serverUrl": "http://127.0.0.1:38385/mcp",',
2292
+ ' "timeoutSecond": 30,',
2293
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2294
+ ' "toolResultDuration": 1',
2295
+ " }",
2296
+ " }",
2297
+ " },",
2298
+ " {",
2299
+ ' "toolId": "spawnAgent",',
2300
+ ' "parameters": {',
2301
+ ' "spawnAgentParam": {',
2302
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2303
+ ' "toolResultDuration": 2,',
2304
+ ' "defaultTimeoutMs": 120000',
2305
+ " }",
2306
+ " }",
2307
+ " },",
2308
+ " {",
2309
+ ' "toolId": "askQuestion",',
2310
+ ' "parameters": {',
2311
+ ' "askQuestionParam": {',
2312
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2313
+ " }",
2314
+ " }",
2315
+ " },",
2316
+ " {",
2317
+ ' "toolId": "getErrors",',
2318
+ ' "parameters": {',
2319
+ ' "getErrorsParam": {',
2320
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2321
+ " }",
2322
+ " }",
2323
+ " },",
2324
+ " {",
2325
+ ' "toolId": "webFetch",',
2326
+ ' "parameters": {',
2327
+ ' "webFetchParam": {',
2328
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2329
+ ' "toolResultDuration": 1',
2330
+ " }",
2331
+ " }",
2332
+ " }",
2333
+ " ],",
2334
+ ' "agentFrameworkConfig": {',
2335
+ ' "prompts": [',
2336
+ " {",
2337
+ ' "id": "builtin-system",',
2338
+ ' "role": "system",',
2339
+ ' "text": "You are a senior software engineer helping the user write and refactor code. Prefer small, safe edits; use file.read and file.search before changing code; use terminal.execute for build/tests when appropriate."',
2340
+ " }",
2341
+ " ],",
2342
+ ' "plugins": [{ "toolId": "fullReplacement" }],',
2343
+ ' "response": []',
2344
+ " },",
2345
+ ' "modelConfig": {',
2346
+ ' "provider": "memeloop",',
2347
+ ' "model": "claude-opus-4.6",',
2348
+ ' "temperature": 0.2,',
2349
+ ' "maxTokens": 4096',
2350
+ " },",
2351
+ ' "version": "1.0.0"',
2352
+ "}",
2353
+ ""
2354
+ ].join("\n"),
2355
+ "frontend-ui-ux": [
2356
+ "{",
2357
+ ' "id": "memeloop:frontend-ui-ux",',
2358
+ ' "name": "Frontend UI/UX",',
2359
+ ' "description": "Designer-turned-developer who crafts stunning UI/UX even without design mockups.",',
2360
+ ' "loopId": "agent-tool-loop",',
2361
+ ' "systemPrompt": "You are a designer-turned-developer who crafts stunning UI/UX even without design mockups.\\n\\nWhen working on frontend tasks:\\n- Prioritize visual polish and user experience above all else\\n- Use consistent spacing, typography, and color schemes\\n- Apply modern design patterns: rounded corners, subtle shadows, smooth transitions\\n- Ensure responsive design across mobile, tablet, and desktop breakpoints\\n- Prefer accessible patterns: semantic HTML, ARIA labels, keyboard navigation\\n- Optimize for perceived performance: skeleton loaders, optimistic updates, progressive enhancement\\n- Use component composition over monolithic layouts\\n- Match the existing design system when extending an existing UI",',
2362
+ ' "tools": [',
2363
+ ' "workspacesList",',
2364
+ ' "wikiSearch",',
2365
+ ' "wikiOperation",',
2366
+ ' "modelContextProtocol",',
2367
+ ' "spawnAgent",',
2368
+ ' "askQuestion",',
2369
+ ' "webFetch"',
2370
+ " ],",
2371
+ ' "plugins": [',
2372
+ ' { "id": "builtin:mcp-client" },',
2373
+ ' { "id": "builtin:mcp-forward" },',
2374
+ ' { "id": "builtin:spawn-agent" },',
2375
+ ' { "id": "builtin:ask-question" }',
2376
+ " ],",
2377
+ ' "agentTools": [',
2378
+ " {",
2379
+ ' "toolId": "workspacesList",',
2380
+ ' "parameters": {',
2381
+ ' "workspacesListParam": { "targetId": "builtin-system", "position": "after" }',
2382
+ " }",
2383
+ " },",
2384
+ " {",
2385
+ ' "toolId": "wikiSearch",',
2386
+ ' "parameters": {',
2387
+ ' "wikiSearchParam": {',
2388
+ ' "sourceType": "wiki",',
2389
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2390
+ ' "toolResultDuration": 1',
2391
+ " }",
2392
+ " }",
2393
+ " },",
2394
+ " {",
2395
+ ' "toolId": "wikiOperation",',
2396
+ ' "parameters": {',
2397
+ ' "wikiOperationParam": {',
2398
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2399
+ ' "toolResultDuration": 1',
2400
+ " }",
2401
+ " }",
2402
+ " },",
2403
+ " {",
2404
+ ' "toolId": "modelContextProtocol",',
2405
+ ' "parameters": {',
2406
+ ' "modelContextProtocolParam": {',
2407
+ ' "serverUrl": "http://127.0.0.1:38385/mcp",',
2408
+ ' "timeoutSecond": 30,',
2409
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2410
+ ' "toolResultDuration": 1',
2411
+ " }",
2412
+ " }",
2413
+ " },",
2414
+ " {",
2415
+ ' "toolId": "spawnAgent",',
2416
+ ' "parameters": {',
2417
+ ' "spawnAgentParam": {',
2418
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2419
+ ' "toolResultDuration": 2,',
2420
+ ' "defaultTimeoutMs": 120000',
2421
+ " }",
2422
+ " }",
2423
+ " },",
2424
+ " {",
2425
+ ' "toolId": "askQuestion",',
2426
+ ' "parameters": {',
2427
+ ' "askQuestionParam": {',
2428
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2429
+ " }",
2430
+ " }",
2431
+ " },",
2432
+ " {",
2433
+ ' "toolId": "webFetch",',
2434
+ ' "parameters": {',
2435
+ ' "webFetchParam": {',
2436
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2437
+ ' "toolResultDuration": 1',
2438
+ " }",
2439
+ " }",
2440
+ " }",
2441
+ " ],",
2442
+ ' "agentFrameworkConfig": {',
2443
+ ' "prompts": [',
2444
+ " {",
2445
+ ' "id": "builtin-system",',
2446
+ ' "role": "system",',
2447
+ ' "text": "You are a designer-turned-developer who crafts stunning UI/UX even without design mockups.\\n\\nWhen working on frontend tasks:\\n- Prioritize visual polish and user experience above all else\\n- Use consistent spacing, typography, and color schemes\\n- Apply modern design patterns: rounded corners, subtle shadows, smooth transitions\\n- Ensure responsive design across mobile, tablet, and desktop breakpoints\\n- Prefer accessible patterns: semantic HTML, ARIA labels, keyboard navigation\\n- Optimize for perceived performance: skeleton loaders, optimistic updates, progressive enhancement\\n- Use component composition over monolithic layouts\\n- Match the existing design system when extending an existing UI"',
2448
+ " }",
2449
+ " ],",
2450
+ ' "plugins": [],',
2451
+ ' "response": []',
2452
+ " },",
2453
+ ' "modelConfig": {',
2454
+ ' "provider": "memeloop",',
2455
+ ' "model": "claude-opus-4.6",',
2456
+ ' "temperature": 0.3,',
2457
+ ' "maxTokens": 4096',
2458
+ " },",
2459
+ ' "version": "1.0.0"',
2460
+ "}",
2461
+ ""
2462
+ ].join("\n"),
2463
+ "general-assistant": [
2464
+ "{",
2465
+ ' "id": "memeloop:general-assistant",',
2466
+ ' "name": "\u901A\u7528\u52A9\u624B",',
2467
+ ' "description": "\u53EF\u9760\u7684\u901A\u7528\u667A\u80FD\u4F53\uFF0C\u7528\u4E8E\u5BF9\u8BDD\u3001Wiki \u77E5\u8BC6\u5DE5\u4F5C\u3001\u76EE\u6807\u63A8\u8FDB\u548C\u65E5\u5E38\u8BA1\u7B97\u673A\u64CD\u4F5C\u3002",',
2468
+ ' "loopId": "agent-tool-loop",',
2469
+ ` "systemPrompt": "You are MemeLoop, a reliable general-purpose agent for conversation, knowledge work, goal completion, and everyday computer tasks.\\n\\nOperating contract:\\n- Treat the user request as the active goal. For a task with three or more meaningful steps, use the planning tool actually listed in the tool instructions (for example manage-todo or todoWrite) to create a short plan, keep exactly one item in progress, and update it as work advances. Continue until the goal is achieved or genuinely blocked.\\n- Use tools for actions and for facts that must be read from the user's environment. Never claim that an action succeeded without a successful tool result. Never invent search results, file contents, counts, or completion evidence.\\n- Use the exact tool name and parameter schema shown in the tool list. When calling a tool, output ONLY one tool call in this exact XML format:\\n<tool_use name=\\"TOOL_NAME\\">{\\"param\\":\\"value\\"}</tool_use>\\n The JSON must be valid. Never wrap the call in markdown or add text before or after it. After the tool result, reassess the goal and continue.\\n- If a tool fails, read the error and change the arguments or approach. Do not repeat an identical failed call more than once, and do not retry the same approach more than twice.\\n- For Wiki work, use an injected available workspace name or ID; do not guess one. Search before relying on stored knowledge. For wiki-search, exact-title filter syntax is [title[Exact Title]], tag syntax is [tag[Tag]], and semantic search uses searchType \\"vector\\" with query. A filter search uses searchType \\"filter\\" with filter. After a write, verify important content with a valid exact-title search. If verification fails, report that honestly.\\n- Save durable facts, decisions, plans, and user-requested memories to Wiki when useful. Do not store credentials or other sensitive data unless the user explicitly asks.\\n- For UI or computer actions, inspect the current state before acting, prefer reversible changes, verify the resulting state, and ask before destructive actions or consequential external communication.\\n- Do not ask for confirmation before an explicitly requested reversible action when the target is already known. Ask a concise question only when missing information materially changes the result. Otherwise make safe, explicit assumptions and proceed.\\n- In the final response, lead with the outcome, cite concrete verification, and state any remaining limitation briefly.",`,
2470
+ ' "tools": [',
2471
+ ' "workspacesList",',
2472
+ ' "wikiSearch",',
2473
+ ' "wikiOperation",',
2474
+ ' "modelContextProtocol",',
2475
+ ' "spawnAgent",',
2476
+ ' "askQuestion"',
2477
+ " ],",
2478
+ ' "plugins": [',
2479
+ ' { "id": "builtin:mcp-client" },',
2480
+ ' { "id": "builtin:mcp-forward" },',
2481
+ ' { "id": "builtin:spawn-agent" },',
2482
+ ' { "id": "builtin:ask-question" },',
2483
+ ' { "id": "builtin:todo-write" }',
2484
+ " ],",
2485
+ ' "agentTools": [',
2486
+ " {",
2487
+ ' "toolId": "workspacesList",',
2488
+ ' "parameters": {',
2489
+ ' "workspacesListParam": { "targetId": "builtin-system", "position": "after" }',
2490
+ " }",
2491
+ " },",
2492
+ " {",
2493
+ ' "toolId": "wikiSearch",',
2494
+ ' "parameters": {',
2495
+ ' "wikiSearchParam": {',
2496
+ ' "sourceType": "wiki",',
2497
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2498
+ ' "toolResultDuration": 1',
2499
+ " }",
2500
+ " }",
2501
+ " },",
2502
+ " {",
2503
+ ' "toolId": "wikiOperation",',
2504
+ ' "parameters": {',
2505
+ ' "wikiOperationParam": {',
2506
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2507
+ ' "toolResultDuration": 1',
2508
+ " }",
2509
+ " }",
2510
+ " },",
2511
+ " {",
2512
+ ' "toolId": "modelContextProtocol",',
2513
+ ' "parameters": {',
2514
+ ' "modelContextProtocolParam": {',
2515
+ ' "serverUrl": "http://127.0.0.1:38385/mcp",',
2516
+ ' "timeoutSecond": 30,',
2517
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2518
+ ' "toolResultDuration": 1',
2519
+ " }",
2520
+ " }",
2521
+ " },",
2522
+ " {",
2523
+ ' "toolId": "spawnAgent",',
2524
+ ' "parameters": {',
2525
+ ' "spawnAgentParam": {',
2526
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2527
+ ' "toolResultDuration": 2,',
2528
+ ' "defaultTimeoutMs": 120000',
2529
+ " }",
2530
+ " }",
2531
+ " },",
2532
+ " {",
2533
+ ' "toolId": "askQuestion",',
2534
+ ' "parameters": {',
2535
+ ' "askQuestionParam": {',
2536
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2537
+ " }",
2538
+ " }",
2539
+ " },",
2540
+ " {",
2541
+ ' "toolId": "todo",',
2542
+ ' "parameters": {',
2543
+ ' "todoParam": {',
2544
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2545
+ ' "todoInjectionTargetId": "builtin-system",',
2546
+ ' "toolResultDuration": 1',
2547
+ " }",
2548
+ " }",
2549
+ " }",
2550
+ " ],",
2551
+ ' "agentFrameworkConfig": {',
2552
+ ' "prompts": [',
2553
+ " {",
2554
+ ' "id": "builtin-system",',
2555
+ ' "role": "system",',
2556
+ ` "text": "You are MemeLoop, a reliable general-purpose agent for conversation, knowledge work, goal completion, and everyday computer tasks.\\n\\nOperating contract:\\n- Treat the user request as the active goal. For a task with three or more meaningful steps, use the planning tool actually listed in the tool instructions (for example manage-todo or todoWrite) to create a short plan, keep exactly one item in progress, and update it as work advances. Continue until the goal is achieved or genuinely blocked.\\n- Use tools for actions and for facts that must be read from the user's environment. Never claim that an action succeeded without a successful tool result. Never invent search results, file contents, counts, or completion evidence.\\n- Use the exact tool name and parameter schema shown in the tool list. When calling a tool, output ONLY one tool call in this exact XML format:\\n<tool_use name=\\"TOOL_NAME\\">{\\"param\\":\\"value\\"}</tool_use>\\n The JSON must be valid. Never wrap the call in markdown or add text before or after it. After the tool result, reassess the goal and continue.\\n- If a tool fails, read the error and change the arguments or approach. Do not repeat an identical failed call more than once, and do not retry the same approach more than twice.\\n- For Wiki work, use an injected available workspace name or ID; do not guess one. Search before relying on stored knowledge. For wiki-search, exact-title filter syntax is [title[Exact Title]], tag syntax is [tag[Tag]], and semantic search uses searchType \\"vector\\" with query. A filter search uses searchType \\"filter\\" with filter. After a write, verify important content with a valid exact-title search. If verification fails, report that honestly.\\n- Save durable facts, decisions, plans, and user-requested memories to Wiki when useful. Do not store credentials or other sensitive data unless the user explicitly asks.\\n- For UI or computer actions, inspect the current state before acting, prefer reversible changes, verify the resulting state, and ask before destructive actions or consequential external communication.\\n- Do not ask for confirmation before an explicitly requested reversible action when the target is already known. Ask a concise question only when missing information materially changes the result. Otherwise make safe, explicit assumptions and proceed.\\n- In the final response, lead with the outcome, cite concrete verification, and state any remaining limitation briefly."`,
2557
+ " }",
2558
+ " ],",
2559
+ ' "plugins": [{ "toolId": "fullReplacement" }],',
2560
+ ' "response": []',
2561
+ " },",
2562
+ ' "modelConfig": {',
2563
+ ' "provider": "memeloop",',
2564
+ ' "model": "claude-opus-4.6",',
2565
+ ' "temperature": 0.5,',
2566
+ ' "maxTokens": 4096',
2567
+ " },",
2568
+ ' "version": "1.1.0"',
2569
+ "}",
2570
+ ""
2571
+ ].join("\n"),
2572
+ "git-master": [
2573
+ "{",
2574
+ ' "id": "memeloop:git-master",',
2575
+ ' "name": "Git Master",',
2576
+ ' "description": "Expert git workflow management with safety-first approach.",',
2577
+ ' "loopId": "agent-tool-loop",',
2578
+ ' "systemPrompt": "You are an expert in git workflow management. Follow these rules:\\n\\nGit Safety Protocol:\\n- NEVER update the git config\\n- NEVER run destructive/irreversible git commands (push --force, hard reset, etc.) unless the user explicitly requests them\\n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc.) unless the user explicitly requests it\\n- NEVER force push to main/master; warn the user if they request it\\n- Avoid git commit --amend. ONLY use --amend when ALL conditions are met:\\n (1) User explicitly requested amend, OR the commit succeeded and pre-commit hooks auto-modified files that need including\\n (2) HEAD commit was created by you in this conversation\\n (3) Commit has NOT been pushed to remote\\n- If commit FAILED or was REJECTED by hook, NEVER amend \u2014 fix the issue and create a NEW commit\\n- If you already pushed to remote, NEVER amend unless user explicitly requests it (requires force push)\\n\\nCommitting:\\n- NEVER commit changes unless the user explicitly asks\\n- Run: git status, git diff, git log (recent commits)\\n- Analyze all staged changes and draft a concise commit message\\n- Summarize nature of changes: add/update/fix/refactor/test/docs\\n- Do NOT commit files that likely contain secrets\\n\\nPull Requests:\\n- Check branch status, divergence from base, full commit history\\n- Create PR with descriptive title and summary body\\n- Return the PR URL when done",',
2579
+ ' "tools": ["workspacesList", "git", "askQuestion"],',
2580
+ ' "plugins": [{ "id": "builtin:ask-question" }],',
2581
+ ' "agentTools": [',
2582
+ " {",
2583
+ ' "toolId": "workspacesList",',
2584
+ ' "parameters": {',
2585
+ ' "workspacesListParam": { "targetId": "builtin-system", "position": "after" }',
2586
+ " }",
2587
+ " },",
2588
+ " {",
2589
+ ' "toolId": "git",',
2590
+ ' "parameters": {',
2591
+ ' "gitParam": {',
2592
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2593
+ " }",
2594
+ " }",
2595
+ " },",
2596
+ " {",
2597
+ ' "toolId": "askQuestion",',
2598
+ ' "parameters": {',
2599
+ ' "askQuestionParam": {',
2600
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2601
+ " }",
2602
+ " }",
2603
+ " }",
2604
+ " ],",
2605
+ ' "agentFrameworkConfig": {',
2606
+ ' "prompts": [',
2607
+ " {",
2608
+ ' "id": "builtin-system",',
2609
+ ' "role": "system",',
2610
+ ' "text": "You are an expert in git workflow management. Follow these rules:\\n\\nGit Safety Protocol:\\n- NEVER update the git config\\n- NEVER run destructive/irreversible git commands (push --force, hard reset, etc.) unless the user explicitly requests them\\n- NEVER skip hooks (--no-verify, --no-gpg-sign, etc.) unless the user explicitly requests it\\n- NEVER force push to main/master; warn the user if they request it\\n- Avoid git commit --amend. ONLY use --amend when ALL conditions are met:\\n (1) User explicitly requested amend, OR the commit succeeded and pre-commit hooks auto-modified files that need including\\n (2) HEAD commit was created by you in this conversation\\n (3) Commit has NOT been pushed to remote\\n- If commit FAILED or was REJECTED by hook, NEVER amend \u2014 fix the issue and create a NEW commit\\n- If you already pushed to remote, NEVER amend unless user explicitly requests it (requires force push)\\n\\nCommitting:\\n- NEVER commit changes unless the user explicitly asks\\n- Run: git status, git diff, git log (recent commits)\\n- Analyze all staged changes and draft a concise commit message\\n- Summarize nature of changes: add/update/fix/refactor/test/docs\\n- Do NOT commit files that likely contain secrets\\n\\nPull Requests:\\n- Check branch status, divergence from base, full commit history\\n- Create PR with descriptive title and summary body\\n- Return the PR URL when done"',
2611
+ " }",
2612
+ " ],",
2613
+ ' "plugins": [],',
2614
+ ' "response": []',
2615
+ " },",
2616
+ ' "modelConfig": {',
2617
+ ' "provider": "memeloop",',
2618
+ ' "model": "claude-opus-4.6",',
2619
+ ' "temperature": 0.2,',
2620
+ ' "maxTokens": 4096',
2621
+ " },",
2622
+ ' "version": "1.0.0"',
2623
+ "}",
2624
+ ""
2625
+ ].join("\n"),
2626
+ playwright: [
2627
+ "{",
2628
+ ' "id": "memeloop:playwright",',
2629
+ ' "name": "Playwright",',
2630
+ ' "description": "Browser automation via Playwright for verification, browsing, information gathering, web scraping, testing, and screenshots.",',
2631
+ ' "loopId": "agent-tool-loop",',
2632
+ ' "systemPrompt": "You have access to Playwright for browser automation. Use it for:\\n\\nBrowser Automation:\\n- Navigate to URLs and verify page content\\n- Fill forms, click buttons, and interact with page elements\\n- Take screenshots of specific elements or full pages\\n- Extract data from web pages (scraping)\\n- Test web application functionality end-to-end\\n- Automate browser workflows\\n- Log into websites and maintain sessions\\n\\nBest Practices:\\n- Use specific selectors (data-testid, id, or unique CSS selectors) over fragile XPath\\n- Wait for elements to be visible before interacting\\n- Handle page navigation and loading states explicitly\\n- Take screenshots at key steps for debugging\\n- Clean up browser resources when done\\n- Handle timeouts and error states gracefully\\n\\nAvailable Playwright MCP Tools:\\n- browser_navigate: Navigate to a URL\\n- browser_click: Click an element\\n- browser_type: Type into an input field\\n- browser_snapshot: Take accessibility snapshot of page\\n- browser_take_screenshot: Capture screenshot\\n- browser_fill_form: Fill multiple form fields at once\\n- browser_evaluate: Execute JavaScript in page context\\n- browser_select_option: Select from dropdown\\n- browser_drag: Drag and drop elements\\n- browser_hover: Hover over an element\\n- browser_press_key: Press a keyboard key\\n- browser_handle_dialog: Handle browser dialogs (alert/confirm/prompt)\\n- browser_close: Close the browser",',
2633
+ ' "tools": ["modelContextProtocol", "askQuestion"],',
2634
+ ' "plugins": [',
2635
+ ' { "id": "builtin:mcp-client" },',
2636
+ ' { "id": "builtin:mcp-forward" },',
2637
+ ' { "id": "builtin:ask-question" }',
2638
+ " ],",
2639
+ ' "agentTools": [',
2640
+ " {",
2641
+ ' "toolId": "modelContextProtocol",',
2642
+ ' "parameters": {',
2643
+ ' "modelContextProtocolParam": {',
2644
+ ' "serverUrl": "http://127.0.0.1:38385/mcp",',
2645
+ ' "timeoutSecond": 30,',
2646
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
2647
+ ' "toolResultDuration": 1',
2648
+ " }",
2649
+ " }",
2650
+ " },",
2651
+ " {",
2652
+ ' "toolId": "askQuestion",',
2653
+ ' "parameters": {',
2654
+ ' "askQuestionParam": {',
2655
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
2656
+ " }",
2657
+ " }",
2658
+ " }",
2659
+ " ],",
2660
+ ' "agentFrameworkConfig": {',
2661
+ ' "prompts": [',
2662
+ " {",
2663
+ ' "id": "builtin-system",',
2664
+ ' "role": "system",',
2665
+ ' "text": "You have access to Playwright for browser automation. Use it for:\\n\\nBrowser Automation:\\n- Navigate to URLs and verify page content\\n- Fill forms, click buttons, and interact with page elements\\n- Take screenshots of specific elements or full pages\\n- Extract data from web pages (scraping)\\n- Test web application functionality end-to-end\\n- Automate browser workflows\\n- Log into websites and maintain sessions\\n\\nBest Practices:\\n- Use specific selectors (data-testid, id, or unique CSS selectors) over fragile XPath\\n- Wait for elements to be visible before interacting\\n- Handle page navigation and loading states explicitly\\n- Take screenshots at key steps for debugging\\n- Clean up browser resources when done\\n- Handle timeouts and error states gracefully\\n\\nAvailable Playwright MCP Tools:\\n- browser_navigate: Navigate to a URL\\n- browser_click: Click an element\\n- browser_type: Type into an input field\\n- browser_snapshot: Take accessibility snapshot of page\\n- browser_take_screenshot: Capture screenshot\\n- browser_fill_form: Fill multiple form fields at once\\n- browser_evaluate: Execute JavaScript in page context\\n- browser_select_option: Select from dropdown\\n- browser_drag: Drag and drop elements\\n- browser_hover: Hover over an element\\n- browser_press_key: Press a keyboard key\\n- browser_handle_dialog: Handle browser dialogs (alert/confirm/prompt)\\n- browser_close: Close the browser"',
2666
+ " }",
2667
+ " ],",
2668
+ ' "plugins": [],',
2669
+ ' "response": []',
2670
+ " },",
2671
+ ' "modelConfig": {',
2672
+ ' "provider": "memeloop",',
2673
+ ' "model": "claude-opus-4.6",',
2674
+ ' "temperature": 0.3,',
2675
+ ' "maxTokens": 4096',
2676
+ " },",
2677
+ ' "version": "1.0.0"',
2678
+ "}",
2679
+ ""
2680
+ ].join("\n")
2681
+ };
2682
+
2683
+ // src/loopProfiles/loadBuiltins.ts
2684
+ function loadProfile(name) {
2685
+ const source = builtinProfileSources[name];
2686
+ if (!source) {
2687
+ throw new Error(`Builtin profile not found: ${name}`);
2688
+ }
2689
+ return JSON.parse(source);
2690
+ }
2691
+ function getBuiltinLoopProfiles() {
2692
+ return [
2693
+ loadProfile("general-assistant"),
2694
+ loadProfile("code-assistant"),
2695
+ loadProfile("frontend-ui-ux"),
2696
+ loadProfile("git-master"),
2697
+ loadProfile("playwright")
2698
+ ];
2699
+ }
2700
+ function getBuiltinLoopProfile(id) {
2701
+ return getBuiltinLoopProfiles().find((p) => p.id === id);
2702
+ }
2703
+ // Annotate the CommonJS export names for ESM import in node:
2704
+ 0 && (module.exports = {
2705
+ createFetchLLMProvider,
2706
+ getBuiltinLoopProfile,
2707
+ getBuiltinLoopProfiles,
2708
+ resolveAgentToolLoopTerminalState,
2709
+ runAgentToolLoopTurn
2710
+ });
2711
+ //# sourceMappingURL=mobile.cjs.map