@zooid/acp-client 0.11.0 → 0.11.1
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/package.json +1 -1
- package/src/acp-client.context.test.ts +40 -0
- package/src/acp-client.ts +11 -3
- package/src/types.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zooid/acp-client",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Zooid's ACP client: spawn agent subprocesses, drive them via Agent Client Protocol, route events and permission requests through callbacks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -90,4 +90,44 @@ describe('AcpClient — context MCP wiring', () => {
|
|
|
90
90
|
}
|
|
91
91
|
expect(params.mcpServers.map((s) => s.name)).toEqual(['zooid-context'])
|
|
92
92
|
})
|
|
93
|
+
|
|
94
|
+
it('passes contextThreadId — not the composed session key — to contextSpawn', async () => {
|
|
95
|
+
const calls: Array<{ method: string; params: unknown }> = []
|
|
96
|
+
const contextSpawn = vi.fn(async (threadId: string) => ({
|
|
97
|
+
name: 'zooid-context' as const,
|
|
98
|
+
command: 'node',
|
|
99
|
+
args: ['/bin/zooid-context-mcp.js', '--spawn-id', `spawn-${threadId}`],
|
|
100
|
+
env: [{ name: 'ZOOID_DAEMON_SOCK', value: '/run/zooid/test.sock' }],
|
|
101
|
+
}))
|
|
102
|
+
const client = new AcpClient({
|
|
103
|
+
agent: { id: 'bebop', command: 'x', args: [] },
|
|
104
|
+
onEvent: () => {},
|
|
105
|
+
onApprovalRequest: async () => ({ decision: 'allow', optionId: 'allow' }),
|
|
106
|
+
contextSpawn,
|
|
107
|
+
})
|
|
108
|
+
injectConnection(client, calls)
|
|
109
|
+
// Handoff-arc session: key is composed, context ref is the real root —
|
|
110
|
+
// zooid_get_history must read the real Matrix thread.
|
|
111
|
+
await client.ensureSession('$root|$p1', '!r:example.com', '$root')
|
|
112
|
+
expect(contextSpawn).toHaveBeenCalledWith('$root', '!r:example.com')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('defaults the context ref to the session key when contextThreadId is omitted (back-compat)', async () => {
|
|
116
|
+
const calls: Array<{ method: string; params: unknown }> = []
|
|
117
|
+
const contextSpawn = vi.fn(async (threadId: string) => ({
|
|
118
|
+
name: 'zooid-context' as const,
|
|
119
|
+
command: 'node',
|
|
120
|
+
args: ['/bin/zooid-context-mcp.js', '--spawn-id', `spawn-${threadId}`],
|
|
121
|
+
env: [{ name: 'ZOOID_DAEMON_SOCK', value: '/run/zooid/test.sock' }],
|
|
122
|
+
}))
|
|
123
|
+
const client = new AcpClient({
|
|
124
|
+
agent: { id: 'bebop', command: 'x', args: [] },
|
|
125
|
+
onEvent: () => {},
|
|
126
|
+
onApprovalRequest: async () => ({ decision: 'allow', optionId: 'allow' }),
|
|
127
|
+
contextSpawn,
|
|
128
|
+
})
|
|
129
|
+
injectConnection(client, calls)
|
|
130
|
+
await client.ensureSession('$root', '!r:example.com')
|
|
131
|
+
expect(contextSpawn).toHaveBeenCalledWith('$root', '!r:example.com')
|
|
132
|
+
})
|
|
93
133
|
})
|
package/src/acp-client.ts
CHANGED
|
@@ -162,7 +162,11 @@ export class AcpClient {
|
|
|
162
162
|
this.initialized = false
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
async ensureSession(
|
|
165
|
+
async ensureSession(
|
|
166
|
+
threadId: string,
|
|
167
|
+
channelId?: string,
|
|
168
|
+
contextThreadId?: string,
|
|
169
|
+
): Promise<string> {
|
|
166
170
|
if (!this.connection || !this.initialized) {
|
|
167
171
|
throw new Error('AcpClient.start() must be called before ensureSession()')
|
|
168
172
|
}
|
|
@@ -173,7 +177,7 @@ export class AcpClient {
|
|
|
173
177
|
if (cached) return cached.sessionId
|
|
174
178
|
|
|
175
179
|
const mcpServers = this.options.contextSpawn
|
|
176
|
-
? [await this.options.contextSpawn(threadId, channelId)]
|
|
180
|
+
? [await this.options.contextSpawn(contextThreadId ?? threadId, channelId)]
|
|
177
181
|
: []
|
|
178
182
|
process.stderr.write(
|
|
179
183
|
`[acp-client:${this.options.agent.id}] ensureSession(${threadId}) mcpServers=${
|
|
@@ -260,7 +264,11 @@ export class AcpClient {
|
|
|
260
264
|
let sessionId: string | null = null
|
|
261
265
|
let turnId: string | null = null
|
|
262
266
|
try {
|
|
263
|
-
sessionId = await this.ensureSession(
|
|
267
|
+
sessionId = await this.ensureSession(
|
|
268
|
+
input.threadId,
|
|
269
|
+
input.channelId,
|
|
270
|
+
input.contextThreadId,
|
|
271
|
+
)
|
|
264
272
|
const promptText = stringifyPromptForLog(input.content)
|
|
265
273
|
turnId = this.turns?.startTurn({ sessionId, promptText }) ?? null
|
|
266
274
|
debugLog(this.options.agent.id, 'prompt →', { sessionId, content: input.content })
|
package/src/types.ts
CHANGED
|
@@ -48,6 +48,12 @@ export interface PromptInput {
|
|
|
48
48
|
* transport-context provider sees the real room.
|
|
49
49
|
*/
|
|
50
50
|
channelId?: string
|
|
51
|
+
/**
|
|
52
|
+
* The real thread root when `threadId` is a composed handoff-arc session
|
|
53
|
+
* key ([[ZOD071]]). Feeds the transport-context spawn so history reads
|
|
54
|
+
* target the real thread. Defaults to `threadId`.
|
|
55
|
+
*/
|
|
56
|
+
contextThreadId?: string
|
|
51
57
|
content: ContentBlock[]
|
|
52
58
|
}
|
|
53
59
|
|