@poncho-ai/harness 0.59.12 → 0.59.13

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.59.12 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.59.13 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -9,8 +9,8 @@
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
11
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
12
- ESM dist/index.js 560.73 KB
13
- ESM ⚡️ Build success in 254ms
12
+ ESM dist/index.js 561.36 KB
13
+ ESM ⚡️ Build success in 214ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 8487ms
15
+ DTS ⚡️ Build success in 8568ms
16
16
  DTS dist/index.d.ts 102.50 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.59.13
4
+
5
+ ### Patch Changes
6
+
7
+ - [`bf77523`](https://github.com/cesr/poncho-ai/commit/bf775237af883a53ee90f0a620434a1929ac82ea) Thanks [@cesr](https://github.com/cesr)! - `memory_main_edit` now treats an empty `old_str` as append: `new_str` is
8
+ appended to the end of memory (separated by a blank line when memory is
9
+ non-empty). This also handles the first-ever write into empty memory, so
10
+ `memory_main_edit` alone can bootstrap, add new facts, and edit existing
11
+ text — consumers that want to drop `memory_main_write` from the tool
12
+ surface no longer lose the ability to seed empty memory.
13
+
14
+ Both `memory_main_edit` and `memory_main_write` now return a minimal
15
+ `{ ok: true, bytes }` result instead of echoing the entire memory
16
+ document back as the tool result, which kept re-injecting the whole
17
+ document into the conversation on every targeted edit.
18
+
3
19
  ## 0.59.12
4
20
 
5
21
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1642,7 +1642,7 @@ When \`memory.enabled\` is true in \`poncho.config.js\`, the harness enables a s
1642
1642
 
1643
1643
  - A single persistent main memory document is loaded at run start and interpolated into the system prompt under \`## Persistent Memory\`.
1644
1644
  - \`memory_main_write\` overwrites the entire memory document (for initial writes or full rewrites).
1645
- - \`memory_main_edit\` performs targeted string-replacement edits on memory (find \`old_str\`, replace with \`new_str\`), mirroring \`edit_file\` semantics. The tool description instructs the model to proactively evaluate each turn whether durable memory should be updated.
1645
+ - \`memory_main_edit\` performs targeted string-replacement edits on memory (find \`old_str\`, replace with \`new_str\`), mirroring \`edit_file\` semantics. An empty \`old_str\` appends \`new_str\` to the end of memory, which also handles the first-ever write into empty memory. The tool description instructs the model to proactively evaluate each turn whether durable memory should be updated.
1646
1646
  - \`conversation_recall\` can search, browse, and fetch past conversations. It supports keyword search (scoring by relevance), date-range filtering (\`after\`/\`before\`), and fetching a specific conversation's full message history by ID.
1647
1647
 
1648
1648
  \`\`\`javascript
@@ -5970,22 +5970,22 @@ var createMemoryTools = (store, options) => {
5970
5970
  throw new Error("content is required");
5971
5971
  }
5972
5972
  const memory = await resolveStore(context).updateMainMemory({ content });
5973
- return { ok: true, memory };
5973
+ return { ok: true, bytes: memory.content.length };
5974
5974
  }
5975
5975
  }),
5976
5976
  defineTool6({
5977
5977
  name: "memory_main_edit",
5978
- description: "Edit persistent main memory by replacing an exact string match with new content. The old_str must match exactly one location in memory. Use an empty new_str to delete matched content. Proactively evaluate every turn whether memory should be updated.",
5978
+ description: "Edit persistent main memory. With a non-empty old_str, replace that exact string (which must match exactly one location) with new_str; use an empty new_str to delete the matched content. With an empty old_str, append new_str to the end of memory \u2014 use this to add a brand-new fact or to write the first fact when memory is still empty. Proactively evaluate every turn whether memory should be updated.",
5979
5979
  inputSchema: {
5980
5980
  type: "object",
5981
5981
  properties: {
5982
5982
  old_str: {
5983
5983
  type: "string",
5984
- description: "The exact text to find and replace (must be unique in memory). Include surrounding context if needed to ensure uniqueness."
5984
+ description: "The exact text to find and replace (must be unique in memory). Include surrounding context if needed to ensure uniqueness. Leave empty to append new_str to the end of memory instead."
5985
5985
  },
5986
5986
  new_str: {
5987
5987
  type: "string",
5988
- description: "The replacement text (use empty string to delete the matched content)"
5988
+ description: "The replacement text (use empty string to delete the matched content), or the text to append when old_str is empty."
5989
5989
  }
5990
5990
  },
5991
5991
  required: ["old_str", "new_str"],
@@ -5994,26 +5994,33 @@ var createMemoryTools = (store, options) => {
5994
5994
  handler: async (input, context) => {
5995
5995
  const oldStr = typeof input.old_str === "string" ? input.old_str : "";
5996
5996
  const newStr = typeof input.new_str === "string" ? input.new_str : "";
5997
- if (!oldStr) {
5998
- throw new Error("old_str must not be empty.");
5999
- }
6000
5997
  const current = await resolveStore(context).getMainMemory();
6001
5998
  const content = current.content;
6002
- const first = content.indexOf(oldStr);
6003
- if (first === -1) {
6004
- throw new Error(
6005
- "old_str not found in memory. Make sure it matches exactly, including whitespace and line breaks."
6006
- );
6007
- }
6008
- const last = content.lastIndexOf(oldStr);
6009
- if (first !== last) {
6010
- throw new Error(
6011
- "old_str appears multiple times in memory. Please provide more context to ensure a unique match."
6012
- );
5999
+ let newContent;
6000
+ if (!oldStr) {
6001
+ if (!newStr) {
6002
+ throw new Error("new_str must not be empty when appending (old_str is empty).");
6003
+ }
6004
+ newContent = content ? `${content.replace(/\s+$/, "")}
6005
+
6006
+ ${newStr}` : newStr;
6007
+ } else {
6008
+ const first = content.indexOf(oldStr);
6009
+ if (first === -1) {
6010
+ throw new Error(
6011
+ "old_str not found in memory. Make sure it matches exactly, including whitespace and line breaks."
6012
+ );
6013
+ }
6014
+ const last = content.lastIndexOf(oldStr);
6015
+ if (first !== last) {
6016
+ throw new Error(
6017
+ "old_str appears multiple times in memory. Please provide more context to ensure a unique match."
6018
+ );
6019
+ }
6020
+ newContent = content.slice(0, first) + newStr + content.slice(first + oldStr.length);
6013
6021
  }
6014
- const newContent = content.slice(0, first) + newStr + content.slice(first + oldStr.length);
6015
6022
  const memory = await resolveStore(context).updateMainMemory({ content: newContent });
6016
- return { ok: true, memory };
6023
+ return { ok: true, bytes: memory.content.length };
6017
6024
  }
6018
6025
  }),
6019
6026
  defineTool6({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.59.12",
3
+ "version": "0.59.13",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
package/src/memory.ts CHANGED
@@ -192,15 +192,17 @@ export const createMemoryTools = (
192
192
  throw new Error("content is required");
193
193
  }
194
194
  const memory = await resolveStore(context).updateMainMemory({ content });
195
- return { ok: true, memory };
195
+ return { ok: true, bytes: memory.content.length };
196
196
  },
197
197
  }),
198
198
  defineTool({
199
199
  name: "memory_main_edit",
200
200
  description:
201
- "Edit persistent main memory by replacing an exact string match with new content. " +
202
- "The old_str must match exactly one location in memory. " +
203
- "Use an empty new_str to delete matched content. " +
201
+ "Edit persistent main memory. With a non-empty old_str, replace that exact " +
202
+ "string (which must match exactly one location) with new_str; use an empty " +
203
+ "new_str to delete the matched content. With an empty old_str, append new_str " +
204
+ "to the end of memory — use this to add a brand-new fact or to write the first " +
205
+ "fact when memory is still empty. " +
204
206
  "Proactively evaluate every turn whether memory should be updated.",
205
207
  inputSchema: {
206
208
  type: "object",
@@ -209,11 +211,14 @@ export const createMemoryTools = (
209
211
  type: "string",
210
212
  description:
211
213
  "The exact text to find and replace (must be unique in memory). " +
212
- "Include surrounding context if needed to ensure uniqueness.",
214
+ "Include surrounding context if needed to ensure uniqueness. " +
215
+ "Leave empty to append new_str to the end of memory instead.",
213
216
  },
214
217
  new_str: {
215
218
  type: "string",
216
- description: "The replacement text (use empty string to delete the matched content)",
219
+ description:
220
+ "The replacement text (use empty string to delete the matched content), " +
221
+ "or the text to append when old_str is empty.",
217
222
  },
218
223
  },
219
224
  required: ["old_str", "new_str"],
@@ -222,26 +227,35 @@ export const createMemoryTools = (
222
227
  handler: async (input, context) => {
223
228
  const oldStr = typeof input.old_str === "string" ? input.old_str : "";
224
229
  const newStr = typeof input.new_str === "string" ? input.new_str : "";
225
- if (!oldStr) {
226
- throw new Error("old_str must not be empty.");
227
- }
228
230
  const current = await resolveStore(context).getMainMemory();
229
231
  const content = current.content;
230
- const first = content.indexOf(oldStr);
231
- if (first === -1) {
232
- throw new Error(
233
- "old_str not found in memory. Make sure it matches exactly, including whitespace and line breaks.",
234
- );
235
- }
236
- const last = content.lastIndexOf(oldStr);
237
- if (first !== last) {
238
- throw new Error(
239
- "old_str appears multiple times in memory. Please provide more context to ensure a unique match.",
240
- );
232
+ let newContent: string;
233
+ if (!oldStr) {
234
+ // Append mode: add new_str to the end. Handles the first-ever write
235
+ // (empty memory) and adding new facts without needing existing text
236
+ // to match. Separate from prior content with a blank line when both
237
+ // sides are non-empty.
238
+ if (!newStr) {
239
+ throw new Error("new_str must not be empty when appending (old_str is empty).");
240
+ }
241
+ newContent = content ? `${content.replace(/\s+$/, "")}\n\n${newStr}` : newStr;
242
+ } else {
243
+ const first = content.indexOf(oldStr);
244
+ if (first === -1) {
245
+ throw new Error(
246
+ "old_str not found in memory. Make sure it matches exactly, including whitespace and line breaks.",
247
+ );
248
+ }
249
+ const last = content.lastIndexOf(oldStr);
250
+ if (first !== last) {
251
+ throw new Error(
252
+ "old_str appears multiple times in memory. Please provide more context to ensure a unique match.",
253
+ );
254
+ }
255
+ newContent = content.slice(0, first) + newStr + content.slice(first + oldStr.length);
241
256
  }
242
- const newContent = content.slice(0, first) + newStr + content.slice(first + oldStr.length);
243
257
  const memory = await resolveStore(context).updateMainMemory({ content: newContent });
244
- return { ok: true, memory };
258
+ return { ok: true, bytes: memory.content.length };
245
259
  },
246
260
  }),
247
261
  defineTool({