@shardflux/sdk 0.6.2 → 0.8.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/CHANGELOG.md +109 -1
- package/README.md +202 -9
- package/dist/capture-adapters.d.ts +178 -0
- package/dist/capture-adapters.js +432 -0
- package/dist/capture-serialize.d.ts +97 -0
- package/dist/capture-serialize.js +481 -0
- package/dist/capture-text.d.ts +14 -0
- package/dist/capture-text.js +13 -0
- package/dist/capture.d.ts +288 -0
- package/dist/capture.js +1326 -0
- package/dist/cell.d.ts +7 -0
- package/dist/cell.js +13 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.js +21 -4
- package/dist/egress.d.ts +18 -0
- package/dist/errors.d.ts +8 -1
- package/dist/generated/app-api.d.ts +215 -0
- package/dist/http.d.ts +1 -1
- package/dist/http.js +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.js +4 -1
- package/dist/lifecycle.d.ts +3 -1
- package/dist/lifecycle.js +5 -1
- package/dist/progress.d.ts +3 -1
- package/dist/tar.d.ts +40 -0
- package/dist/tar.js +150 -0
- package/dist/template-file.d.ts +92 -0
- package/dist/template-file.js +326 -0
- package/dist/templates.d.ts +318 -9
- package/dist/templates.js +432 -13
- package/dist/tools.d.ts +49 -33
- package/dist/tools.js +25 -4
- package/dist/workspace.d.ts +25 -2
- package/dist/workspace.js +49 -2
- package/package.json +25 -2
package/dist/tools.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-neutral agent tools for a workspace (TEMPLATES.md):
|
|
3
|
+
*
|
|
4
|
+
* await agent.run({ input, tools: workspaceTools(workspace) });
|
|
5
|
+
*
|
|
6
|
+
* Each tool is { name, description, parameters (JSON Schema 2020-12), execute }.
|
|
7
|
+
* `execute` validates its arguments against `parameters` (the same schema the
|
|
8
|
+
* model saw), then calls the cell gateway through the workspace's managed tool
|
|
9
|
+
* token. The customer's model and agent loop stay in the customer's
|
|
10
|
+
* application; toOpenAITools/toAnthropicTools export the definitions in those
|
|
11
|
+
* providers' formats and executeToolCall dispatches a model's tool call.
|
|
12
|
+
*/
|
|
13
|
+
import { CAPTURE_BARRIER } from "./cell.js";
|
|
1
14
|
export class ToolArgumentError extends Error {
|
|
2
15
|
tool;
|
|
3
16
|
issues;
|
|
@@ -283,11 +296,15 @@ export function workspaceTools(workspace, opts = {}) {
|
|
|
283
296
|
const issues = validateArgs(d.parameters, args);
|
|
284
297
|
if (issues.length > 0)
|
|
285
298
|
throw new ToolArgumentError(`${prefix}${d.name}`, issues);
|
|
286
|
-
|
|
299
|
+
// Read-your-writes: tool calls captured before this one are in the workspace before it runs (bounded).
|
|
300
|
+
const barrier = workspace[CAPTURE_BARRIER];
|
|
301
|
+
const pending = typeof barrier === 'function' ? barrier.call(workspace) : undefined;
|
|
302
|
+
if (pending)
|
|
303
|
+
await pending;
|
|
304
|
+
return d.run(args, options.signal ? { signal: options.signal } : {});
|
|
287
305
|
},
|
|
288
306
|
}));
|
|
289
307
|
}
|
|
290
|
-
/** OpenAI tool definitions: Chat Completions (`{type:'function', function:{...}}`) or Responses API. */
|
|
291
308
|
export function toOpenAITools(tools, opts = {}) {
|
|
292
309
|
return opts.api === 'responses'
|
|
293
310
|
? tools.map((t) => ({ type: 'function', name: t.name, description: t.description, parameters: t.parameters, strict: false }))
|
|
@@ -299,7 +316,10 @@ export function toAnthropicTools(tools) {
|
|
|
299
316
|
}
|
|
300
317
|
/**
|
|
301
318
|
* Runs a model's tool call: `arguments` may be the JSON string (OpenAI) or an object (Anthropic
|
|
302
|
-
* `input`). Throws for unknown tools and invalid arguments (ToolArgumentError).
|
|
319
|
+
* `input`). Throws for unknown tools and invalid arguments (ToolArgumentError). The call's `id` / `call_id` is passed
|
|
320
|
+
* to `execute` as `toolCallId` (0.7.0+), so `executeToolCall(capture.tools(tools), call)` records it. `input` is
|
|
321
|
+
* `unknown` (0.8.0+), as in the Anthropic SDK's `ToolUseBlock`, so a tool_use block is passed as it is; `execute`
|
|
322
|
+
* validates it.
|
|
303
323
|
*/
|
|
304
324
|
export async function executeToolCall(tools, call, options = {}) {
|
|
305
325
|
const tool = tools.find((t) => t.name === call.name);
|
|
@@ -313,5 +333,6 @@ export async function executeToolCall(tools, call, options = {}) {
|
|
|
313
333
|
catch {
|
|
314
334
|
throw new ToolArgumentError(call.name, ['arguments are not valid JSON']);
|
|
315
335
|
}
|
|
316
|
-
|
|
336
|
+
const toolCallId = call.call_id ?? call.id;
|
|
337
|
+
return tool.execute(args, toolCallId === undefined ? options : { ...options, toolCallId });
|
|
317
338
|
}
|
package/dist/workspace.d.ts
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
* tool tokens and cell clients (one per agent label / tool set).
|
|
4
4
|
*/
|
|
5
5
|
import type { ClientContext, DiskLayout, ForkTarget, Operation, WaitOptions, WorkspaceLifetime, WorkspaceOrigin, WorkspacePurpose, WorkspaceView } from './client.js';
|
|
6
|
-
import { CellClient } from './cell.js';
|
|
6
|
+
import { CAPTURE_BARRIER, CellClient } from './cell.js';
|
|
7
|
+
import { ToolCallCapture } from './capture.js';
|
|
8
|
+
import type { ToolCallCaptureOptions } from './capture.js';
|
|
7
9
|
import type { FinishedOperation, LifecycleOptions, WaitedLifecycleOptions } from './lifecycle.js';
|
|
8
10
|
import { Trace } from './progress.js';
|
|
9
11
|
import type { LifecycleTiming, ProgressListener } from './progress.js';
|
|
10
12
|
import { WorkspaceSecrets } from './secrets.js';
|
|
11
13
|
import type { CellClientOptions, WorkspaceChangesPage, WorkspaceChangesParams } from './cell.js';
|
|
12
|
-
import type { SaveAsTemplateParams, SaveAsTemplateResponse } from './templates.js';
|
|
14
|
+
import type { SaveAsTemplateParams, SaveAsTemplateResponse, WorkspaceStartup } from './templates.js';
|
|
13
15
|
import { ToolTokenManager } from './tokens.js';
|
|
14
16
|
import type { ToolName, ToolToken } from './tokens.js';
|
|
15
17
|
export interface WakeOptions {
|
|
@@ -59,10 +61,18 @@ export declare class Workspace {
|
|
|
59
61
|
get origin(): WorkspaceOrigin | null;
|
|
60
62
|
/** How a session ended (closed, idle_timeout, draft_discarded); null while live or for a plain delete. */
|
|
61
63
|
get endedReason(): WorkspaceView['ended_reason'];
|
|
64
|
+
/**
|
|
65
|
+
* Start commands and services of the workspace's template version (0.7.0; contracts §24.4): `state` pending, running,
|
|
66
|
+
* ready or failed (the failed step, its exit code, reason and output tail). Null when the version has neither, or on
|
|
67
|
+
* an older API. A failed startup leaves the workspace running for inspection; the next open runs the failed step again.
|
|
68
|
+
*/
|
|
69
|
+
get startup(): WorkspaceStartup | null;
|
|
62
70
|
/** The raw view (GET /v1/workspaces/{id}). */
|
|
63
71
|
get data(): WorkspaceView;
|
|
64
72
|
/** Secret names bound to this workspace (injected into every exec/PTY start): `get()`, `set(names)`. */
|
|
65
73
|
get secrets(): WorkspaceSecrets;
|
|
74
|
+
/** The workspace's text inputs `{NAME: value}` (0.7.0; secret inputs are bound secrets, never listed here). */
|
|
75
|
+
inputs(): Promise<Record<string, string>>;
|
|
66
76
|
refresh(): Promise<this>;
|
|
67
77
|
/** Waits for the active operation (if any) and refreshes. */
|
|
68
78
|
waitUntilReady(opts?: WaitOptions): Promise<this>;
|
|
@@ -123,6 +133,19 @@ export declare class Workspace {
|
|
|
123
133
|
*/
|
|
124
134
|
reset(opts: WaitedLifecycleOptions): Promise<FinishedOperation>;
|
|
125
135
|
reset(opts?: LifecycleOptions): Promise<Operation>;
|
|
136
|
+
/**
|
|
137
|
+
* Captures the tool calls of your agent harness into this workspace (docs/decisions/0006-tool-call-capture.md): each
|
|
138
|
+
* call's input and full output become files under `dir` (default `/home/user/tool-calls/<run>/`), so the agent can
|
|
139
|
+
* work on them with code, and they are in snapshots and forks. Wrapped tools return exactly what they returned before;
|
|
140
|
+
* capture never throws into the harness. Shardflux calls through this client (exec, files, workspaceTools, snapshot,
|
|
141
|
+
* fork, suspend, close, saveAsTemplate) first wait for writes recorded before them; delete and reset drop them.
|
|
142
|
+
*
|
|
143
|
+
* const capture = workspace.captureToolCalls();
|
|
144
|
+
* const out = await capture.run(block, () => myTools[block.name](block.input));
|
|
145
|
+
*/
|
|
146
|
+
captureToolCalls(opts?: ToolCallCaptureOptions): ToolCallCapture;
|
|
147
|
+
/** Internal: waits for tool-call capture writes recorded so far (workspaceTools calls it before each tool). */
|
|
148
|
+
[CAPTURE_BARRIER](): Promise<void> | undefined;
|
|
126
149
|
/** Saves this layered workspace as the next version of an organization template (contracts §19.8). */
|
|
127
150
|
saveAsTemplate(params: SaveAsTemplateParams): Promise<SaveAsTemplateResponse>;
|
|
128
151
|
/**
|
package/dist/workspace.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { CellClient, DEFAULT_TRANSITION_TIMEOUT_MS } from "./cell.js";
|
|
1
|
+
import { CAPTURE_BARRIER, CellClient, DEFAULT_TRANSITION_TIMEOUT_MS } from "./cell.js";
|
|
2
|
+
import { ToolCallCapture } from "./capture.js";
|
|
2
3
|
import { OperationFailedError, ShardfluxApiError } from "./errors.js";
|
|
3
|
-
import { randomId } from "./http.js";
|
|
4
|
+
import { defaultSleep, randomId } from "./http.js";
|
|
4
5
|
import { AFTER_WAIT, TRACE } from "./lifecycle.js";
|
|
5
6
|
import { Trace, combineListeners, traced } from "./progress.js";
|
|
6
7
|
import { WorkspaceSecrets } from "./secrets.js";
|
|
@@ -107,6 +108,14 @@ export class Workspace {
|
|
|
107
108
|
get endedReason() {
|
|
108
109
|
return this.#view.ended_reason ?? null;
|
|
109
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Start commands and services of the workspace's template version (0.7.0; contracts §24.4): `state` pending, running,
|
|
113
|
+
* ready or failed (the failed step, its exit code, reason and output tail). Null when the version has neither, or on
|
|
114
|
+
* an older API. A failed startup leaves the workspace running for inspection; the next open runs the failed step again.
|
|
115
|
+
*/
|
|
116
|
+
get startup() {
|
|
117
|
+
return this.#view.startup ?? null;
|
|
118
|
+
}
|
|
110
119
|
/** The raw view (GET /v1/workspaces/{id}). */
|
|
111
120
|
get data() {
|
|
112
121
|
return this.#view;
|
|
@@ -115,6 +124,10 @@ export class Workspace {
|
|
|
115
124
|
get secrets() {
|
|
116
125
|
return new WorkspaceSecrets(this.#ctx, this.id);
|
|
117
126
|
}
|
|
127
|
+
/** The workspace's text inputs `{NAME: value}` (0.7.0; secret inputs are bound secrets, never listed here). */
|
|
128
|
+
inputs() {
|
|
129
|
+
return this.#ctx.workspaces.inputs(this.id);
|
|
130
|
+
}
|
|
118
131
|
async refresh() {
|
|
119
132
|
this.#view = await this.#ctx.http.json('GET', `/v1/workspaces/${encodeURIComponent(this.id)}`, {}, this.#ctx.authorization);
|
|
120
133
|
return this;
|
|
@@ -142,6 +155,8 @@ export class Workspace {
|
|
|
142
155
|
return this.#ctx.workspaces.fork(this.id, target, this.#tracked(opts));
|
|
143
156
|
}
|
|
144
157
|
async close(opts = {}) {
|
|
158
|
+
// Closing aborts in-flight cell requests: tool-call capture writes recorded before it are flushed first (bounded).
|
|
159
|
+
await this.#ctx.captures.settle(this.id);
|
|
145
160
|
for (const c of this.#cells.values())
|
|
146
161
|
c.close();
|
|
147
162
|
this.#cells.clear();
|
|
@@ -159,6 +174,37 @@ export class Workspace {
|
|
|
159
174
|
m.invalidate();
|
|
160
175
|
return op;
|
|
161
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Captures the tool calls of your agent harness into this workspace (docs/decisions/0006-tool-call-capture.md): each
|
|
179
|
+
* call's input and full output become files under `dir` (default `/home/user/tool-calls/<run>/`), so the agent can
|
|
180
|
+
* work on them with code, and they are in snapshots and forks. Wrapped tools return exactly what they returned before;
|
|
181
|
+
* capture never throws into the harness. Shardflux calls through this client (exec, files, workspaceTools, snapshot,
|
|
182
|
+
* fork, suspend, close, saveAsTemplate) first wait for writes recorded before them; delete and reset drop them.
|
|
183
|
+
*
|
|
184
|
+
* const capture = workspace.captureToolCalls();
|
|
185
|
+
* const out = await capture.run(block, () => myTools[block.name](block.input));
|
|
186
|
+
*/
|
|
187
|
+
captureToolCalls(opts = {}) {
|
|
188
|
+
const defaults = this.#defaults.tools;
|
|
189
|
+
const tools = defaults && !defaults.includes('files') ? [...defaults, 'files'] : defaults;
|
|
190
|
+
const agentLabel = opts.agentLabel ?? this.#defaults.agentLabel;
|
|
191
|
+
const manager = this.tokens({ ...(agentLabel !== undefined ? { agentLabel } : {}), ...(tools !== undefined ? { tools } : {}) });
|
|
192
|
+
// The capture's own client: not in #cells (close() flushes it before aborting those) and without the barrier.
|
|
193
|
+
const cell = new CellClient(this.id, manager, {
|
|
194
|
+
fetch: this.#ctx.fetch,
|
|
195
|
+
userAgent: this.#ctx.userAgent,
|
|
196
|
+
sleep: this.#ctx.sleep,
|
|
197
|
+
maxRetries: 0,
|
|
198
|
+
...(opts.transitionTimeoutMs !== undefined ? { transitionTimeoutMs: opts.transitionTimeoutMs } : {}),
|
|
199
|
+
...(this.#ctx.onProgress ? { onProgress: this.#ctx.onProgress } : {}),
|
|
200
|
+
wake: opts.wake === undefined ? (timeoutMs, signal) => this.wake({ timeoutMs, ...(signal ? { signal } : {}) }) : opts.wake,
|
|
201
|
+
});
|
|
202
|
+
return new ToolCallCapture({ workspaceId: this.id, cell, registry: this.#ctx.captures, ...(this.#ctx.sleep !== defaultSleep ? { sleep: this.#ctx.sleep } : {}) }, opts);
|
|
203
|
+
}
|
|
204
|
+
/** Internal: waits for tool-call capture writes recorded so far (workspaceTools calls it before each tool). */
|
|
205
|
+
[CAPTURE_BARRIER]() {
|
|
206
|
+
return this.#ctx.captures.settle(this.id);
|
|
207
|
+
}
|
|
162
208
|
/** Saves this layered workspace as the next version of an organization template (contracts §19.8). */
|
|
163
209
|
saveAsTemplate(params) {
|
|
164
210
|
return this.#ctx.workspaces.saveAsTemplate(this.id, params);
|
|
@@ -205,6 +251,7 @@ export class Workspace {
|
|
|
205
251
|
...cellOpts,
|
|
206
252
|
...(listener ? { onProgress: listener } : {}),
|
|
207
253
|
wake: wake === undefined ? (timeoutMs, signal) => this.wake({ timeoutMs, ...(signal ? { signal } : {}), ...(onProgress ? { onProgress } : {}) }) : wake,
|
|
254
|
+
[CAPTURE_BARRIER]: () => this.#ctx.captures.settle(this.id),
|
|
208
255
|
});
|
|
209
256
|
this.#cells.set(k, c);
|
|
210
257
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shardflux/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shardflux TypeScript SDK: open persistent agent workspaces by key and give your agent workspace tools (exec, files, processes, PTY, git, browser).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -36,13 +36,36 @@
|
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"yaml": "^2.4.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"yaml": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
39
47
|
"devDependencies": {
|
|
48
|
+
"@ai-sdk/provider": "4.0.18",
|
|
49
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.283",
|
|
50
|
+
"@anthropic-ai/sdk": "0.128.0",
|
|
40
51
|
"@eslint/js": "10.0.1",
|
|
52
|
+
"@langchain/core": "1.2.13",
|
|
53
|
+
"@langchain/langgraph": "1.4.18",
|
|
54
|
+
"@mastra/core": "1.71.0",
|
|
55
|
+
"@modelcontextprotocol/client": "2.1.0",
|
|
56
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
57
|
+
"@openai/agents-core": "0.18.0",
|
|
41
58
|
"@types/node": "24.13.6",
|
|
59
|
+
"ai": "7.0.118",
|
|
60
|
+
"ajv": "8.20.0",
|
|
42
61
|
"eslint": "10.11.0",
|
|
62
|
+
"langchain": "1.5.14",
|
|
63
|
+
"openai": "7.23.0",
|
|
43
64
|
"openapi-typescript": "7.13.0",
|
|
44
65
|
"typescript": "5.9.3",
|
|
45
|
-
"typescript-eslint": "8.70.1"
|
|
66
|
+
"typescript-eslint": "8.70.1",
|
|
67
|
+
"yaml": "2.9.1",
|
|
68
|
+
"zod": "4.6.5"
|
|
46
69
|
},
|
|
47
70
|
"scripts": {
|
|
48
71
|
"build": "node scripts/build.mjs",
|