@poncho-ai/harness 0.24.0 → 0.25.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.
- package/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-lint.log +6 -0
- package/.turbo/turbo-test.log +135 -0
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.js +175 -78
- package/package.json +1 -1
- package/src/harness.ts +122 -38
- package/src/memory.ts +63 -46
- package/test/harness.test.ts +129 -2
- package/test/memory.test.ts +100 -15
package/test/memory.test.ts
CHANGED
|
@@ -5,7 +5,6 @@ describe("memory store factory", () => {
|
|
|
5
5
|
it("uses memory provider by default", async () => {
|
|
6
6
|
const store = createMemoryStore("agent-test");
|
|
7
7
|
const updated = await store.updateMainMemory({
|
|
8
|
-
mode: "replace",
|
|
9
8
|
content: "Cesar prefers short bullet points.",
|
|
10
9
|
});
|
|
11
10
|
expect(updated.content).toContain("short bullet points");
|
|
@@ -13,24 +12,17 @@ describe("memory store factory", () => {
|
|
|
13
12
|
expect(fetched.content).toContain("short bullet points");
|
|
14
13
|
});
|
|
15
14
|
|
|
16
|
-
it("
|
|
17
|
-
const store = createMemoryStore("agent-
|
|
18
|
-
await store.updateMainMemory({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const result = await store.updateMainMemory({
|
|
23
|
-
mode: "append",
|
|
24
|
-
content: "Appended line.",
|
|
25
|
-
});
|
|
26
|
-
expect(result.content).toContain("Initial memory.");
|
|
27
|
-
expect(result.content).toContain("Appended line.");
|
|
15
|
+
it("overwrites previous content on update", async () => {
|
|
16
|
+
const store = createMemoryStore("agent-overwrite");
|
|
17
|
+
await store.updateMainMemory({ content: "First version." });
|
|
18
|
+
const result = await store.updateMainMemory({ content: "Second version." });
|
|
19
|
+
expect(result.content).toBe("Second version.");
|
|
20
|
+
expect(result.content).not.toContain("First version.");
|
|
28
21
|
});
|
|
29
22
|
|
|
30
23
|
it("falls back gracefully when upstash is not configured", async () => {
|
|
31
24
|
const store = createMemoryStore("agent-fallback", { provider: "upstash" });
|
|
32
25
|
const updated = await store.updateMainMemory({
|
|
33
|
-
mode: "replace",
|
|
34
26
|
content: "Fallback path still stores memory",
|
|
35
27
|
});
|
|
36
28
|
expect(updated.content).toContain("Fallback path");
|
|
@@ -43,8 +35,101 @@ describe("memory tools", () => {
|
|
|
43
35
|
const tools = createMemoryTools(store);
|
|
44
36
|
expect(tools.map((tool) => tool.name)).toEqual([
|
|
45
37
|
"memory_main_get",
|
|
46
|
-
"
|
|
38
|
+
"memory_main_write",
|
|
39
|
+
"memory_main_edit",
|
|
47
40
|
"conversation_recall",
|
|
48
41
|
]);
|
|
49
42
|
});
|
|
43
|
+
|
|
44
|
+
describe("memory_main_write", () => {
|
|
45
|
+
it("writes content to memory", async () => {
|
|
46
|
+
const store = createMemoryStore("agent-write");
|
|
47
|
+
const tools = createMemoryTools(store);
|
|
48
|
+
const writeTool = tools.find((t) => t.name === "memory_main_write")!;
|
|
49
|
+
const result = await writeTool.handler(
|
|
50
|
+
{ content: "User prefers dark mode." },
|
|
51
|
+
{ runId: "r1", agentId: "a1", step: 0, workingDir: ".", parameters: {} },
|
|
52
|
+
);
|
|
53
|
+
expect(result).toEqual({
|
|
54
|
+
ok: true,
|
|
55
|
+
memory: expect.objectContaining({ content: "User prefers dark mode." }),
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("errors when content is empty", async () => {
|
|
60
|
+
const store = createMemoryStore("agent-write-empty");
|
|
61
|
+
const tools = createMemoryTools(store);
|
|
62
|
+
const writeTool = tools.find((t) => t.name === "memory_main_write")!;
|
|
63
|
+
await expect(
|
|
64
|
+
writeTool.handler(
|
|
65
|
+
{ content: " " },
|
|
66
|
+
{ runId: "r1", agentId: "a1", step: 0, workingDir: ".", parameters: {} },
|
|
67
|
+
),
|
|
68
|
+
).rejects.toThrow("content is required");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("memory_main_edit", () => {
|
|
73
|
+
const setupMemory = async () => {
|
|
74
|
+
const store = createMemoryStore("agent-edit-" + Math.random());
|
|
75
|
+
await store.updateMainMemory({
|
|
76
|
+
content: "- prefers dark mode\n- likes TypeScript\n- uses vim",
|
|
77
|
+
});
|
|
78
|
+
const tools = createMemoryTools(store);
|
|
79
|
+
const editTool = tools.find((t) => t.name === "memory_main_edit")!;
|
|
80
|
+
const ctx = { runId: "r1", agentId: "a1", step: 0, workingDir: ".", parameters: {} };
|
|
81
|
+
return { store, editTool, ctx };
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
it("replaces a unique string match in memory", async () => {
|
|
85
|
+
const { store, editTool, ctx } = await setupMemory();
|
|
86
|
+
const result = await editTool.handler(
|
|
87
|
+
{ old_str: "likes TypeScript", new_str: "loves TypeScript" },
|
|
88
|
+
ctx,
|
|
89
|
+
);
|
|
90
|
+
expect(result).toEqual({
|
|
91
|
+
ok: true,
|
|
92
|
+
memory: expect.objectContaining({
|
|
93
|
+
content: "- prefers dark mode\n- loves TypeScript\n- uses vim",
|
|
94
|
+
}),
|
|
95
|
+
});
|
|
96
|
+
const fetched = await store.getMainMemory();
|
|
97
|
+
expect(fetched.content).toContain("loves TypeScript");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("deletes matched content when new_str is empty", async () => {
|
|
101
|
+
const { store, editTool, ctx } = await setupMemory();
|
|
102
|
+
await editTool.handler(
|
|
103
|
+
{ old_str: "\n- likes TypeScript", new_str: "" },
|
|
104
|
+
ctx,
|
|
105
|
+
);
|
|
106
|
+
const fetched = await store.getMainMemory();
|
|
107
|
+
expect(fetched.content).toBe("- prefers dark mode\n- uses vim");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("errors when old_str is empty", async () => {
|
|
111
|
+
const { editTool, ctx } = await setupMemory();
|
|
112
|
+
await expect(
|
|
113
|
+
editTool.handler({ old_str: "", new_str: "anything" }, ctx),
|
|
114
|
+
).rejects.toThrow("old_str must not be empty");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("errors when old_str is not found in memory", async () => {
|
|
118
|
+
const { editTool, ctx } = await setupMemory();
|
|
119
|
+
await expect(
|
|
120
|
+
editTool.handler({ old_str: "nonexistent text", new_str: "x" }, ctx),
|
|
121
|
+
).rejects.toThrow("old_str not found in memory");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("errors when old_str matches multiple locations", async () => {
|
|
125
|
+
const store = createMemoryStore("agent-edit-dup");
|
|
126
|
+
await store.updateMainMemory({ content: "foo bar foo" });
|
|
127
|
+
const tools = createMemoryTools(store);
|
|
128
|
+
const editTool = tools.find((t) => t.name === "memory_main_edit")!;
|
|
129
|
+
const ctx = { runId: "r1", agentId: "a1", step: 0, workingDir: ".", parameters: {} };
|
|
130
|
+
await expect(
|
|
131
|
+
editTool.handler({ old_str: "foo", new_str: "baz" }, ctx),
|
|
132
|
+
).rejects.toThrow("old_str appears multiple times");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
50
135
|
});
|