macro-agent 0.0.17 → 0.1.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/dist/acp/macro-agent.d.ts +2 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +52 -20
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +6 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +103 -37
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/map-adapter.d.ts +1 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +57 -8
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/store/event-store.d.ts +5 -0
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +34 -0
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +5 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/acp/__tests__/history.test.ts +8 -4
- package/src/acp/macro-agent.ts +60 -26
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +802 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +461 -2
- package/src/map/adapter/acp-over-map.ts +116 -43
- package/src/map/adapter/map-adapter.ts +79 -9
- package/src/store/__tests__/event-store.test.ts +40 -0
- package/src/store/event-store.ts +42 -0
- package/src/store/types/agents.ts +1 -0
|
@@ -30,6 +30,7 @@ function createMockAgent(overrides: Partial<Agent> = {}): Agent {
|
|
|
30
30
|
lineage: [],
|
|
31
31
|
config: {},
|
|
32
32
|
cwd: "/test/cwd",
|
|
33
|
+
plan: [],
|
|
33
34
|
created_at: Date.now(),
|
|
34
35
|
started_at: Date.now(),
|
|
35
36
|
...overrides,
|
|
@@ -268,7 +269,7 @@ describe("ACP-over-MAP history persistence", () => {
|
|
|
268
269
|
title: "Read file",
|
|
269
270
|
status: "completed",
|
|
270
271
|
rawInput: { path: "/test.txt" },
|
|
271
|
-
|
|
272
|
+
rawOutput: "file contents",
|
|
272
273
|
},
|
|
273
274
|
]);
|
|
274
275
|
|
|
@@ -306,6 +307,93 @@ describe("ACP-over-MAP history persistence", () => {
|
|
|
306
307
|
});
|
|
307
308
|
});
|
|
308
309
|
|
|
310
|
+
it("should extract tool output from rawOutput ContentBlock array", async () => {
|
|
311
|
+
await setup([
|
|
312
|
+
{
|
|
313
|
+
sessionUpdate: "tool_call",
|
|
314
|
+
toolCallId: "tc-array",
|
|
315
|
+
title: "Read file",
|
|
316
|
+
status: "completed",
|
|
317
|
+
rawInput: { path: "/test.txt" },
|
|
318
|
+
rawOutput: [
|
|
319
|
+
{ type: "text", text: "line 1" },
|
|
320
|
+
{ type: "text", text: "line 2" },
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
]);
|
|
324
|
+
|
|
325
|
+
const streamId = "test-stream-array-output";
|
|
326
|
+
const agentId = "agent-1" as AgentId;
|
|
327
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
328
|
+
|
|
329
|
+
await handler.processRequest(
|
|
330
|
+
agentId,
|
|
331
|
+
envelope(streamId, "session/prompt", {
|
|
332
|
+
prompt: [{ type: "text", text: "Read it" }],
|
|
333
|
+
}, sessionId),
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const historyResult = await handler.processRequest(
|
|
337
|
+
agentId,
|
|
338
|
+
envelope(streamId, "_macro/getHistory", { sessionId }),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const turns = (historyResult.acp.result as { turns: { role: string; content: unknown }[] }).turns;
|
|
342
|
+
const assistantContent = turns[1].content as {
|
|
343
|
+
parts: { type: string; output?: string }[];
|
|
344
|
+
};
|
|
345
|
+
const toolPart = assistantContent.parts.find((p) => p.type === "tool");
|
|
346
|
+
expect(toolPart?.output).toBe("line 1\nline 2");
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("should merge title from initial tool_call into tool_call_update", async () => {
|
|
350
|
+
// Simulates WebSearch/WebFetch: initial tool_call has title, but
|
|
351
|
+
// tool_call_update (completed) does not include title.
|
|
352
|
+
await setup([
|
|
353
|
+
{
|
|
354
|
+
sessionUpdate: "tool_call",
|
|
355
|
+
toolCallId: "tc-ws",
|
|
356
|
+
title: "Search query here",
|
|
357
|
+
status: "pending",
|
|
358
|
+
rawInput: { query: "test" },
|
|
359
|
+
_meta: { claudeCode: { toolName: "WebSearch" } },
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
sessionUpdate: "tool_call_update",
|
|
363
|
+
toolCallId: "tc-ws",
|
|
364
|
+
status: "completed",
|
|
365
|
+
rawOutput: "search results",
|
|
366
|
+
// No title, no rawInput, no _meta — should use cached values
|
|
367
|
+
},
|
|
368
|
+
]);
|
|
369
|
+
|
|
370
|
+
const streamId = "test-stream-merge-title";
|
|
371
|
+
const agentId = "agent-1" as AgentId;
|
|
372
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
373
|
+
|
|
374
|
+
await handler.processRequest(
|
|
375
|
+
agentId,
|
|
376
|
+
envelope(streamId, "session/prompt", {
|
|
377
|
+
prompt: [{ type: "text", text: "Search for test" }],
|
|
378
|
+
}, sessionId),
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
const historyResult = await handler.processRequest(
|
|
382
|
+
agentId,
|
|
383
|
+
envelope(streamId, "_macro/getHistory", { sessionId }),
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const turns = (historyResult.acp.result as { turns: { role: string; content: unknown }[] }).turns;
|
|
387
|
+
const assistantContent = turns[1].content as {
|
|
388
|
+
parts: { type: string; title?: string; name?: string; input?: unknown; output?: string }[];
|
|
389
|
+
};
|
|
390
|
+
const toolPart = assistantContent.parts.find((p) => p.type === "tool");
|
|
391
|
+
expect(toolPart?.title).toBe("Search query here");
|
|
392
|
+
expect(toolPart?.name).toBe("WebSearch");
|
|
393
|
+
expect(toolPart?.input).toEqual({ query: "test" });
|
|
394
|
+
expect(toolPart?.output).toBe("search results");
|
|
395
|
+
});
|
|
396
|
+
|
|
309
397
|
it("should accumulate history across multiple prompts", async () => {
|
|
310
398
|
const { agentManager } = await setup([
|
|
311
399
|
{
|
|
@@ -392,7 +480,7 @@ describe("ACP-over-MAP history persistence", () => {
|
|
|
392
480
|
title: "Done tool",
|
|
393
481
|
status: "completed",
|
|
394
482
|
rawInput: { x: 1 },
|
|
395
|
-
|
|
483
|
+
rawOutput: "result",
|
|
396
484
|
},
|
|
397
485
|
]);
|
|
398
486
|
|
|
@@ -661,4 +749,375 @@ describe("ACP-over-MAP history persistence", () => {
|
|
|
661
749
|
const turnsNoAgent = (historyNoAgent.acp.result as { turns: unknown[] }).turns;
|
|
662
750
|
expect(turnsNoAgent).toHaveLength(0);
|
|
663
751
|
});
|
|
752
|
+
|
|
753
|
+
it("should include agent cwd in getHistory response", async () => {
|
|
754
|
+
await setup([
|
|
755
|
+
{
|
|
756
|
+
sessionUpdate: "agent_message_chunk",
|
|
757
|
+
content: { type: "text", text: "Working in dir" },
|
|
758
|
+
},
|
|
759
|
+
]);
|
|
760
|
+
|
|
761
|
+
const agentId = "agent-1" as AgentId;
|
|
762
|
+
const streamId = "test-stream-cwd";
|
|
763
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
764
|
+
|
|
765
|
+
await handler.processRequest(
|
|
766
|
+
agentId,
|
|
767
|
+
envelope(streamId, "session/prompt", {
|
|
768
|
+
prompt: [{ type: "text", text: "Where are you?" }],
|
|
769
|
+
}, sessionId),
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
const historyResult = await handler.processRequest(
|
|
773
|
+
agentId,
|
|
774
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
const result = historyResult.acp.result as { turns: unknown[]; cwd: string | null };
|
|
778
|
+
expect(result.cwd).toBe("/test/cwd");
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
it("should return null cwd when agentId is not provided", async () => {
|
|
782
|
+
await setup([
|
|
783
|
+
{
|
|
784
|
+
sessionUpdate: "agent_message_chunk",
|
|
785
|
+
content: { type: "text", text: "Hello" },
|
|
786
|
+
},
|
|
787
|
+
]);
|
|
788
|
+
|
|
789
|
+
const agentId = "agent-1" as AgentId;
|
|
790
|
+
const streamId = "test-stream-cwd-null";
|
|
791
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
792
|
+
|
|
793
|
+
await handler.processRequest(
|
|
794
|
+
agentId,
|
|
795
|
+
envelope(streamId, "session/prompt", {
|
|
796
|
+
prompt: [{ type: "text", text: "Hi" }],
|
|
797
|
+
}, sessionId),
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
// Query without agentId — cwd should be null
|
|
801
|
+
const historyResult = await handler.processRequest(
|
|
802
|
+
agentId,
|
|
803
|
+
envelope(streamId, "_macro/getHistory", { sessionId }),
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
const result = historyResult.acp.result as { turns: unknown[]; cwd: string | null };
|
|
807
|
+
expect(result.cwd).toBeNull();
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
it("should capture plan entries from streaming and include in getHistory", async () => {
|
|
811
|
+
await setup([
|
|
812
|
+
{
|
|
813
|
+
sessionUpdate: "agent_message_chunk",
|
|
814
|
+
content: { type: "text", text: "Planning..." },
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
sessionUpdate: "plan",
|
|
818
|
+
entries: [
|
|
819
|
+
{ content: "Analyze codebase", priority: "high", status: "in_progress" },
|
|
820
|
+
{ content: "Write tests", priority: "medium", status: "pending" },
|
|
821
|
+
{ content: "Deploy", priority: "low", status: "pending" },
|
|
822
|
+
],
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
sessionUpdate: "agent_message_chunk",
|
|
826
|
+
content: { type: "text", text: " Done." },
|
|
827
|
+
},
|
|
828
|
+
]);
|
|
829
|
+
|
|
830
|
+
const agentId = "agent-1" as AgentId;
|
|
831
|
+
const streamId = "test-stream-plan";
|
|
832
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
833
|
+
|
|
834
|
+
await handler.processRequest(
|
|
835
|
+
agentId,
|
|
836
|
+
envelope(streamId, "session/prompt", {
|
|
837
|
+
prompt: [{ type: "text", text: "Make a plan" }],
|
|
838
|
+
}, sessionId),
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
const historyResult = await handler.processRequest(
|
|
842
|
+
agentId,
|
|
843
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
844
|
+
);
|
|
845
|
+
|
|
846
|
+
const result = historyResult.acp.result as {
|
|
847
|
+
turns: unknown[];
|
|
848
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
expect(result.plan).toHaveLength(3);
|
|
852
|
+
expect(result.plan[0]).toEqual({
|
|
853
|
+
content: "Analyze codebase",
|
|
854
|
+
priority: "high",
|
|
855
|
+
status: "in_progress",
|
|
856
|
+
});
|
|
857
|
+
expect(result.plan[1]).toEqual({
|
|
858
|
+
content: "Write tests",
|
|
859
|
+
priority: "medium",
|
|
860
|
+
status: "pending",
|
|
861
|
+
});
|
|
862
|
+
expect(result.plan[2]).toEqual({
|
|
863
|
+
content: "Deploy",
|
|
864
|
+
priority: "low",
|
|
865
|
+
status: "pending",
|
|
866
|
+
});
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
it("should return empty plan when no plan updates were received", async () => {
|
|
870
|
+
await setup([
|
|
871
|
+
{
|
|
872
|
+
sessionUpdate: "agent_message_chunk",
|
|
873
|
+
content: { type: "text", text: "No plan here" },
|
|
874
|
+
},
|
|
875
|
+
]);
|
|
876
|
+
|
|
877
|
+
const agentId = "agent-1" as AgentId;
|
|
878
|
+
const streamId = "test-stream-no-plan";
|
|
879
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
880
|
+
|
|
881
|
+
await handler.processRequest(
|
|
882
|
+
agentId,
|
|
883
|
+
envelope(streamId, "session/prompt", {
|
|
884
|
+
prompt: [{ type: "text", text: "Just chat" }],
|
|
885
|
+
}, sessionId),
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
const historyResult = await handler.processRequest(
|
|
889
|
+
agentId,
|
|
890
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
const result = historyResult.acp.result as {
|
|
894
|
+
turns: unknown[];
|
|
895
|
+
plan: unknown[];
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
expect(result.plan).toEqual([]);
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
it("should use latest plan when multiple plan updates are received", async () => {
|
|
902
|
+
await setup([
|
|
903
|
+
{
|
|
904
|
+
sessionUpdate: "plan",
|
|
905
|
+
entries: [
|
|
906
|
+
{ content: "Step 1", priority: "high", status: "pending" },
|
|
907
|
+
],
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
sessionUpdate: "agent_message_chunk",
|
|
911
|
+
content: { type: "text", text: "Working..." },
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
sessionUpdate: "plan",
|
|
915
|
+
entries: [
|
|
916
|
+
{ content: "Step 1", priority: "high", status: "completed" },
|
|
917
|
+
{ content: "Step 2", priority: "medium", status: "in_progress" },
|
|
918
|
+
],
|
|
919
|
+
},
|
|
920
|
+
]);
|
|
921
|
+
|
|
922
|
+
const agentId = "agent-1" as AgentId;
|
|
923
|
+
const streamId = "test-stream-plan-latest";
|
|
924
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
925
|
+
|
|
926
|
+
await handler.processRequest(
|
|
927
|
+
agentId,
|
|
928
|
+
envelope(streamId, "session/prompt", {
|
|
929
|
+
prompt: [{ type: "text", text: "Work on it" }],
|
|
930
|
+
}, sessionId),
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
const historyResult = await handler.processRequest(
|
|
934
|
+
agentId,
|
|
935
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
936
|
+
);
|
|
937
|
+
|
|
938
|
+
const result = historyResult.acp.result as {
|
|
939
|
+
turns: unknown[];
|
|
940
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
// Should have the LATEST plan (second update)
|
|
944
|
+
expect(result.plan).toHaveLength(2);
|
|
945
|
+
expect(result.plan[0].status).toBe("completed");
|
|
946
|
+
expect(result.plan[1].status).toBe("in_progress");
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
it("should persist plan across multiple prompts (latest wins)", async () => {
|
|
950
|
+
const { agentManager } = await setup([
|
|
951
|
+
{
|
|
952
|
+
sessionUpdate: "plan",
|
|
953
|
+
entries: [
|
|
954
|
+
{ content: "Initial task", priority: "high", status: "in_progress" },
|
|
955
|
+
],
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
sessionUpdate: "agent_message_chunk",
|
|
959
|
+
content: { type: "text", text: "First response" },
|
|
960
|
+
},
|
|
961
|
+
]);
|
|
962
|
+
|
|
963
|
+
const agentId = "agent-1" as AgentId;
|
|
964
|
+
const streamId = "test-stream-plan-persist";
|
|
965
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
966
|
+
|
|
967
|
+
// First prompt — sets initial plan
|
|
968
|
+
await handler.processRequest(
|
|
969
|
+
agentId,
|
|
970
|
+
envelope(streamId, "session/prompt", {
|
|
971
|
+
prompt: [{ type: "text", text: "Start working" }],
|
|
972
|
+
}, sessionId),
|
|
973
|
+
);
|
|
974
|
+
|
|
975
|
+
// Verify plan from first prompt
|
|
976
|
+
let historyResult = await handler.processRequest(
|
|
977
|
+
agentId,
|
|
978
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
979
|
+
);
|
|
980
|
+
let result = historyResult.acp.result as {
|
|
981
|
+
turns: unknown[];
|
|
982
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
983
|
+
};
|
|
984
|
+
expect(result.plan).toHaveLength(1);
|
|
985
|
+
expect(result.plan[0].content).toBe("Initial task");
|
|
986
|
+
|
|
987
|
+
// Second prompt with updated plan
|
|
988
|
+
(agentManager.prompt as ReturnType<typeof vi.fn>).mockReturnValue({
|
|
989
|
+
[Symbol.asyncIterator]: async function* () {
|
|
990
|
+
yield {
|
|
991
|
+
sessionUpdate: "plan",
|
|
992
|
+
entries: [
|
|
993
|
+
{ content: "Initial task", priority: "high", status: "completed" },
|
|
994
|
+
{ content: "New task", priority: "medium", status: "in_progress" },
|
|
995
|
+
],
|
|
996
|
+
};
|
|
997
|
+
yield {
|
|
998
|
+
sessionUpdate: "agent_message_chunk",
|
|
999
|
+
content: { type: "text", text: "Second response" },
|
|
1000
|
+
};
|
|
1001
|
+
},
|
|
1002
|
+
} as any);
|
|
1003
|
+
|
|
1004
|
+
await handler.processRequest(
|
|
1005
|
+
agentId,
|
|
1006
|
+
envelope(streamId, "session/prompt", {
|
|
1007
|
+
prompt: [{ type: "text", text: "Continue" }],
|
|
1008
|
+
}, sessionId),
|
|
1009
|
+
);
|
|
1010
|
+
|
|
1011
|
+
// Plan should now reflect the second prompt's update
|
|
1012
|
+
historyResult = await handler.processRequest(
|
|
1013
|
+
agentId,
|
|
1014
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
1015
|
+
);
|
|
1016
|
+
result = historyResult.acp.result as {
|
|
1017
|
+
turns: unknown[];
|
|
1018
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
1019
|
+
};
|
|
1020
|
+
expect(result.plan).toHaveLength(2);
|
|
1021
|
+
expect(result.plan[0].status).toBe("completed");
|
|
1022
|
+
expect(result.plan[1].content).toBe("New task");
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
it("should keep plan from earlier prompt if new prompt has no plan updates", async () => {
|
|
1026
|
+
const { agentManager } = await setup([
|
|
1027
|
+
{
|
|
1028
|
+
sessionUpdate: "plan",
|
|
1029
|
+
entries: [
|
|
1030
|
+
{ content: "Persistent task", priority: "high", status: "in_progress" },
|
|
1031
|
+
],
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
sessionUpdate: "agent_message_chunk",
|
|
1035
|
+
content: { type: "text", text: "First" },
|
|
1036
|
+
},
|
|
1037
|
+
]);
|
|
1038
|
+
|
|
1039
|
+
const agentId = "agent-1" as AgentId;
|
|
1040
|
+
const streamId = "test-stream-plan-keep";
|
|
1041
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
1042
|
+
|
|
1043
|
+
// First prompt — sets plan
|
|
1044
|
+
await handler.processRequest(
|
|
1045
|
+
agentId,
|
|
1046
|
+
envelope(streamId, "session/prompt", {
|
|
1047
|
+
prompt: [{ type: "text", text: "Plan it" }],
|
|
1048
|
+
}, sessionId),
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
// Second prompt with NO plan updates
|
|
1052
|
+
(agentManager.prompt as ReturnType<typeof vi.fn>).mockReturnValue({
|
|
1053
|
+
[Symbol.asyncIterator]: async function* () {
|
|
1054
|
+
yield {
|
|
1055
|
+
sessionUpdate: "agent_message_chunk",
|
|
1056
|
+
content: { type: "text", text: "No plan this time" },
|
|
1057
|
+
};
|
|
1058
|
+
},
|
|
1059
|
+
} as any);
|
|
1060
|
+
|
|
1061
|
+
await handler.processRequest(
|
|
1062
|
+
agentId,
|
|
1063
|
+
envelope(streamId, "session/prompt", {
|
|
1064
|
+
prompt: [{ type: "text", text: "Just chat" }],
|
|
1065
|
+
}, sessionId),
|
|
1066
|
+
);
|
|
1067
|
+
|
|
1068
|
+
// Plan should still be present from the first prompt
|
|
1069
|
+
const historyResult = await handler.processRequest(
|
|
1070
|
+
agentId,
|
|
1071
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
1072
|
+
);
|
|
1073
|
+
const result = historyResult.acp.result as {
|
|
1074
|
+
turns: unknown[];
|
|
1075
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
1076
|
+
};
|
|
1077
|
+
expect(result.plan).toHaveLength(1);
|
|
1078
|
+
expect(result.plan[0].content).toBe("Persistent task");
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
it("should include both plan and cwd together in getHistory response", async () => {
|
|
1082
|
+
await setup([
|
|
1083
|
+
{
|
|
1084
|
+
sessionUpdate: "plan",
|
|
1085
|
+
entries: [
|
|
1086
|
+
{ content: "Do something", priority: "high", status: "pending" },
|
|
1087
|
+
],
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
sessionUpdate: "agent_message_chunk",
|
|
1091
|
+
content: { type: "text", text: "Got it" },
|
|
1092
|
+
},
|
|
1093
|
+
]);
|
|
1094
|
+
|
|
1095
|
+
const agentId = "agent-1" as AgentId;
|
|
1096
|
+
const streamId = "test-stream-plan-cwd";
|
|
1097
|
+
const sessionId = await initAndCreateSession(streamId, agentId);
|
|
1098
|
+
|
|
1099
|
+
await handler.processRequest(
|
|
1100
|
+
agentId,
|
|
1101
|
+
envelope(streamId, "session/prompt", {
|
|
1102
|
+
prompt: [{ type: "text", text: "Go" }],
|
|
1103
|
+
}, sessionId),
|
|
1104
|
+
);
|
|
1105
|
+
|
|
1106
|
+
const historyResult = await handler.processRequest(
|
|
1107
|
+
agentId,
|
|
1108
|
+
envelope(streamId, "_macro/getHistory", { sessionId, agentId }),
|
|
1109
|
+
);
|
|
1110
|
+
|
|
1111
|
+
const result = historyResult.acp.result as {
|
|
1112
|
+
turns: unknown[];
|
|
1113
|
+
plan: Array<{ content: string; priority: string; status: string }>;
|
|
1114
|
+
cwd: string | null;
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
// Both fields present
|
|
1118
|
+
expect(result.turns).toHaveLength(2);
|
|
1119
|
+
expect(result.plan).toHaveLength(1);
|
|
1120
|
+
expect(result.plan[0].content).toBe("Do something");
|
|
1121
|
+
expect(result.cwd).toBe("/test/cwd");
|
|
1122
|
+
});
|
|
664
1123
|
});
|