memeloop 0.1.0 → 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 (48) hide show
  1. package/dist/browser.d.cts +7 -7
  2. package/dist/browser.d.ts +7 -7
  3. package/dist/{chunk-44YHBKDL.js → chunk-2C6BJZI3.js} +3 -3
  4. package/dist/{chunk-HVB2BR3H.js → chunk-KFS2EJT6.js} +2 -2
  5. package/dist/{chunk-XHRBV6I3.js → chunk-MAJWHAKR.js} +2 -2
  6. package/dist/{chunk-QFHAAIIM.js → chunk-T7FSXWFR.js} +95 -8
  7. package/dist/chunk-T7FSXWFR.js.map +1 -0
  8. package/dist/conversation.d.cts +1 -1
  9. package/dist/conversation.d.ts +1 -1
  10. package/dist/{fetchProvider-Cm0sO4Tl.d.ts → fetchProvider-WWnWnQFP.d.ts} +1 -1
  11. package/dist/{fetchProvider-BpcGVSOG.d.cts → fetchProvider-toTHy5Nu.d.cts} +1 -1
  12. package/dist/index.cjs +295 -201
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +10 -10
  15. package/dist/index.d.ts +10 -10
  16. package/dist/index.js +11 -5
  17. package/dist/index.js.map +1 -1
  18. package/dist/llm-providers.d.cts +1 -1
  19. package/dist/llm-providers.d.ts +1 -1
  20. package/dist/loop-api.cjs +291 -201
  21. package/dist/loop-api.cjs.map +1 -1
  22. package/dist/loop-api.d.cts +5 -5
  23. package/dist/loop-api.d.ts +5 -5
  24. package/dist/loop-api.js +6 -4
  25. package/dist/mobile.cjs +235 -149
  26. package/dist/mobile.cjs.map +1 -1
  27. package/dist/mobile.d.cts +3 -3
  28. package/dist/mobile.d.ts +3 -3
  29. package/dist/mobile.js +2 -2
  30. package/dist/{orchestration-portable-Zw0g5tbj.d.ts → orchestration-portable-BHB_YrNN.d.ts} +1 -1
  31. package/dist/{orchestration-portable-Bsf8YRfp.d.cts → orchestration-portable-mvYBvGBb.d.cts} +1 -1
  32. package/dist/orchestration-portable.d.cts +2 -2
  33. package/dist/orchestration-portable.d.ts +2 -2
  34. package/dist/{promptConcat-deDSWZE3.d.ts → promptConcat-0WNFTg4l.d.ts} +2 -2
  35. package/dist/{promptConcat-WTN-uHcz.d.cts → promptConcat-D6wr5V-V.d.cts} +2 -2
  36. package/dist/{providerRegistry-9trr5aoK.d.ts → providerRegistry-Bi6pAvSj.d.ts} +1 -1
  37. package/dist/{providerRegistry-xk_B1Ekv.d.cts → providerRegistry-CPsktuiX.d.cts} +1 -1
  38. package/dist/{registry-8eztoD_r.d.cts → registry-D0kbxksn.d.cts} +2 -2
  39. package/dist/{registry-DV24sI-3.d.ts → registry-DDbvhlhs.d.ts} +2 -2
  40. package/dist/{runtime-SKSXVYIM.js → runtime-PGWR6FIV.js} +3 -3
  41. package/dist/{scriptDeploymentPipeline-DsnT0AG6.d.ts → scriptDeploymentPipeline-CXJcC82H.d.ts} +2 -1
  42. package/dist/{scriptDeploymentPipeline-BAeo1dPb.d.cts → scriptDeploymentPipeline-yG1ZhVVI.d.cts} +2 -1
  43. package/package.json +1 -1
  44. package/dist/chunk-QFHAAIIM.js.map +0 -1
  45. /package/dist/{chunk-44YHBKDL.js.map → chunk-2C6BJZI3.js.map} +0 -0
  46. /package/dist/{chunk-HVB2BR3H.js.map → chunk-KFS2EJT6.js.map} +0 -0
  47. /package/dist/{chunk-XHRBV6I3.js.map → chunk-MAJWHAKR.js.map} +0 -0
  48. /package/dist/{runtime-SKSXVYIM.js.map → runtime-PGWR6FIV.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import { k as ILLMProvider } from './scriptDeploymentPipeline-BAeo1dPb.cjs';
1
+ import { k as ILLMProvider } from './scriptDeploymentPipeline-yG1ZhVVI.cjs';
2
2
  import './interface-IrKBFtL1.cjs';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { k as ILLMProvider } from './scriptDeploymentPipeline-DsnT0AG6.js';
1
+ import { k as ILLMProvider } from './scriptDeploymentPipeline-CXJcC82H.js';
2
2
  import './interface-IrKBFtL1.js';
3
3
 
4
4
  /**
package/dist/loop-api.cjs CHANGED
@@ -2667,6 +2667,199 @@ var init_compaction = __esm({
2667
2667
  }
2668
2668
  });
2669
2669
 
2670
+ // src/conversation/parts.ts
2671
+ function tryParseJson(value) {
2672
+ try {
2673
+ return JSON.parse(value);
2674
+ } catch {
2675
+ return void 0;
2676
+ }
2677
+ }
2678
+ function parseLegacyToolResultContent(content) {
2679
+ const match = /(?:<functions_result>\s*)?Tool:\s*(.+?)\nParameters:\s*(.+?)\n(Error|Result):\s*([\s\S]*?)\s*(?:<\/functions_result>|$)/su.exec(content.trim());
2680
+ if (!match) return null;
2681
+ const [, rawToolName, rawParameters, kind, rawBody] = match;
2682
+ const parsedParameters = tryParseJson(rawParameters.trim());
2683
+ const result = rawBody.trim();
2684
+ return {
2685
+ type: "tool-result",
2686
+ toolName: rawToolName.trim(),
2687
+ parameters: parsedParameters,
2688
+ result,
2689
+ isError: kind === "Error",
2690
+ payload: tryParseJson(result)
2691
+ };
2692
+ }
2693
+ function isTextPart(part) {
2694
+ return part.type === "text";
2695
+ }
2696
+ function isReasoningPart(part) {
2697
+ return part.type === "reasoning";
2698
+ }
2699
+ function isToolCallPart(part) {
2700
+ return part.type === "tool-call";
2701
+ }
2702
+ function isAttachmentPart(part) {
2703
+ return part.type === "attachment";
2704
+ }
2705
+ function isToolResultPart(part) {
2706
+ return part.type === "tool-result";
2707
+ }
2708
+ function buildToolResultSummary(part) {
2709
+ const prefix = part.isError ? "Error" : "Result";
2710
+ const suffix = part.result.trim();
2711
+ if (suffix.length === 0) return `${prefix} from ${part.toolName}`;
2712
+ return `${prefix} from ${part.toolName}: ${suffix}`;
2713
+ }
2714
+ function projectChatMessageParts(parts) {
2715
+ const text = parts.filter(isTextPart).map((part) => part.text.trim()).filter(Boolean);
2716
+ const reasoning = parts.filter(isReasoningPart).map((part) => part.text.trim()).filter(Boolean);
2717
+ const toolCalls = parts.filter(isToolCallPart).map((part) => ({ id: part.toolCallId, toolName: part.toolName, arguments: part.arguments }));
2718
+ const attachments = parts.filter(isAttachmentPart).map((part) => part.attachment);
2719
+ const toolResults = parts.filter(isToolResultPart);
2720
+ let content = text.join("\n\n");
2721
+ if (content.length === 0 && toolResults.length > 0) {
2722
+ content = toolResults.map(buildToolResultSummary).join("\n\n");
2723
+ }
2724
+ if (content.length === 0 && toolCalls.length > 0) {
2725
+ content = toolCalls.map((part) => `Tool call: ${part.toolName}`).join("\n\n");
2726
+ }
2727
+ return {
2728
+ content,
2729
+ reasoning_content: reasoning.length > 0 ? reasoning.join("\n\n") : void 0,
2730
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
2731
+ attachments: attachments.length > 0 ? attachments : void 0
2732
+ };
2733
+ }
2734
+ function buildLegacyChatMessageParts(input) {
2735
+ const parts = [];
2736
+ if (input.role !== "tool" && typeof input.content === "string" && input.content.trim().length > 0) {
2737
+ parts.push({ type: "text", text: input.content });
2738
+ }
2739
+ if (typeof input.reasoning_content === "string" && input.reasoning_content.trim().length > 0) {
2740
+ parts.push({ type: "reasoning", text: input.reasoning_content });
2741
+ }
2742
+ if (input.toolCalls) {
2743
+ for (const toolCall of input.toolCalls) {
2744
+ parts.push({
2745
+ type: "tool-call",
2746
+ toolCallId: toolCall.id,
2747
+ toolName: toolCall.toolName,
2748
+ arguments: toolCall.arguments
2749
+ });
2750
+ }
2751
+ }
2752
+ if (input.attachments) {
2753
+ for (const attachment of input.attachments) {
2754
+ parts.push({ type: "attachment", attachment });
2755
+ }
2756
+ }
2757
+ if (input.role === "tool") {
2758
+ const metadata = input.metadata ?? {};
2759
+ const parsed = typeof input.content === "string" ? parseLegacyToolResultContent(input.content) : null;
2760
+ const toolName = typeof metadata.toolId === "string" && metadata.toolId.length > 0 ? metadata.toolId : parsed?.toolName ?? "tool";
2761
+ const result = parsed?.result ?? (typeof input.content === "string" ? input.content : "");
2762
+ const payload = parsed?.payload ?? tryParseJson(result);
2763
+ parts.push({
2764
+ type: "tool-result",
2765
+ toolName,
2766
+ parameters: metadata.toolParameters ?? parsed?.parameters,
2767
+ result,
2768
+ isError: metadata.isError === true || parsed?.isError === true,
2769
+ payload,
2770
+ detailRef: input.detailRef
2771
+ });
2772
+ }
2773
+ return parts;
2774
+ }
2775
+ function getChatMessageParts(message) {
2776
+ return message.parts ?? buildLegacyChatMessageParts(message);
2777
+ }
2778
+ var init_parts = __esm({
2779
+ "src/conversation/parts.ts"() {
2780
+ "use strict";
2781
+ }
2782
+ });
2783
+
2784
+ // src/conversation/factory.ts
2785
+ function createChatMessage(input) {
2786
+ const now = Date.now();
2787
+ const parts = input.parts ?? buildLegacyChatMessageParts({
2788
+ role: input.role,
2789
+ content: input.content,
2790
+ reasoning_content: input.reasoning_content,
2791
+ toolCalls: input.toolCalls,
2792
+ attachments: input.attachments,
2793
+ detailRef: input.detailRef,
2794
+ metadata: input.metadata
2795
+ });
2796
+ const projection = projectChatMessageParts(parts);
2797
+ return {
2798
+ messageId: input.messageId,
2799
+ conversationId: input.conversationId,
2800
+ originNodeId: input.originNodeId ?? "unknown",
2801
+ timestamp: now,
2802
+ lamportClock: input.lamportClock ?? now,
2803
+ role: input.role,
2804
+ parts: parts.length > 0 ? parts : void 0,
2805
+ content: input.content ?? projection.content,
2806
+ contentType: input.contentType ?? "text/plain",
2807
+ metadata: input.metadata,
2808
+ duration: input.duration,
2809
+ toolCalls: input.toolCalls ?? projection.toolCalls,
2810
+ reasoning_content: input.reasoning_content ?? projection.reasoning_content,
2811
+ hidden: input.hidden,
2812
+ attachments: input.attachments ?? projection.attachments,
2813
+ detailRef: input.detailRef
2814
+ };
2815
+ }
2816
+ function createAgentInstanceFromDefinition(definition, overrides) {
2817
+ const now = /* @__PURE__ */ new Date();
2818
+ return {
2819
+ ...definition,
2820
+ id: overrides.id,
2821
+ agentDefId: definition.id,
2822
+ name: overrides.name ?? definition.name,
2823
+ status: overrides.status ?? DEFAULT_INSTANCE_STATUS,
2824
+ messages: [],
2825
+ created: now,
2826
+ modified: now,
2827
+ closed: overrides.closed ?? false,
2828
+ volatile: overrides.volatile ?? false,
2829
+ isDelegatedAgentRun: overrides.isDelegatedAgentRun,
2830
+ parentAgentRunId: overrides.parentAgentRunId,
2831
+ agentFrameworkConfig: overrides.agentFrameworkConfig
2832
+ };
2833
+ }
2834
+ var DEFAULT_INSTANCE_STATUS;
2835
+ var init_factory = __esm({
2836
+ "src/conversation/factory.ts"() {
2837
+ "use strict";
2838
+ init_parts();
2839
+ DEFAULT_INSTANCE_STATUS = {
2840
+ state: "completed",
2841
+ modified: /* @__PURE__ */ new Date()
2842
+ };
2843
+ }
2844
+ });
2845
+
2846
+ // src/conversation/types.ts
2847
+ var init_types = __esm({
2848
+ "src/conversation/types.ts"() {
2849
+ "use strict";
2850
+ }
2851
+ });
2852
+
2853
+ // src/conversation/index.ts
2854
+ var init_conversation = __esm({
2855
+ "src/conversation/index.ts"() {
2856
+ "use strict";
2857
+ init_factory();
2858
+ init_parts();
2859
+ init_types();
2860
+ }
2861
+ });
2862
+
2670
2863
  // src/tools/pluginRegistry.ts
2671
2864
  function getActivePluginRegistry() {
2672
2865
  return activeOverride ?? defaultPluginRegistry;
@@ -2817,7 +3010,9 @@ function parseToolParameters(parametersText) {
2817
3010
  return import_json5.default.parse(trimmedText);
2818
3011
  } catch {
2819
3012
  }
2820
- return { input: trimmedText.substring(0, MAX_FALLBACK_INPUT_LENGTH) };
3013
+ return {
3014
+ [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)}`
3015
+ };
2821
3016
  }
2822
3017
  function extractFunctionCallsParameters(text) {
2823
3018
  const parameters = {};
@@ -2870,12 +3065,13 @@ function matchAllToolCallings(responseText) {
2870
3065
  }
2871
3066
  return { calls, parallel };
2872
3067
  }
2873
- var import_json5, MAX_FALLBACK_INPUT_LENGTH, toolPatterns;
3068
+ var import_json5, MAX_FALLBACK_INPUT_LENGTH, TOOL_PARAMETER_PARSE_ERROR_KEY, toolPatterns;
2874
3069
  var init_responsePatternUtility = __esm({
2875
3070
  "src/promptUtilities/responsePatternUtility.ts"() {
2876
3071
  "use strict";
2877
3072
  import_json5 = __toESM(require("json5"), 1);
2878
3073
  MAX_FALLBACK_INPUT_LENGTH = 1e3;
3074
+ TOOL_PARAMETER_PARSE_ERROR_KEY = "__memeloopToolParameterParseError";
2879
3075
  toolPatterns = [
2880
3076
  {
2881
3077
  name: "tool_use",
@@ -3229,199 +3425,6 @@ var init_llmStream = __esm({
3229
3425
  }
3230
3426
  });
3231
3427
 
3232
- // src/conversation/parts.ts
3233
- function tryParseJson(value) {
3234
- try {
3235
- return JSON.parse(value);
3236
- } catch {
3237
- return void 0;
3238
- }
3239
- }
3240
- function parseLegacyToolResultContent(content) {
3241
- const match = /(?:<functions_result>\s*)?Tool:\s*(.+?)\nParameters:\s*(.+?)\n(Error|Result):\s*([\s\S]*?)\s*(?:<\/functions_result>|$)/su.exec(content.trim());
3242
- if (!match) return null;
3243
- const [, rawToolName, rawParameters, kind, rawBody] = match;
3244
- const parsedParameters = tryParseJson(rawParameters.trim());
3245
- const result = rawBody.trim();
3246
- return {
3247
- type: "tool-result",
3248
- toolName: rawToolName.trim(),
3249
- parameters: parsedParameters,
3250
- result,
3251
- isError: kind === "Error",
3252
- payload: tryParseJson(result)
3253
- };
3254
- }
3255
- function isTextPart(part) {
3256
- return part.type === "text";
3257
- }
3258
- function isReasoningPart(part) {
3259
- return part.type === "reasoning";
3260
- }
3261
- function isToolCallPart(part) {
3262
- return part.type === "tool-call";
3263
- }
3264
- function isAttachmentPart(part) {
3265
- return part.type === "attachment";
3266
- }
3267
- function isToolResultPart(part) {
3268
- return part.type === "tool-result";
3269
- }
3270
- function buildToolResultSummary(part) {
3271
- const prefix = part.isError ? "Error" : "Result";
3272
- const suffix = part.result.trim();
3273
- if (suffix.length === 0) return `${prefix} from ${part.toolName}`;
3274
- return `${prefix} from ${part.toolName}: ${suffix}`;
3275
- }
3276
- function projectChatMessageParts(parts) {
3277
- const text = parts.filter(isTextPart).map((part) => part.text.trim()).filter(Boolean);
3278
- const reasoning = parts.filter(isReasoningPart).map((part) => part.text.trim()).filter(Boolean);
3279
- const toolCalls = parts.filter(isToolCallPart).map((part) => ({ id: part.toolCallId, toolName: part.toolName, arguments: part.arguments }));
3280
- const attachments = parts.filter(isAttachmentPart).map((part) => part.attachment);
3281
- const toolResults = parts.filter(isToolResultPart);
3282
- let content = text.join("\n\n");
3283
- if (content.length === 0 && toolResults.length > 0) {
3284
- content = toolResults.map(buildToolResultSummary).join("\n\n");
3285
- }
3286
- if (content.length === 0 && toolCalls.length > 0) {
3287
- content = toolCalls.map((part) => `Tool call: ${part.toolName}`).join("\n\n");
3288
- }
3289
- return {
3290
- content,
3291
- reasoning_content: reasoning.length > 0 ? reasoning.join("\n\n") : void 0,
3292
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
3293
- attachments: attachments.length > 0 ? attachments : void 0
3294
- };
3295
- }
3296
- function buildLegacyChatMessageParts(input) {
3297
- const parts = [];
3298
- if (input.role !== "tool" && typeof input.content === "string" && input.content.trim().length > 0) {
3299
- parts.push({ type: "text", text: input.content });
3300
- }
3301
- if (typeof input.reasoning_content === "string" && input.reasoning_content.trim().length > 0) {
3302
- parts.push({ type: "reasoning", text: input.reasoning_content });
3303
- }
3304
- if (input.toolCalls) {
3305
- for (const toolCall of input.toolCalls) {
3306
- parts.push({
3307
- type: "tool-call",
3308
- toolCallId: toolCall.id,
3309
- toolName: toolCall.toolName,
3310
- arguments: toolCall.arguments
3311
- });
3312
- }
3313
- }
3314
- if (input.attachments) {
3315
- for (const attachment of input.attachments) {
3316
- parts.push({ type: "attachment", attachment });
3317
- }
3318
- }
3319
- if (input.role === "tool") {
3320
- const metadata = input.metadata ?? {};
3321
- const parsed = typeof input.content === "string" ? parseLegacyToolResultContent(input.content) : null;
3322
- const toolName = typeof metadata.toolId === "string" && metadata.toolId.length > 0 ? metadata.toolId : parsed?.toolName ?? "tool";
3323
- const result = parsed?.result ?? (typeof input.content === "string" ? input.content : "");
3324
- const payload = parsed?.payload ?? tryParseJson(result);
3325
- parts.push({
3326
- type: "tool-result",
3327
- toolName,
3328
- parameters: metadata.toolParameters ?? parsed?.parameters,
3329
- result,
3330
- isError: metadata.isError === true || parsed?.isError === true,
3331
- payload,
3332
- detailRef: input.detailRef
3333
- });
3334
- }
3335
- return parts;
3336
- }
3337
- function getChatMessageParts(message) {
3338
- return message.parts ?? buildLegacyChatMessageParts(message);
3339
- }
3340
- var init_parts = __esm({
3341
- "src/conversation/parts.ts"() {
3342
- "use strict";
3343
- }
3344
- });
3345
-
3346
- // src/conversation/factory.ts
3347
- function createChatMessage(input) {
3348
- const now = Date.now();
3349
- const parts = input.parts ?? buildLegacyChatMessageParts({
3350
- role: input.role,
3351
- content: input.content,
3352
- reasoning_content: input.reasoning_content,
3353
- toolCalls: input.toolCalls,
3354
- attachments: input.attachments,
3355
- detailRef: input.detailRef,
3356
- metadata: input.metadata
3357
- });
3358
- const projection = projectChatMessageParts(parts);
3359
- return {
3360
- messageId: input.messageId,
3361
- conversationId: input.conversationId,
3362
- originNodeId: input.originNodeId ?? "unknown",
3363
- timestamp: now,
3364
- lamportClock: input.lamportClock ?? now,
3365
- role: input.role,
3366
- parts: parts.length > 0 ? parts : void 0,
3367
- content: input.content ?? projection.content,
3368
- contentType: input.contentType ?? "text/plain",
3369
- metadata: input.metadata,
3370
- duration: input.duration,
3371
- toolCalls: input.toolCalls ?? projection.toolCalls,
3372
- reasoning_content: input.reasoning_content ?? projection.reasoning_content,
3373
- hidden: input.hidden,
3374
- attachments: input.attachments ?? projection.attachments,
3375
- detailRef: input.detailRef
3376
- };
3377
- }
3378
- function createAgentInstanceFromDefinition(definition, overrides) {
3379
- const now = /* @__PURE__ */ new Date();
3380
- return {
3381
- ...definition,
3382
- id: overrides.id,
3383
- agentDefId: definition.id,
3384
- name: overrides.name ?? definition.name,
3385
- status: overrides.status ?? DEFAULT_INSTANCE_STATUS,
3386
- messages: [],
3387
- created: now,
3388
- modified: now,
3389
- closed: overrides.closed ?? false,
3390
- volatile: overrides.volatile ?? false,
3391
- isDelegatedAgentRun: overrides.isDelegatedAgentRun,
3392
- parentAgentRunId: overrides.parentAgentRunId,
3393
- agentFrameworkConfig: overrides.agentFrameworkConfig
3394
- };
3395
- }
3396
- var DEFAULT_INSTANCE_STATUS;
3397
- var init_factory = __esm({
3398
- "src/conversation/factory.ts"() {
3399
- "use strict";
3400
- init_parts();
3401
- DEFAULT_INSTANCE_STATUS = {
3402
- state: "completed",
3403
- modified: /* @__PURE__ */ new Date()
3404
- };
3405
- }
3406
- });
3407
-
3408
- // src/conversation/types.ts
3409
- var init_types = __esm({
3410
- "src/conversation/types.ts"() {
3411
- "use strict";
3412
- }
3413
- });
3414
-
3415
- // src/conversation/index.ts
3416
- var init_conversation = __esm({
3417
- "src/conversation/index.ts"() {
3418
- "use strict";
3419
- init_factory();
3420
- init_parts();
3421
- init_types();
3422
- }
3423
- });
3424
-
3425
3428
  // src/promptUtilities/promptConcat.ts
3426
3429
  function collectPromptSourcePaths(prompts, basePath = "agentFrameworkConfig.prompts") {
3427
3430
  const out = {};
@@ -3888,6 +3891,10 @@ async function executeRegistryTool(context, toolId, parameters) {
3888
3891
  }
3889
3892
  }
3890
3893
  async function executeWithGuards(context, options, conversationId, recentToolCalls, call) {
3894
+ const parameterParseError = call.parameters[TOOL_PARAMETER_PARSE_ERROR_KEY];
3895
+ if (typeof parameterParseError === "string") {
3896
+ return { text: parameterParseError, isError: true };
3897
+ }
3891
3898
  const signature = `${call.toolId}:${JSON.stringify(call.parameters)}`;
3892
3899
  recentToolCalls.push(signature);
3893
3900
  const threshold = Math.max(2, options?.doomLoopThreshold ?? 3);
@@ -4038,6 +4045,7 @@ var init_toolCallRunner = __esm({
4038
4045
  init_unknownEffect();
4039
4046
  init_errors();
4040
4047
  init_resources();
4048
+ init_responsePatternUtility();
4041
4049
  init_nextLamport();
4042
4050
  init_structuredToolResult();
4043
4051
  init_registry();
@@ -4336,6 +4344,49 @@ function resolveMaxIterations(context) {
4336
4344
  const configured = context.agentToolLoop?.maxIterations;
4337
4345
  return configured != null && configured > 0 ? configured : DEFAULT_MAX_ITERATIONS;
4338
4346
  }
4347
+ function pluginToolCallSignature(calls) {
4348
+ return calls.map((call) => `${call.toolId}:${JSON.stringify(call.parameters)}`).join("|");
4349
+ }
4350
+ async function blockRepeatedPluginToolCalls(context, input, state, calls, hookContext) {
4351
+ if (calls.length === 0) return { blocked: false };
4352
+ const signature = pluginToolCallSignature(calls);
4353
+ state.recentToolCalls.push(signature);
4354
+ const threshold = Math.max(2, context.agentToolLoop?.doomLoopThreshold ?? 3);
4355
+ const last = state.recentToolCalls.slice(-threshold);
4356
+ if (last.length !== threshold || !last.every((entry) => entry === signature)) {
4357
+ return { blocked: false };
4358
+ }
4359
+ const message = `Blocked by doom-loop guard: the model repeated the same tool call ${threshold} times. Change the arguments or approach before trying again.`;
4360
+ const firstCall = calls[0];
4361
+ const lamportClock = await nextLamportClockForConversation(
4362
+ context.storage,
4363
+ input.conversationId
4364
+ );
4365
+ const toolMessage = createChatMessage({
4366
+ messageId: `${input.conversationId}:t:doom-loop:${state.iteration}:${Date.now().toString(36)}`,
4367
+ conversationId: input.conversationId,
4368
+ originNodeId: "local",
4369
+ lamportClock,
4370
+ role: "tool",
4371
+ parts: [{
4372
+ type: "tool-result",
4373
+ toolName: firstCall.toolId,
4374
+ parameters: firstCall.parameters,
4375
+ result: message,
4376
+ isError: true
4377
+ }],
4378
+ metadata: {
4379
+ isToolResult: true,
4380
+ isError: true,
4381
+ toolId: firstCall.toolId,
4382
+ toolParameters: firstCall.parameters,
4383
+ doomLoopBlocked: true
4384
+ }
4385
+ });
4386
+ hookContext.agent.messages.push(toolMessage);
4387
+ await context.storage.appendMessage(toolMessage);
4388
+ return { blocked: true, message };
4389
+ }
4339
4390
  function createAgentToolLoopState(context) {
4340
4391
  return {
4341
4392
  iteration: 0,
@@ -4476,7 +4527,7 @@ async function* runAgentToolLoopIteration(context, input, state) {
4476
4527
  iteration
4477
4528
  }
4478
4529
  };
4479
- const messages = await buildLlmMessages(context, input.conversationId, history);
4530
+ const messages = await buildLlmMessages(hookContext, input.conversationId, history);
4480
4531
  const request = { conversationId: input.conversationId, messages };
4481
4532
  const assistantMessageId = `${input.conversationId}:a:${iteration}:${Date.now().toString(36)}`;
4482
4533
  const assistantLamportClock = await nextLamportClockForConversation(
@@ -4533,6 +4584,31 @@ async function* runAgentToolLoopIteration(context, input, state) {
4533
4584
  await hookContext.persistAgentMessage?.(assistantMessage);
4534
4585
  const { calls, parallel } = matchAllToolCallings(assistantText);
4535
4586
  if (hasPlugins && frameworkConfig) {
4587
+ const doomLoop = await blockRepeatedPluginToolCalls(
4588
+ context,
4589
+ input,
4590
+ state,
4591
+ calls,
4592
+ hookContext
4593
+ );
4594
+ if (doomLoop.blocked) {
4595
+ yield {
4596
+ type: "tool",
4597
+ data: {
4598
+ toolId: calls[0].toolId,
4599
+ parameters: calls[0].parameters,
4600
+ parallel,
4601
+ result: doomLoop.message,
4602
+ isError: true
4603
+ }
4604
+ };
4605
+ yield finishAgentToolLoopThinking(state, "error", {
4606
+ status: "blocked",
4607
+ conversationId: input.conversationId,
4608
+ reason: doomLoop.message
4609
+ });
4610
+ return { action: "stop", reason: "error" };
4611
+ }
4536
4612
  const { hooks } = await createHooksWithPlugins(
4537
4613
  frameworkConfig,
4538
4614
  {
@@ -4645,6 +4721,7 @@ var DEFAULT_MAX_ITERATIONS;
4645
4721
  var init_turnPrimitives = __esm({
4646
4722
  "src/loopAPI/agent-tool-loop/turnPrimitives.ts"() {
4647
4723
  "use strict";
4724
+ init_conversation();
4648
4725
  init_responseConcat();
4649
4726
  init_responsePatternUtility();
4650
4727
  init_nextLamport();
@@ -6718,9 +6795,9 @@ var init_builtinProfileSources = __esm({
6718
6795
  "{",
6719
6796
  ' "id": "memeloop:general-assistant",',
6720
6797
  ' "name": "\u901A\u7528\u52A9\u624B",',
6721
- ' "description": "\u901A\u7528\u81EA\u7136\u8BED\u8A00\u52A9\u7406\uFF0C\u7528\u4E8E\u65E5\u5E38\u95EE\u7B54\u548C\u7B80\u5355\u4EFB\u52A1\u3002",',
6798
+ ' "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",',
6722
6799
  ' "loopId": "agent-tool-loop",',
6723
- ' "systemPrompt": "You are a helpful general-purpose assistant. When you need to use a tool, output ONLY the tool call in this exact XML format:\\n<tool_use name=\\"TOOL_NAME\\">{\\"param\\":\\"value\\"}</tool_use>\\nNever wrap tool calls in markdown code blocks or add explanatory text before/after the tool call in the same message. After receiving the tool result, continue responding normally.",',
6800
+ ` "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.",`,
6724
6801
  ' "tools": [',
6725
6802
  ' "workspacesList",',
6726
6803
  ' "wikiSearch",',
@@ -6733,7 +6810,8 @@ var init_builtinProfileSources = __esm({
6733
6810
  ' { "id": "builtin:mcp-client" },',
6734
6811
  ' { "id": "builtin:mcp-forward" },',
6735
6812
  ' { "id": "builtin:spawn-agent" },',
6736
- ' { "id": "builtin:ask-question" }',
6813
+ ' { "id": "builtin:ask-question" },',
6814
+ ' { "id": "builtin:todo-write" }',
6737
6815
  " ],",
6738
6816
  ' "agentTools": [',
6739
6817
  " {",
@@ -6789,6 +6867,16 @@ var init_builtinProfileSources = __esm({
6789
6867
  ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
6790
6868
  " }",
6791
6869
  " }",
6870
+ " },",
6871
+ " {",
6872
+ ' "toolId": "todo",',
6873
+ ' "parameters": {',
6874
+ ' "todoParam": {',
6875
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
6876
+ ' "todoInjectionTargetId": "builtin-system",',
6877
+ ' "toolResultDuration": 1',
6878
+ " }",
6879
+ " }",
6792
6880
  " }",
6793
6881
  " ],",
6794
6882
  ' "agentFrameworkConfig": {',
@@ -6796,7 +6884,7 @@ var init_builtinProfileSources = __esm({
6796
6884
  " {",
6797
6885
  ' "id": "builtin-system",',
6798
6886
  ' "role": "system",',
6799
- ' "text": "You are a helpful general-purpose assistant. When you need to use a tool, output ONLY the tool call in this exact XML format:\\n<tool_use name=\\"TOOL_NAME\\">{\\"param\\":\\"value\\"}</tool_use>\\nNever wrap tool calls in markdown code blocks or add explanatory text before/after the tool call in the same message. After receiving the tool result, continue responding normally."',
6887
+ ` "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."`,
6800
6888
  " }",
6801
6889
  " ],",
6802
6890
  ' "plugins": [{ "toolId": "fullReplacement" }],',
@@ -6808,7 +6896,7 @@ var init_builtinProfileSources = __esm({
6808
6896
  ' "temperature": 0.5,',
6809
6897
  ' "maxTokens": 4096',
6810
6898
  " },",
6811
- ' "version": "1.0.0"',
6899
+ ' "version": "1.1.0"',
6812
6900
  "}",
6813
6901
  ""
6814
6902
  ].join("\n"),
@@ -7346,6 +7434,7 @@ __export(loop_api_exports, {
7346
7434
  PLUGIN_TASK: () => PLUGIN_TASK,
7347
7435
  PLUGIN_TODO_WRITE: () => PLUGIN_TODO_WRITE,
7348
7436
  ProviderRegistry: () => ProviderRegistry,
7437
+ TOOL_PARAMETER_PARSE_ERROR_KEY: () => TOOL_PARAMETER_PARSE_ERROR_KEY,
7349
7438
  TokenTracker: () => TokenTracker,
7350
7439
  autoCompact: () => autoCompact,
7351
7440
  buildAgent: () => buildAgent,
@@ -7967,6 +8056,7 @@ function clearPluginRegistrations() {
7967
8056
  PLUGIN_TASK,
7968
8057
  PLUGIN_TODO_WRITE,
7969
8058
  ProviderRegistry,
8059
+ TOOL_PARAMETER_PARSE_ERROR_KEY,
7970
8060
  TokenTracker,
7971
8061
  autoCompact,
7972
8062
  buildAgent,