@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 +10 -0
- package/dist/capability-discovery.js +5 -0
- package/dist/index.js +7 -1
- package/dist/retained-execution.d.ts +1 -1
- package/dist/retained-execution.js +17 -4
- package/dist/wire.js +11 -5
- package/package.json +7 -4
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
...(
|
|
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
|
-
...(
|
|
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.
|
|
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": "^
|
|
65
|
-
"undici": "
|
|
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
|
}
|