bernard-agent 0.8.1 → 0.9.0

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 (174) hide show
  1. package/README.md +80 -44
  2. package/dist/agent.d.ts +14 -3
  3. package/dist/agent.js +228 -38
  4. package/dist/agent.js.map +1 -1
  5. package/dist/builtin-specialists/correction-agent.json +32 -0
  6. package/dist/builtin-specialists/file-wrapper.json +43 -0
  7. package/dist/builtin-specialists/shell-wrapper.json +50 -0
  8. package/dist/builtin-specialists/specialist-creator.json +32 -0
  9. package/dist/builtin-specialists/web-wrapper.json +38 -0
  10. package/dist/candidate-bootstrap.d.ts +18 -0
  11. package/dist/candidate-bootstrap.js +61 -0
  12. package/dist/candidate-bootstrap.js.map +1 -0
  13. package/dist/config.d.ts +126 -10
  14. package/dist/config.js +222 -45
  15. package/dist/config.js.map +1 -1
  16. package/dist/context.js +23 -6
  17. package/dist/context.js.map +1 -1
  18. package/dist/correction-candidates.d.ts +54 -0
  19. package/dist/correction-candidates.js +138 -0
  20. package/dist/correction-candidates.js.map +1 -0
  21. package/dist/correction.d.ts +67 -0
  22. package/dist/correction.js +138 -0
  23. package/dist/correction.js.map +1 -0
  24. package/dist/critic.js +2 -1
  25. package/dist/critic.js.map +1 -1
  26. package/dist/cron/notes-store.d.ts +41 -0
  27. package/dist/cron/notes-store.js +134 -0
  28. package/dist/cron/notes-store.js.map +1 -0
  29. package/dist/cron/runner.js +25 -3
  30. package/dist/cron/runner.js.map +1 -1
  31. package/dist/cron/scoped-notes-tools.d.ts +24 -0
  32. package/dist/cron/scoped-notes-tools.js +50 -0
  33. package/dist/cron/scoped-notes-tools.js.map +1 -0
  34. package/dist/custom-providers.d.ts +80 -0
  35. package/dist/custom-providers.js +238 -0
  36. package/dist/custom-providers.js.map +1 -0
  37. package/dist/fs-utils.d.ts +2 -0
  38. package/dist/fs-utils.js +44 -0
  39. package/dist/fs-utils.js.map +1 -0
  40. package/dist/history.js +3 -1
  41. package/dist/history.js.map +1 -1
  42. package/dist/image.d.ts +59 -0
  43. package/dist/image.js +228 -0
  44. package/dist/image.js.map +1 -0
  45. package/dist/index.js +72 -4
  46. package/dist/index.js.map +1 -1
  47. package/dist/mcp.js +1 -1
  48. package/dist/mcp.js.map +1 -1
  49. package/dist/memory.d.ts +13 -0
  50. package/dist/memory.js +45 -4
  51. package/dist/memory.js.map +1 -1
  52. package/dist/menu.d.ts +97 -0
  53. package/dist/menu.js +338 -0
  54. package/dist/menu.js.map +1 -0
  55. package/dist/os-info.d.ts +22 -0
  56. package/dist/os-info.js +111 -0
  57. package/dist/os-info.js.map +1 -0
  58. package/dist/output.d.ts +35 -1
  59. package/dist/output.js +256 -45
  60. package/dist/output.js.map +1 -1
  61. package/dist/pac.d.ts +14 -2
  62. package/dist/pac.js +5 -5
  63. package/dist/pac.js.map +1 -1
  64. package/dist/paths.d.ts +5 -0
  65. package/dist/paths.js +6 -1
  66. package/dist/paths.js.map +1 -1
  67. package/dist/plan-store.d.ts +47 -0
  68. package/dist/plan-store.js +94 -0
  69. package/dist/plan-store.js.map +1 -0
  70. package/dist/prompt-rewriter.d.ts +29 -0
  71. package/dist/prompt-rewriter.js +155 -0
  72. package/dist/prompt-rewriter.js.map +1 -0
  73. package/dist/providers/index.d.ts +56 -4
  74. package/dist/providers/index.js +86 -5
  75. package/dist/providers/index.js.map +1 -1
  76. package/dist/providers/profiles.d.ts +37 -0
  77. package/dist/providers/profiles.js +110 -0
  78. package/dist/providers/profiles.js.map +1 -0
  79. package/dist/providers/types.d.ts +11 -2
  80. package/dist/providers/types.js +3 -0
  81. package/dist/providers/types.js.map +1 -1
  82. package/dist/rag-query.js +15 -1
  83. package/dist/rag-query.js.map +1 -1
  84. package/dist/react.d.ts +38 -0
  85. package/dist/react.js +116 -0
  86. package/dist/react.js.map +1 -0
  87. package/dist/reasoning-log.d.ts +30 -0
  88. package/dist/reasoning-log.js +102 -0
  89. package/dist/reasoning-log.js.map +1 -0
  90. package/dist/reference-resolver.d.ts +47 -0
  91. package/dist/reference-resolver.js +316 -0
  92. package/dist/reference-resolver.js.map +1 -0
  93. package/dist/reference-tool-lookup.d.ts +37 -0
  94. package/dist/reference-tool-lookup.js +318 -0
  95. package/dist/reference-tool-lookup.js.map +1 -0
  96. package/dist/repl.js +1038 -371
  97. package/dist/repl.js.map +1 -1
  98. package/dist/setup.js +2 -1
  99. package/dist/setup.js.map +1 -1
  100. package/dist/specialist-detector.js +2 -1
  101. package/dist/specialist-detector.js.map +1 -1
  102. package/dist/specialists.d.ts +74 -3
  103. package/dist/specialists.js +152 -20
  104. package/dist/specialists.js.map +1 -1
  105. package/dist/structured-output.d.ts +58 -0
  106. package/dist/structured-output.js +138 -0
  107. package/dist/structured-output.js.map +1 -0
  108. package/dist/theme.d.ts +2 -0
  109. package/dist/theme.js +18 -12
  110. package/dist/theme.js.map +1 -1
  111. package/dist/tool-call-repair.d.ts +29 -0
  112. package/dist/tool-call-repair.js +99 -0
  113. package/dist/tool-call-repair.js.map +1 -0
  114. package/dist/tool-profiles.d.ts +70 -0
  115. package/dist/tool-profiles.js +385 -0
  116. package/dist/tool-profiles.js.map +1 -0
  117. package/dist/tools/activity-summary.d.ts +15 -0
  118. package/dist/tools/activity-summary.js +44 -0
  119. package/dist/tools/activity-summary.js.map +1 -0
  120. package/dist/tools/ask-user.d.ts +49 -0
  121. package/dist/tools/ask-user.js +52 -0
  122. package/dist/tools/ask-user.js.map +1 -0
  123. package/dist/tools/augment.d.ts +17 -0
  124. package/dist/tools/augment.js +102 -0
  125. package/dist/tools/augment.js.map +1 -0
  126. package/dist/tools/cron-logs.js +7 -0
  127. package/dist/tools/cron-logs.js.map +1 -1
  128. package/dist/tools/cron-notes.d.ts +52 -0
  129. package/dist/tools/cron-notes.js +105 -0
  130. package/dist/tools/cron-notes.js.map +1 -0
  131. package/dist/tools/datetime.d.ts +7 -0
  132. package/dist/tools/datetime.js +29 -3
  133. package/dist/tools/datetime.js.map +1 -1
  134. package/dist/tools/evaluate.d.ts +20 -0
  135. package/dist/tools/evaluate.js +29 -0
  136. package/dist/tools/evaluate.js.map +1 -0
  137. package/dist/tools/index.js +4 -0
  138. package/dist/tools/index.js.map +1 -1
  139. package/dist/tools/mcp.d.ts +3 -3
  140. package/dist/tools/plan.d.ts +81 -0
  141. package/dist/tools/plan.js +108 -0
  142. package/dist/tools/plan.js.map +1 -0
  143. package/dist/tools/result-cap.d.ts +24 -0
  144. package/dist/tools/result-cap.js +44 -0
  145. package/dist/tools/result-cap.js.map +1 -0
  146. package/dist/tools/routine.d.ts +3 -3
  147. package/dist/tools/shell.d.ts +14 -1
  148. package/dist/tools/shell.js +86 -4
  149. package/dist/tools/shell.js.map +1 -1
  150. package/dist/tools/specialist-run.d.ts +5 -3
  151. package/dist/tools/specialist-run.js +115 -24
  152. package/dist/tools/specialist-run.js.map +1 -1
  153. package/dist/tools/specialist.d.ts +83 -3
  154. package/dist/tools/specialist.js +83 -3
  155. package/dist/tools/specialist.js.map +1 -1
  156. package/dist/tools/subagent.js +32 -14
  157. package/dist/tools/subagent.js.map +1 -1
  158. package/dist/tools/task.d.ts +5 -5
  159. package/dist/tools/task.js +9 -42
  160. package/dist/tools/task.js.map +1 -1
  161. package/dist/tools/think.d.ts +18 -0
  162. package/dist/tools/think.js +25 -0
  163. package/dist/tools/think.js.map +1 -0
  164. package/dist/tools/tool-wrapper-run.d.ts +121 -0
  165. package/dist/tools/tool-wrapper-run.js +382 -0
  166. package/dist/tools/tool-wrapper-run.js.map +1 -0
  167. package/dist/tools/types.d.ts +28 -2
  168. package/dist/tools/web-search.d.ts +31 -0
  169. package/dist/tools/web-search.js +172 -0
  170. package/dist/tools/web-search.js.map +1 -0
  171. package/dist/tools/wrap-with-specialist.d.ts +55 -0
  172. package/dist/tools/wrap-with-specialist.js +137 -0
  173. package/dist/tools/wrap-with-specialist.js.map +1 -0
  174. package/package.json +2 -2
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeRepairHook = makeRepairHook;
4
+ const ai_1 = require("ai");
5
+ const index_js_1 = require("./providers/index.js");
6
+ const logger_js_1 = require("./logger.js");
7
+ /**
8
+ * Heuristic detector for tool-call argument truncation. When the model emits a
9
+ * massive single string argument (e.g. a 16 KB heredoc inside a `command`
10
+ * field), the response may be cut off mid-string, producing
11
+ * "Unterminated string in JSON" or similar from JSON.parse.
12
+ */
13
+ function looksLikeTruncationError(message) {
14
+ return (/unterminated string/i.test(message) ||
15
+ /unexpected end of (json|input)/i.test(message) ||
16
+ /expected.*after.*in json/i.test(message));
17
+ }
18
+ /**
19
+ * Produces an `experimental_repairToolCall` hook for `generateText`. When the
20
+ * AI SDK fails to parse a model's tool-call arguments (or the model targets a
21
+ * nonexistent tool), the hook runs ONE focused generation asking the model to
22
+ * re-emit a valid tool call. Returns the corrected call, or `null` to let the
23
+ * SDK throw.
24
+ *
25
+ * The repair attempt is bounded to a single retry per failed tool call — no
26
+ * looping, no escalation. Failures are logged to the debug stream.
27
+ *
28
+ * Special-cases JSON truncation (the model packed too much content into a
29
+ * single string arg) by hinting at `file_write` + `shell` as the safe pattern
30
+ * for large payloads.
31
+ */
32
+ function makeRepairHook(opts) {
33
+ const { config, provider, model, label, abortSignal } = opts;
34
+ const resolvedProvider = provider ?? config.provider;
35
+ const resolvedModel = model ?? config.model;
36
+ return async ({ toolCall, tools, parameterSchema, messages, system, error }) => {
37
+ try {
38
+ const errorMessage = error instanceof Error ? error.message : String(error);
39
+ const isInvalidArgs = ai_1.InvalidToolArgumentsError.isInstance(error);
40
+ const isNoSuchTool = ai_1.NoSuchToolError.isInstance(error);
41
+ let hint = '';
42
+ if (isInvalidArgs && looksLikeTruncationError(errorMessage)) {
43
+ hint =
44
+ '\n\nThe arguments appear to have been truncated mid-string. For payloads larger than ~1 KB (file contents, scripts, JSON bodies), write the content to a file using `file_write` (or save a script with `file_write` and execute it with `shell`) instead of inlining it as a tool-call argument.';
45
+ }
46
+ else if (isNoSuchTool) {
47
+ const available = Object.keys(tools).slice(0, 25).join(', ');
48
+ hint = `\n\nThe tool "${toolCall.toolName}" does not exist. Available tools include: ${available}.`;
49
+ }
50
+ let schemaText = '';
51
+ try {
52
+ const schema = parameterSchema({ toolName: toolCall.toolName });
53
+ schemaText = `\n\nExpected parameter schema for \`${toolCall.toolName}\`:\n\`\`\`json\n${JSON.stringify(schema, null, 2)}\n\`\`\``;
54
+ }
55
+ catch {
56
+ // No schema available (e.g. unknown tool) — skip.
57
+ }
58
+ const recoveryMessage = {
59
+ role: 'user',
60
+ content: `Your previous tool call to \`${toolCall.toolName}\` failed to parse:\n\n${errorMessage}${schemaText}${hint}\n\nRe-emit the tool call with valid arguments. Do not explain — just call the tool.`,
61
+ };
62
+ const repairMessages = [...messages, recoveryMessage];
63
+ const result = await (0, ai_1.generateText)({
64
+ model: (0, index_js_1.getModelForConfig)(config, resolvedProvider, resolvedModel),
65
+ providerOptions: (0, index_js_1.getProviderOptionsForConfig)(config, resolvedProvider),
66
+ tools,
67
+ toolChoice: isNoSuchTool ? 'auto' : { type: 'tool', toolName: toolCall.toolName },
68
+ maxSteps: 1,
69
+ maxTokens: config.maxTokens,
70
+ system,
71
+ messages: repairMessages,
72
+ abortSignal,
73
+ });
74
+ const repaired = result.toolCalls?.[0];
75
+ if (!repaired) {
76
+ (0, logger_js_1.debugLog)(`tool-call-repair:${label}:no-call`, {
77
+ toolName: toolCall.toolName,
78
+ errorMessage,
79
+ });
80
+ return null;
81
+ }
82
+ (0, logger_js_1.debugLog)(`tool-call-repair:${label}:ok`, {
83
+ original: toolCall.toolName,
84
+ repaired: repaired.toolName,
85
+ });
86
+ return {
87
+ toolCallType: 'function',
88
+ toolCallId: toolCall.toolCallId,
89
+ toolName: repaired.toolName,
90
+ args: JSON.stringify(repaired.args),
91
+ };
92
+ }
93
+ catch (err) {
94
+ (0, logger_js_1.debugLog)(`tool-call-repair:${label}:error`, err instanceof Error ? err.message : String(err));
95
+ return null;
96
+ }
97
+ };
98
+ }
99
+ //# sourceMappingURL=tool-call-repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call-repair.js","sourceRoot":"","sources":["../src/tool-call-repair.ts"],"names":[],"mappings":";;AAsDA,wCA0EC;AAhID,2BAOY;AACZ,mDAAsF;AAEtF,2CAAuC;AAgBvC;;;;;GAKG;AACH,SAAS,wBAAwB,CAAC,OAAe;IAC/C,OAAO,CACL,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC;QACpC,iCAAiC,CAAC,IAAI,CAAC,OAAO,CAAC;QAC/C,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAC1C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,cAAc,CAC5B,IAAwB;IAExB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7D,MAAM,gBAAgB,GAAG,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;IACrD,MAAM,aAAa,GAAG,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;IAE5C,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;QAC7E,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,MAAM,aAAa,GAAG,8BAAyB,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAClE,MAAM,YAAY,GAAG,oBAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAEvD,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,aAAa,IAAI,wBAAwB,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC5D,IAAI;oBACF,mSAAmS,CAAC;YACxS,CAAC;iBAAM,IAAI,YAAY,EAAE,CAAC;gBACxB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7D,IAAI,GAAG,iBAAiB,QAAQ,CAAC,QAAQ,8CAA8C,SAAS,GAAG,CAAC;YACtG,CAAC;YAED,IAAI,UAAU,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAChE,UAAU,GAAG,uCAAuC,QAAQ,CAAC,QAAQ,oBAAoB,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC;YACrI,CAAC;YAAC,MAAM,CAAC;gBACP,kDAAkD;YACpD,CAAC;YAED,MAAM,eAAe,GAAgB;gBACnC,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,gCAAgC,QAAQ,CAAC,QAAQ,0BAA0B,YAAY,GAAG,UAAU,GAAG,IAAI,sFAAsF;aAC3M,CAAC;YAEF,MAAM,cAAc,GAAkB,CAAC,GAAG,QAAQ,EAAE,eAAe,CAAC,CAAC;YAErE,MAAM,MAAM,GAAG,MAAM,IAAA,iBAAY,EAAC;gBAChC,KAAK,EAAE,IAAA,4BAAiB,EAAC,MAAM,EAAE,gBAAgB,EAAE,aAAa,CAAC;gBACjE,eAAe,EAAE,IAAA,sCAA2B,EAAC,MAAM,EAAE,gBAAgB,CAAC;gBACtE,KAAK;gBACL,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE;gBACjF,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,MAAM;gBACN,QAAQ,EAAE,cAAc;gBACxB,WAAW;aACZ,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,IAAA,oBAAQ,EAAC,oBAAoB,KAAK,UAAU,EAAE;oBAC5C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,YAAY;iBACb,CAAC,CAAC;gBACH,OAAO,IAAI,CAAC;YACd,CAAC;YAED,IAAA,oBAAQ,EAAC,oBAAoB,KAAK,KAAK,EAAE;gBACvC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;aAC5B,CAAC,CAAC;YAEH,OAAO;gBACL,YAAY,EAAE,UAAU;gBACxB,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;aACpC,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAA,oBAAQ,EAAC,oBAAoB,KAAK,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9F,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,70 @@
1
+ export interface ToolProfileExample {
2
+ summary: string;
3
+ args: string;
4
+ note?: string;
5
+ }
6
+ export interface ToolProfileBadExample {
7
+ summary: string;
8
+ args: string;
9
+ errorSnippet: string;
10
+ fix: string;
11
+ note?: string;
12
+ }
13
+ export interface ToolProfile {
14
+ toolName: string;
15
+ category?: string;
16
+ guidelines: string[];
17
+ goodExamples: ToolProfileExample[];
18
+ badExamples: ToolProfileBadExample[];
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ errorCount: number;
22
+ successCount: number;
23
+ }
24
+ export declare const MAX_PROFILE_EXAMPLES = 5;
25
+ /** Classifies a shell command string into a sub-category for profile lookup. */
26
+ export declare function classifyShellCommand(command: string): string;
27
+ export type ToolErrorInfo = {
28
+ isError: true;
29
+ snippet: string;
30
+ } | {
31
+ isError: false;
32
+ };
33
+ /**
34
+ * Detects whether a tool's return value indicates an error. Each tool has a
35
+ * different error shape so we normalize them into a single discriminated union.
36
+ */
37
+ export declare function detectToolError(toolName: string, result: unknown): ToolErrorInfo;
38
+ export declare class ToolProfileStore {
39
+ private dirReady;
40
+ constructor();
41
+ private ensureDir;
42
+ private filePath;
43
+ get(toolKey: string): ToolProfile | undefined;
44
+ getOrCreate(toolKey: string): ToolProfile;
45
+ save(profile: ToolProfile): void;
46
+ recordBadExample(toolKey: string, args: string, errorSnippet: string): void;
47
+ recordGoodExample(toolKey: string, args: string, note?: string): void;
48
+ /**
49
+ * After a bad example with `fix === '(awaiting successful retry)'`, if the
50
+ * same tool key succeeds, patch the most recent unfixed bad example with the
51
+ * working args.
52
+ */
53
+ patchLastBadWithFix(toolKey: string, workingArgs: string): void;
54
+ list(): ToolProfile[];
55
+ private seedDefaults;
56
+ }
57
+ /**
58
+ * Approximate character budget for the rendered profiles block. At ~4 chars/token
59
+ * this gives ~1000 tokens — enough for guidance without crowding the context.
60
+ * Profiles are sorted by error count (highest first) so the most valuable
61
+ * guidance survives when the budget is tight.
62
+ */
63
+ export declare const MAX_PROFILE_PROMPT_CHARS = 4000;
64
+ /**
65
+ * Renders tool profiles into a compact system-prompt block. Only profiles with
66
+ * at least one guideline or bad example are included. At most 2 bad examples
67
+ * shown per tool. Profiles are sorted by error count (most errors first) and
68
+ * the total output is capped at {@link MAX_PROFILE_PROMPT_CHARS}.
69
+ */
70
+ export declare function buildToolProfilesPrompt(store: ToolProfileStore): string;
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MAX_PROFILE_PROMPT_CHARS = exports.ToolProfileStore = exports.MAX_PROFILE_EXAMPLES = void 0;
37
+ exports.classifyShellCommand = classifyShellCommand;
38
+ exports.detectToolError = detectToolError;
39
+ exports.buildToolProfilesPrompt = buildToolProfilesPrompt;
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
+ const paths_js_1 = require("./paths.js");
43
+ const fs_utils_js_1 = require("./fs-utils.js");
44
+ exports.MAX_PROFILE_EXAMPLES = 5;
45
+ const SEED_MARKER = '.seeded-v1';
46
+ // ---------------------------------------------------------------------------
47
+ // Shell command classification
48
+ // ---------------------------------------------------------------------------
49
+ const SHELL_CATEGORIES = [
50
+ { pattern: /^\s*git\b/, category: 'git' },
51
+ { pattern: /^\s*gh\b/, category: 'gh' },
52
+ { pattern: /^\s*(docker|docker-compose)\b/, category: 'docker' },
53
+ { pattern: /^\s*(npm|yarn|pnpm|bun)\b/, category: 'npm' },
54
+ {
55
+ pattern: /^\s*(ls|find|cp|mv|mkdir|rm|cat|head|tail|stat|chmod|chown|ln|du|df|wc)\b/,
56
+ category: 'fs',
57
+ },
58
+ { pattern: /^\s*(curl|wget)\b/, category: 'http' },
59
+ { pattern: /^\s*(systemctl|service|journalctl)\b/, category: 'systemd' },
60
+ { pattern: /^\s*(python3?|node|ruby|perl|tsx|ts-node)\b/, category: 'runtime' },
61
+ ];
62
+ /** Classifies a shell command string into a sub-category for profile lookup. */
63
+ function classifyShellCommand(command) {
64
+ for (const { pattern, category } of SHELL_CATEGORIES) {
65
+ if (pattern.test(command))
66
+ return category;
67
+ }
68
+ return 'general';
69
+ }
70
+ /**
71
+ * Detects whether a tool's return value indicates an error. Each tool has a
72
+ * different error shape so we normalize them into a single discriminated union.
73
+ */
74
+ function detectToolError(toolName, result) {
75
+ if (result === null || result === undefined)
76
+ return { isError: false };
77
+ // shell: { output: string, is_error: boolean }
78
+ if (toolName === 'shell' && typeof result === 'object') {
79
+ const r = result;
80
+ if (r.is_error === true) {
81
+ return { isError: true, snippet: String(r.output ?? '').slice(0, 200) };
82
+ }
83
+ return { isError: false };
84
+ }
85
+ // web_read: returns string starting with "Error:"
86
+ if (toolName === 'web_read' && typeof result === 'string') {
87
+ if (result.startsWith('Error:')) {
88
+ return { isError: true, snippet: result.slice(0, 200) };
89
+ }
90
+ return { isError: false };
91
+ }
92
+ // web_search: provider failures / no-result diagnostics are returned as strings
93
+ if (toolName === 'web_search' && typeof result === 'string') {
94
+ if (result.startsWith('web_search returned no results')) {
95
+ return { isError: true, snippet: result.slice(0, 200) };
96
+ }
97
+ return { isError: false };
98
+ }
99
+ // file_read_lines, file_edit_lines: { error: string }
100
+ if ((toolName === 'file_read_lines' || toolName === 'file_edit_lines') &&
101
+ typeof result === 'object') {
102
+ const r = result;
103
+ if (typeof r.error === 'string') {
104
+ return { isError: true, snippet: r.error.slice(0, 200) };
105
+ }
106
+ return { isError: false };
107
+ }
108
+ // Generic fallback for MCP and unknown tools: string starting with "Error"
109
+ if (typeof result === 'string' && result.startsWith('Error')) {
110
+ return { isError: true, snippet: result.slice(0, 200) };
111
+ }
112
+ return { isError: false };
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // Seeded profiles
116
+ // ---------------------------------------------------------------------------
117
+ const SEEDED_PROFILES = {
118
+ 'shell.git': {
119
+ guidelines: [
120
+ 'Always check `git status` before destructive operations.',
121
+ 'Use `--oneline` for compact log output.',
122
+ 'Prefer `git log main..HEAD` to see branch-only commits.',
123
+ ],
124
+ goodExamples: [
125
+ {
126
+ summary: 'Log branch commits vs main',
127
+ args: '{"command":"git log --oneline main..HEAD"}',
128
+ },
129
+ ],
130
+ },
131
+ 'shell.gh': {
132
+ guidelines: [
133
+ 'Use `gh issue list --json` for machine-parseable output.',
134
+ 'Always pass `--repo owner/repo` when context is ambiguous.',
135
+ ],
136
+ goodExamples: [],
137
+ },
138
+ 'shell.docker': {
139
+ guidelines: [
140
+ 'Prefer `docker compose` (v2) over `docker-compose` (v1).',
141
+ 'Use `--format json` with inspect commands for reliable parsing.',
142
+ ],
143
+ goodExamples: [],
144
+ },
145
+ 'shell.npm': {
146
+ guidelines: [
147
+ 'Use `--json` flag where available for structured output.',
148
+ 'Prefer `npm ci` over `npm install` in CI/scripts for reproducibility.',
149
+ ],
150
+ goodExamples: [],
151
+ },
152
+ 'shell.fs': {
153
+ guidelines: [
154
+ 'Quote all paths to handle spaces.',
155
+ 'Use `find -print0 | xargs -0` for filenames with spaces/newlines.',
156
+ 'Prefer `file_read_lines`/`file_edit_lines` over `cat`/`sed` for reading and editing files.',
157
+ ],
158
+ goodExamples: [],
159
+ },
160
+ 'shell.http': {
161
+ guidelines: [
162
+ 'Use `-s` (silent) with curl to suppress progress bars.',
163
+ 'Always set a timeout with `-m` or `--max-time` to avoid hangs.',
164
+ ],
165
+ goodExamples: [],
166
+ },
167
+ web_read: {
168
+ guidelines: [
169
+ 'Always pass a CSS selector to scope large pages.',
170
+ 'URL must start with http:// or https://.',
171
+ ],
172
+ goodExamples: [
173
+ {
174
+ summary: 'Fetch docs with article selector',
175
+ args: '{"url":"https://example.com/docs","selector":"article"}',
176
+ },
177
+ ],
178
+ },
179
+ file_read_lines: {
180
+ guidelines: [
181
+ 'Use offset+limit to paginate files larger than ~200 lines.',
182
+ 'Always read before editing to get current line numbers.',
183
+ ],
184
+ goodExamples: [],
185
+ },
186
+ file_edit_lines: {
187
+ guidelines: [
188
+ 'Read first with file_read_lines to get exact line numbers — they shift after edits.',
189
+ 'Edits are atomic: all operations succeed or all revert.',
190
+ ],
191
+ goodExamples: [],
192
+ },
193
+ };
194
+ // ---------------------------------------------------------------------------
195
+ // Store
196
+ // ---------------------------------------------------------------------------
197
+ class ToolProfileStore {
198
+ dirReady = false;
199
+ constructor() {
200
+ this.ensureDir();
201
+ this.seedDefaults();
202
+ }
203
+ ensureDir() {
204
+ if (this.dirReady)
205
+ return;
206
+ fs.mkdirSync(paths_js_1.TOOL_PROFILES_DIR, { recursive: true });
207
+ this.dirReady = true;
208
+ }
209
+ filePath(toolKey) {
210
+ const safe = toolKey.replace(/[^a-zA-Z0-9._-]/g, '-');
211
+ return path.join(paths_js_1.TOOL_PROFILES_DIR, `${safe}.json`);
212
+ }
213
+ get(toolKey) {
214
+ try {
215
+ return JSON.parse(fs.readFileSync(this.filePath(toolKey), 'utf-8'));
216
+ }
217
+ catch {
218
+ return undefined;
219
+ }
220
+ }
221
+ getOrCreate(toolKey) {
222
+ const existing = this.get(toolKey);
223
+ if (existing)
224
+ return existing;
225
+ const now = new Date().toISOString();
226
+ return {
227
+ toolName: toolKey,
228
+ guidelines: [],
229
+ goodExamples: [],
230
+ badExamples: [],
231
+ createdAt: now,
232
+ updatedAt: now,
233
+ errorCount: 0,
234
+ successCount: 0,
235
+ };
236
+ }
237
+ save(profile) {
238
+ this.ensureDir();
239
+ const updated = { ...profile, updatedAt: new Date().toISOString() };
240
+ (0, fs_utils_js_1.atomicWriteFileSync)(this.filePath(profile.toolName), JSON.stringify(updated, null, 2));
241
+ }
242
+ recordBadExample(toolKey, args, errorSnippet) {
243
+ const profile = this.getOrCreate(toolKey);
244
+ const bad = {
245
+ summary: `Failed: ${args.slice(0, 80)}`,
246
+ args: args.slice(0, 200),
247
+ errorSnippet,
248
+ fix: '(awaiting successful retry)',
249
+ };
250
+ const updated = [...profile.badExamples, bad].slice(-exports.MAX_PROFILE_EXAMPLES);
251
+ this.save({ ...profile, badExamples: updated, errorCount: profile.errorCount + 1 });
252
+ }
253
+ recordGoodExample(toolKey, args, note) {
254
+ const profile = this.getOrCreate(toolKey);
255
+ const good = {
256
+ summary: 'Successful call',
257
+ args: args.slice(0, 200),
258
+ note,
259
+ };
260
+ const updated = [...profile.goodExamples, good].slice(-exports.MAX_PROFILE_EXAMPLES);
261
+ this.save({ ...profile, goodExamples: updated, successCount: profile.successCount + 1 });
262
+ }
263
+ /**
264
+ * After a bad example with `fix === '(awaiting successful retry)'`, if the
265
+ * same tool key succeeds, patch the most recent unfixed bad example with the
266
+ * working args.
267
+ */
268
+ patchLastBadWithFix(toolKey, workingArgs) {
269
+ const profile = this.get(toolKey);
270
+ if (!profile || profile.badExamples.length === 0)
271
+ return;
272
+ const bads = [...profile.badExamples];
273
+ const last = bads[bads.length - 1];
274
+ if (last.fix === '(awaiting successful retry)') {
275
+ bads[bads.length - 1] = { ...last, fix: `Use instead: ${workingArgs.slice(0, 200)}` };
276
+ this.save({ ...profile, badExamples: bads });
277
+ }
278
+ }
279
+ list() {
280
+ try {
281
+ return fs
282
+ .readdirSync(paths_js_1.TOOL_PROFILES_DIR)
283
+ .filter((f) => f.endsWith('.json'))
284
+ .flatMap((f) => {
285
+ try {
286
+ return [
287
+ JSON.parse(fs.readFileSync(path.join(paths_js_1.TOOL_PROFILES_DIR, f), 'utf-8')),
288
+ ];
289
+ }
290
+ catch {
291
+ return [];
292
+ }
293
+ });
294
+ }
295
+ catch {
296
+ return [];
297
+ }
298
+ }
299
+ seedDefaults() {
300
+ const markerPath = path.join(paths_js_1.TOOL_PROFILES_DIR, SEED_MARKER);
301
+ if (fs.existsSync(markerPath))
302
+ return;
303
+ try {
304
+ const now = new Date().toISOString();
305
+ for (const [toolKey, seed] of Object.entries(SEEDED_PROFILES)) {
306
+ if (this.get(toolKey))
307
+ continue;
308
+ const profile = {
309
+ toolName: toolKey,
310
+ guidelines: seed.guidelines,
311
+ goodExamples: seed.goodExamples,
312
+ badExamples: [],
313
+ createdAt: now,
314
+ updatedAt: now,
315
+ errorCount: 0,
316
+ successCount: 0,
317
+ };
318
+ this.save(profile);
319
+ }
320
+ fs.writeFileSync(markerPath, now, 'utf-8');
321
+ }
322
+ catch {
323
+ // best-effort; never block startup
324
+ }
325
+ }
326
+ }
327
+ exports.ToolProfileStore = ToolProfileStore;
328
+ // ---------------------------------------------------------------------------
329
+ // System prompt rendering
330
+ // ---------------------------------------------------------------------------
331
+ /**
332
+ * Approximate character budget for the rendered profiles block. At ~4 chars/token
333
+ * this gives ~1000 tokens — enough for guidance without crowding the context.
334
+ * Profiles are sorted by error count (highest first) so the most valuable
335
+ * guidance survives when the budget is tight.
336
+ */
337
+ exports.MAX_PROFILE_PROMPT_CHARS = 4000;
338
+ /**
339
+ * Renders tool profiles into a compact system-prompt block. Only profiles with
340
+ * at least one guideline or bad example are included. At most 2 bad examples
341
+ * shown per tool. Profiles are sorted by error count (most errors first) and
342
+ * the total output is capped at {@link MAX_PROFILE_PROMPT_CHARS}.
343
+ */
344
+ function buildToolProfilesPrompt(store) {
345
+ const profiles = store
346
+ .list()
347
+ .filter((p) => p.guidelines.length > 0 || p.badExamples.length > 0)
348
+ .sort((a, b) => b.errorCount - a.errorCount);
349
+ if (profiles.length === 0)
350
+ return '';
351
+ const header = '## Tool Usage Profiles\n\nThe following notes apply when calling these tools:\n';
352
+ let totalChars = header.length;
353
+ const sections = [header];
354
+ for (const profile of profiles) {
355
+ const label = profile.toolName.startsWith('shell.')
356
+ ? `shell (${profile.toolName.slice(6)} commands)`
357
+ : profile.toolName;
358
+ const sectionLines = [`### ${label}`];
359
+ for (const g of profile.guidelines) {
360
+ sectionLines.push(`- ${g}`);
361
+ }
362
+ const shownBad = profile.badExamples.slice(-2);
363
+ if (shownBad.length > 0) {
364
+ sectionLines.push('');
365
+ sectionLines.push('Avoid these patterns (observed errors):');
366
+ for (const b of shownBad) {
367
+ sectionLines.push(`- BAD: ${b.args} -> Error: ${b.errorSnippet}`);
368
+ if (b.fix && b.fix !== '(awaiting successful retry)') {
369
+ sectionLines.push(` FIX: ${b.fix}`);
370
+ }
371
+ }
372
+ }
373
+ sectionLines.push('');
374
+ const section = sectionLines.join('\n');
375
+ if (totalChars + section.length > exports.MAX_PROFILE_PROMPT_CHARS)
376
+ break;
377
+ totalChars += section.length;
378
+ sections.push(section);
379
+ }
380
+ // Only the header — nothing fit the budget (unlikely but safe)
381
+ if (sections.length <= 1)
382
+ return '';
383
+ return sections.join('\n');
384
+ }
385
+ //# sourceMappingURL=tool-profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-profiles.js","sourceRoot":"","sources":["../src/tool-profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Builds a deterministic Markdown summary of every tool call recorded by a
3
+ * `generateText` run. Used as a post-run activity log so callers can verify
4
+ * what a sub-agent or specialist actually did, even when the model's prose
5
+ * output is empty or under-reports the side effects.
6
+ */
7
+ export declare function buildActivitySummary(steps: unknown[] | undefined): string;
8
+ /**
9
+ * Returns the model's text with an Activity Log appended. When the text is
10
+ * empty or whitespace-only, emits a preamble explaining that the activity was
11
+ * reconstructed from the tool-call log.
12
+ *
13
+ * `agentLabel` identifies the caller in the empty-text preamble (e.g. "specialist", "subagent").
14
+ */
15
+ export declare function appendActivitySummary(text: string, steps: unknown[] | undefined, agentLabel: string): string;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildActivitySummary = buildActivitySummary;
4
+ exports.appendActivitySummary = appendActivitySummary;
5
+ const critic_js_1 = require("../critic.js");
6
+ const ARG_PREVIEW = 200;
7
+ const RESULT_PREVIEW = 400;
8
+ function previewValue(v, limit) {
9
+ const s = typeof v === 'string' ? v : JSON.stringify(v ?? null);
10
+ return s.slice(0, limit);
11
+ }
12
+ /**
13
+ * Builds a deterministic Markdown summary of every tool call recorded by a
14
+ * `generateText` run. Used as a post-run activity log so callers can verify
15
+ * what a sub-agent or specialist actually did, even when the model's prose
16
+ * output is empty or under-reports the side effects.
17
+ */
18
+ function buildActivitySummary(steps) {
19
+ const log = (0, critic_js_1.extractToolCallLog)((steps ?? []));
20
+ if (log.length === 0) {
21
+ return '## Activity Log\n(no tool calls)';
22
+ }
23
+ const lines = log.map((e, i) => `${i + 1}. ${e.toolName}(${previewValue(e.args, ARG_PREVIEW)})\n → ${previewValue(e.result, RESULT_PREVIEW)}`);
24
+ return ['## Activity Log', `${log.length} tool call(s):`, ...lines].join('\n');
25
+ }
26
+ /**
27
+ * Returns the model's text with an Activity Log appended. When the text is
28
+ * empty or whitespace-only, emits a preamble explaining that the activity was
29
+ * reconstructed from the tool-call log.
30
+ *
31
+ * `agentLabel` identifies the caller in the empty-text preamble (e.g. "specialist", "subagent").
32
+ */
33
+ function appendActivitySummary(text, steps, agentLabel) {
34
+ const summary = buildActivitySummary(steps);
35
+ if (!text.trim()) {
36
+ return [
37
+ `(${agentLabel} produced no text summary; activity reconstructed from tool-call log)`,
38
+ '',
39
+ summary,
40
+ ].join('\n');
41
+ }
42
+ return `${text.trimEnd()}\n\n${summary}`;
43
+ }
44
+ //# sourceMappingURL=activity-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-summary.js","sourceRoot":"","sources":["../../src/tools/activity-summary.ts"],"names":[],"mappings":";;AAgBA,oDAUC;AASD,sDAcC;AAjDD,4CAAkD;AAElD,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,SAAS,YAAY,CAAC,CAAU,EAAE,KAAa;IAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,SAAgB,oBAAoB,CAAC,KAA4B;IAC/D,MAAM,GAAG,GAAG,IAAA,8BAAkB,EAAC,CAAC,KAAK,IAAI,EAAE,CAA6C,CAAC,CAAC;IAC1F,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,kCAAkC,CAAC;IAC5C,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CACnB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAClH,CAAC;IACF,OAAO,CAAC,iBAAiB,EAAE,GAAG,GAAG,CAAC,MAAM,gBAAgB,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,qBAAqB,CACnC,IAAY,EACZ,KAA4B,EAC5B,UAAkB;IAElB,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACjB,OAAO;YACL,IAAI,UAAU,uEAAuE;YACrF,EAAE;YACF,OAAO;SACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,CAAC;AAC3C,CAAC"}