memeloop 0.1.0 → 0.1.2

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 (55) hide show
  1. package/THIRD_PARTY_NOTICES.md +29 -0
  2. package/dist/browser.d.cts +7 -7
  3. package/dist/browser.d.ts +7 -7
  4. package/dist/{chunk-44YHBKDL.js → chunk-2C6BJZI3.js} +3 -3
  5. package/dist/{chunk-HVB2BR3H.js → chunk-KFS2EJT6.js} +2 -2
  6. package/dist/{chunk-XHRBV6I3.js → chunk-MAJWHAKR.js} +2 -2
  7. package/dist/{chunk-QFHAAIIM.js → chunk-T7FSXWFR.js} +95 -8
  8. package/dist/chunk-T7FSXWFR.js.map +1 -0
  9. package/dist/conversation.d.cts +1 -1
  10. package/dist/conversation.d.ts +1 -1
  11. package/dist/{fetchProvider-Cm0sO4Tl.d.ts → fetchProvider-WWnWnQFP.d.ts} +1 -1
  12. package/dist/{fetchProvider-BpcGVSOG.d.cts → fetchProvider-toTHy5Nu.d.cts} +1 -1
  13. package/dist/index.cjs +295 -201
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +10 -10
  16. package/dist/index.d.ts +10 -10
  17. package/dist/index.js +11 -5
  18. package/dist/index.js.map +1 -1
  19. package/dist/llm-providers.d.cts +1 -1
  20. package/dist/llm-providers.d.ts +1 -1
  21. package/dist/loop-api.cjs +291 -201
  22. package/dist/loop-api.cjs.map +1 -1
  23. package/dist/loop-api.d.cts +5 -5
  24. package/dist/loop-api.d.ts +5 -5
  25. package/dist/loop-api.js +6 -4
  26. package/dist/mobile.cjs +235 -149
  27. package/dist/mobile.cjs.map +1 -1
  28. package/dist/mobile.d.cts +3 -3
  29. package/dist/mobile.d.ts +3 -3
  30. package/dist/mobile.js +2 -2
  31. package/dist/model-catalog.cjs +246 -0
  32. package/dist/model-catalog.cjs.map +1 -0
  33. package/dist/model-catalog.d.cts +57 -0
  34. package/dist/model-catalog.d.ts +57 -0
  35. package/dist/model-catalog.js +213 -0
  36. package/dist/model-catalog.js.map +1 -0
  37. package/dist/{orchestration-portable-Zw0g5tbj.d.ts → orchestration-portable-BHB_YrNN.d.ts} +1 -1
  38. package/dist/{orchestration-portable-Bsf8YRfp.d.cts → orchestration-portable-mvYBvGBb.d.cts} +1 -1
  39. package/dist/orchestration-portable.d.cts +2 -2
  40. package/dist/orchestration-portable.d.ts +2 -2
  41. package/dist/{promptConcat-deDSWZE3.d.ts → promptConcat-0WNFTg4l.d.ts} +2 -2
  42. package/dist/{promptConcat-WTN-uHcz.d.cts → promptConcat-D6wr5V-V.d.cts} +2 -2
  43. package/dist/{providerRegistry-9trr5aoK.d.ts → providerRegistry-Bi6pAvSj.d.ts} +1 -1
  44. package/dist/{providerRegistry-xk_B1Ekv.d.cts → providerRegistry-CPsktuiX.d.cts} +1 -1
  45. package/dist/{registry-8eztoD_r.d.cts → registry-D0kbxksn.d.cts} +2 -2
  46. package/dist/{registry-DV24sI-3.d.ts → registry-DDbvhlhs.d.ts} +2 -2
  47. package/dist/{runtime-SKSXVYIM.js → runtime-PGWR6FIV.js} +3 -3
  48. package/dist/{scriptDeploymentPipeline-DsnT0AG6.d.ts → scriptDeploymentPipeline-CXJcC82H.d.ts} +2 -1
  49. package/dist/{scriptDeploymentPipeline-BAeo1dPb.d.cts → scriptDeploymentPipeline-yG1ZhVVI.d.cts} +2 -1
  50. package/package.json +9 -2
  51. package/dist/chunk-QFHAAIIM.js.map +0 -1
  52. /package/dist/{chunk-44YHBKDL.js.map → chunk-2C6BJZI3.js.map} +0 -0
  53. /package/dist/{chunk-HVB2BR3H.js.map → chunk-KFS2EJT6.js.map} +0 -0
  54. /package/dist/{chunk-XHRBV6I3.js.map → chunk-MAJWHAKR.js.map} +0 -0
  55. /package/dist/{runtime-SKSXVYIM.js.map → runtime-PGWR6FIV.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -15833,6 +15833,199 @@ var init_scriptRuntime = __esm({
15833
15833
  }
15834
15834
  });
15835
15835
 
15836
+ // src/conversation/parts.ts
15837
+ function tryParseJson(value) {
15838
+ try {
15839
+ return JSON.parse(value);
15840
+ } catch {
15841
+ return void 0;
15842
+ }
15843
+ }
15844
+ function parseLegacyToolResultContent(content) {
15845
+ const match = /(?:<functions_result>\s*)?Tool:\s*(.+?)\nParameters:\s*(.+?)\n(Error|Result):\s*([\s\S]*?)\s*(?:<\/functions_result>|$)/su.exec(content.trim());
15846
+ if (!match) return null;
15847
+ const [, rawToolName, rawParameters, kind, rawBody] = match;
15848
+ const parsedParameters = tryParseJson(rawParameters.trim());
15849
+ const result = rawBody.trim();
15850
+ return {
15851
+ type: "tool-result",
15852
+ toolName: rawToolName.trim(),
15853
+ parameters: parsedParameters,
15854
+ result,
15855
+ isError: kind === "Error",
15856
+ payload: tryParseJson(result)
15857
+ };
15858
+ }
15859
+ function isTextPart(part) {
15860
+ return part.type === "text";
15861
+ }
15862
+ function isReasoningPart(part) {
15863
+ return part.type === "reasoning";
15864
+ }
15865
+ function isToolCallPart(part) {
15866
+ return part.type === "tool-call";
15867
+ }
15868
+ function isAttachmentPart(part) {
15869
+ return part.type === "attachment";
15870
+ }
15871
+ function isToolResultPart(part) {
15872
+ return part.type === "tool-result";
15873
+ }
15874
+ function buildToolResultSummary(part) {
15875
+ const prefix = part.isError ? "Error" : "Result";
15876
+ const suffix = part.result.trim();
15877
+ if (suffix.length === 0) return `${prefix} from ${part.toolName}`;
15878
+ return `${prefix} from ${part.toolName}: ${suffix}`;
15879
+ }
15880
+ function projectChatMessageParts(parts) {
15881
+ const text = parts.filter(isTextPart).map((part) => part.text.trim()).filter(Boolean);
15882
+ const reasoning = parts.filter(isReasoningPart).map((part) => part.text.trim()).filter(Boolean);
15883
+ const toolCalls = parts.filter(isToolCallPart).map((part) => ({ id: part.toolCallId, toolName: part.toolName, arguments: part.arguments }));
15884
+ const attachments = parts.filter(isAttachmentPart).map((part) => part.attachment);
15885
+ const toolResults = parts.filter(isToolResultPart);
15886
+ let content = text.join("\n\n");
15887
+ if (content.length === 0 && toolResults.length > 0) {
15888
+ content = toolResults.map(buildToolResultSummary).join("\n\n");
15889
+ }
15890
+ if (content.length === 0 && toolCalls.length > 0) {
15891
+ content = toolCalls.map((part) => `Tool call: ${part.toolName}`).join("\n\n");
15892
+ }
15893
+ return {
15894
+ content,
15895
+ reasoning_content: reasoning.length > 0 ? reasoning.join("\n\n") : void 0,
15896
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
15897
+ attachments: attachments.length > 0 ? attachments : void 0
15898
+ };
15899
+ }
15900
+ function buildLegacyChatMessageParts(input) {
15901
+ const parts = [];
15902
+ if (input.role !== "tool" && typeof input.content === "string" && input.content.trim().length > 0) {
15903
+ parts.push({ type: "text", text: input.content });
15904
+ }
15905
+ if (typeof input.reasoning_content === "string" && input.reasoning_content.trim().length > 0) {
15906
+ parts.push({ type: "reasoning", text: input.reasoning_content });
15907
+ }
15908
+ if (input.toolCalls) {
15909
+ for (const toolCall of input.toolCalls) {
15910
+ parts.push({
15911
+ type: "tool-call",
15912
+ toolCallId: toolCall.id,
15913
+ toolName: toolCall.toolName,
15914
+ arguments: toolCall.arguments
15915
+ });
15916
+ }
15917
+ }
15918
+ if (input.attachments) {
15919
+ for (const attachment of input.attachments) {
15920
+ parts.push({ type: "attachment", attachment });
15921
+ }
15922
+ }
15923
+ if (input.role === "tool") {
15924
+ const metadata = input.metadata ?? {};
15925
+ const parsed = typeof input.content === "string" ? parseLegacyToolResultContent(input.content) : null;
15926
+ const toolName = typeof metadata.toolId === "string" && metadata.toolId.length > 0 ? metadata.toolId : parsed?.toolName ?? "tool";
15927
+ const result = parsed?.result ?? (typeof input.content === "string" ? input.content : "");
15928
+ const payload = parsed?.payload ?? tryParseJson(result);
15929
+ parts.push({
15930
+ type: "tool-result",
15931
+ toolName,
15932
+ parameters: metadata.toolParameters ?? parsed?.parameters,
15933
+ result,
15934
+ isError: metadata.isError === true || parsed?.isError === true,
15935
+ payload,
15936
+ detailRef: input.detailRef
15937
+ });
15938
+ }
15939
+ return parts;
15940
+ }
15941
+ function getChatMessageParts(message) {
15942
+ return message.parts ?? buildLegacyChatMessageParts(message);
15943
+ }
15944
+ var init_parts = __esm({
15945
+ "src/conversation/parts.ts"() {
15946
+ "use strict";
15947
+ }
15948
+ });
15949
+
15950
+ // src/conversation/factory.ts
15951
+ function createChatMessage(input) {
15952
+ const now = Date.now();
15953
+ const parts = input.parts ?? buildLegacyChatMessageParts({
15954
+ role: input.role,
15955
+ content: input.content,
15956
+ reasoning_content: input.reasoning_content,
15957
+ toolCalls: input.toolCalls,
15958
+ attachments: input.attachments,
15959
+ detailRef: input.detailRef,
15960
+ metadata: input.metadata
15961
+ });
15962
+ const projection = projectChatMessageParts(parts);
15963
+ return {
15964
+ messageId: input.messageId,
15965
+ conversationId: input.conversationId,
15966
+ originNodeId: input.originNodeId ?? "unknown",
15967
+ timestamp: now,
15968
+ lamportClock: input.lamportClock ?? now,
15969
+ role: input.role,
15970
+ parts: parts.length > 0 ? parts : void 0,
15971
+ content: input.content ?? projection.content,
15972
+ contentType: input.contentType ?? "text/plain",
15973
+ metadata: input.metadata,
15974
+ duration: input.duration,
15975
+ toolCalls: input.toolCalls ?? projection.toolCalls,
15976
+ reasoning_content: input.reasoning_content ?? projection.reasoning_content,
15977
+ hidden: input.hidden,
15978
+ attachments: input.attachments ?? projection.attachments,
15979
+ detailRef: input.detailRef
15980
+ };
15981
+ }
15982
+ function createAgentInstanceFromDefinition(definition, overrides) {
15983
+ const now = /* @__PURE__ */ new Date();
15984
+ return {
15985
+ ...definition,
15986
+ id: overrides.id,
15987
+ agentDefId: definition.id,
15988
+ name: overrides.name ?? definition.name,
15989
+ status: overrides.status ?? DEFAULT_INSTANCE_STATUS,
15990
+ messages: [],
15991
+ created: now,
15992
+ modified: now,
15993
+ closed: overrides.closed ?? false,
15994
+ volatile: overrides.volatile ?? false,
15995
+ isDelegatedAgentRun: overrides.isDelegatedAgentRun,
15996
+ parentAgentRunId: overrides.parentAgentRunId,
15997
+ agentFrameworkConfig: overrides.agentFrameworkConfig
15998
+ };
15999
+ }
16000
+ var DEFAULT_INSTANCE_STATUS;
16001
+ var init_factory = __esm({
16002
+ "src/conversation/factory.ts"() {
16003
+ "use strict";
16004
+ init_parts();
16005
+ DEFAULT_INSTANCE_STATUS = {
16006
+ state: "completed",
16007
+ modified: /* @__PURE__ */ new Date()
16008
+ };
16009
+ }
16010
+ });
16011
+
16012
+ // src/conversation/types.ts
16013
+ var init_types = __esm({
16014
+ "src/conversation/types.ts"() {
16015
+ "use strict";
16016
+ }
16017
+ });
16018
+
16019
+ // src/conversation/index.ts
16020
+ var init_conversation = __esm({
16021
+ "src/conversation/index.ts"() {
16022
+ "use strict";
16023
+ init_factory();
16024
+ init_parts();
16025
+ init_types();
16026
+ }
16027
+ });
16028
+
15836
16029
  // src/tools/pluginRegistry.ts
15837
16030
  function getActivePluginRegistry() {
15838
16031
  return activeOverride ?? defaultPluginRegistry;
@@ -15996,7 +16189,9 @@ function parseToolParameters(parametersText) {
15996
16189
  return import_json5.default.parse(trimmedText);
15997
16190
  } catch {
15998
16191
  }
15999
- return { input: trimmedText.substring(0, MAX_FALLBACK_INPUT_LENGTH) };
16192
+ return {
16193
+ [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)}`
16194
+ };
16000
16195
  }
16001
16196
  function extractFunctionCallsParameters(text) {
16002
16197
  const parameters = {};
@@ -16049,12 +16244,13 @@ function matchAllToolCallings(responseText) {
16049
16244
  }
16050
16245
  return { calls, parallel };
16051
16246
  }
16052
- var import_json5, MAX_FALLBACK_INPUT_LENGTH, toolPatterns;
16247
+ var import_json5, MAX_FALLBACK_INPUT_LENGTH, TOOL_PARAMETER_PARSE_ERROR_KEY, toolPatterns;
16053
16248
  var init_responsePatternUtility = __esm({
16054
16249
  "src/promptUtilities/responsePatternUtility.ts"() {
16055
16250
  "use strict";
16056
16251
  import_json5 = __toESM(require("json5"), 1);
16057
16252
  MAX_FALLBACK_INPUT_LENGTH = 1e3;
16253
+ TOOL_PARAMETER_PARSE_ERROR_KEY = "__memeloopToolParameterParseError";
16058
16254
  toolPatterns = [
16059
16255
  {
16060
16256
  name: "tool_use",
@@ -16579,199 +16775,6 @@ var init_llmStream = __esm({
16579
16775
  }
16580
16776
  });
16581
16777
 
16582
- // src/conversation/parts.ts
16583
- function tryParseJson(value) {
16584
- try {
16585
- return JSON.parse(value);
16586
- } catch {
16587
- return void 0;
16588
- }
16589
- }
16590
- function parseLegacyToolResultContent(content) {
16591
- const match = /(?:<functions_result>\s*)?Tool:\s*(.+?)\nParameters:\s*(.+?)\n(Error|Result):\s*([\s\S]*?)\s*(?:<\/functions_result>|$)/su.exec(content.trim());
16592
- if (!match) return null;
16593
- const [, rawToolName, rawParameters, kind, rawBody] = match;
16594
- const parsedParameters = tryParseJson(rawParameters.trim());
16595
- const result = rawBody.trim();
16596
- return {
16597
- type: "tool-result",
16598
- toolName: rawToolName.trim(),
16599
- parameters: parsedParameters,
16600
- result,
16601
- isError: kind === "Error",
16602
- payload: tryParseJson(result)
16603
- };
16604
- }
16605
- function isTextPart(part) {
16606
- return part.type === "text";
16607
- }
16608
- function isReasoningPart(part) {
16609
- return part.type === "reasoning";
16610
- }
16611
- function isToolCallPart(part) {
16612
- return part.type === "tool-call";
16613
- }
16614
- function isAttachmentPart(part) {
16615
- return part.type === "attachment";
16616
- }
16617
- function isToolResultPart(part) {
16618
- return part.type === "tool-result";
16619
- }
16620
- function buildToolResultSummary(part) {
16621
- const prefix = part.isError ? "Error" : "Result";
16622
- const suffix = part.result.trim();
16623
- if (suffix.length === 0) return `${prefix} from ${part.toolName}`;
16624
- return `${prefix} from ${part.toolName}: ${suffix}`;
16625
- }
16626
- function projectChatMessageParts(parts) {
16627
- const text = parts.filter(isTextPart).map((part) => part.text.trim()).filter(Boolean);
16628
- const reasoning = parts.filter(isReasoningPart).map((part) => part.text.trim()).filter(Boolean);
16629
- const toolCalls = parts.filter(isToolCallPart).map((part) => ({ id: part.toolCallId, toolName: part.toolName, arguments: part.arguments }));
16630
- const attachments = parts.filter(isAttachmentPart).map((part) => part.attachment);
16631
- const toolResults = parts.filter(isToolResultPart);
16632
- let content = text.join("\n\n");
16633
- if (content.length === 0 && toolResults.length > 0) {
16634
- content = toolResults.map(buildToolResultSummary).join("\n\n");
16635
- }
16636
- if (content.length === 0 && toolCalls.length > 0) {
16637
- content = toolCalls.map((part) => `Tool call: ${part.toolName}`).join("\n\n");
16638
- }
16639
- return {
16640
- content,
16641
- reasoning_content: reasoning.length > 0 ? reasoning.join("\n\n") : void 0,
16642
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
16643
- attachments: attachments.length > 0 ? attachments : void 0
16644
- };
16645
- }
16646
- function buildLegacyChatMessageParts(input) {
16647
- const parts = [];
16648
- if (input.role !== "tool" && typeof input.content === "string" && input.content.trim().length > 0) {
16649
- parts.push({ type: "text", text: input.content });
16650
- }
16651
- if (typeof input.reasoning_content === "string" && input.reasoning_content.trim().length > 0) {
16652
- parts.push({ type: "reasoning", text: input.reasoning_content });
16653
- }
16654
- if (input.toolCalls) {
16655
- for (const toolCall of input.toolCalls) {
16656
- parts.push({
16657
- type: "tool-call",
16658
- toolCallId: toolCall.id,
16659
- toolName: toolCall.toolName,
16660
- arguments: toolCall.arguments
16661
- });
16662
- }
16663
- }
16664
- if (input.attachments) {
16665
- for (const attachment of input.attachments) {
16666
- parts.push({ type: "attachment", attachment });
16667
- }
16668
- }
16669
- if (input.role === "tool") {
16670
- const metadata = input.metadata ?? {};
16671
- const parsed = typeof input.content === "string" ? parseLegacyToolResultContent(input.content) : null;
16672
- const toolName = typeof metadata.toolId === "string" && metadata.toolId.length > 0 ? metadata.toolId : parsed?.toolName ?? "tool";
16673
- const result = parsed?.result ?? (typeof input.content === "string" ? input.content : "");
16674
- const payload = parsed?.payload ?? tryParseJson(result);
16675
- parts.push({
16676
- type: "tool-result",
16677
- toolName,
16678
- parameters: metadata.toolParameters ?? parsed?.parameters,
16679
- result,
16680
- isError: metadata.isError === true || parsed?.isError === true,
16681
- payload,
16682
- detailRef: input.detailRef
16683
- });
16684
- }
16685
- return parts;
16686
- }
16687
- function getChatMessageParts(message) {
16688
- return message.parts ?? buildLegacyChatMessageParts(message);
16689
- }
16690
- var init_parts = __esm({
16691
- "src/conversation/parts.ts"() {
16692
- "use strict";
16693
- }
16694
- });
16695
-
16696
- // src/conversation/factory.ts
16697
- function createChatMessage(input) {
16698
- const now = Date.now();
16699
- const parts = input.parts ?? buildLegacyChatMessageParts({
16700
- role: input.role,
16701
- content: input.content,
16702
- reasoning_content: input.reasoning_content,
16703
- toolCalls: input.toolCalls,
16704
- attachments: input.attachments,
16705
- detailRef: input.detailRef,
16706
- metadata: input.metadata
16707
- });
16708
- const projection = projectChatMessageParts(parts);
16709
- return {
16710
- messageId: input.messageId,
16711
- conversationId: input.conversationId,
16712
- originNodeId: input.originNodeId ?? "unknown",
16713
- timestamp: now,
16714
- lamportClock: input.lamportClock ?? now,
16715
- role: input.role,
16716
- parts: parts.length > 0 ? parts : void 0,
16717
- content: input.content ?? projection.content,
16718
- contentType: input.contentType ?? "text/plain",
16719
- metadata: input.metadata,
16720
- duration: input.duration,
16721
- toolCalls: input.toolCalls ?? projection.toolCalls,
16722
- reasoning_content: input.reasoning_content ?? projection.reasoning_content,
16723
- hidden: input.hidden,
16724
- attachments: input.attachments ?? projection.attachments,
16725
- detailRef: input.detailRef
16726
- };
16727
- }
16728
- function createAgentInstanceFromDefinition(definition, overrides) {
16729
- const now = /* @__PURE__ */ new Date();
16730
- return {
16731
- ...definition,
16732
- id: overrides.id,
16733
- agentDefId: definition.id,
16734
- name: overrides.name ?? definition.name,
16735
- status: overrides.status ?? DEFAULT_INSTANCE_STATUS,
16736
- messages: [],
16737
- created: now,
16738
- modified: now,
16739
- closed: overrides.closed ?? false,
16740
- volatile: overrides.volatile ?? false,
16741
- isDelegatedAgentRun: overrides.isDelegatedAgentRun,
16742
- parentAgentRunId: overrides.parentAgentRunId,
16743
- agentFrameworkConfig: overrides.agentFrameworkConfig
16744
- };
16745
- }
16746
- var DEFAULT_INSTANCE_STATUS;
16747
- var init_factory = __esm({
16748
- "src/conversation/factory.ts"() {
16749
- "use strict";
16750
- init_parts();
16751
- DEFAULT_INSTANCE_STATUS = {
16752
- state: "completed",
16753
- modified: /* @__PURE__ */ new Date()
16754
- };
16755
- }
16756
- });
16757
-
16758
- // src/conversation/types.ts
16759
- var init_types = __esm({
16760
- "src/conversation/types.ts"() {
16761
- "use strict";
16762
- }
16763
- });
16764
-
16765
- // src/conversation/index.ts
16766
- var init_conversation = __esm({
16767
- "src/conversation/index.ts"() {
16768
- "use strict";
16769
- init_factory();
16770
- init_parts();
16771
- init_types();
16772
- }
16773
- });
16774
-
16775
16778
  // src/promptUtilities/promptConcat.ts
16776
16779
  function collectPromptSourcePaths(prompts, basePath = "agentFrameworkConfig.prompts") {
16777
16780
  const out = {};
@@ -17238,6 +17241,10 @@ async function executeRegistryTool(context, toolId, parameters) {
17238
17241
  }
17239
17242
  }
17240
17243
  async function executeWithGuards(context, options, conversationId, recentToolCalls, call) {
17244
+ const parameterParseError = call.parameters[TOOL_PARAMETER_PARSE_ERROR_KEY];
17245
+ if (typeof parameterParseError === "string") {
17246
+ return { text: parameterParseError, isError: true };
17247
+ }
17241
17248
  const signature = `${call.toolId}:${JSON.stringify(call.parameters)}`;
17242
17249
  recentToolCalls.push(signature);
17243
17250
  const threshold = Math.max(2, options?.doomLoopThreshold ?? 3);
@@ -17388,6 +17395,7 @@ var init_toolCallRunner = __esm({
17388
17395
  init_unknownEffect();
17389
17396
  init_errors();
17390
17397
  init_resources();
17398
+ init_responsePatternUtility();
17391
17399
  init_nextLamport();
17392
17400
  init_structuredToolResult();
17393
17401
  init_registry();
@@ -17737,6 +17745,49 @@ function resolveMaxIterations(context) {
17737
17745
  const configured = context.agentToolLoop?.maxIterations;
17738
17746
  return configured != null && configured > 0 ? configured : DEFAULT_MAX_ITERATIONS;
17739
17747
  }
17748
+ function pluginToolCallSignature(calls) {
17749
+ return calls.map((call) => `${call.toolId}:${JSON.stringify(call.parameters)}`).join("|");
17750
+ }
17751
+ async function blockRepeatedPluginToolCalls(context, input, state, calls, hookContext) {
17752
+ if (calls.length === 0) return { blocked: false };
17753
+ const signature = pluginToolCallSignature(calls);
17754
+ state.recentToolCalls.push(signature);
17755
+ const threshold = Math.max(2, context.agentToolLoop?.doomLoopThreshold ?? 3);
17756
+ const last = state.recentToolCalls.slice(-threshold);
17757
+ if (last.length !== threshold || !last.every((entry) => entry === signature)) {
17758
+ return { blocked: false };
17759
+ }
17760
+ const message = `Blocked by doom-loop guard: the model repeated the same tool call ${threshold} times. Change the arguments or approach before trying again.`;
17761
+ const firstCall = calls[0];
17762
+ const lamportClock = await nextLamportClockForConversation(
17763
+ context.storage,
17764
+ input.conversationId
17765
+ );
17766
+ const toolMessage = createChatMessage({
17767
+ messageId: `${input.conversationId}:t:doom-loop:${state.iteration}:${Date.now().toString(36)}`,
17768
+ conversationId: input.conversationId,
17769
+ originNodeId: "local",
17770
+ lamportClock,
17771
+ role: "tool",
17772
+ parts: [{
17773
+ type: "tool-result",
17774
+ toolName: firstCall.toolId,
17775
+ parameters: firstCall.parameters,
17776
+ result: message,
17777
+ isError: true
17778
+ }],
17779
+ metadata: {
17780
+ isToolResult: true,
17781
+ isError: true,
17782
+ toolId: firstCall.toolId,
17783
+ toolParameters: firstCall.parameters,
17784
+ doomLoopBlocked: true
17785
+ }
17786
+ });
17787
+ hookContext.agent.messages.push(toolMessage);
17788
+ await context.storage.appendMessage(toolMessage);
17789
+ return { blocked: true, message };
17790
+ }
17740
17791
  function createAgentToolLoopState(context) {
17741
17792
  return {
17742
17793
  iteration: 0,
@@ -17877,7 +17928,7 @@ async function* runAgentToolLoopIteration(context, input, state) {
17877
17928
  iteration
17878
17929
  }
17879
17930
  };
17880
- const messages = await buildLlmMessages(context, input.conversationId, history);
17931
+ const messages = await buildLlmMessages(hookContext, input.conversationId, history);
17881
17932
  const request = { conversationId: input.conversationId, messages };
17882
17933
  const assistantMessageId = `${input.conversationId}:a:${iteration}:${Date.now().toString(36)}`;
17883
17934
  const assistantLamportClock = await nextLamportClockForConversation(
@@ -17934,6 +17985,31 @@ async function* runAgentToolLoopIteration(context, input, state) {
17934
17985
  await hookContext.persistAgentMessage?.(assistantMessage);
17935
17986
  const { calls, parallel } = matchAllToolCallings(assistantText);
17936
17987
  if (hasPlugins && frameworkConfig) {
17988
+ const doomLoop = await blockRepeatedPluginToolCalls(
17989
+ context,
17990
+ input,
17991
+ state,
17992
+ calls,
17993
+ hookContext
17994
+ );
17995
+ if (doomLoop.blocked) {
17996
+ yield {
17997
+ type: "tool",
17998
+ data: {
17999
+ toolId: calls[0].toolId,
18000
+ parameters: calls[0].parameters,
18001
+ parallel,
18002
+ result: doomLoop.message,
18003
+ isError: true
18004
+ }
18005
+ };
18006
+ yield finishAgentToolLoopThinking(state, "error", {
18007
+ status: "blocked",
18008
+ conversationId: input.conversationId,
18009
+ reason: doomLoop.message
18010
+ });
18011
+ return { action: "stop", reason: "error" };
18012
+ }
17937
18013
  const { hooks } = await createHooksWithPlugins(
17938
18014
  frameworkConfig,
17939
18015
  {
@@ -18046,6 +18122,7 @@ var DEFAULT_MAX_ITERATIONS;
18046
18122
  var init_turnPrimitives = __esm({
18047
18123
  "src/loopAPI/agent-tool-loop/turnPrimitives.ts"() {
18048
18124
  "use strict";
18125
+ init_conversation();
18049
18126
  init_responseConcat();
18050
18127
  init_responsePatternUtility();
18051
18128
  init_nextLamport();
@@ -20528,9 +20605,9 @@ var init_builtinProfileSources = __esm({
20528
20605
  "{",
20529
20606
  ' "id": "memeloop:general-assistant",',
20530
20607
  ' "name": "\u901A\u7528\u52A9\u624B",',
20531
- ' "description": "\u901A\u7528\u81EA\u7136\u8BED\u8A00\u52A9\u7406\uFF0C\u7528\u4E8E\u65E5\u5E38\u95EE\u7B54\u548C\u7B80\u5355\u4EFB\u52A1\u3002",',
20608
+ ' "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",',
20532
20609
  ' "loopId": "agent-tool-loop",',
20533
- ' "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.",',
20610
+ ` "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.",`,
20534
20611
  ' "tools": [',
20535
20612
  ' "workspacesList",',
20536
20613
  ' "wikiSearch",',
@@ -20543,7 +20620,8 @@ var init_builtinProfileSources = __esm({
20543
20620
  ' { "id": "builtin:mcp-client" },',
20544
20621
  ' { "id": "builtin:mcp-forward" },',
20545
20622
  ' { "id": "builtin:spawn-agent" },',
20546
- ' { "id": "builtin:ask-question" }',
20623
+ ' { "id": "builtin:ask-question" },',
20624
+ ' { "id": "builtin:todo-write" }',
20547
20625
  " ],",
20548
20626
  ' "agentTools": [',
20549
20627
  " {",
@@ -20599,6 +20677,16 @@ var init_builtinProfileSources = __esm({
20599
20677
  ' "toolListPosition": { "targetId": "builtin-system", "position": "after" }',
20600
20678
  " }",
20601
20679
  " }",
20680
+ " },",
20681
+ " {",
20682
+ ' "toolId": "todo",',
20683
+ ' "parameters": {',
20684
+ ' "todoParam": {',
20685
+ ' "toolListPosition": { "targetId": "builtin-system", "position": "after" },',
20686
+ ' "todoInjectionTargetId": "builtin-system",',
20687
+ ' "toolResultDuration": 1',
20688
+ " }",
20689
+ " }",
20602
20690
  " }",
20603
20691
  " ],",
20604
20692
  ' "agentFrameworkConfig": {',
@@ -20606,7 +20694,7 @@ var init_builtinProfileSources = __esm({
20606
20694
  " {",
20607
20695
  ' "id": "builtin-system",',
20608
20696
  ' "role": "system",',
20609
- ' "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."',
20697
+ ` "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."`,
20610
20698
  " }",
20611
20699
  " ],",
20612
20700
  ' "plugins": [{ "toolId": "fullReplacement" }],',
@@ -20618,7 +20706,7 @@ var init_builtinProfileSources = __esm({
20618
20706
  ' "temperature": 0.5,',
20619
20707
  ' "maxTokens": 4096',
20620
20708
  " },",
20621
- ' "version": "1.0.0"',
20709
+ ' "version": "1.1.0"',
20622
20710
  "}",
20623
20711
  ""
20624
20712
  ].join("\n"),
@@ -26439,6 +26527,7 @@ __export(src_exports, {
26439
26527
  TOOL_OPERATION_API_VERSION: () => TOOL_OPERATION_API_VERSION,
26440
26528
  TOOL_OPERATION_CONDITION_EFFECT_UNKNOWN: () => TOOL_OPERATION_CONDITION_EFFECT_UNKNOWN,
26441
26529
  TOOL_OPERATION_KIND: () => TOOL_OPERATION_KIND,
26530
+ TOOL_PARAMETER_PARSE_ERROR_KEY: () => TOOL_PARAMETER_PARSE_ERROR_KEY,
26442
26531
  TextMessageRenderer: () => TextMessageRenderer,
26443
26532
  TiddlyWikiHttpStorage: () => TiddlyWikiHttpStorage,
26444
26533
  TokenTracker: () => TokenTracker,
@@ -30457,6 +30546,10 @@ function defineTool(definition) {
30457
30546
  return false;
30458
30547
  }
30459
30548
  try {
30549
+ const parameterParseError = toolCall.parameters[TOOL_PARAMETER_PARSE_ERROR_KEY];
30550
+ if (typeof parameterParseError === "string") {
30551
+ throw new Error(parameterParseError);
30552
+ }
30460
30553
  const validatedParameters = toolSchema.parse(toolCall.parameters);
30461
30554
  const approvalConfig = ourToolConfig.approval;
30462
30555
  const decision = evaluateApproval(
@@ -30983,6 +31076,7 @@ function getToolDefinition(toolId) {
30983
31076
  TOOL_OPERATION_API_VERSION,
30984
31077
  TOOL_OPERATION_CONDITION_EFFECT_UNKNOWN,
30985
31078
  TOOL_OPERATION_KIND,
31079
+ TOOL_PARAMETER_PARSE_ERROR_KEY,
30986
31080
  TextMessageRenderer,
30987
31081
  TiddlyWikiHttpStorage,
30988
31082
  TokenTracker,