@tangle-network/agent-provider-tangle 0.12.2 → 0.13.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 +4 -5
- package/dist/tangle-capabilities.d.ts +8 -0
- package/dist/tangle-capabilities.js +29 -0
- package/dist/tangle-provider.js +93 -66
- package/dist/tangle-types.d.ts +5 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# @tangle-network/agent-provider-tangle
|
|
2
2
|
|
|
3
3
|
Wraps `@tangle-network/sandbox` as an `AgentEnvironmentProvider`.
|
|
4
|
-
The peer range is `>=0.
|
|
5
|
-
The floor is 0.
|
|
6
|
-
The
|
|
7
|
-
|
|
8
|
-
This adapter never falls back to it.
|
|
4
|
+
The peer range is `>=0.30.1 <1.0.0`, and this package is developed and tested against 0.30.1.
|
|
5
|
+
The floor is 0.30.1 because interaction claims use the Sandbox backend catalog exposed by `listBackends()`.
|
|
6
|
+
The provider fails closed when the configured backend or its catalog entry cannot be read.
|
|
7
|
+
Newer SDKs may also provide `getBackend()` as a lookup over the same catalog.
|
|
9
8
|
|
|
10
9
|
```ts
|
|
11
10
|
import { Sandbox } from '@tangle-network/sandbox'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentEnvironmentCapabilities, HarnessType } from "@tangle-network/agent-interface";
|
|
2
|
+
import type { BackendRegistryEntry } from "@tangle-network/sandbox";
|
|
2
3
|
import type { SandboxClientLike, SandboxInstanceLike } from "./tangle-types.js";
|
|
3
4
|
import type { DeploymentCapabilitySupport } from "./tangle-deployment-capabilities.js";
|
|
4
5
|
import type { ResourceProfile } from "@tangle-network/agent-interface";
|
|
@@ -13,6 +14,13 @@ import { type ObservationSurfaceSupport } from "./tangle-observation.js";
|
|
|
13
14
|
* nothing backs becomes an action the caller selects and finds missing.
|
|
14
15
|
*/
|
|
15
16
|
export declare function defaultTangleSandboxCapabilities(harness?: HarnessType): AgentEnvironmentCapabilities;
|
|
17
|
+
/**
|
|
18
|
+
* Keep only interaction kinds the selected Sandbox backend advertises.
|
|
19
|
+
*
|
|
20
|
+
* The backend catalog is the authority for harness-specific interactions.
|
|
21
|
+
* An absent entry means the provider cannot prove any interaction support.
|
|
22
|
+
*/
|
|
23
|
+
export declare function narrowTangleCapabilitiesToBackend(declared: AgentEnvironmentCapabilities, backend: BackendRegistryEntry | undefined): AgentEnvironmentCapabilities;
|
|
16
24
|
/**
|
|
17
25
|
* Adapter-surface facts that gate declared capabilities: which methods this
|
|
18
26
|
* process can actually call. Every fact defaults to false when it cannot be
|
|
@@ -114,6 +114,35 @@ export function defaultTangleSandboxCapabilities(harness) {
|
|
|
114
114
|
},
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Keep only interaction kinds the selected Sandbox backend advertises.
|
|
119
|
+
*
|
|
120
|
+
* The backend catalog is the authority for harness-specific interactions.
|
|
121
|
+
* An absent entry means the provider cannot prove any interaction support.
|
|
122
|
+
*/
|
|
123
|
+
export function narrowTangleCapabilitiesToBackend(declared, backend) {
|
|
124
|
+
if (declared.interactions === undefined || backend === undefined) {
|
|
125
|
+
if (declared.interactions === undefined)
|
|
126
|
+
return declared;
|
|
127
|
+
const narrowed = { ...declared };
|
|
128
|
+
delete narrowed.interactions;
|
|
129
|
+
return narrowed;
|
|
130
|
+
}
|
|
131
|
+
const supportedKinds = new Set(backend.capabilities.interactions);
|
|
132
|
+
const kinds = declared.interactions.kinds.filter((kind) => supportedKinds.has(kind));
|
|
133
|
+
if (kinds.length === 0) {
|
|
134
|
+
const narrowed = { ...declared };
|
|
135
|
+
delete narrowed.interactions;
|
|
136
|
+
return narrowed;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
...declared,
|
|
140
|
+
interactions: {
|
|
141
|
+
...declared.interactions,
|
|
142
|
+
kinds,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
117
146
|
// One reserved id names both probe handles; neither ever reaches the service.
|
|
118
147
|
const CAPABILITY_PROBE_ID = "__tangle-capability-probe__";
|
|
119
148
|
export function sandboxCapabilitySupport(box, client, requestedResources) {
|
package/dist/tangle-provider.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AgentEnvironmentCapabilitiesSchema } from "@tangle-network/agent-interface/environment-provider";
|
|
1
|
+
import { AgentEnvironmentCapabilitiesSchema, createAgentEnvironmentWithIdempotency, } from "@tangle-network/agent-interface/environment-provider";
|
|
2
2
|
import { createTangleExactProcessProvider, } from "./exact-process.js";
|
|
3
|
-
import { capabilitiesForClient, defaultTangleSandboxCapabilities, } from "./tangle-capabilities.js";
|
|
3
|
+
import { capabilitiesForClient, defaultTangleSandboxCapabilities, narrowTangleCapabilitiesToBackend, } from "./tangle-capabilities.js";
|
|
4
4
|
import { sandboxInstanceAsEnvironment } from "./tangle-environment.js";
|
|
5
5
|
import { assertCreateInputShape, assertMappedCreateOptions, assertMappedSecretNames, assertNoInlineSecretValues, sandboxOptionsFromCreateInput } from "./tangle-create-options.js";
|
|
6
6
|
import { statusFromUnknown } from "./tangle-environment-values.js";
|
|
@@ -25,85 +25,97 @@ export function createTangleProvider(options) {
|
|
|
25
25
|
if (!exactProcess && configured.exactProcess) {
|
|
26
26
|
throw new Error("Tangle capabilities cannot advertise exactProcess without exactProcess configuration");
|
|
27
27
|
}
|
|
28
|
+
const backend = configured.interactions === undefined
|
|
29
|
+
? undefined
|
|
30
|
+
: await resolveDefaultBackend(options.client, options.defaultBackend);
|
|
31
|
+
const narrowed = narrowTangleCapabilitiesToBackend(configured, backend);
|
|
28
32
|
return exactProcess
|
|
29
33
|
? {
|
|
30
|
-
...
|
|
34
|
+
...narrowed,
|
|
31
35
|
exactProcess: { egress: ["blocked", "strict"] },
|
|
32
36
|
}
|
|
33
|
-
:
|
|
37
|
+
: narrowed;
|
|
34
38
|
};
|
|
35
39
|
// Provider-boundary document: client-stage facts only. It also validates
|
|
36
40
|
// the configured document, so create() and get() call it before any effect.
|
|
37
41
|
const narrowedProviderCapabilities = (declared) => AgentEnvironmentCapabilitiesSchema.parse(capabilitiesForClient(declared, options.client));
|
|
38
42
|
const resolveCapabilities = async () => narrowedProviderCapabilities(await resolveDeclaredCapabilities());
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const createRecords = new Map();
|
|
44
|
+
const createEnvironment = async (input) => {
|
|
45
|
+
assertCreateInputShape(input);
|
|
46
|
+
input.signal?.throwIfAborted();
|
|
47
|
+
assertNoInlineSecretValues(input);
|
|
48
|
+
if (input.providerOptions && Object.keys(input.providerOptions).length > 0) {
|
|
49
|
+
throw new Error("Tangle create providerOptions are not supported");
|
|
50
|
+
}
|
|
51
|
+
// The sandbox stage narrows from the declared document, not the
|
|
52
|
+
// provider-boundary one: the client stage cannot observe box-scoped
|
|
53
|
+
// facts, so measured instance facts must decide them per sandbox.
|
|
54
|
+
const declaredCapabilities = await resolveDeclaredCapabilities();
|
|
55
|
+
narrowedProviderCapabilities(declaredCapabilities);
|
|
56
|
+
const createOptions = options.mapCreateInput?.(input) ??
|
|
57
|
+
sandboxOptionsFromCreateInput(input, options.defaultBackend ?? "opencode");
|
|
58
|
+
assertMappedCreateOptions(createOptions);
|
|
59
|
+
if (input.idempotencyKey !== undefined &&
|
|
60
|
+
createOptions.idempotencyKey !== input.idempotencyKey) {
|
|
61
|
+
throw new Error("Tangle mapped create options must preserve input idempotencyKey");
|
|
62
|
+
}
|
|
63
|
+
assertMappedSecretNames(createOptions);
|
|
64
|
+
input.signal?.throwIfAborted();
|
|
65
|
+
const createPromise = options.client.create(createOptions, input.signal ? { signal: input.signal } : undefined);
|
|
66
|
+
let box;
|
|
67
|
+
try {
|
|
68
|
+
box = await awaitWithSignal(createPromise, input.signal);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
if (input.signal?.aborted) {
|
|
72
|
+
void createPromise
|
|
73
|
+
.then(async (lateBox) => {
|
|
74
|
+
if (!lateBox.delete) {
|
|
75
|
+
attachCleanupHandle(error, lateBox);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
await lateBox.delete();
|
|
80
|
+
}
|
|
81
|
+
catch (cleanupError) {
|
|
82
|
+
attachCleanupHandle(error, lateBox, cleanupError);
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
.catch((lateError) => attachCleanupHandle(error, undefined, lateError));
|
|
50
86
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const declaredCapabilities = await resolveDeclaredCapabilities();
|
|
55
|
-
narrowedProviderCapabilities(declaredCapabilities);
|
|
56
|
-
const createOptions = options.mapCreateInput?.(input) ??
|
|
57
|
-
sandboxOptionsFromCreateInput(input, options.defaultBackend ?? "opencode");
|
|
58
|
-
assertMappedCreateOptions(createOptions);
|
|
59
|
-
assertMappedSecretNames(createOptions);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
60
90
|
input.signal?.throwIfAborted();
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!lateBox.delete) {
|
|
71
|
-
attachCleanupHandle(error, lateBox);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
await lateBox.delete();
|
|
76
|
-
}
|
|
77
|
-
catch (cleanupError) {
|
|
78
|
-
attachCleanupHandle(error, lateBox, cleanupError);
|
|
79
|
-
}
|
|
80
|
-
})
|
|
81
|
-
.catch((lateError) => attachCleanupHandle(error, undefined, lateError));
|
|
82
|
-
}
|
|
83
|
-
throw error;
|
|
91
|
+
const requestedResources = requestedResourceProfile(input.resources);
|
|
92
|
+
const environment = await sandboxInstanceAsEnvironment(box, providerName, options.client, declaredCapabilities, input.signal ? { signal: input.signal } : undefined, requestedResources === undefined ? undefined : { resources: requestedResources });
|
|
93
|
+
input.signal?.throwIfAborted();
|
|
94
|
+
return environment;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (!box.delete) {
|
|
98
|
+
const baseError = error instanceof Error ? error : new Error(String(error));
|
|
99
|
+
throw Object.assign(baseError, { cleanupHandle: box });
|
|
84
100
|
}
|
|
85
101
|
try {
|
|
86
|
-
|
|
87
|
-
const requestedResources = requestedResourceProfile(input.resources);
|
|
88
|
-
const environment = await sandboxInstanceAsEnvironment(box, providerName, options.client, declaredCapabilities, input.signal ? { signal: input.signal } : undefined, requestedResources === undefined ? undefined : { resources: requestedResources });
|
|
89
|
-
input.signal?.throwIfAborted();
|
|
90
|
-
return environment;
|
|
102
|
+
await box.delete();
|
|
91
103
|
}
|
|
92
|
-
catch (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
await box.delete();
|
|
99
|
-
}
|
|
100
|
-
catch (cleanupError) {
|
|
101
|
-
const combined = new AggregateError([error, cleanupError], "Tangle environment validation and cleanup both failed");
|
|
102
|
-
attachCleanupHandle(combined, box, cleanupError);
|
|
103
|
-
throw combined;
|
|
104
|
-
}
|
|
105
|
-
throw error;
|
|
104
|
+
catch (cleanupError) {
|
|
105
|
+
const combined = new AggregateError([error, cleanupError], "Tangle environment validation and cleanup both failed");
|
|
106
|
+
attachCleanupHandle(combined, box, cleanupError);
|
|
107
|
+
throw combined;
|
|
106
108
|
}
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
name: providerName,
|
|
114
|
+
...(exactProcess ? { exactProcess } : {}),
|
|
115
|
+
capabilities: resolveCapabilities,
|
|
116
|
+
...(options.validateProfile ? { validateProfile: options.validateProfile } : {}),
|
|
117
|
+
create(input) {
|
|
118
|
+
return createAgentEnvironmentWithIdempotency(createRecords, input, () => createEnvironment(input));
|
|
107
119
|
},
|
|
108
120
|
...(options.client.get
|
|
109
121
|
? {
|
|
@@ -176,6 +188,21 @@ export function createTangleProvider(options) {
|
|
|
176
188
|
: {}),
|
|
177
189
|
};
|
|
178
190
|
}
|
|
191
|
+
async function resolveDefaultBackend(client, defaultBackend) {
|
|
192
|
+
if (defaultBackend === undefined)
|
|
193
|
+
return undefined;
|
|
194
|
+
try {
|
|
195
|
+
if (client.getBackend)
|
|
196
|
+
return await client.getBackend(defaultBackend);
|
|
197
|
+
if (!client.listBackends)
|
|
198
|
+
return undefined;
|
|
199
|
+
const catalog = await client.listBackends();
|
|
200
|
+
return catalog.backends.find((backend) => backend.type === defaultBackend);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
179
206
|
function assertProviderOperationOptions(options, label) {
|
|
180
207
|
if (options === undefined)
|
|
181
208
|
return;
|
package/dist/tangle-types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BackendType, CreateSandboxOptions, ExecResult as SandboxExecResult, PromptOptions, PromptResult, SandboxEvent } from "@tangle-network/sandbox";
|
|
1
|
+
import type { BackendRegistryEntry, BackendRegistryResponse, BackendType, CreateSandboxOptions, ExecResult as SandboxExecResult, PromptOptions, PromptResult, SandboxEvent } from "@tangle-network/sandbox";
|
|
2
2
|
import type { AgentRunCancellationAcknowledgement, AgentRunCancellationRequest, AgentExecutionPreparationReceipt, AgentInteractiveSessionControlClaim, AgentInteractiveSessionControlClaimAcknowledgement, AgentInteractiveSessionControlClaimRequest, AgentInteractiveSessionPromptAcknowledgement, AgentInteractiveSessionPromptCommand, AgentInteractiveSessionStopAcknowledgement, AgentInteractiveSessionStopCommand, AgentProfile, InputPart, InteractionRequest, InteractionResponseCommand } from "@tangle-network/agent-interface";
|
|
3
3
|
import type { AgentEnvironmentCapabilities, AgentEnvironmentProvider, CreateAgentEnvironmentInput } from "@tangle-network/agent-interface/environment-provider";
|
|
4
4
|
export interface TangleExactProcessOptions {
|
|
@@ -20,6 +20,10 @@ export interface SandboxClientLike {
|
|
|
20
20
|
fetch?(path: string, options?: RequestInit, fetchOptions?: {
|
|
21
21
|
timeoutMs?: number;
|
|
22
22
|
}): Promise<Response>;
|
|
23
|
+
/** Canonical backend catalog served by authenticated `/v1/backends`. */
|
|
24
|
+
listBackends?(): Promise<BackendRegistryResponse>;
|
|
25
|
+
/** Lookup over the same canonical backend catalog, when the SDK provides it. */
|
|
26
|
+
getBackend?(type: string): Promise<BackendRegistryEntry | undefined>;
|
|
23
27
|
get?(id: string, requestOptions?: {
|
|
24
28
|
signal?: AbortSignal;
|
|
25
29
|
}): Promise<SandboxInstanceLike | null>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-provider-tangle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "AgentEnvironmentProvider adapter for Tangle sandboxes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -85,10 +85,10 @@
|
|
|
85
85
|
"LICENSE"
|
|
86
86
|
],
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@tangle-network/agent-interface": "^1.0.
|
|
88
|
+
"@tangle-network/agent-interface": "^1.0.1"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
|
-
"@tangle-network/sandbox": ">=0.
|
|
91
|
+
"@tangle-network/sandbox": ">=0.30.1 <1.0.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependenciesMeta": {
|
|
94
94
|
"@tangle-network/sandbox": {
|
|
@@ -96,13 +96,13 @@
|
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
|
-
"@tangle-network/agent-eval": "0.
|
|
100
|
-
"@tangle-network/agent-runtime": "0.
|
|
101
|
-
"@tangle-network/sandbox": "0.
|
|
99
|
+
"@tangle-network/agent-eval": "0.149.0",
|
|
100
|
+
"@tangle-network/agent-runtime": "0.142.3",
|
|
101
|
+
"@tangle-network/sandbox": "0.30.1",
|
|
102
102
|
"@types/node": "25.6.0",
|
|
103
103
|
"typescript": "^6.0.3",
|
|
104
104
|
"vitest": "^4.1.5",
|
|
105
|
-
"@tangle-network/agent-provider-testkit": "0.8.
|
|
105
|
+
"@tangle-network/agent-provider-testkit": "0.8.3"
|
|
106
106
|
},
|
|
107
107
|
"scripts": {
|
|
108
108
|
"build": "tsc -p tsconfig.json",
|