@poncho-ai/harness 0.37.2 → 0.39.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.
@@ -64,6 +64,86 @@ function runEngineTests(name: string, factory: () => Promise<{ engine: StorageEn
64
64
  expect(results).toHaveLength(1);
65
65
  expect(results[0].title).toBe("alpha beta");
66
66
  });
67
+
68
+ it("persists parentConversationId atomically when provided to create", async () => {
69
+ const parent = await engine.conversations.create("o", "Parent");
70
+ const child = await engine.conversations.create("o", "Child", null, {
71
+ parentConversationId: parent.conversationId,
72
+ subagentMeta: { task: "do thing", status: "running" },
73
+ messages: [{ role: "user", content: "do thing" }],
74
+ });
75
+
76
+ // Returned object reflects init fields
77
+ expect(child.parentConversationId).toBe(parent.conversationId);
78
+ expect(child.subagentMeta?.task).toBe("do thing");
79
+ expect(child.messages).toHaveLength(1);
80
+
81
+ // listSummaries reads the dedicated column — child must be linked to parent.
82
+ const summaries = await engine.conversations.list("o");
83
+ const childSummary = summaries.find((s) => s.conversationId === child.conversationId);
84
+ expect(childSummary?.parentConversationId).toBe(parent.conversationId);
85
+
86
+ // get() rehydrates from data blob — parent + meta must round-trip.
87
+ const reloaded = await engine.conversations.get(child.conversationId);
88
+ expect(reloaded?.parentConversationId).toBe(parent.conversationId);
89
+ expect(reloaded?.subagentMeta?.task).toBe("do thing");
90
+ expect(reloaded?.messages).toHaveLength(1);
91
+ });
92
+
93
+ it("persists thread anchor (parentMessageId + threadMeta) and lists threads", async () => {
94
+ const parent = await engine.conversations.create("o", "Parent");
95
+ const anchorId = "msg-anchor-1";
96
+ const thread = await engine.conversations.create("o", "Thread A", null, {
97
+ parentConversationId: parent.conversationId,
98
+ parentMessageId: anchorId,
99
+ messages: [
100
+ { role: "user", content: "hi", metadata: { id: "m0" } },
101
+ { role: "assistant", content: "hello", metadata: { id: anchorId } },
102
+ ],
103
+ threadMeta: {
104
+ parentMessageSummary: "hello",
105
+ snapshotLength: 2,
106
+ },
107
+ });
108
+ expect(thread.parentMessageId).toBe(anchorId);
109
+ expect(thread.threadMeta?.snapshotLength).toBe(2);
110
+
111
+ // Summary surfaces the column
112
+ const summary = (await engine.conversations.list("o")).find(
113
+ (s) => s.conversationId === thread.conversationId,
114
+ );
115
+ expect(summary?.parentMessageId).toBe(anchorId);
116
+
117
+ // get() round-trips threadMeta from the JSON blob
118
+ const reloaded = await engine.conversations.get(thread.conversationId);
119
+ expect(reloaded?.parentMessageId).toBe(anchorId);
120
+ expect(reloaded?.threadMeta?.parentMessageSummary).toBe("hello");
121
+
122
+ // listThreads filters to children with parent_message_id set
123
+ const threads = await engine.conversations.listThreads(parent.conversationId);
124
+ expect(threads.length).toBe(1);
125
+ expect(threads[0].conversationId).toBe(thread.conversationId);
126
+ expect(threads[0].parentMessageId).toBe(anchorId);
127
+ });
128
+
129
+ it("listThreads excludes subagent-only children (no parentMessageId)", async () => {
130
+ const parent = await engine.conversations.create("o", "Parent");
131
+ // Subagent: parentConversationId set but no parentMessageId
132
+ await engine.conversations.create("o", "Subagent", null, {
133
+ parentConversationId: parent.conversationId,
134
+ subagentMeta: { task: "x", status: "completed" },
135
+ });
136
+ // Thread: both set
137
+ const thread = await engine.conversations.create("o", "Thread", null, {
138
+ parentConversationId: parent.conversationId,
139
+ parentMessageId: "anchor",
140
+ threadMeta: { snapshotLength: 1 },
141
+ });
142
+
143
+ const threads = await engine.conversations.listThreads(parent.conversationId);
144
+ expect(threads).toHaveLength(1);
145
+ expect(threads[0].conversationId).toBe(thread.conversationId);
146
+ });
67
147
  });
68
148
 
69
149
  // -- Memory --