@oharness/engine 0.5.0 → 0.6.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 (114) hide show
  1. package/dist/agent/agent.d.ts +63 -0
  2. package/dist/agent/agent.js +257 -7
  3. package/dist/agent/agent.js.map +1 -1
  4. package/dist/agent/memory-backup.d.ts +38 -0
  5. package/dist/agent/memory-backup.js +126 -0
  6. package/dist/agent/memory-backup.js.map +1 -0
  7. package/dist/agent/memory-consolidate.d.ts +47 -0
  8. package/dist/agent/memory-consolidate.js +118 -0
  9. package/dist/agent/memory-consolidate.js.map +1 -0
  10. package/dist/agent/memory-errors.d.ts +73 -0
  11. package/dist/agent/memory-errors.js +74 -0
  12. package/dist/agent/memory-errors.js.map +1 -0
  13. package/dist/agent/memory-extract.d.ts +36 -0
  14. package/dist/agent/memory-extract.js +169 -0
  15. package/dist/agent/memory-extract.js.map +1 -0
  16. package/dist/agent/memory-limits.d.ts +115 -0
  17. package/dist/agent/memory-limits.js +109 -0
  18. package/dist/agent/memory-limits.js.map +1 -0
  19. package/dist/agent/memory-links.d.ts +21 -0
  20. package/dist/agent/memory-links.js +45 -0
  21. package/dist/agent/memory-links.js.map +1 -0
  22. package/dist/agent/memory-merge.d.ts +34 -0
  23. package/dist/agent/memory-merge.js +152 -0
  24. package/dist/agent/memory-merge.js.map +1 -0
  25. package/dist/agent/memory-provider.d.ts +73 -0
  26. package/dist/agent/memory-provider.js +2 -0
  27. package/dist/agent/memory-provider.js.map +1 -0
  28. package/dist/agent/memory-recall.d.ts +72 -0
  29. package/dist/agent/memory-recall.js +192 -0
  30. package/dist/agent/memory-recall.js.map +1 -0
  31. package/dist/agent/memory-redact.d.ts +15 -0
  32. package/dist/agent/memory-redact.js +48 -0
  33. package/dist/agent/memory-redact.js.map +1 -0
  34. package/dist/agent/memory-review.d.ts +47 -0
  35. package/dist/agent/memory-review.js +127 -0
  36. package/dist/agent/memory-review.js.map +1 -0
  37. package/dist/agent/memory-usage.d.ts +24 -0
  38. package/dist/agent/memory-usage.js +68 -0
  39. package/dist/agent/memory-usage.js.map +1 -0
  40. package/dist/agent/memory.d.ts +137 -14
  41. package/dist/agent/memory.js +431 -130
  42. package/dist/agent/memory.js.map +1 -1
  43. package/dist/agent/permissions.d.ts +10 -2
  44. package/dist/agent/permissions.js +22 -3
  45. package/dist/agent/permissions.js.map +1 -1
  46. package/dist/agent/session.d.ts +8 -1
  47. package/dist/agent/session.js +9 -0
  48. package/dist/agent/session.js.map +1 -1
  49. package/dist/agent/store.d.ts +3 -0
  50. package/dist/agent/store.js.map +1 -1
  51. package/dist/agent/titles.js +2 -2
  52. package/dist/config.d.ts +7 -1
  53. package/dist/config.js +27 -0
  54. package/dist/config.js.map +1 -1
  55. package/dist/core/audit.d.ts +19 -0
  56. package/dist/core/types.d.ts +6 -0
  57. package/dist/core/types.js +12 -0
  58. package/dist/core/types.js.map +1 -1
  59. package/dist/harness.d.ts +7 -1
  60. package/dist/harness.js +33 -2
  61. package/dist/harness.js.map +1 -1
  62. package/dist/providers/builtin.d.ts +20 -0
  63. package/dist/providers/builtin.js +82 -0
  64. package/dist/providers/builtin.js.map +1 -1
  65. package/dist/providers/catalog.js +30 -3
  66. package/dist/providers/catalog.js.map +1 -1
  67. package/dist/providers/index.d.ts +2 -2
  68. package/dist/providers/index.js +1 -1
  69. package/dist/providers/index.js.map +1 -1
  70. package/dist/providers/piai.js +17 -8
  71. package/dist/providers/piai.js.map +1 -1
  72. package/dist/providers/registry.d.ts +5 -0
  73. package/dist/providers/registry.js +10 -2
  74. package/dist/providers/registry.js.map +1 -1
  75. package/dist/providers/types.d.ts +31 -0
  76. package/dist/providers/types.js +36 -0
  77. package/dist/providers/types.js.map +1 -1
  78. package/dist/runtime-plugins/builtin/memory-coordinator.d.ts +79 -0
  79. package/dist/runtime-plugins/builtin/memory-coordinator.js +169 -0
  80. package/dist/runtime-plugins/builtin/memory-coordinator.js.map +1 -0
  81. package/dist/runtime-plugins/builtin/memory-migrate.d.ts +35 -0
  82. package/dist/runtime-plugins/builtin/memory-migrate.js +141 -0
  83. package/dist/runtime-plugins/builtin/memory-migrate.js.map +1 -0
  84. package/dist/runtime-plugins/builtin/memory.d.ts +144 -5
  85. package/dist/runtime-plugins/builtin/memory.js +1016 -112
  86. package/dist/runtime-plugins/builtin/memory.js.map +1 -1
  87. package/dist/runtime-plugins/builtin/studio.js +19 -4
  88. package/dist/runtime-plugins/builtin/studio.js.map +1 -1
  89. package/dist/runtime-plugins/cloud-connector.js +4 -1
  90. package/dist/runtime-plugins/cloud-connector.js.map +1 -1
  91. package/dist/runtime-plugins/extensions.d.ts +9 -0
  92. package/dist/runtime-plugins/extensions.js +15 -0
  93. package/dist/runtime-plugins/extensions.js.map +1 -1
  94. package/dist/runtime-plugins/host.js +24 -2
  95. package/dist/runtime-plugins/host.js.map +1 -1
  96. package/dist/runtime-plugins/types.d.ts +6 -0
  97. package/dist/tools/builtin/ask.d.ts +9 -0
  98. package/dist/tools/builtin/ask.js +71 -0
  99. package/dist/tools/builtin/ask.js.map +1 -0
  100. package/dist/tools/builtin/index.d.ts +1 -0
  101. package/dist/tools/builtin/index.js +3 -0
  102. package/dist/tools/builtin/index.js.map +1 -1
  103. package/dist/tools/builtin/memory.d.ts +5 -5
  104. package/dist/tools/builtin/memory.js +151 -40
  105. package/dist/tools/builtin/memory.js.map +1 -1
  106. package/dist/tools/index.d.ts +2 -0
  107. package/dist/tools/index.js +1 -0
  108. package/dist/tools/index.js.map +1 -1
  109. package/dist/tools/questions.d.ts +89 -0
  110. package/dist/tools/questions.js +97 -0
  111. package/dist/tools/questions.js.map +1 -0
  112. package/dist/tools/types.d.ts +7 -0
  113. package/dist/tools/types.js.map +1 -1
  114. package/package.json +2 -2
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+ import { defineTool } from "../define.js";
3
+ import { ASK_USER_TOOL, describeResult } from "../questions.js";
4
+ const OptionSchema = z.object({
5
+ label: z.string().trim().min(1).max(80).describe("What the user clicks; 1-5 words"),
6
+ description: z.string().trim().max(300).optional().describe("What choosing this means, or its trade-off"),
7
+ preview: z
8
+ .string()
9
+ .max(4000)
10
+ .optional()
11
+ .describe("Optional code, layout or snippet shown while this option is focused"),
12
+ });
13
+ const QuestionSchema = z
14
+ .object({
15
+ header: z.string().trim().min(1).max(16).describe("Very short tag shown on the card, e.g. \"Database\""),
16
+ question: z.string().trim().min(1).max(500).describe("The full question, ending with a question mark"),
17
+ multiSelect: z.boolean().default(false).describe("Allow more than one option to be chosen"),
18
+ options: z.array(OptionSchema).min(2).max(4).describe("2-4 distinct choices; an \"Other\" field is always added"),
19
+ })
20
+ .refine((question) => new Set(question.options.map((option) => option.label)).size === question.options.length, {
21
+ message: "option labels must be unique",
22
+ path: ["options"],
23
+ });
24
+ /**
25
+ * Stops the turn on a question only a person can answer.
26
+ *
27
+ * Read-only on purpose: asking changes nothing, so it needs no approval, and
28
+ * plan mode — which refuses everything else that is not read-only — is exactly
29
+ * when clarifying before committing to a plan is most useful. An explicit deny
30
+ * rule still turns it off for anyone who wants the agent fully autonomous.
31
+ */
32
+ export const askUserTool = defineTool({
33
+ name: ASK_USER_TOOL,
34
+ description: [
35
+ "Ask the user 1-4 multiple-choice questions and wait for the answer.",
36
+ "Use it only when the answer changes what you do next and cannot be found in the code, the configuration, or a sensible default.",
37
+ "Do not ask for facts you can look up, and do not ask \"should I proceed?\" or \"is this plan OK?\".",
38
+ "Put related questions in one call rather than asking several times in a row.",
39
+ "If you recommend an option, list it first and end its label with \"(Recommended)\".",
40
+ "Never add an \"Other\" option yourself: the user can always type their own answer.",
41
+ "In plan mode, use this to clarify requirements before presenting the plan.",
42
+ ].join(" "),
43
+ parameters: z.object({
44
+ questions: z.array(QuestionSchema).min(1).max(4).describe("The questions, in the order they should be answered"),
45
+ }),
46
+ readOnly: true,
47
+ // One card at a time: a second question racing the first would leave the
48
+ // person answering in whichever order the frontend happened to draw them.
49
+ concurrencySafe: false,
50
+ renderTitle: (input) => input.questions.length === 1 ? `Ask(${input.questions[0].header})` : `Ask(${input.questions.length} questions)`,
51
+ async execute(input, ctx) {
52
+ const questions = input.questions.map((question, index) => ({
53
+ id: `q${index + 1}`,
54
+ header: question.header,
55
+ question: question.question,
56
+ multiSelect: question.multiSelect,
57
+ options: question.options.map((option) => ({
58
+ label: option.label,
59
+ ...(option.description ? { description: option.description } : {}),
60
+ ...(option.preview ? { preview: option.preview } : {}),
61
+ })),
62
+ }));
63
+ const result = ctx.ask ? await ctx.ask(questions) : { outcome: "unavailable" };
64
+ return {
65
+ content: [{ type: "text", text: describeResult(questions, result) }],
66
+ isError: result.outcome === "unavailable" || result.outcome === "aborted",
67
+ metadata: { questions, result },
68
+ };
69
+ },
70
+ });
71
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../../src/tools/builtin/ask.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Tool } from "../types.ts";
2
+ export { askUserTool } from "./ask.ts";
2
3
  export { bashTool } from "./bash.ts";
3
4
  export { artifactTool, artifactReadTool, artifactTools, ARTIFACT_METADATA_KEY } from "./artifact.ts";
4
5
  export { readTool, writeTool, editTool, listTool, fileTools, resolvePath } from "./fs.ts";
@@ -4,6 +4,8 @@ import { globTool, grepTool, searchTools } from "./search.js";
4
4
  import { recallTool } from "./recall.js";
5
5
  import { todoTool } from "./todo.js";
6
6
  import { artifactReadTool, artifactTool, artifactTools } from "./artifact.js";
7
+ import { askUserTool } from "./ask.js";
8
+ export { askUserTool } from "./ask.js";
7
9
  export { bashTool } from "./bash.js";
8
10
  export { artifactTool, artifactReadTool, artifactTools, ARTIFACT_METADATA_KEY } from "./artifact.js";
9
11
  export { readTool, writeTool, editTool, listTool, fileTools, resolvePath } from "./fs.js";
@@ -21,6 +23,7 @@ export const builtinTools = [
21
23
  bashTool,
22
24
  recallTool,
23
25
  todoTool,
26
+ askUserTool,
24
27
  ...artifactTools,
25
28
  ];
26
29
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9E,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACrG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC,GAAG,SAAS;IACZ,GAAG,WAAW;IACd,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,GAAG,aAAa;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAW;IACnC,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,gBAAgB;CACjB,CAAC;AAEF,KAAK,SAAS,CAAC;AACf,KAAK,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACrG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC,GAAG,SAAS;IACZ,GAAG,WAAW;IACd,QAAQ;IACR,UAAU;IACV,QAAQ;IACR,WAAW;IACX,GAAG,aAAa;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAW;IACnC,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,gBAAgB;CACjB,CAAC;AAEF,KAAK,SAAS,CAAC;AACf,KAAK,QAAQ,CAAC"}
@@ -1,10 +1,10 @@
1
- import type { MemoryStore } from "../../agent/memory.ts";
1
+ import type { MemoryStore, MemoryStores } from "../../agent/memory.ts";
2
2
  import type { Tool } from "../types.ts";
3
3
  /**
4
- * Read and write the agent's durable notes.
4
+ * Read, write and delete the agent's durable notes.
5
5
  *
6
- * Split into two tools rather than one with a `mode` argument: writing a note
7
- * is a decision the model should make deliberately, and a single tool whose
6
+ * Separate tools rather than one with a `mode` argument: writing a note is a
7
+ * decision the model should make deliberately, and a single tool whose
8
8
  * behaviour flips on a string is one the model gets wrong under pressure.
9
9
  */
10
- export declare function createMemoryTools(memory: MemoryStore): Tool[];
10
+ export declare function createMemoryTools(memory: MemoryStore | MemoryStores): Tool[];
@@ -1,76 +1,187 @@
1
1
  import { z } from "zod";
2
+ import { findScoped, loadScoped, memoryNote, storeFor } from "../../agent/memory.js";
3
+ import { backupNote } from "../../agent/memory-backup.js";
4
+ import { MEMORY_SCOPES, MEMORY_TYPES, defaultScopeFor } from "../../agent/memory-limits.js";
5
+ import { extractLinks } from "../../agent/memory-links.js";
6
+ import { rankNotes } from "../../agent/memory-recall.js";
7
+ import { findSecrets } from "../../agent/memory-redact.js";
2
8
  import { defineTool } from "../define.js";
3
9
  import { toolError, toolText } from "../types.js";
4
10
  /**
5
- * Read and write the agent's durable notes.
11
+ * Read, write and delete the agent's durable notes.
6
12
  *
7
- * Split into two tools rather than one with a `mode` argument: writing a note
8
- * is a decision the model should make deliberately, and a single tool whose
13
+ * Separate tools rather than one with a `mode` argument: writing a note is a
14
+ * decision the model should make deliberately, and a single tool whose
9
15
  * behaviour flips on a string is one the model gets wrong under pressure.
10
16
  */
11
17
  export function createMemoryTools(memory) {
18
+ const stores = "project" in memory && !("load" in memory) ? memory : { project: memory };
12
19
  const read = defineTool({
13
20
  name: "memory",
14
21
  readOnly: true,
15
22
  description: "Read notes recorded in earlier sessions. Call with an id from the memory index " +
16
- "in the system prompt to read one in full, or with a query to search. The index " +
17
- "shows summaries only — read the note before relying on it.",
23
+ "in the system prompt, or from a <recalled-memory> block, to read one in full with " +
24
+ "the notes it links to and the notes that link to it. Call with a query to search. " +
25
+ "The index shows summaries only — read the note before relying on it.",
18
26
  parameters: z.object({
19
27
  id: z.string().optional().describe("Note id to read in full"),
20
28
  query: z.string().optional().describe("Text to search summaries, bodies and tags for"),
21
29
  }),
22
30
  renderTitle: (input) => `Memory(${input.id ?? input.query ?? "all"})`,
23
31
  async execute(input) {
24
- const entries = await memory.load();
25
- if (entries.length === 0) {
32
+ const { notes, links } = await loadScoped(stores);
33
+ if (notes.length === 0)
26
34
  return toolText("No notes have been recorded yet.");
27
- }
28
35
  if (input.id) {
29
- const entry = entries.find((candidate) => candidate.id === input.id);
30
- if (!entry) {
31
- return toolError(`No note with id "${input.id}". Known ids: ${entries.map((e) => e.id).join(", ")}`);
36
+ const note = findScoped(notes, input.id);
37
+ if (!note) {
38
+ const near = rankNotes(notes, input.id.replace(/[-_]/g, " ")).slice(0, 5);
39
+ return toolError(`No note with id "${input.id}".` +
40
+ (near.length ? ` Closest: ${near.map((entry) => `\`${entry.note.id}\``).join(", ")}` : ""));
32
41
  }
33
- return toolText(render(entry));
42
+ const summaryOf = (id) => findScoped(notes, id)?.summary ?? "";
43
+ const sections = [render(note)];
44
+ const outgoing = links.outgoing.get(note.id) ?? [];
45
+ const incoming = links.incoming.get(note.id) ?? [];
46
+ const dangling = links.dangling.get(note.id) ?? [];
47
+ if (outgoing.length)
48
+ sections.push(`Links to:\n${outgoing.map((id) => `- \`${id}\` — ${summaryOf(id)}`).join("\n")}`);
49
+ if (incoming.length)
50
+ sections.push(`Linked from:\n${incoming.map((id) => `- \`${id}\` — ${summaryOf(id)}`).join("\n")}`);
51
+ if (dangling.length)
52
+ sections.push(`Links to notes that do not exist yet: ${dangling.map((id) => `\`${id}\``).join(", ")}`);
53
+ return toolText(sections.join("\n\n"));
34
54
  }
35
- const matches = input.query ? await memory.search(input.query) : entries;
36
- if (matches.length === 0) {
37
- return toolText(`No note matches "${input.query}".`);
55
+ let matches;
56
+ if (input.query) {
57
+ matches = rankNotes(notes, input.query).map((entry) => entry.note);
58
+ if (!matches.length) {
59
+ const needle = input.query.toLowerCase();
60
+ matches = notes.filter((note) => note.summary.toLowerCase().includes(needle) || note.body.toLowerCase().includes(needle) ||
61
+ note.tags.some((tag) => tag.toLowerCase().includes(needle)) || note.id.toLowerCase().includes(needle));
62
+ }
38
63
  }
39
- return toolText(matches.slice(0, 10).map(render).join("\n\n---\n\n"), {
40
- matched: matches.length,
41
- });
64
+ else {
65
+ matches = [...notes].sort((a, b) => (b.updatedAt ?? b.createdAt) - (a.updatedAt ?? a.createdAt));
66
+ }
67
+ if (matches.length === 0)
68
+ return toolText(`No note matches "${input.query}".`);
69
+ return toolText(matches.slice(0, 10).map(render).join("\n\n---\n\n"), { matched: matches.length });
42
70
  },
43
71
  });
44
72
  const write = defineTool({
45
73
  name: "remember",
46
- description: "Record something worth carrying into future sessions — a correction, a convention " +
47
- "this project follows, an approach that worked. Do not record what the code or git " +
48
- "history already says, or anything that only matters to the current task. Writing " +
49
- "the same summary again updates the existing note rather than adding a duplicate.",
74
+ description: "Record something worth carrying into future sessions — a correction, a preference, a " +
75
+ "convention this project follows, a decision and why, where something external lives. " +
76
+ "Do not record what the code or git history already says, anything that only matters to " +
77
+ "the current task, or credentials. The summary is what later messages are matched against, " +
78
+ "so write it as one concrete line naming the subject, and put the other words someone might use " +
79
+ "for it in `tags`: synonyms and the term in the other language in use. Pass `id` to update a specific note; " +
80
+ "writing the same summary again also updates rather than duplicates. The result lists " +
81
+ "related existing notes: update one of those instead when it covers the same thing, and " +
82
+ "link the rest from the body as [[note-id]].",
50
83
  parameters: z.object({
51
- summary: z
52
- .string()
53
- .min(4)
54
- .describe("One line naming the lesson; this is what appears in the index"),
55
- body: z
56
- .string()
57
- .min(4)
58
- .describe("The note itself: what was learned, why it matters, how to apply it"),
59
- tags: z.array(z.string()).optional().describe("Tags to help find it later"),
84
+ summary: z.string().min(4).describe("One concrete line naming the lesson; matched against future messages"),
85
+ body: z.string().min(4).describe("The note itself: the fact, why it matters, how to apply it. Link related notes as [[note-id]]"),
86
+ type: z.enum(MEMORY_TYPES).optional().describe("user: who the user is and how they like to work. feedback: a correction or a confirmed approach. " +
87
+ "project: a decision, constraint or piece of ongoing work not derivable from the code. reference: where external information lives"),
88
+ scope: z.enum(MEMORY_SCOPES).optional().describe("user: holds in every project. project: tied to this codebase. Defaults to user for user notes and project otherwise; " +
89
+ "choose user for feedback only when it plainly applies to every project"),
90
+ id: z.string().optional().describe("Existing note id to update"),
91
+ tags: z.array(z.string()).optional().describe("Words to find it by beyond the summary's own: synonyms and the other language's term, e.g. border, 边框, 描边. Recall matches words, not meaning"),
60
92
  }),
61
93
  renderTitle: (input) => `Remember(${input.summary.slice(0, 40)})`,
62
94
  async execute(input) {
63
- const entry = await memory.remember(input);
64
- return toolText(`Recorded as \`${entry.id}\`.`, { id: entry.id, file: entry.file });
95
+ const secrets = findSecrets(`${input.summary}\n${input.body}`);
96
+ if (secrets.length) {
97
+ return toolError(`Not recorded: the note contains what looks like a credential (${secrets.join(", ")}). Notes sync and are shown to future sessions; describe where the secret lives instead of including it.`);
98
+ }
99
+ const { notes } = await loadScoped(stores);
100
+ let scope;
101
+ let targetId;
102
+ if (input.id) {
103
+ const existing = findScoped(notes, input.id);
104
+ if (!existing)
105
+ return toolError(`No note with id "${input.id}" to update.`);
106
+ scope = existing.scope;
107
+ targetId = existing.id;
108
+ }
109
+ else {
110
+ scope = input.scope ?? defaultScopeFor(input.type);
111
+ if (scope === "user" && !stores.user)
112
+ scope = "project";
113
+ }
114
+ let entry;
115
+ try {
116
+ entry = await storeFor(stores, scope).remember({
117
+ summary: input.summary, body: input.body,
118
+ ...(input.tags ? { tags: input.tags } : {}),
119
+ ...(input.type ? { type: input.type } : {}),
120
+ ...(targetId ? { id: targetId } : {}),
121
+ });
122
+ }
123
+ catch (error) {
124
+ return toolError(error instanceof Error ? error.message : String(error));
125
+ }
126
+ const lines = [`Recorded as \`${entry.id}\` (${[scope, entry.type].filter(Boolean).join(" · ")}).`];
127
+ const others = notes.filter((note) => note.id !== entry.id);
128
+ const related = rankNotes(others, `${entry.summary}\n${entry.body}`)
129
+ .filter((candidate) => candidate.strong > 0)
130
+ .slice(0, 3);
131
+ if (related.length) {
132
+ const top = related[0];
133
+ lines.push("", "Related notes — if one covers the same thing, update it with its `id` and forget this one; otherwise link them as [[note-id]]:");
134
+ for (const candidate of related) {
135
+ const flag = candidate === top && sameSubject(candidate.note.summary, entry.summary) ? " (possible duplicate)" : "";
136
+ lines.push(`- \`${candidate.note.id}\` — ${candidate.note.summary}${flag}`);
137
+ }
138
+ }
139
+ const known = new Set(notes.map((note) => note.id));
140
+ const dangling = extractLinks(entry.body).filter((id) => !known.has(id) && id !== entry.id);
141
+ if (dangling.length)
142
+ lines.push("", `Links to notes that do not exist yet: ${dangling.map((id) => `\`${id}\``).join(", ")}`);
143
+ return toolText(lines.join("\n"), { id: entry.id, file: entry.file, scope });
65
144
  },
66
145
  });
67
- return [read, write];
146
+ const forget = defineTool({
147
+ name: "forget",
148
+ description: "Delete a memory note that turned out to be wrong or no longer applies. A backup is kept " +
149
+ "on this machine. Prefer updating a note with `remember` when it is only partly out of date.",
150
+ parameters: z.object({
151
+ id: z.string().describe("Id of the note to delete"),
152
+ }),
153
+ renderTitle: (input) => `Forget(${input.id})`,
154
+ async execute(input) {
155
+ const { notes, links } = await loadScoped(stores);
156
+ const note = findScoped(notes, input.id);
157
+ if (!note)
158
+ return toolError(`No note with id "${input.id}".`);
159
+ const store = storeFor(stores, note.scope);
160
+ await backupNote(store, memoryNote(note.entry), "forget");
161
+ await store.forget(note.id);
162
+ const incoming = links.incoming.get(note.id) ?? [];
163
+ return toolText(`Deleted \`${note.id}\`.` +
164
+ (incoming.length ? ` ${incoming.length} note${incoming.length === 1 ? "" : "s"} still link to it: ${incoming.map((id) => `\`${id}\``).join(", ")}.` : ""));
165
+ },
166
+ });
167
+ return [read, write, forget];
168
+ }
169
+ function sameSubject(a, b) {
170
+ const words = (value) => new Set(value.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 1));
171
+ const left = words(a);
172
+ const right = words(b);
173
+ if (!left.size || !right.size)
174
+ return false;
175
+ let shared = 0;
176
+ for (const word of left)
177
+ if (right.has(word))
178
+ shared++;
179
+ return shared / Math.min(left.size, right.size) >= 0.6;
68
180
  }
69
- function render(entry) {
70
- const when = entry.createdAt
71
- ? new Date(entry.createdAt).toISOString().slice(0, 10)
72
- : "unknown date";
73
- const tags = entry.tags.length > 0 ? ` · ${entry.tags.join(", ")}` : "";
74
- return `### ${entry.id} (${when}${tags})\n${entry.summary}\n\n${entry.body}`;
181
+ function render(note) {
182
+ const when = note.createdAt ? new Date(note.createdAt).toISOString().slice(0, 10) : "unknown date";
183
+ const updated = note.updatedAt && note.updatedAt !== note.createdAt ? `, updated ${new Date(note.updatedAt).toISOString().slice(0, 10)}` : "";
184
+ const labels = [note.scope, note.type, ...note.tags].filter(Boolean).join(", ");
185
+ return `### ${note.id} (${when}${updated} · ${labels})\n${note.summary}\n\n${note.body}`;
75
186
  }
76
187
  //# sourceMappingURL=memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/tools/builtin/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/tools/builtin/memory.ts"],"names":[],"mappings":"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"}
@@ -4,4 +4,6 @@ export { ToolRegistry, matchesFilter, matchPattern } from "./registry.ts";
4
4
  export type { ToolFilter } from "./registry.ts";
5
5
  export { toolText, toolError, toolImage, toolResultText } from "./types.ts";
6
6
  export type { SubagentRunOptions, SubagentRunResult, Tool, ToolContent, ToolContext, ToolHost, ToolProgress, ToolResult, } from "./types.ts";
7
+ export { ASK_USER_TOOL, QUESTION_TEXT_LIMIT, checkAnswer, describeResult, picksFromNumbers } from "./questions.ts";
8
+ export type { Question, QuestionOption, QuestionPick, QuestionPrompt, QuestionRequest, QuestionResult, } from "./questions.ts";
7
9
  export * from "./builtin/index.ts";
@@ -1,5 +1,6 @@
1
1
  export { defineTool } from "./define.js";
2
2
  export { ToolRegistry, matchesFilter, matchPattern } from "./registry.js";
3
3
  export { toolText, toolError, toolImage, toolResultText } from "./types.js";
4
+ export { ASK_USER_TOOL, QUESTION_TEXT_LIMIT, checkAnswer, describeResult, picksFromNumbers } from "./questions.js";
4
5
  export * from "./builtin/index.js";
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAW5E,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAW5E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AASnH,cAAc,oBAAoB,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Questions a tool puts to the person running the agent.
3
+ *
4
+ * Lives in the tool layer rather than beside the permission engine because the
5
+ * `ask_user` tool builds these and the tool layer never imports the agent. The
6
+ * agent only carries them from a tool to whatever frontend can answer.
7
+ */
8
+ export interface QuestionOption {
9
+ label: string;
10
+ description?: string;
11
+ /** Shown beside the options while this one is focused — code, a layout, a snippet. */
12
+ preview?: string;
13
+ }
14
+ export interface Question {
15
+ /** `q1`..`q4`, in the order asked. Answers are keyed by it. */
16
+ id: string;
17
+ /** A short tag for the card, e.g. "Database". */
18
+ header: string;
19
+ question: string;
20
+ multiSelect: boolean;
21
+ options: QuestionOption[];
22
+ }
23
+ export interface QuestionRequest {
24
+ /** The tool call asking, which is also what a frontend pairs the answer with. */
25
+ id: string;
26
+ sessionId: string;
27
+ agentId: string;
28
+ questions: Question[];
29
+ }
30
+ export interface QuestionPick {
31
+ /** Labels of the chosen options, exactly as offered. */
32
+ selected: string[];
33
+ /** Free text from the "other" field, which every question has. */
34
+ other?: string;
35
+ }
36
+ /**
37
+ * How a question ended.
38
+ *
39
+ * `dismissed` is a person deciding not to choose; `unavailable` is there being
40
+ * nobody to ask; `aborted` is the turn stopping underneath the question. They
41
+ * read differently to the model, which is told to do different things after
42
+ * each, so they are not folded together.
43
+ */
44
+ export type QuestionResult = {
45
+ outcome: "answered";
46
+ answers: Record<string, QuestionPick>;
47
+ } | {
48
+ outcome: "dismissed";
49
+ note?: string;
50
+ } | {
51
+ outcome: "unavailable";
52
+ } | {
53
+ outcome: "aborted";
54
+ };
55
+ /**
56
+ * Puts questions to a person. The signal fires when the turn is interrupted;
57
+ * a frontend should take the card down then rather than leave it answerable.
58
+ */
59
+ export type QuestionPrompt = (request: QuestionRequest, signal: AbortSignal) => Promise<QuestionResult>;
60
+ export declare const ASK_USER_TOOL = "ask_user";
61
+ /** The longest free-text answer or dismissal note carried back to the model. */
62
+ export declare const QUESTION_TEXT_LIMIT = 2000;
63
+ /**
64
+ * An answer from outside the process, checked against what was asked.
65
+ *
66
+ * Frontends post whatever their page sent, so a label is only accepted if it
67
+ * was one of the options, a single-choice question gets one pick, and every
68
+ * question has something. Returns a reason instead when it does not hold up.
69
+ */
70
+ export declare function checkAnswer(questions: readonly Question[], raw: unknown): {
71
+ ok: true;
72
+ result: QuestionResult;
73
+ } | {
74
+ ok: false;
75
+ error: string;
76
+ };
77
+ /**
78
+ * Options picked by number, for frontends that read a line of text: "1,3" or
79
+ * "1 3". Numbers that name no option are dropped rather than guessed at.
80
+ */
81
+ export declare function picksFromNumbers(question: Question, text: string): string[];
82
+ /**
83
+ * What the model reads back.
84
+ *
85
+ * Each outcome says what to do next, because a bare "dismissed" is an
86
+ * invitation to guess the answer anyway — which is the one thing asking was
87
+ * meant to prevent.
88
+ */
89
+ export declare function describeResult(questions: readonly Question[], result: QuestionResult): string;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Questions a tool puts to the person running the agent.
3
+ *
4
+ * Lives in the tool layer rather than beside the permission engine because the
5
+ * `ask_user` tool builds these and the tool layer never imports the agent. The
6
+ * agent only carries them from a tool to whatever frontend can answer.
7
+ */
8
+ export const ASK_USER_TOOL = "ask_user";
9
+ /** The longest free-text answer or dismissal note carried back to the model. */
10
+ export const QUESTION_TEXT_LIMIT = 2000;
11
+ /**
12
+ * An answer from outside the process, checked against what was asked.
13
+ *
14
+ * Frontends post whatever their page sent, so a label is only accepted if it
15
+ * was one of the options, a single-choice question gets one pick, and every
16
+ * question has something. Returns a reason instead when it does not hold up.
17
+ */
18
+ export function checkAnswer(questions, raw) {
19
+ if (typeof raw !== "object" || raw === null)
20
+ return { ok: false, error: "answer must be an object" };
21
+ const body = raw;
22
+ if (body["outcome"] === "dismissed") {
23
+ const note = typeof body["note"] === "string" ? body["note"].trim().slice(0, QUESTION_TEXT_LIMIT) : "";
24
+ return { ok: true, result: note ? { outcome: "dismissed", note } : { outcome: "dismissed" } };
25
+ }
26
+ if (body["outcome"] !== "answered")
27
+ return { ok: false, error: "outcome must be answered or dismissed" };
28
+ const given = body["answers"];
29
+ if (typeof given !== "object" || given === null)
30
+ return { ok: false, error: "answers are required" };
31
+ const answers = {};
32
+ for (const question of questions) {
33
+ const entry = given[question.id];
34
+ if (typeof entry !== "object" || entry === null)
35
+ return { ok: false, error: `${question.id} is unanswered` };
36
+ const pick = entry;
37
+ const selected = Array.isArray(pick["selected"])
38
+ ? [...new Set(pick["selected"].filter((label) => typeof label === "string"))]
39
+ : [];
40
+ const offered = new Set(question.options.map((option) => option.label));
41
+ const unknown = selected.find((label) => !offered.has(label));
42
+ if (unknown !== undefined)
43
+ return { ok: false, error: `${question.id}: "${unknown}" was not an option` };
44
+ const other = typeof pick["other"] === "string" ? pick["other"].trim().slice(0, QUESTION_TEXT_LIMIT) : "";
45
+ if (!question.multiSelect && selected.length + (other ? 1 : 0) > 1) {
46
+ return { ok: false, error: `${question.id} takes one answer` };
47
+ }
48
+ if (!selected.length && !other)
49
+ return { ok: false, error: `${question.id} is unanswered` };
50
+ answers[question.id] = other ? { selected, other } : { selected };
51
+ }
52
+ return { ok: true, result: { outcome: "answered", answers } };
53
+ }
54
+ /**
55
+ * Options picked by number, for frontends that read a line of text: "1,3" or
56
+ * "1 3". Numbers that name no option are dropped rather than guessed at.
57
+ */
58
+ export function picksFromNumbers(question, text) {
59
+ const labels = text
60
+ .split(/[\s,,、]+/)
61
+ .map(Number)
62
+ .filter((n) => Number.isInteger(n) && n >= 1 && n <= question.options.length)
63
+ .map((n) => question.options[n - 1].label);
64
+ return [...new Set(labels)];
65
+ }
66
+ /**
67
+ * What the model reads back.
68
+ *
69
+ * Each outcome says what to do next, because a bare "dismissed" is an
70
+ * invitation to guess the answer anyway — which is the one thing asking was
71
+ * meant to prevent.
72
+ */
73
+ export function describeResult(questions, result) {
74
+ switch (result.outcome) {
75
+ case "answered": {
76
+ const lines = questions.map((question) => {
77
+ const pick = result.answers[question.id];
78
+ const parts = [...(pick?.selected ?? [])];
79
+ if (pick?.other)
80
+ parts.push(`other: "${pick.other}"`);
81
+ return `- [${question.header}] ${question.question}\n → ${parts.join(", ") || "(no answer)"}`;
82
+ });
83
+ return `The user answered:\n${lines.join("\n")}`;
84
+ }
85
+ case "dismissed":
86
+ return [
87
+ "The user closed the question without choosing.",
88
+ result.note ? `They wrote instead: "${result.note}"` : "",
89
+ "Do not assume an answer. Act on what they wrote if it settles the question; otherwise say in plain text what you need, or stop.",
90
+ ].filter(Boolean).join("\n");
91
+ case "unavailable":
92
+ return "Nobody is available to answer questions in this run. Pick a sensible default, carry on, and state the assumption in your final reply.";
93
+ case "aborted":
94
+ return "The turn was interrupted while the question was waiting for an answer.";
95
+ }
96
+ }
97
+ //# sourceMappingURL=questions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"questions.js","sourceRoot":"","sources":["../../src/tools/questions.ts"],"names":[],"mappings":"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"}