@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zooid/acp-client",
3
- "version": "0.11.0",
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(threadId: string, channelId?: string): Promise<string> {
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(input.threadId, input.channelId)
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