@tanstack/ai-acp 0.2.2 → 0.2.4

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.
@@ -2,14 +2,17 @@ import { EventType, normalizeSystemPrompts } from '@tanstack/ai'
2
2
  import { toRunErrorRawEvent } from '@tanstack/ai/adapter-internals'
3
3
  import { BaseTextAdapter } from '@tanstack/ai/adapters'
4
4
  import {
5
+ DurableAttachNotSupportedError,
5
6
  SandboxCapability,
6
7
  buildApprovalRequestedEvent,
7
8
  createBridgeEventChannel,
8
9
  getSandbox,
10
+ getSandboxDurability,
9
11
  getToolBridgeProvisioner,
10
12
  getWorkspaceProjection,
11
13
  mergeChunkStreams,
12
14
  nodeHttpBridgeProvisioner,
15
+ resolveDurableRunId,
13
16
  resolveHarnessCwd,
14
17
  } from '@tanstack/ai-sandbox'
15
18
  import { AsyncQueue } from '../stream/queue'
@@ -331,8 +334,56 @@ export class AcpCompatibleTextAdapter<
331
334
  const modelOptions = options.modelOptions
332
335
  const cwd = modelOptions?.cwd ?? this.harness.cwd ?? DEFAULT_WORKDIR
333
336
  const harnessCwd = resolveHarnessCwd(sandbox, cwd)
334
- const runId = options.runId ?? this.generateId()
337
+ // This adapter does not journal yet, so a generated id is still fine.
338
+ // Routed through the helper anyway so that whenever it gains journaling
339
+ // it inherits the caller-supplied-runId requirement instead of
340
+ // re-deriving it (see `packages/ai-sandbox/src/durability.ts`).
341
+ const runId = resolveDurableRunId(options.runId, {
342
+ durable: false,
343
+ adapter: 'acp',
344
+ fallback: () => this.generateId(),
345
+ })
335
346
  const threadId = options.threadId ?? this.generateId()
347
+
348
+ // Durability wired onto a path that cannot deliver it. Two outcomes, split
349
+ // by whether a first attempt has already run.
350
+ //
351
+ // ATTACH is fatal. `sandboxRunDriver`'s `drive()` sets `attach: true` only
352
+ // when a previous host was already streaming this run, so continuing past
353
+ // here reaches `startAcpSession` + `session.prompt(...)` and re-runs the
354
+ // agent from scratch against the workspace that attempt already mutated,
355
+ // appending its whole output to a log that still holds the first
356
+ // attempt's. This adapter has no journal to tail, no
357
+ // `awaitAttachableJournal` to refuse the attach up front, and no
358
+ // `alignedIfAttaching` to suppress the already-delivered prefix — so there
359
+ // is nothing between here and that corruption except this throw.
360
+ //
361
+ // A FRESH durable run only fails to be recoverable LATER, which an app may
362
+ // knowingly accept (it can wire `withSandbox({ runs, durability })` once at
363
+ // the middleware level and still route some runs through this adapter). So
364
+ // that is a warn, not a throw: audible, not fatal. Once per run, not per
365
+ // chunk — a per-chunk warning would be worse than none. Mirrors
366
+ // `ai-grok-build`'s `chatStreamAcp`.
367
+ const durability = options.capabilities
368
+ ? getSandboxDurability(options.capabilities, { optional: true })
369
+ : undefined
370
+ if (durability !== undefined) {
371
+ if (durability.attach) {
372
+ throw new DurableAttachNotSupportedError(
373
+ 'acp',
374
+ 'this adapter drives the harness over a bidirectional ACP ' +
375
+ 'connection and does not journal',
376
+ )
377
+ }
378
+ logger.warn(
379
+ 'acp: sandbox durability is wired but this adapter never journals — ' +
380
+ 'this run will not be recoverable on reconnect. Use a journaling ' +
381
+ 'harness adapter for runs that must survive a host restart, or drop ' +
382
+ 'durability if these runs are not meant to.',
383
+ { runId, adapter: 'acp' },
384
+ )
385
+ }
386
+
336
387
  const channel = createBridgeEventChannel({
337
388
  model: this.model,
338
389
  threadId,
@@ -133,7 +133,10 @@ function webSocketNdjsonToAcpStream(ws: WebSocket): AcpJsonRpcStream {
133
133
 
134
134
  const writable = new WritableStream<Uint8Array>({
135
135
  write(chunk) {
136
- ws.send(chunk)
136
+ // TS 5.7+ types Uint8Array as generic over its buffer (ArrayBufferLike),
137
+ // which no longer structurally matches the DOM `BufferSource` param.
138
+ // Runtime accepts any typed array; narrow to the lib's expected type.
139
+ ws.send(chunk as BufferSource)
137
140
  },
138
141
  close() {
139
142
  ws.close()
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}