glm-acp-agent 1.0.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 (102) hide show
  1. package/README.md +365 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +62 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/credentials.d.ts +15 -0
  7. package/dist/llm/credentials.d.ts.map +1 -0
  8. package/dist/llm/credentials.js +54 -0
  9. package/dist/llm/credentials.js.map +1 -0
  10. package/dist/llm/glm-client.d.ts +63 -0
  11. package/dist/llm/glm-client.d.ts.map +1 -0
  12. package/dist/llm/glm-client.js +217 -0
  13. package/dist/llm/glm-client.js.map +1 -0
  14. package/dist/llm/logger.d.ts +19 -0
  15. package/dist/llm/logger.d.ts.map +1 -0
  16. package/dist/llm/logger.js +44 -0
  17. package/dist/llm/logger.js.map +1 -0
  18. package/dist/protocol/agent.d.ts +77 -0
  19. package/dist/protocol/agent.d.ts.map +1 -0
  20. package/dist/protocol/agent.js +732 -0
  21. package/dist/protocol/agent.js.map +1 -0
  22. package/dist/protocol/connection.d.ts +9 -0
  23. package/dist/protocol/connection.d.ts.map +1 -0
  24. package/dist/protocol/connection.js +18 -0
  25. package/dist/protocol/connection.js.map +1 -0
  26. package/dist/protocol/image-preprocessor.d.ts +32 -0
  27. package/dist/protocol/image-preprocessor.d.ts.map +1 -0
  28. package/dist/protocol/image-preprocessor.js +149 -0
  29. package/dist/protocol/image-preprocessor.js.map +1 -0
  30. package/dist/protocol/session-store.d.ts +54 -0
  31. package/dist/protocol/session-store.d.ts.map +1 -0
  32. package/dist/protocol/session-store.js +109 -0
  33. package/dist/protocol/session-store.js.map +1 -0
  34. package/dist/protocol/system-prompt.d.ts +29 -0
  35. package/dist/protocol/system-prompt.d.ts.map +1 -0
  36. package/dist/protocol/system-prompt.js +103 -0
  37. package/dist/protocol/system-prompt.js.map +1 -0
  38. package/dist/setup.d.ts +8 -0
  39. package/dist/setup.d.ts.map +1 -0
  40. package/dist/setup.js +95 -0
  41. package/dist/setup.js.map +1 -0
  42. package/dist/tests/agent.test.d.ts +2 -0
  43. package/dist/tests/agent.test.d.ts.map +1 -0
  44. package/dist/tests/agent.test.js +1118 -0
  45. package/dist/tests/agent.test.js.map +1 -0
  46. package/dist/tests/credentials.test.d.ts +2 -0
  47. package/dist/tests/credentials.test.d.ts.map +1 -0
  48. package/dist/tests/credentials.test.js +112 -0
  49. package/dist/tests/credentials.test.js.map +1 -0
  50. package/dist/tests/executor.test.d.ts +2 -0
  51. package/dist/tests/executor.test.d.ts.map +1 -0
  52. package/dist/tests/executor.test.js +497 -0
  53. package/dist/tests/executor.test.js.map +1 -0
  54. package/dist/tests/glm-client.test.d.ts +2 -0
  55. package/dist/tests/glm-client.test.d.ts.map +1 -0
  56. package/dist/tests/glm-client.test.js +205 -0
  57. package/dist/tests/glm-client.test.js.map +1 -0
  58. package/dist/tests/image-preprocessor.test.d.ts +2 -0
  59. package/dist/tests/image-preprocessor.test.d.ts.map +1 -0
  60. package/dist/tests/image-preprocessor.test.js +133 -0
  61. package/dist/tests/image-preprocessor.test.js.map +1 -0
  62. package/dist/tests/integration.test.d.ts +2 -0
  63. package/dist/tests/integration.test.d.ts.map +1 -0
  64. package/dist/tests/integration.test.js +192 -0
  65. package/dist/tests/integration.test.js.map +1 -0
  66. package/dist/tests/logger.test.d.ts +2 -0
  67. package/dist/tests/logger.test.d.ts.map +1 -0
  68. package/dist/tests/logger.test.js +14 -0
  69. package/dist/tests/logger.test.js.map +1 -0
  70. package/dist/tests/mcp-arg-remap.test.d.ts +2 -0
  71. package/dist/tests/mcp-arg-remap.test.d.ts.map +1 -0
  72. package/dist/tests/mcp-arg-remap.test.js +65 -0
  73. package/dist/tests/mcp-arg-remap.test.js.map +1 -0
  74. package/dist/tests/vision-mcp-client.test.d.ts +2 -0
  75. package/dist/tests/vision-mcp-client.test.d.ts.map +1 -0
  76. package/dist/tests/vision-mcp-client.test.js +129 -0
  77. package/dist/tests/vision-mcp-client.test.js.map +1 -0
  78. package/dist/tests/zai-mcp-client.test.d.ts +2 -0
  79. package/dist/tests/zai-mcp-client.test.d.ts.map +1 -0
  80. package/dist/tests/zai-mcp-client.test.js +386 -0
  81. package/dist/tests/zai-mcp-client.test.js.map +1 -0
  82. package/dist/tools/definitions.d.ts +18 -0
  83. package/dist/tools/definitions.d.ts.map +1 -0
  84. package/dist/tools/definitions.js +149 -0
  85. package/dist/tools/definitions.js.map +1 -0
  86. package/dist/tools/executor.d.ts +48 -0
  87. package/dist/tools/executor.d.ts.map +1 -0
  88. package/dist/tools/executor.js +670 -0
  89. package/dist/tools/executor.js.map +1 -0
  90. package/dist/tools/mcp-arg-remap.d.ts +21 -0
  91. package/dist/tools/mcp-arg-remap.d.ts.map +1 -0
  92. package/dist/tools/mcp-arg-remap.js +70 -0
  93. package/dist/tools/mcp-arg-remap.js.map +1 -0
  94. package/dist/tools/vision-mcp-client.d.ts +38 -0
  95. package/dist/tools/vision-mcp-client.d.ts.map +1 -0
  96. package/dist/tools/vision-mcp-client.js +191 -0
  97. package/dist/tools/vision-mcp-client.js.map +1 -0
  98. package/dist/tools/zai-mcp-client.d.ts +24 -0
  99. package/dist/tools/zai-mcp-client.d.ts.map +1 -0
  100. package/dist/tools/zai-mcp-client.js +189 -0
  101. package/dist/tools/zai-mcp-client.js.map +1 -0
  102. package/package.json +37 -0
@@ -0,0 +1,205 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { GlmClient, getAvailableModels } from "../llm/glm-client.js";
4
+ test("constructor uses the coding endpoint by default", () => {
5
+ process.env["Z_AI_API_KEY"] = "test-key";
6
+ delete process.env["ACP_GLM_BASE_URL"];
7
+ try {
8
+ const c = new GlmClient();
9
+ const url = c.client.baseURL;
10
+ assert.equal(url, "https://api.z.ai/api/coding/paas/v4");
11
+ }
12
+ finally {
13
+ delete process.env["Z_AI_API_KEY"];
14
+ }
15
+ });
16
+ // We don't want to actually hit the network, but the OpenAI SDK still
17
+ // constructs a client when we instantiate GlmClient. We stub the
18
+ // `client.chat.completions.create` method on the underlying OpenAI client.
19
+ function fakeStream(chunks) {
20
+ return {
21
+ [Symbol.asyncIterator]() {
22
+ let i = 0;
23
+ return {
24
+ next() {
25
+ if (i < chunks.length) {
26
+ return Promise.resolve({ value: chunks[i++], done: false });
27
+ }
28
+ return Promise.resolve({ value: undefined, done: true });
29
+ },
30
+ };
31
+ },
32
+ };
33
+ }
34
+ function makeClient(stream) {
35
+ process.env["Z_AI_API_KEY"] = "test-key";
36
+ const c = new GlmClient();
37
+ // The OpenAI SDK exposes `chat.completions.create`. Replace it with a stub.
38
+ c.client = {
39
+ chat: { completions: { create: () => Promise.resolve(stream) } },
40
+ };
41
+ return c;
42
+ }
43
+ test("streamChat yields text chunks for delta.content", async () => {
44
+ const stream = fakeStream([
45
+ { choices: [{ delta: { content: "Hel" }, finish_reason: null }] },
46
+ { choices: [{ delta: { content: "lo" }, finish_reason: null }] },
47
+ { choices: [{ delta: {}, finish_reason: "stop" }] },
48
+ ]);
49
+ const c = makeClient(stream);
50
+ const out = [];
51
+ let lastStop;
52
+ for await (const chunk of c.streamChat([])) {
53
+ if (chunk.text)
54
+ out.push(chunk.text);
55
+ if (chunk.done)
56
+ lastStop = chunk.stopReason;
57
+ }
58
+ assert.deepEqual(out, ["Hel", "lo"]);
59
+ assert.equal(lastStop, "stop");
60
+ });
61
+ test("streamChat surfaces reasoning_content as thinking chunks", async () => {
62
+ const stream = fakeStream([
63
+ { choices: [{ delta: { reasoning_content: "Hmm..." }, finish_reason: null }] },
64
+ { choices: [{ delta: { content: "Answer" }, finish_reason: "stop" }] },
65
+ ]);
66
+ const c = makeClient(stream);
67
+ const thoughts = [];
68
+ const text = [];
69
+ for await (const chunk of c.streamChat([])) {
70
+ if (chunk.thinking)
71
+ thoughts.push(chunk.thinking);
72
+ if (chunk.text)
73
+ text.push(chunk.text);
74
+ }
75
+ assert.deepEqual(thoughts, ["Hmm..."]);
76
+ assert.deepEqual(text, ["Answer"]);
77
+ });
78
+ test("streamChat assembles tool calls across deltas", async () => {
79
+ const stream = fakeStream([
80
+ {
81
+ choices: [
82
+ {
83
+ delta: {
84
+ tool_calls: [
85
+ { index: 0, id: "tc1", function: { name: "read_file", arguments: "" } },
86
+ ],
87
+ },
88
+ finish_reason: null,
89
+ },
90
+ ],
91
+ },
92
+ {
93
+ choices: [
94
+ {
95
+ delta: {
96
+ tool_calls: [{ index: 0, function: { arguments: '{"path":"/x' } }],
97
+ },
98
+ finish_reason: null,
99
+ },
100
+ ],
101
+ },
102
+ {
103
+ choices: [
104
+ {
105
+ delta: { tool_calls: [{ index: 0, function: { arguments: '"}' } }] },
106
+ finish_reason: "tool_calls",
107
+ },
108
+ ],
109
+ },
110
+ ]);
111
+ const c = makeClient(stream);
112
+ const calls = [];
113
+ for await (const chunk of c.streamChat([])) {
114
+ if (chunk.toolCall)
115
+ calls.push(chunk.toolCall);
116
+ }
117
+ assert.equal(calls.length, 1);
118
+ assert.equal(calls[0]?.id, "tc1");
119
+ assert.equal(calls[0]?.name, "read_file");
120
+ assert.equal(calls[0]?.arguments, '{"path":"/x"}');
121
+ });
122
+ test("streamChat captures usage from the trailing usage chunk", async () => {
123
+ const stream = fakeStream([
124
+ { choices: [{ delta: { content: "ok" }, finish_reason: "stop" }] },
125
+ {
126
+ choices: [],
127
+ usage: { prompt_tokens: 12, completion_tokens: 7, total_tokens: 19 },
128
+ },
129
+ ]);
130
+ const c = makeClient(stream);
131
+ let usage;
132
+ for await (const chunk of c.streamChat([])) {
133
+ if (chunk.usage) {
134
+ usage = {
135
+ inputTokens: chunk.usage.inputTokens,
136
+ outputTokens: chunk.usage.outputTokens,
137
+ totalTokens: chunk.usage.totalTokens,
138
+ };
139
+ }
140
+ }
141
+ assert.deepEqual(usage, { inputTokens: 12, outputTokens: 7, totalTokens: 19 });
142
+ });
143
+ test("constructor throws if Z_AI_API_KEY is missing", () => {
144
+ const old = process.env["Z_AI_API_KEY"];
145
+ delete process.env["Z_AI_API_KEY"];
146
+ try {
147
+ assert.throws(() => new GlmClient(), /Z_AI_API_KEY/);
148
+ }
149
+ finally {
150
+ if (old !== undefined)
151
+ process.env["Z_AI_API_KEY"] = old;
152
+ }
153
+ });
154
+ test("getAvailableModels returns the Coding Plan allowlist by default", () => {
155
+ const old = process.env["ACP_GLM_AVAILABLE_MODELS"];
156
+ delete process.env["ACP_GLM_AVAILABLE_MODELS"];
157
+ try {
158
+ const ids = getAvailableModels().map((m) => m.modelId);
159
+ assert.deepEqual(ids, ["glm-5.1", "glm-5-turbo", "glm-4.7", "glm-4.5-air"]);
160
+ assert.ok(!ids.includes("glm-4v-plus"), "glm-4v-plus must not be advertised");
161
+ assert.ok(!ids.includes("glm-4.6"), "glm-4.6 must not be advertised");
162
+ assert.ok(!ids.includes("glm-4.5"), "glm-4.5 must not be advertised");
163
+ }
164
+ finally {
165
+ if (old !== undefined)
166
+ process.env["ACP_GLM_AVAILABLE_MODELS"] = old;
167
+ }
168
+ });
169
+ test("ACP_GLM_AVAILABLE_MODELS env override still wins over the built-in list", () => {
170
+ const old = process.env["ACP_GLM_AVAILABLE_MODELS"];
171
+ process.env["ACP_GLM_AVAILABLE_MODELS"] = "custom-a, custom-b";
172
+ try {
173
+ const ids = getAvailableModels().map((m) => m.modelId);
174
+ assert.deepEqual(ids, ["custom-a", "custom-b"]);
175
+ }
176
+ finally {
177
+ if (old === undefined)
178
+ delete process.env["ACP_GLM_AVAILABLE_MODELS"];
179
+ else
180
+ process.env["ACP_GLM_AVAILABLE_MODELS"] = old;
181
+ }
182
+ });
183
+ test("streamChat does not flush partial tool calls (missing id or name)", async () => {
184
+ // Stream a tool_call delta that only contains arguments – no id, no name.
185
+ // The client should silently drop the partial entry instead of yielding it.
186
+ const stream = fakeStream([
187
+ {
188
+ choices: [
189
+ {
190
+ delta: { tool_calls: [{ index: 0, function: { arguments: '{"foo":1}' } }] },
191
+ finish_reason: null,
192
+ },
193
+ ],
194
+ },
195
+ { choices: [{ delta: {}, finish_reason: "stop" }] },
196
+ ]);
197
+ const c = makeClient(stream);
198
+ const calls = [];
199
+ for await (const chunk of c.streamChat([])) {
200
+ if (chunk.toolCall)
201
+ calls.push({ id: chunk.toolCall.id, name: chunk.toolCall.name });
202
+ }
203
+ assert.equal(calls.length, 0);
204
+ });
205
+ //# sourceMappingURL=glm-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glm-client.test.js","sourceRoot":"","sources":["../../src/tests/glm-client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=image-preprocessor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-preprocessor.test.d.ts","sourceRoot":"","sources":["../../src/tests/image-preprocessor.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { preprocessImageBlocks, buildPromptBlockDiagnosticLines } from "../protocol/image-preprocessor.js";
5
+ function makeClient(impl) {
6
+ return { callTool: impl, async dispose() { } };
7
+ }
8
+ test("preprocessImageBlocks returns the input unchanged when no images are present", async () => {
9
+ const result = await preprocessImageBlocks([{ type: "text", text: "hi" }], makeClient(async () => { throw new Error("should not be called"); }));
10
+ assert.deepEqual(result.blocks, [{ type: "text", text: "hi" }]);
11
+ assert.equal(result.cleanups.length, 0);
12
+ });
13
+ test("preprocessImageBlocks forwards a remote URI directly to the vision client", async () => {
14
+ let seen = null;
15
+ const result = await preprocessImageBlocks([
16
+ { type: "text", text: "What is this?" },
17
+ { type: "image", data: "", mimeType: "image/png", uri: "https://example.com/cat.png" },
18
+ ], makeClient(async (_name, args) => {
19
+ seen = args;
20
+ return { content: [{ type: "text", text: "A cat." }] };
21
+ }));
22
+ assert.equal(seen?.["image_source"], "https://example.com/cat.png");
23
+ assert.equal(typeof seen?.["prompt"], "string", "callTool must always receive a prompt field");
24
+ // Image block must have been replaced with a text annotation.
25
+ assert.equal(result.blocks.length, 2);
26
+ const last = result.blocks[1];
27
+ assert.equal(last.type, "text");
28
+ assert.match(last.text ?? "", /<image_analysis index="1">[\s\S]*A cat\.[\s\S]*<\/image_analysis>/);
29
+ });
30
+ test("preprocessImageBlocks prefers base64 data over URI when both are present", async () => {
31
+ let seenSource = "";
32
+ let seenPrompt;
33
+ const result = await preprocessImageBlocks([{ type: "image", data: "AAAA", mimeType: "image/png", uri: "https://example.com/should-not-use.png" }], makeClient(async (_name, args) => {
34
+ seenSource = String(args["image_source"]);
35
+ seenPrompt = args["prompt"];
36
+ return { content: [{ type: "text", text: "blank image" }] };
37
+ }));
38
+ for (const c of result.cleanups)
39
+ await c();
40
+ assert.ok(!seenSource.startsWith("https://"), "URI must not be used when base64 data is available");
41
+ assert.ok(seenSource.length > 0, "a temp file path must have been passed");
42
+ assert.equal(typeof seenPrompt, "string", "callTool must receive a prompt field");
43
+ });
44
+ test("preprocessImageBlocks materializes inline data to a temp file and cleans it up", async () => {
45
+ let seenPath = "";
46
+ let seenPrompt;
47
+ const result = await preprocessImageBlocks([{ type: "image", data: "AAAA", mimeType: "image/png" }], makeClient(async (_name, args) => {
48
+ seenPath = String(args["image_source"]);
49
+ seenPrompt = args["prompt"];
50
+ assert.ok(existsSync(seenPath), "temp file must exist while vision MCP is invoked");
51
+ const bytes = readFileSync(seenPath);
52
+ assert.equal(bytes.length, 3); // base64 "AAAA" = 3 bytes
53
+ return { content: [{ type: "text", text: "blank" }] };
54
+ }));
55
+ // Run cleanups after the call returns and verify the file is gone.
56
+ for (const c of result.cleanups)
57
+ await c();
58
+ assert.equal(existsSync(seenPath), false);
59
+ assert.equal(typeof seenPrompt, "string", "callTool must receive a prompt field");
60
+ });
61
+ test("preprocessImageBlocks degrades gracefully when the vision client fails", async () => {
62
+ const result = await preprocessImageBlocks([
63
+ { type: "text", text: "Look:" },
64
+ { type: "image", data: "", mimeType: "image/png", uri: "https://example.com/x.png" },
65
+ ], makeClient(async () => { throw new Error("quota exceeded"); }));
66
+ const annotation = result.blocks.at(-1);
67
+ assert.equal(annotation.type, "text");
68
+ assert.match(annotation.text ?? "", /image_analysis_error/);
69
+ assert.match(annotation.text ?? "", /quota exceeded/);
70
+ });
71
+ test("preprocessImageBlocks skips vision when no client is given and notes the image", async () => {
72
+ const result = await preprocessImageBlocks([{ type: "image", data: "AAAA", mimeType: "image/png" }], null);
73
+ const block = result.blocks[0];
74
+ assert.equal(block.type, "text");
75
+ assert.match(block.text ?? "", /image attached \(not analyzed/i);
76
+ assert.equal(result.cleanups.length, 0);
77
+ });
78
+ // ---------------------------------------------------------------------------
79
+ // buildPromptBlockDiagnosticLines
80
+ // ---------------------------------------------------------------------------
81
+ test("buildPromptBlockDiagnosticLines summarizes block types without leaking base64", () => {
82
+ const base64Data = Buffer.from("fake image payload data").toString("base64");
83
+ const lines = buildPromptBlockDiagnosticLines([
84
+ { type: "text", text: "hello" },
85
+ { type: "image", data: base64Data, mimeType: "image/jpeg" },
86
+ ]);
87
+ const summary = lines[0] ?? "";
88
+ assert.ok(summary.includes("text×1"), "summary must count text blocks");
89
+ assert.ok(summary.includes("image×1"), "summary must count image blocks");
90
+ for (const line of lines) {
91
+ assert.ok(!line.includes(base64Data), "base64 payload must not appear in diagnostic output");
92
+ }
93
+ const imageLine = lines.find((l) => l.includes("image block"));
94
+ assert.ok(imageLine, "image block diagnostic line must be present");
95
+ assert.ok(imageLine.includes("data_bytes"), "approximate byte count must be logged");
96
+ assert.ok(imageLine.includes("uri=false"), "URI presence must be false when uri is absent");
97
+ });
98
+ test("buildPromptBlockDiagnosticLines logs approximate decoded byte count for base64 data", () => {
99
+ // 4 base64 chars ≈ 3 decoded bytes; Math.floor(4 * 0.75) = 3
100
+ const lines = buildPromptBlockDiagnosticLines([
101
+ { type: "image", data: "AAAA", mimeType: "image/png" },
102
+ ]);
103
+ const imageLine = lines.find((l) => l.includes("image block")) ?? "";
104
+ assert.ok(imageLine.includes("data_bytes≈3"), "should log approximate decoded byte count");
105
+ });
106
+ test("buildPromptBlockDiagnosticLines marks URI presence when uri is set", () => {
107
+ const lines = buildPromptBlockDiagnosticLines([
108
+ { type: "image", data: "", mimeType: "image/png", uri: "https://example.com/cat.png" },
109
+ ]);
110
+ const imageLine = lines.find((l) => l.includes("image block")) ?? "";
111
+ assert.ok(imageLine.includes("uri=true"), "URI presence must be true when uri is set");
112
+ });
113
+ test("buildPromptBlockDiagnosticLines logs safe URI basename for resource_link", () => {
114
+ const lines = buildPromptBlockDiagnosticLines([
115
+ { type: "resource_link", uri: "file:///home/user/private/secret-config.ts", name: "secret-config.ts" },
116
+ ]);
117
+ const rl = lines.find((l) => l.includes("resource_link block")) ?? "";
118
+ assert.ok(rl.length > 0, "resource_link diagnostic line must be present");
119
+ assert.ok(!rl.includes("/home/user/private/"), "full directory path must not appear");
120
+ assert.ok(rl.includes("secret-config.ts"), "basename should appear");
121
+ });
122
+ test("buildPromptBlockDiagnosticLines redacts data: URIs for resources", () => {
123
+ const lines = buildPromptBlockDiagnosticLines([
124
+ {
125
+ type: "resource",
126
+ resource: { uri: "data:text/plain;base64,SGVsbG8=", text: "Hello" },
127
+ },
128
+ ]);
129
+ const rl = lines.find((l) => l.includes("resource block")) ?? "";
130
+ assert.ok(rl.includes("data:<redacted>"), "data: URI must be redacted");
131
+ assert.ok(!rl.includes("SGVsbG8="), "base64 payload in data URI must not appear");
132
+ });
133
+ //# sourceMappingURL=image-preprocessor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-preprocessor.test.js","sourceRoot":"","sources":["../../src/tests/image-preprocessor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/tests/integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,192 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync } from "node:fs";
4
+ import { tmpdir as osTmpdir } from "node:os";
5
+ import { join as pathJoin } from "node:path";
6
+ // Defence in depth: redirect the default session-persistence directory to an
7
+ // isolated tempdir so any forgotten `sessionStore: null` opt-out can't write
8
+ // to the developer's home.
9
+ process.env["ACP_GLM_SESSION_DIR"] = mkdtempSync(pathJoin(osTmpdir(), "glm-acp-integration-test-"));
10
+ import { AgentSideConnection, ClientSideConnection, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
11
+ import { GlmAcpAgent } from "../protocol/agent.js";
12
+ /**
13
+ * End-to-end style test: wire two `TransformStream`s together so that the
14
+ * AgentSideConnection (running our GlmAcpAgent) and a fake ClientSideConnection
15
+ * exchange real JSON-RPC newline-delimited frames over in-memory streams.
16
+ * This validates that the agent is wire-compatible with the official SDK.
17
+ */
18
+ function pairedStreams() {
19
+ const aToB = new TransformStream();
20
+ const bToA = new TransformStream();
21
+ return {
22
+ a: ndJsonStream(aToB.writable, bToA.readable),
23
+ b: ndJsonStream(bToA.writable, aToB.readable),
24
+ };
25
+ }
26
+ class StubClient {
27
+ updates = [];
28
+ reads = [];
29
+ fileContents = new Map();
30
+ permissionResponses = [];
31
+ async sessionUpdate(params) {
32
+ this.updates.push(params);
33
+ }
34
+ async requestPermission() {
35
+ const next = this.permissionResponses.shift();
36
+ return next ?? { outcome: { outcome: "selected", optionId: "allow" } };
37
+ }
38
+ async readTextFile(params) {
39
+ this.reads.push({ path: params.path });
40
+ const content = this.fileContents.get(params.path);
41
+ if (content === undefined)
42
+ throw new Error(`file not found: ${params.path}`);
43
+ return { content };
44
+ }
45
+ }
46
+ function makeStreamingGlm(steps) {
47
+ let i = 0;
48
+ return {
49
+ async *streamChat() {
50
+ const step = steps[i++];
51
+ if (!step)
52
+ throw new Error("streamChat called more times than expected");
53
+ for (const chunk of step)
54
+ yield chunk;
55
+ },
56
+ };
57
+ }
58
+ test("end-to-end initialize / new session / prompt round-trip via real SDK transport", async () => {
59
+ const { a, b } = pairedStreams();
60
+ const stub = new StubClient();
61
+ // Agent side
62
+ const glm = makeStreamingGlm([
63
+ [
64
+ { thinking: "Let me think." },
65
+ { text: "Hello!" },
66
+ { done: true, stopReason: "stop" },
67
+ ],
68
+ ]);
69
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
+ const _agentConn = new AgentSideConnection((conn) => new GlmAcpAgent(conn, { glm, sessionStore: null }), a);
71
+ // Client side
72
+ const clientConn = new ClientSideConnection(() => stub, b);
73
+ const initResp = await clientConn.initialize({
74
+ protocolVersion: PROTOCOL_VERSION,
75
+ clientCapabilities: {
76
+ fs: { readTextFile: true, writeTextFile: true },
77
+ terminal: false,
78
+ },
79
+ });
80
+ assert.equal(initResp.protocolVersion, PROTOCOL_VERSION);
81
+ assert.equal(initResp.agentInfo?.name, "glm-acp-agent");
82
+ const session = await clientConn.newSession({ cwd: "/tmp", mcpServers: [] });
83
+ assert.ok(typeof session.sessionId === "string" && session.sessionId.length > 0);
84
+ const prompt = await clientConn.prompt({
85
+ sessionId: session.sessionId,
86
+ prompt: [{ type: "text", text: "Hi there" }],
87
+ });
88
+ assert.equal(prompt.stopReason, "end_turn");
89
+ // Confirm the client received streaming updates including a thought chunk and a message chunk.
90
+ const updateKinds = stub.updates.map((u) => u.update.sessionUpdate);
91
+ assert.ok(updateKinds.includes("agent_thought_chunk"));
92
+ assert.ok(updateKinds.includes("agent_message_chunk"));
93
+ assert.ok(updateKinds.includes("session_info_update"));
94
+ });
95
+ test("end-to-end tool call: agent reads a file via the stub client", async () => {
96
+ const { a, b } = pairedStreams();
97
+ const stub = new StubClient();
98
+ stub.fileContents.set("/tmp/x.ts", "export const x = 1;");
99
+ let callIndex = 0;
100
+ const glm = {
101
+ async *streamChat() {
102
+ callIndex++;
103
+ if (callIndex === 1) {
104
+ yield {
105
+ toolCall: {
106
+ id: "tc1",
107
+ name: "read_file",
108
+ arguments: JSON.stringify({ path: "/tmp/x.ts" }),
109
+ },
110
+ };
111
+ yield { done: true, stopReason: "tool_calls" };
112
+ }
113
+ else {
114
+ yield { text: "Read it." };
115
+ yield { done: true, stopReason: "stop" };
116
+ }
117
+ },
118
+ };
119
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
120
+ const _agentConn = new AgentSideConnection((conn) => new GlmAcpAgent(conn, { glm, sessionStore: null }), a);
121
+ const clientConn = new ClientSideConnection(() => stub, b);
122
+ await clientConn.initialize({
123
+ protocolVersion: PROTOCOL_VERSION,
124
+ clientCapabilities: { fs: { readTextFile: true, writeTextFile: true } },
125
+ });
126
+ const session = await clientConn.newSession({ cwd: "/tmp", mcpServers: [] });
127
+ const result = await clientConn.prompt({
128
+ sessionId: session.sessionId,
129
+ prompt: [{ type: "text", text: "read it" }],
130
+ });
131
+ assert.equal(result.stopReason, "end_turn");
132
+ assert.deepEqual(stub.reads, [{ path: "/tmp/x.ts" }]);
133
+ // The client should have seen `tool_call` and `tool_call_update` notifications.
134
+ const updateKinds = stub.updates.map((u) => u.update.sessionUpdate);
135
+ assert.ok(updateKinds.includes("tool_call"));
136
+ assert.ok(updateKinds.includes("tool_call_update"));
137
+ });
138
+ test("end-to-end cancellation via session/cancel notification", async () => {
139
+ const { a, b } = pairedStreams();
140
+ const stub = new StubClient();
141
+ // The stub yields one chunk, signals via `started`, then suspends until the
142
+ // abort signal fires. This makes the cancel point deterministic without
143
+ // any reliance on setTimeout pacing.
144
+ let resolveStarted;
145
+ const started = new Promise((r) => (resolveStarted = r));
146
+ const glm = {
147
+ async *streamChat(_messages, signal) {
148
+ yield { text: "starting" };
149
+ resolveStarted();
150
+ await new Promise((resolve) => {
151
+ if (signal?.aborted)
152
+ return resolve();
153
+ signal?.addEventListener("abort", () => resolve(), { once: true });
154
+ });
155
+ yield { done: true, stopReason: "stop" };
156
+ },
157
+ };
158
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
+ const _agentConn = new AgentSideConnection((conn) => new GlmAcpAgent(conn, { glm, sessionStore: null }), a);
160
+ const clientConn = new ClientSideConnection(() => stub, b);
161
+ await clientConn.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} });
162
+ const session = await clientConn.newSession({ cwd: "/tmp", mcpServers: [] });
163
+ const promptPromise = clientConn.prompt({
164
+ sessionId: session.sessionId,
165
+ prompt: [{ type: "text", text: "go" }],
166
+ });
167
+ await started;
168
+ await clientConn.cancel({ sessionId: session.sessionId });
169
+ const result = await promptPromise;
170
+ assert.equal(result.stopReason, "cancelled");
171
+ });
172
+ test("end-to-end session/list and session/close advertised on initialize and routable", async () => {
173
+ const { a, b } = pairedStreams();
174
+ const stub = new StubClient();
175
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
176
+ const _agentConn = new AgentSideConnection((conn) => new GlmAcpAgent(conn, { glm: makeStreamingGlm([]), sessionStore: null }), a);
177
+ const clientConn = new ClientSideConnection(() => stub, b);
178
+ const initResp = await clientConn.initialize({
179
+ protocolVersion: PROTOCOL_VERSION,
180
+ clientCapabilities: {},
181
+ });
182
+ assert.ok(initResp.agentCapabilities?.sessionCapabilities?.list);
183
+ assert.ok(initResp.agentCapabilities?.sessionCapabilities?.close);
184
+ const a1 = await clientConn.newSession({ cwd: "/tmp/a", mcpServers: [] });
185
+ await clientConn.newSession({ cwd: "/tmp/b", mcpServers: [] });
186
+ const list = await clientConn.listSessions({});
187
+ assert.equal(list.sessions.length, 2);
188
+ await clientConn.closeSession({ sessionId: a1.sessionId });
189
+ const list2 = await clientConn.listSessions({});
190
+ assert.equal(list2.sessions.length, 1);
191
+ });
192
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/tests/integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=logger.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/tests/logger.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { maskSecret } from "../llm/logger.js";
4
+ test("maskSecret masks all but last 4 chars", () => {
5
+ assert.equal(maskSecret("abcdefgh"), "****efgh");
6
+ });
7
+ test("maskSecret returns **** for short strings", () => {
8
+ assert.equal(maskSecret("ab"), "****");
9
+ assert.equal(maskSecret("abcd"), "****");
10
+ });
11
+ test("maskSecret handles exactly 5 chars", () => {
12
+ assert.equal(maskSecret("abcde"), "****bcde");
13
+ });
14
+ //# sourceMappingURL=logger.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.test.js","sourceRoot":"","sources":["../../src/tests/logger.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACjD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE;IACrD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAC9C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-arg-remap.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-arg-remap.test.d.ts","sourceRoot":"","sources":["../../src/tests/mcp-arg-remap.test.ts"],"names":[],"mappings":""}