@tangle-network/agent-provider-cli-bridge 0.11.0 → 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.
package/README.md CHANGED
@@ -78,6 +78,14 @@ Retained native sessions currently require `kind: 'host'`.
78
78
  The provider rejects a sandbox default before it creates the retained session; use one-shot execution for `kind: 'sandbox'`.
79
79
  The Bridge currently refuses `netJail` with `kind: 'sandbox'`; use the sandbox's own egress policy.
80
80
 
81
+ ### Native workspace cwd
82
+
83
+ CLI Bridge accepts `workspace.cwd` only when its `base` is `"host"`.
84
+ Its `path` is a native host process directory, so it may be absolute or empty.
85
+ The adapter rejects a repository-based cwd before it sends a Bridge request.
86
+ Tangle Sandbox accepts `workspace.cwd` with `base: "repository"` and a portable POSIX path.
87
+ The capability document reports these supported cwd bases under `workspace.cwdBases`.
88
+
81
89
  Passing the same `sessionId` on later turns continues the same CLI conversation while the creating process still holds the environment.
82
90
  `executionId` gives a turn stable bridge identity, and `lastEventId` reattaches after a reader failure.
83
91
  `dispatch()` starts a bridge-owned durable run and returns after detaching its HTTP reader.
@@ -85,6 +93,8 @@ The returned `AgentSession` exposes status, cursor-based event replay, the termi
85
93
  Cancellation returns only after cli-bridge confirms the run is terminal.
86
94
  A direct stream treats a finish frame as provisional until cli-bridge returns the same run's aggregate result.
87
95
  A retained replay confirms its terminal state from the retained run endpoint.
96
+ Terminal results retain the newest 1,024 events and preserve full text and usage totals.
97
+ Use `session.events()` when a caller needs the complete retained event history.
88
98
  Retained native runs use canonical runtime envelopes and finish with a terminal status event.
89
99
  Pass any emitted event `id` back as `since` to resume after that event.
90
100
  The canonical envelope identity remains available as `event.data.eventId`.
@@ -147,6 +147,11 @@ export function narrowCliBridgeCapabilities(adapter, reported, selectedBackend,
147
147
  git: false,
148
148
  upload: false,
149
149
  download: false,
150
+ // Host cwd support belongs to this adapter's process transport. The
151
+ // remote backend document does not own or describe that path.
152
+ ...(adapter.workspace.cwdBases === undefined
153
+ ? {}
154
+ : { cwdBases: adapter.workspace.cwdBases }),
150
155
  },
151
156
  branching: { checkpoint: false, fork: false },
152
157
  placement: adapter.placement && reported.placement,
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { agentEnvironmentCreateInputDigest, createAgentEnvironmentWithIdempotency, } from "@tangle-network/agent-interface/environment-provider";
2
- import { harnessTypeSchema, harnessSystemPromptIntents, snapshotAgentProfile, } from "@tangle-network/agent-interface";
2
+ import { harnessTypeSchema, harnessSystemPromptIntents, snapshotAgentProfile, WorkspaceRequestSchema, workspaceCwdPathForBase, } from "@tangle-network/agent-interface";
3
3
  import { createCliBridgeEnvironment, } from "./retained-environment.js";
4
4
  import { lookupExactCliBridgeRun, } from "./retained-control.js";
5
5
  import { cachedCliBridgeCapabilityDiscovery, narrowCliBridgeCapabilities, } from "./capability-discovery.js";
@@ -57,10 +57,15 @@ export function createCliBridgeProvider(options) {
57
57
  if (typeof input.profile === "string") {
58
58
  throw new Error(`createCliBridgeProvider requires an inline AgentProfile; named profile "${input.profile}" is unsupported`);
59
59
  }
60
+ const workspace = input.workspace === undefined
61
+ ? undefined
62
+ : WorkspaceRequestSchema.parse(input.workspace);
63
+ workspaceCwdPathForBase(workspace?.cwd, "host", "CLI Bridge");
60
64
  const profile = snapshotAgentProfile(input.profile);
61
65
  const environmentInput = {
62
66
  ...input,
63
67
  profile,
68
+ ...(workspace === undefined ? {} : { workspace }),
64
69
  };
65
70
  const selectedBackend = selectedBackendFromInput(environmentInput, configuredBackend);
66
71
  const hasEnvironmentModel = selectedBackend !== undefined ||
@@ -225,6 +230,7 @@ export function defaultCliBridgeCapabilities(harness) {
225
230
  git: false,
226
231
  upload: false,
227
232
  download: false,
233
+ cwdBases: { repository: false, host: true },
228
234
  },
229
235
  branching: { checkpoint: false, fork: false },
230
236
  placement: true,
@@ -1,4 +1,4 @@
1
- import type { TokenUsage } from "@tangle-network/agent-interface";
1
+ import { type TokenUsage } from "@tangle-network/agent-interface";
2
2
  import type { AgentEnvironmentEvent, AgentSessionRef, AgentTurnResult, CreateAgentEnvironmentInput } from "@tangle-network/agent-interface/environment-provider";
3
3
  import type { CliBridgeProviderOptions } from "./provider-options.js";
4
4
  import { type CliBridgeRun, type CliBridgeSessionState, type PreparedCliBridgeRun } from "./retained-run-state.js";
@@ -1,3 +1,4 @@
1
+ import { AgentTurnResultSchema, } from "@tangle-network/agent-interface";
1
2
  import { cancelCliBridgeRun, captureCliBridgeRunIdentity, cliBridgeCancellationSignal, detachCliBridgeReader, getCliBridgeRun, } from "./retained-control.js";
2
3
  import { bindCliBridgeRun, bindCliBridgeSession, exactControlRefForRun, restoreCliBridgeRun, restoreCliBridgeSession, } from "./retained-run-state.js";
3
4
  import { CliBridgeRequestRejectedError, streamCliBridgeTurn, } from "./retained-stream.js";
@@ -5,6 +6,7 @@ import { beginCliBridgeNativeTurn, } from "./retained-native.js";
5
6
  import { MAX_CLI_BRIDGE_CONTROL_RESPONSE_BYTES, readBoundedCliBridgeResponse, requestHeaders, trimSlash, } from "./transport.js";
6
7
  import { modelRequestCount } from "./wire.js";
7
8
  import { lookupCliBridgeContext } from "./context-transfer.js";
9
+ const MAX_CLI_BRIDGE_RESULT_EVENTS = 1_024;
8
10
  export async function* streamTrackedCliBridgeTurn(options, environmentInput, providerName, prepared, transport, runs, sessions, readers, nativeSessions, useNativeInteractions) {
9
11
  const originalTurn = prepared.turn;
10
12
  if (originalTurn.detach) {
@@ -252,6 +254,7 @@ function assertCanonicalEventBinding(event, run, providerName) {
252
254
  }
253
255
  export async function collectCliBridgeTurnResult(source, run, options, transport, signal) {
254
256
  const events = [];
257
+ let eventCount = 0;
255
258
  let text = "";
256
259
  let usage;
257
260
  let observedModelRequests = 0;
@@ -262,7 +265,11 @@ export async function collectCliBridgeTurnResult(source, run, options, transport
262
265
  let streamError;
263
266
  try {
264
267
  for await (const event of source) {
265
- events.push(event);
268
+ if (eventCount < MAX_CLI_BRIDGE_RESULT_EVENTS)
269
+ events.push(event);
270
+ else
271
+ events[eventCount % MAX_CLI_BRIDGE_RESULT_EVENTS] = event;
272
+ eventCount += 1;
266
273
  const finalText = event.data.finalText;
267
274
  if (typeof finalText === "string") {
268
275
  text = finalText;
@@ -307,7 +314,13 @@ export async function collectCliBridgeTurnResult(source, run, options, transport
307
314
  throw new Error(`cli-bridge run "${run.id}" has no terminal result`);
308
315
  }
309
316
  const success = snapshot.status === "done" && streamError === undefined;
310
- return {
317
+ const resultEvents = eventCount <= MAX_CLI_BRIDGE_RESULT_EVENTS
318
+ ? events
319
+ : [
320
+ ...events.slice(eventCount % MAX_CLI_BRIDGE_RESULT_EVENTS),
321
+ ...events.slice(0, eventCount % MAX_CLI_BRIDGE_RESULT_EVENTS),
322
+ ];
323
+ return AgentTurnResultSchema.parse({
311
324
  text,
312
325
  success,
313
326
  ...(!success
@@ -335,8 +348,8 @@ export async function collectCliBridgeTurnResult(source, run, options, transport
335
348
  ...(servedModel === undefined ? {} : { model: servedModel }),
336
349
  ...(systemFingerprint === undefined ? {} : { system_fingerprint: systemFingerprint }),
337
350
  },
338
- events,
339
- };
351
+ events: resultEvents,
352
+ });
340
353
  }
341
354
  /** Keep reasoning and tool updates out of the assistant's visible result text. */
342
355
  export function visibleTextDelta(event) {
package/dist/wire.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import { AgentExactRunControlRefSchema, RequestedInteractionsSchema, } from "@tangle-network/agent-interface";
2
+ import { AgentExactRunControlRefSchema, RequestedInteractionsSchema, WorkspaceRequestSchema, workspaceCwdPathForBase, } from "@tangle-network/agent-interface";
3
3
  export function toChatCompletionsBody(options, environmentInput, turn, coordinates) {
4
4
  const profile = inlineProfile(environmentInput.profile);
5
5
  const execution = executionFromInput(options, environmentInput);
6
+ const workspaceCwd = bridgeWorkspaceCwd(environmentInput);
6
7
  const interactions = turn.interactions === undefined
7
8
  ? undefined
8
9
  : RequestedInteractionsSchema.parse(turn.interactions);
@@ -21,7 +22,7 @@ export function toChatCompletionsBody(options, environmentInput, turn, coordinat
21
22
  ? { effort: profile.model.reasoningEffort }
22
23
  : {}),
23
24
  ...(environmentInput.env ? { env: environmentInput.env } : {}),
24
- ...(environmentInput.workspace?.cwd ? { cwd: environmentInput.workspace.cwd } : {}),
25
+ ...(workspaceCwd === undefined ? {} : { cwd: workspaceCwd }),
25
26
  ...(execution ? { execution } : {}),
26
27
  ...(interactions === undefined ? {} : { interactions }),
27
28
  ...(turn.contextTransfer === undefined
@@ -55,14 +56,13 @@ export function resolveBridgeModel(options, environmentInput, turn, profile) {
55
56
  }
56
57
  export function toRetainedSessionBody(options, environmentInput, profile, sessionId, model) {
57
58
  const execution = retainedExecutionFromInput(options, environmentInput);
59
+ const workspaceCwd = bridgeWorkspaceCwd(environmentInput);
58
60
  return {
59
61
  id: sessionId,
60
62
  model,
61
63
  interaction_policy: "interactive",
62
64
  ...(options.defaultMode ? { mode: options.defaultMode } : {}),
63
- ...(environmentInput.workspace?.cwd !== undefined
64
- ? { cwd: environmentInput.workspace.cwd }
65
- : {}),
65
+ ...(workspaceCwd === undefined ? {} : { cwd: workspaceCwd }),
66
66
  ...(execution !== undefined ? { execution } : {}),
67
67
  ...(profile ? { agent_profile: profile } : {}),
68
68
  ...(environmentInput.env !== undefined ? { env: environmentInput.env } : {}),
@@ -176,6 +176,12 @@ function retainedExecutionFromInput(options, input) {
176
176
  }
177
177
  return execution;
178
178
  }
179
+ function bridgeWorkspaceCwd(input) {
180
+ const workspace = input.workspace === undefined
181
+ ? undefined
182
+ : WorkspaceRequestSchema.parse(input.workspace);
183
+ return workspaceCwdPathForBase(workspace?.cwd, "host", "CLI Bridge");
184
+ }
179
185
  export async function* parseSse(body) {
180
186
  const decoder = new TextDecoder();
181
187
  let buffer = "";
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-provider-cli-bridge",
3
- "version": "0.11.0",
3
+ "version": "1.0.0",
4
4
  "description": "AgentEnvironmentProvider adapter for cli-bridge retained sessions and one-shot turns",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.19.0"
9
+ },
7
10
  "main": "./dist/index.js",
8
11
  "types": "./dist/index.d.ts",
9
12
  "exports": {
@@ -61,8 +64,8 @@
61
64
  "LICENSE"
62
65
  ],
63
66
  "dependencies": {
64
- "@tangle-network/agent-interface": "^1.9.0",
65
- "undici": "7.29.0"
67
+ "@tangle-network/agent-interface": "^2.0.0",
68
+ "undici": "8.10.0"
66
69
  },
67
70
  "devDependencies": {
68
71
  "@types/node": "26.4.0",
@@ -74,6 +77,6 @@
74
77
  "check-types": "tsc --noEmit",
75
78
  "clean": "rm -rf dist",
76
79
  "test": "vitest run src",
77
- "test:integration": "test -n \"$CLI_BRIDGE_INTEGRATION_ROOT\" || { echo 'CLI_BRIDGE_INTEGRATION_ROOT is required; see README' >&2; exit 1; }; vitest run tests/cli-bridge.integration.test.ts"
80
+ "test:integration": "test -n \"$CLI_BRIDGE_INTEGRATION_ROOT\" || { echo 'CLI_BRIDGE_INTEGRATION_ROOT is required; see README' >&2; exit 1; }; pnpm run build && vitest run tests/cli-bridge.integration.test.ts"
78
81
  }
79
82
  }