@tangle-network/agent-provider-tangle 0.12.1 → 0.12.3

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.
@@ -1,4 +1,4 @@
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
3
  import { capabilitiesForClient, defaultTangleSandboxCapabilities, } from "./tangle-capabilities.js";
4
4
  import { sandboxInstanceAsEnvironment } from "./tangle-environment.js";
@@ -36,74 +36,82 @@ export function createTangleProvider(options) {
36
36
  // the configured document, so create() and get() call it before any effect.
37
37
  const narrowedProviderCapabilities = (declared) => AgentEnvironmentCapabilitiesSchema.parse(capabilitiesForClient(declared, options.client));
38
38
  const resolveCapabilities = async () => narrowedProviderCapabilities(await resolveDeclaredCapabilities());
39
- return {
40
- name: providerName,
41
- ...(exactProcess ? { exactProcess } : {}),
42
- capabilities: resolveCapabilities,
43
- ...(options.validateProfile ? { validateProfile: options.validateProfile } : {}),
44
- async create(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");
39
+ const createRecords = new Map();
40
+ const createEnvironment = async (input) => {
41
+ assertCreateInputShape(input);
42
+ input.signal?.throwIfAborted();
43
+ assertNoInlineSecretValues(input);
44
+ if (input.providerOptions && Object.keys(input.providerOptions).length > 0) {
45
+ throw new Error("Tangle create providerOptions are not supported");
46
+ }
47
+ // The sandbox stage narrows from the declared document, not the
48
+ // provider-boundary one: the client stage cannot observe box-scoped
49
+ // facts, so measured instance facts must decide them per sandbox.
50
+ const declaredCapabilities = await resolveDeclaredCapabilities();
51
+ narrowedProviderCapabilities(declaredCapabilities);
52
+ const createOptions = options.mapCreateInput?.(input) ??
53
+ sandboxOptionsFromCreateInput(input, options.defaultBackend ?? "opencode");
54
+ assertMappedCreateOptions(createOptions);
55
+ if (input.idempotencyKey !== undefined &&
56
+ createOptions.idempotencyKey !== input.idempotencyKey) {
57
+ throw new Error("Tangle mapped create options must preserve input idempotencyKey");
58
+ }
59
+ assertMappedSecretNames(createOptions);
60
+ input.signal?.throwIfAborted();
61
+ const createPromise = options.client.create(createOptions, input.signal ? { signal: input.signal } : undefined);
62
+ let box;
63
+ try {
64
+ box = await awaitWithSignal(createPromise, input.signal);
65
+ }
66
+ catch (error) {
67
+ if (input.signal?.aborted) {
68
+ void createPromise
69
+ .then(async (lateBox) => {
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));
50
82
  }
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
- assertMappedSecretNames(createOptions);
83
+ throw error;
84
+ }
85
+ try {
60
86
  input.signal?.throwIfAborted();
61
- const createPromise = options.client.create(createOptions, input.signal ? { signal: input.signal } : undefined);
62
- let box;
63
- try {
64
- box = await awaitWithSignal(createPromise, input.signal);
65
- }
66
- catch (error) {
67
- if (input.signal?.aborted) {
68
- void createPromise
69
- .then(async (lateBox) => {
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;
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;
91
+ }
92
+ catch (error) {
93
+ if (!box.delete) {
94
+ const baseError = error instanceof Error ? error : new Error(String(error));
95
+ throw Object.assign(baseError, { cleanupHandle: box });
84
96
  }
85
97
  try {
86
- input.signal?.throwIfAborted();
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;
98
+ await box.delete();
91
99
  }
92
- catch (error) {
93
- if (!box.delete) {
94
- const baseError = error instanceof Error ? error : new Error(String(error));
95
- throw Object.assign(baseError, { cleanupHandle: box });
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;
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;
106
104
  }
105
+ throw error;
106
+ }
107
+ };
108
+ return {
109
+ name: providerName,
110
+ ...(exactProcess ? { exactProcess } : {}),
111
+ capabilities: resolveCapabilities,
112
+ ...(options.validateProfile ? { validateProfile: options.validateProfile } : {}),
113
+ create(input) {
114
+ return createAgentEnvironmentWithIdempotency(createRecords, input, () => createEnvironment(input));
107
115
  },
108
116
  ...(options.client.get
109
117
  ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-provider-tangle",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "AgentEnvironmentProvider adapter for Tangle sandboxes",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -85,7 +85,7 @@
85
85
  "LICENSE"
86
86
  ],
87
87
  "dependencies": {
88
- "@tangle-network/agent-interface": "0.56.0"
88
+ "@tangle-network/agent-interface": "^1.0.1"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "@tangle-network/sandbox": ">=0.23.0 <1.0.0"
@@ -102,7 +102,7 @@
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.1"
105
+ "@tangle-network/agent-provider-testkit": "0.8.3"
106
106
  },
107
107
  "scripts": {
108
108
  "build": "tsc -p tsconfig.json",