@tangle-network/agent-provider-tangle 0.9.0 → 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.
@@ -1,5 +1,5 @@
1
1
  import type { BackendType, CreateSandboxOptions, ExecResult as SandboxExecResult, PromptOptions, PromptResult, SandboxEvent } from "@tangle-network/sandbox";
2
- import type { AgentRunCancellationAcknowledgement, AgentRunCancellationRequest, InputPart } from "@tangle-network/agent-interface";
2
+ import type { AgentRunCancellationAcknowledgement, AgentRunCancellationRequest, 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 {
5
5
  teamId?: string;
@@ -30,6 +30,29 @@ export interface SandboxClientLike {
30
30
  signal?: AbortSignal;
31
31
  }): Promise<SandboxInstanceLike[]>;
32
32
  describePlacement?(box: SandboxInstanceLike): unknown;
33
+ /** Account usage counters for the credential behind this client. */
34
+ usage?(): Promise<SandboxAccountUsageLike>;
35
+ /** Plan, credit balance, and concurrency ceiling for the account. */
36
+ subscription?(): Promise<SandboxSubscriptionLike>;
37
+ }
38
+ /** The account usage counters the observation reads. */
39
+ export interface SandboxAccountUsageLike {
40
+ activeSandboxes: number;
41
+ periodStart: Date | string;
42
+ periodEnd: Date | string;
43
+ }
44
+ /**
45
+ * The subscription fields the observation reads.
46
+ *
47
+ * `creditsAvailableUsd` can be negative on an overage plan, and
48
+ * `maxConcurrentSandboxes` is 0 when the account has no ceiling. Neither value
49
+ * fits the contract's non-negative credit and quota shapes, so the observation
50
+ * reports those two cases as unavailable instead of clamping them.
51
+ */
52
+ export interface SandboxSubscriptionLike {
53
+ plan: string;
54
+ creditsAvailableUsd: number;
55
+ maxConcurrentSandboxes: number;
33
56
  }
34
57
  /**
35
58
  * The `GET /capabilities` document as this adapter reads it: what the DEPLOYED
@@ -70,6 +93,16 @@ export interface SandboxRuntimeCapabilityDocument {
70
93
  /** Buffered run events replay by execution. */
71
94
  eventReplay?: boolean;
72
95
  };
96
+ interactions?: {
97
+ /**
98
+ * The interaction route records every acknowledged resolution durably:
99
+ * repeating a response replays the recorded resolution, a different answer
100
+ * for a recorded resolution raises a conflict, and the deployment refuses
101
+ * rather than acknowledge a resolution it cannot record. Absent on an
102
+ * image that predates the flag, which is unknown and never a claim.
103
+ */
104
+ responseDedupe?: boolean;
105
+ };
73
106
  }
74
107
  export interface SandboxProcessStatusLike {
75
108
  pid: number;
@@ -99,11 +132,112 @@ export interface SandboxProcessManagerLike {
99
132
  signal?: AbortSignal;
100
133
  }): Promise<SandboxProcessLike>;
101
134
  }
135
+ /**
136
+ * The connection fields this adapter reads.
137
+ *
138
+ * The Sandbox connection object also carries a bearer token and its expiry.
139
+ * Neither is declared here, so no code path can copy a credential into an
140
+ * observation: the adapter reads the runtime URL and nothing else.
141
+ */
142
+ export interface SandboxConnectionLike {
143
+ runtimeUrl?: string;
144
+ }
145
+ /** Live cgroup sample for one sandbox. `null` fields mean the host reported none. */
146
+ export interface SandboxResourceUsageLike {
147
+ memoryCurrentMb: number;
148
+ memoryPeakMb: number | null;
149
+ memoryLimitMb: number | null;
150
+ cpuUsageUsec: number;
151
+ sampledAtMs: number;
152
+ }
153
+ /**
154
+ * The GPU lease fields the observation reads: the accelerator actually
155
+ * attached, and the compute cost charged for it. `billing` exists after the
156
+ * lease stops; `estimatedCustomerCostUsd` is the running estimate before that.
157
+ */
158
+ export interface SandboxGpuLeaseLike {
159
+ accelerator: {
160
+ kind: string;
161
+ count: number;
162
+ memoryMB?: number;
163
+ };
164
+ region?: string;
165
+ billing?: {
166
+ customerCostUsd: number;
167
+ };
168
+ estimatedCustomerCostUsd?: number;
169
+ }
170
+ /** Interactive terminal metadata the runtime reports for one PTY. */
171
+ export interface SandboxTerminalInfoLike {
172
+ sessionId: string;
173
+ connectionId?: string;
174
+ name?: string;
175
+ shell?: string;
176
+ command?: string;
177
+ cwd?: string;
178
+ cols?: number;
179
+ rows?: number;
180
+ createdAt?: string;
181
+ lastActivityAt?: string;
182
+ isRunning?: boolean;
183
+ exitCode?: number;
184
+ exitSignal?: string;
185
+ }
186
+ /** The `ready` acknowledgement the terminal WebSocket returns on attach. */
187
+ export interface SandboxTerminalReadyLike {
188
+ connectionId: string;
189
+ sessionId: string;
190
+ /** True when the runtime reattached an existing PTY and replays its history. */
191
+ restored: boolean;
192
+ /** How long the runtime keeps the PTY alive after this socket closes. */
193
+ detachTimeoutMs: number;
194
+ }
195
+ /** Callbacks bound before the terminal socket opens. */
196
+ export interface SandboxTerminalHandlersLike {
197
+ onData?: (data: Uint8Array) => void;
198
+ onReady?: (info: SandboxTerminalReadyLike) => void;
199
+ onExit?: (info: {
200
+ exitCode?: number;
201
+ exitSignal?: string;
202
+ }) => void;
203
+ onError?: (error: Error) => void;
204
+ onClose?: (code: number, reason: string) => void;
205
+ }
206
+ /** One live terminal WebSocket. */
207
+ export interface SandboxTerminalStreamLike {
208
+ readonly connectionId: string;
209
+ readonly ready: SandboxTerminalReadyLike;
210
+ readonly isOpen: boolean;
211
+ write(data: string | Uint8Array): void;
212
+ resize(cols: number, rows: number): void;
213
+ close(): Promise<void>;
214
+ }
215
+ /**
216
+ * The terminal surface this adapter binds: metadata lookup plus the live PTY
217
+ * attach. Reusing a connection id reattaches an existing PTY and replays its
218
+ * buffered output; a new id starts a shell or the requested command.
219
+ */
220
+ export interface SandboxTerminalsLike {
221
+ get(sessionId: string): Promise<SandboxTerminalInfoLike | null>;
222
+ attach(connectionId: string, options?: {
223
+ cols?: number;
224
+ rows?: number;
225
+ command?: string;
226
+ cwd?: string;
227
+ handlers?: SandboxTerminalHandlersLike;
228
+ }): Promise<SandboxTerminalStreamLike>;
229
+ }
102
230
  export interface SandboxInstanceLike {
103
231
  id: string;
104
232
  name?: string;
105
233
  status?: unknown;
106
234
  metadata?: Record<string, unknown>;
235
+ /** Network location of the sandbox runtime, without its bearer. */
236
+ connection?: SandboxConnectionLike;
237
+ /** When the platform retires this sandbox, when it set a lifetime. */
238
+ expiresAt?: Date | string;
239
+ /** GPU lease attached at create time, when one was requested. */
240
+ gpuLease?: SandboxGpuLeaseLike;
107
241
  streamPrompt(message: string | InputPart[], options?: PromptOptions): AsyncIterable<SandboxEvent>;
108
242
  prompt?(message: string | InputPart[], options?: PromptOptions): Promise<PromptResult>;
109
243
  dispatchPrompt?(message: string | InputPart[], options?: PromptOptions): Promise<unknown>;
@@ -155,6 +289,14 @@ export interface SandboxInstanceLike {
155
289
  * reads; a malformed document throws.
156
290
  */
157
291
  capabilities?(): Promise<SandboxRuntimeCapabilityDocument | null>;
292
+ /**
293
+ * Live cgroup sample for the whole sandbox. Resolves to null when the host
294
+ * collects no cgroup statistics, which the observation reports as an absent
295
+ * measurement rather than a zero.
296
+ */
297
+ resourceUsage?(): Promise<SandboxResourceUsageLike | null>;
298
+ /** Interactive terminal transport. Absent on a client that cannot serve a PTY. */
299
+ terminals?: SandboxTerminalsLike;
158
300
  refresh?(options?: {
159
301
  signal?: AbortSignal;
160
302
  }): Promise<void>;
@@ -186,6 +328,44 @@ export interface SandboxSessionLike {
186
328
  cancelRun?(request: AgentRunCancellationRequest, options?: {
187
329
  signal?: AbortSignal;
188
330
  }): Promise<AgentRunCancellationAcknowledgement>;
331
+ /**
332
+ * Every ask still awaiting a response on this session. The adapter reads the
333
+ * answer spec from here to refuse an answer the ask does not accept, so an
334
+ * ask that has already left the outstanding set is absent rather than an
335
+ * error. Absent on a Sandbox SDK that cannot list the outstanding set.
336
+ */
337
+ interactions?(options?: {
338
+ signal?: AbortSignal;
339
+ }): Promise<readonly InteractionRequest[]>;
340
+ /**
341
+ * Deliver one digest-bound response to the exact ask its binding names.
342
+ *
343
+ * The result carries the acknowledgement the deployment's durable record
344
+ * produced, and `serverResult` carries that record itself. Absent on a
345
+ * Sandbox SDK older than 0.23.0, whose response path selected an ask by
346
+ * position rather than by id.
347
+ */
348
+ respondToInteraction?(command: InteractionResponseCommand, options?: {
349
+ signal?: AbortSignal;
350
+ }): Promise<SandboxInteractionCommandResultLike>;
351
+ }
352
+ /**
353
+ * The Sandbox SDK's reply to one response command.
354
+ *
355
+ * Both members are read as unvalidated wire content: the acknowledgement
356
+ * reaches the canonical schema before this adapter returns it, and the
357
+ * resolution is read only for the two facts the acknowledgement cannot
358
+ * carry — whether the deployment confirmed delivery, and the digest of the
359
+ * response a conflicting resolution already holds.
360
+ */
361
+ export interface SandboxInteractionCommandResultLike {
362
+ acknowledgement: unknown;
363
+ serverResult?: {
364
+ status?: unknown;
365
+ delivered?: unknown;
366
+ existingResponseDigest?: unknown;
367
+ [key: string]: unknown;
368
+ };
189
369
  }
190
370
  export interface TangleProviderOptions {
191
371
  client: SandboxClientLike;
@@ -0,0 +1,22 @@
1
+ import type { TokenUsage } from "@tangle-network/agent-interface";
2
+ /** One execution's measured token usage and cost. */
3
+ export interface ExecutionUsageRecord {
4
+ executionId: string;
5
+ usage: TokenUsage;
6
+ observedAt: string;
7
+ }
8
+ /**
9
+ * The newest per-execution usage this environment handle measured.
10
+ *
11
+ * Sandbox reports token usage and cost on the result of one execution, never
12
+ * for the environment as a whole, so the only environment-scoped answer is the
13
+ * newest execution the handle actually saw. The record lives with the handle:
14
+ * an environment rebuilt through `provider.get(id)` starts with none, and the
15
+ * observation then reports the usage surface as unavailable rather than as a
16
+ * measured zero.
17
+ */
18
+ export interface ExecutionUsageLog {
19
+ record(executionId: string | undefined, usage: TokenUsage | undefined): void;
20
+ latest(): ExecutionUsageRecord | undefined;
21
+ }
22
+ export declare function createExecutionUsageLog(): ExecutionUsageLog;
@@ -0,0 +1,22 @@
1
+ import { boundedIdentifier } from "./tangle-contract-safety.js";
2
+ export function createExecutionUsageLog() {
3
+ let latest;
4
+ return {
5
+ record(executionId, usage) {
6
+ // Usage without the execution it belongs to cannot be attributed, and an
7
+ // execution without usage measured nothing. Neither is recorded.
8
+ if (executionId === undefined || usage === undefined)
9
+ return;
10
+ latest = {
11
+ executionId: boundedIdentifier(executionId, "Tangle execution id"),
12
+ usage,
13
+ observedAt: new Date().toISOString(),
14
+ };
15
+ },
16
+ latest() {
17
+ return latest === undefined
18
+ ? undefined
19
+ : { ...latest, usage: { ...latest.usage } };
20
+ },
21
+ };
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-provider-tangle",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "AgentEnvironmentProvider adapter for Tangle sandboxes",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,6 +31,8 @@
31
31
  "dist/tangle-exact-process-environment.js",
32
32
  "dist/tangle-contract-safety.d.ts",
33
33
  "dist/tangle-contract-safety.js",
34
+ "dist/tangle-failure-reason.d.ts",
35
+ "dist/tangle-failure-reason.js",
34
36
  "dist/tangle-exact-process-runtime.d.ts",
35
37
  "dist/tangle-exact-process-runtime.js",
36
38
  "dist/tangle-exact-process-validation.d.ts",
@@ -49,12 +51,24 @@
49
51
  "dist/tangle-environment-dispatch.js",
50
52
  "dist/tangle-environment-session.d.ts",
51
53
  "dist/tangle-environment-session.js",
54
+ "dist/tangle-interaction-response.d.ts",
55
+ "dist/tangle-interaction-response.js",
52
56
  "dist/tangle-environment-control.d.ts",
53
57
  "dist/tangle-environment-control.js",
54
58
  "dist/tangle-environment-validation.d.ts",
55
59
  "dist/tangle-environment-validation.js",
56
60
  "dist/tangle-events.d.ts",
57
61
  "dist/tangle-events.js",
62
+ "dist/tangle-observation.d.ts",
63
+ "dist/tangle-observation.js",
64
+ "dist/tangle-resources.d.ts",
65
+ "dist/tangle-resources.js",
66
+ "dist/tangle-terminal.d.ts",
67
+ "dist/tangle-terminal.js",
68
+ "dist/tangle-terminal-frames.d.ts",
69
+ "dist/tangle-terminal-frames.js",
70
+ "dist/tangle-usage-log.d.ts",
71
+ "dist/tangle-usage-log.js",
58
72
  "dist/tangle-prompt.d.ts",
59
73
  "dist/tangle-prompt.js",
60
74
  "dist/tangle-provider.d.ts",
@@ -69,10 +83,10 @@
69
83
  "LICENSE"
70
84
  ],
71
85
  "dependencies": {
72
- "@tangle-network/agent-interface": "0.51.0"
86
+ "@tangle-network/agent-interface": "0.52.0"
73
87
  },
74
88
  "peerDependencies": {
75
- "@tangle-network/sandbox": ">=0.19.6 <1.0.0"
89
+ "@tangle-network/sandbox": ">=0.23.0 <1.0.0"
76
90
  },
77
91
  "peerDependenciesMeta": {
78
92
  "@tangle-network/sandbox": {
@@ -82,11 +96,11 @@
82
96
  "devDependencies": {
83
97
  "@tangle-network/agent-eval": "0.145.3",
84
98
  "@tangle-network/agent-runtime": "0.132.13",
85
- "@tangle-network/sandbox": "0.22.0",
99
+ "@tangle-network/sandbox": "0.23.0",
86
100
  "@types/node": "25.6.0",
87
101
  "typescript": "^6.0.3",
88
102
  "vitest": "^4.1.5",
89
- "@tangle-network/agent-provider-testkit": "0.7.1"
103
+ "@tangle-network/agent-provider-testkit": "0.7.2"
90
104
  },
91
105
  "scripts": {
92
106
  "build": "tsc -p tsconfig.json",