@tangle-network/agent-provider-cli-bridge 0.9.6 → 0.10.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.
|
@@ -63,7 +63,14 @@ export function narrowCliBridgeCapabilities(adapter, reported, selectedBackend,
|
|
|
63
63
|
};
|
|
64
64
|
const nativeContinuation = supportsCliBridgeNativeContinuation(adapter) &&
|
|
65
65
|
supportsCliBridgeNativeContinuation(reported)
|
|
66
|
-
? {
|
|
66
|
+
? {
|
|
67
|
+
atomicBoundary: true,
|
|
68
|
+
requestIdempotency: true,
|
|
69
|
+
...(adapter.nativeContinuation?.admissionControl === true &&
|
|
70
|
+
reported.nativeContinuation?.admissionControl === true
|
|
71
|
+
? { admissionControl: true }
|
|
72
|
+
: {}),
|
|
73
|
+
}
|
|
67
74
|
: undefined;
|
|
68
75
|
const sessions = {
|
|
69
76
|
continue: adapter.sessions.continue && reported.sessions.continue,
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { agentSessionStatusFromRun, cancelCliBridgeRun, cancelExactCliBridgeRun,
|
|
|
2
2
|
import { addTokenUsage, collectCliBridgeTurnResult, dispatchCliBridgeTurn, streamCliBridgeSessionEvents, streamTrackedCliBridgeTurn, } from "./retained-execution.js";
|
|
3
3
|
import { createExecutionUsageLog, observeCliBridgeEnvironment, } from "./observation.js";
|
|
4
4
|
import { cliBridgeInteractionResponder } from "./interaction-response.js";
|
|
5
|
-
import { assertCliBridgeRequestedInteractions, assertCliBridgeTurnModel, continueCliBridgeNative, readCliBridgeNativeContextBoundary, supportsCliBridgeNativeContinuation, supportsCliBridgeNativeInteractions, } from "./retained-native.js";
|
|
5
|
+
import { assertCliBridgeRequestedInteractions, assertCliBridgeTurnModel, continueCliBridgeNative, readCliBridgeNativeContextBoundary, supportsCliBridgeNativeContinuation, supportsCliBridgeNativeAdmissionControl, supportsCliBridgeNativeInteractions, } from "./retained-native.js";
|
|
6
6
|
import { assertRunMatchesControlRef, exactControlRefForSession, prepareCliBridgeRun, runFromControlRef, } from "./retained-run-state.js";
|
|
7
7
|
import { createCliBridgeTransport } from "./transport.js";
|
|
8
8
|
/**
|
|
@@ -269,7 +269,7 @@ function createCliBridgeSession(args) {
|
|
|
269
269
|
return readCliBridgeNativeContextBoundary(args.options, args.providerName, args.transport, requireCurrentRun(), boundaryOptions?.signal);
|
|
270
270
|
},
|
|
271
271
|
async continueNative(request, continuationOptions) {
|
|
272
|
-
const result = await continueCliBridgeNative(args.options, args.providerName, args.transport, requireCurrentRun(), request, continuationOptions, args.runs);
|
|
272
|
+
const result = await continueCliBridgeNative(args.options, args.providerName, args.transport, requireCurrentRun(), request, continuationOptions, args.runs, supportsCliBridgeNativeAdmissionControl(args.capabilities));
|
|
273
273
|
if ("result" in result && result.result.usage !== undefined) {
|
|
274
274
|
args.usageLog.record(result.controlRef.executionId, result.result.usage);
|
|
275
275
|
}
|
|
@@ -14,6 +14,8 @@ export type CliBridgeNativeSessionCache = Map<string, Promise<CliBridgeNativeSes
|
|
|
14
14
|
export declare function supportsCliBridgeNativeInteractions(capabilities: AgentEnvironmentCapabilities, selectedBackend?: string): boolean;
|
|
15
15
|
/** Native continuation is exposed only when the Bridge proves both guarantees. */
|
|
16
16
|
export declare function supportsCliBridgeNativeContinuation(capabilities: AgentEnvironmentCapabilities): boolean;
|
|
17
|
+
/** Early continuation control is valid only with the complete retained-run contract. */
|
|
18
|
+
export declare function supportsCliBridgeNativeAdmissionControl(capabilities: AgentEnvironmentCapabilities): boolean;
|
|
17
19
|
/** Reject posture the selected environment did not advertise before transport use. */
|
|
18
20
|
export declare function assertCliBridgeRequestedInteractions(capabilities: AgentEnvironmentCapabilities, requested: RequestedInteractions | undefined): void;
|
|
19
21
|
/** Keep capability discovery and every native turn on one exact model route. */
|
|
@@ -21,7 +23,7 @@ export declare function assertCliBridgeTurnModel(options: CliBridgeProviderOptio
|
|
|
21
23
|
/** Read the Bridge-owned exact boundary for the current retained run. */
|
|
22
24
|
export declare function readCliBridgeNativeContextBoundary(options: CliBridgeProviderOptions, providerName: string, transport: CliBridgeTransport, run: CliBridgeRun, signal?: AbortSignal): Promise<NativeContextBoundaryProof | null>;
|
|
23
25
|
/** Send one canonical same-session continuation and advance the live run identity. */
|
|
24
|
-
export declare function continueCliBridgeNative(options: CliBridgeProviderOptions, providerName: string, transport: CliBridgeTransport, run: CliBridgeRun, request: NativeContextContinuationRequest, continuationOptions: AgentNativeContextContinuationOptions, runs: Map<string, CliBridgeRun
|
|
26
|
+
export declare function continueCliBridgeNative(options: CliBridgeProviderOptions, providerName: string, transport: CliBridgeTransport, run: CliBridgeRun, request: NativeContextContinuationRequest, continuationOptions: AgentNativeContextContinuationOptions, runs: Map<string, CliBridgeRun>, admissionControl: boolean): Promise<AgentNativeContextContinuationResult>;
|
|
25
27
|
/**
|
|
26
28
|
* Create or reuse the server's retained native session for one external id.
|
|
27
29
|
*
|
package/dist/retained-native.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentNativeContextContinuationResultSchema, AgentExactRunControlRefSchema, NativeContextBoundaryProofSchema, NativeContextContinuationRequestSchema, RequestedInteractionsSchema, agentNativeContextContinuationResultMatchesRequest, canonicalCandidateDigest, nativeContextContinuationTurnDigest, sameAgentRunControlRef, } from "@tangle-network/agent-interface";
|
|
1
|
+
import { AgentNativeContextContinuationResultSchema, AgentNativeContextContinuationAdmissionSchema, AgentExactRunControlRefSchema, NativeContextBoundaryProofSchema, NativeContextContinuationRequestSchema, RequestedInteractionsSchema, agentNativeContextContinuationResultMatchesRequest, agentNativeContextContinuationAdmissionMatchesRequest, canonicalCandidateDigest, nativeContextContinuationTurnDigest, sameAgentRunControlRef, } from "@tangle-network/agent-interface";
|
|
2
2
|
import { CliBridgeRequestRejectedError } from "./retained-stream.js";
|
|
3
3
|
import { advanceCliBridgeRun, exactControlRefForRun, } from "./retained-run-state.js";
|
|
4
4
|
import { MAX_CLI_BRIDGE_CONTROL_RESPONSE_BYTES, readBoundedCliBridgeResponse, requestHeaders, trimSlash, } from "./transport.js";
|
|
@@ -26,6 +26,16 @@ export function supportsCliBridgeNativeContinuation(capabilities) {
|
|
|
26
26
|
capabilities.nativeContinuation?.atomicBoundary === true &&
|
|
27
27
|
capabilities.nativeContinuation.requestIdempotency === true);
|
|
28
28
|
}
|
|
29
|
+
/** Early continuation control is valid only with the complete retained-run contract. */
|
|
30
|
+
export function supportsCliBridgeNativeAdmissionControl(capabilities) {
|
|
31
|
+
const retained = capabilities.retainedControl;
|
|
32
|
+
return Boolean(supportsCliBridgeNativeContinuation(capabilities) &&
|
|
33
|
+
capabilities.nativeContinuation?.admissionControl === true &&
|
|
34
|
+
retained?.exactRunIdentity === true &&
|
|
35
|
+
retained.resultIdentity === true &&
|
|
36
|
+
retained.eventIdentity === true &&
|
|
37
|
+
retained.cancellationIdempotency === true);
|
|
38
|
+
}
|
|
29
39
|
/** Reject posture the selected environment did not advertise before transport use. */
|
|
30
40
|
export function assertCliBridgeRequestedInteractions(capabilities, requested) {
|
|
31
41
|
if (requested === undefined)
|
|
@@ -88,7 +98,7 @@ export async function readCliBridgeNativeContextBoundary(options, providerName,
|
|
|
88
98
|
return proof.data;
|
|
89
99
|
}
|
|
90
100
|
/** Send one canonical same-session continuation and advance the live run identity. */
|
|
91
|
-
export async function continueCliBridgeNative(options, providerName, transport, run, request, continuationOptions, runs) {
|
|
101
|
+
export async function continueCliBridgeNative(options, providerName, transport, run, request, continuationOptions, runs, admissionControl) {
|
|
92
102
|
const exactRequest = NativeContextContinuationRequestSchema.parse(request);
|
|
93
103
|
const current = currentCliBridgeControlRef(run, providerName);
|
|
94
104
|
if (!sameAgentRunControlRef(current, exactRequest.run)) {
|
|
@@ -98,37 +108,99 @@ export async function continueCliBridgeNative(options, providerName, transport,
|
|
|
98
108
|
exactRequest.turnDigest) {
|
|
99
109
|
throw new Error("cli-bridge native continuation turn does not match its request digest");
|
|
100
110
|
}
|
|
111
|
+
if (continuationOptions.onAdmission !== undefined && !admissionControl) {
|
|
112
|
+
throw new Error("cli-bridge native continuation does not advertise early admission control");
|
|
113
|
+
}
|
|
101
114
|
const operation = continuationSignal(continuationOptions);
|
|
115
|
+
const endpoint = `${trimSlash(options.baseUrl)}/v1/sessions/${encodeURIComponent(exactRequest.run.sessionId)}/continue`;
|
|
116
|
+
const body = JSON.stringify({ request: exactRequest, turn: continuationOptions.turn });
|
|
117
|
+
const requestInit = {
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: requestHeaders(options),
|
|
120
|
+
body,
|
|
121
|
+
...(operation.signal ? { signal: operation.signal } : {}),
|
|
122
|
+
};
|
|
102
123
|
try {
|
|
103
124
|
operation.signal?.throwIfAborted();
|
|
104
|
-
const response = await transport.fetch(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
body: JSON.stringify({ request: exactRequest, turn: continuationOptions.turn }),
|
|
108
|
-
...(operation.signal ? { signal: operation.signal } : {}),
|
|
109
|
-
});
|
|
125
|
+
const response = await transport.fetch(continuationOptions.onAdmission === undefined
|
|
126
|
+
? endpoint
|
|
127
|
+
: `${endpoint}?return=admission`, requestInit);
|
|
110
128
|
const responseText = await readBoundedCliBridgeResponse(response, MAX_NATIVE_CONTINUATION_RESPONSE_BYTES, operation.signal);
|
|
129
|
+
if (continuationOptions.onAdmission !== undefined && response.status === 202) {
|
|
130
|
+
const admission = parseNativeContinuationAdmission(responseText);
|
|
131
|
+
assertContinuationAdmissionBinding(exactRequest, admission);
|
|
132
|
+
assertContinuationAdmissionHeaders(response, admission.controlRef);
|
|
133
|
+
advanceCliBridgeRun(run, admission.controlRef, providerName, runs);
|
|
134
|
+
continuationOptions.onAdmission(admission.controlRef);
|
|
135
|
+
operation.signal?.throwIfAborted();
|
|
136
|
+
const terminalResponse = await transport.fetch(endpoint, requestInit);
|
|
137
|
+
const terminalText = await readBoundedCliBridgeResponse(terminalResponse, MAX_NATIVE_CONTINUATION_RESPONSE_BYTES, operation.signal);
|
|
138
|
+
return acceptNativeContinuationResult(terminalResponse, terminalText, exactRequest, run, providerName, runs);
|
|
139
|
+
}
|
|
111
140
|
const outcome = parseNativeContinuationResult(responseText);
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
throw new Error("cli-bridge native continuation returned an acknowledgement for another request");
|
|
117
|
-
}
|
|
118
|
-
if (!response.ok) {
|
|
119
|
-
throw new Error(`cli-bridge native continuation returned HTTP ${response.status} for an accepted result`);
|
|
120
|
-
}
|
|
121
|
-
if (!("controlRef" in outcome)) {
|
|
122
|
-
throw new Error("cli-bridge native continuation omitted its current control reference");
|
|
123
|
-
}
|
|
124
|
-
advanceCliBridgeRun(run, outcome.controlRef, providerName, runs);
|
|
141
|
+
if (continuationOptions.onAdmission !== undefined &&
|
|
142
|
+
(outcome.acknowledgement.status === "accepted" ||
|
|
143
|
+
outcome.acknowledgement.status === "replayed")) {
|
|
144
|
+
throw new Error("cli-bridge native continuation omitted its advertised early admission");
|
|
125
145
|
}
|
|
126
|
-
return outcome;
|
|
146
|
+
return acceptParsedNativeContinuationResult(response, outcome, exactRequest, run, providerName, runs);
|
|
127
147
|
}
|
|
128
148
|
finally {
|
|
129
149
|
operation.dispose();
|
|
130
150
|
}
|
|
131
151
|
}
|
|
152
|
+
function acceptNativeContinuationResult(response, responseText, request, run, providerName, runs) {
|
|
153
|
+
return acceptParsedNativeContinuationResult(response, parseNativeContinuationResult(responseText), request, run, providerName, runs);
|
|
154
|
+
}
|
|
155
|
+
function acceptParsedNativeContinuationResult(response, outcome, exactRequest, run, providerName, runs) {
|
|
156
|
+
assertContinuationAcknowledgementBinding(exactRequest, outcome);
|
|
157
|
+
if (outcome.acknowledgement.status === "accepted" ||
|
|
158
|
+
outcome.acknowledgement.status === "replayed") {
|
|
159
|
+
if (!agentNativeContextContinuationResultMatchesRequest(exactRequest, outcome)) {
|
|
160
|
+
throw new Error("cli-bridge native continuation returned an acknowledgement for another request");
|
|
161
|
+
}
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
throw new Error(`cli-bridge native continuation returned HTTP ${response.status} for an accepted result`);
|
|
164
|
+
}
|
|
165
|
+
if (!("controlRef" in outcome)) {
|
|
166
|
+
throw new Error("cli-bridge native continuation omitted its current control reference");
|
|
167
|
+
}
|
|
168
|
+
advanceCliBridgeRun(run, outcome.controlRef, providerName, runs);
|
|
169
|
+
}
|
|
170
|
+
return outcome;
|
|
171
|
+
}
|
|
172
|
+
function parseNativeContinuationAdmission(value) {
|
|
173
|
+
const parsed = safeJson(value);
|
|
174
|
+
try {
|
|
175
|
+
return AgentNativeContextContinuationAdmissionSchema.parse(parsed);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
throw new Error("cli-bridge native continuation returned an invalid admission", {
|
|
179
|
+
cause: error,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function assertContinuationAdmissionBinding(request, admission) {
|
|
184
|
+
if (!agentNativeContextContinuationAdmissionMatchesRequest(request, admission)) {
|
|
185
|
+
throw new Error("cli-bridge native continuation admission is not bound to the request");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function assertContinuationAdmissionHeaders(response, controlRef) {
|
|
189
|
+
const expected = new Map([
|
|
190
|
+
["x-run-id", controlRef.runId],
|
|
191
|
+
["x-run-request-digest", controlRef.requestDigest],
|
|
192
|
+
["x-run-provider", controlRef.provider],
|
|
193
|
+
["x-run-environment-id", controlRef.environmentId],
|
|
194
|
+
["x-run-session-id", controlRef.sessionId],
|
|
195
|
+
["x-run-execution-id", controlRef.executionId],
|
|
196
|
+
["location", `/v1/runs/${encodeURIComponent(controlRef.runId)}`],
|
|
197
|
+
]);
|
|
198
|
+
for (const [name, value] of expected) {
|
|
199
|
+
if (response.headers.get(name) !== value) {
|
|
200
|
+
throw new Error(`cli-bridge native continuation admission has invalid ${name}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
132
204
|
function currentCliBridgeControlRef(run, providerName) {
|
|
133
205
|
if (run.controlRef !== undefined) {
|
|
134
206
|
const controlRef = AgentExactRunControlRefSchema.parse(run.controlRef);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-provider-cli-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "AgentEnvironmentProvider adapter for cli-bridge retained sessions and one-shot turns",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"LICENSE"
|
|
60
60
|
],
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@tangle-network/agent-interface": "^1.
|
|
62
|
+
"@tangle-network/agent-interface": "^1.8.0",
|
|
63
63
|
"undici": "7.29.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|