@deepstrike/wasm 0.2.42 → 0.2.44
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/dist/harness/index.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface AttemptRequest {
|
|
|
7
7
|
sessionId?: string;
|
|
8
8
|
goal: string;
|
|
9
9
|
criteria?: Criterion[];
|
|
10
|
+
/**
|
|
11
|
+
* Multimodal inputs (images / audio) attached to the task. Forwarded to every attempt
|
|
12
|
+
* unconditionally; the runner seeds them per session idempotently, so fresh-session carries
|
|
13
|
+
* re-seed while same-session carries do not double.
|
|
14
|
+
*/
|
|
15
|
+
attachments?: import("../types.js").ContentPart[];
|
|
10
16
|
extensions?: Record<string, unknown>;
|
|
11
17
|
inheritEvents?: Array<{
|
|
12
18
|
seq: number;
|
package/dist/harness/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export class RuntimeAttemptBody {
|
|
|
14
14
|
sessionId: context.sessionId,
|
|
15
15
|
goal: context.goal,
|
|
16
16
|
criteria: (context.criteria ?? []).map(criterion => criterion.text),
|
|
17
|
+
...(context.attachments?.length ? { attachments: context.attachments } : {}),
|
|
17
18
|
extensions: context.extensions,
|
|
18
19
|
...(context.attempt === 1 && context.inheritEvents
|
|
19
20
|
? { inheritEvents: context.inheritEvents }
|
|
@@ -18,7 +18,6 @@ export function restoreKernelRuntime(runtime, snapshot) {
|
|
|
18
18
|
}, 1);
|
|
19
19
|
kernelWireStates.set(runtime, { operationId, nextEventSequence });
|
|
20
20
|
}
|
|
21
|
-
let nextOperationSequence = 1;
|
|
22
21
|
const kernelWireStates = new WeakMap();
|
|
23
22
|
function tryParseJson(s) {
|
|
24
23
|
try {
|
|
@@ -267,7 +266,10 @@ function mapKernelAction(raw) {
|
|
|
267
266
|
function stepInput(runtime, event) {
|
|
268
267
|
let state = kernelWireStates.get(runtime);
|
|
269
268
|
if (!state) {
|
|
270
|
-
|
|
269
|
+
// Globally unique, never a process-local counter: durable session logs key the kernel
|
|
270
|
+
// genesis/transaction chains by (sessionId, operationId) and outlive this isolate, so a
|
|
271
|
+
// counter that restarts at 1 collides with a prior chain on the same session.
|
|
272
|
+
state = { operationId: `wasm-operation-${crypto.randomUUID()}`, nextEventSequence: 1 };
|
|
271
273
|
kernelWireStates.set(runtime, state);
|
|
272
274
|
}
|
|
273
275
|
const correlatedEvent = event.kind === "cancel_operation"
|
|
@@ -43,14 +43,15 @@ export declare class LargeResultSpool {
|
|
|
43
43
|
private writeToDriver;
|
|
44
44
|
private generatePreview;
|
|
45
45
|
processToolResult(result: ToolResult): Promise<SpooledToolResult>;
|
|
46
|
-
|
|
46
|
+
private callKey;
|
|
47
|
+
persistOutput(sessionId: string, callId: string, content: string): Promise<string>;
|
|
47
48
|
readSpooledResult(spoolRef: string): Promise<string>;
|
|
48
49
|
/**
|
|
49
50
|
* O7: locate a spooled output by the tool call's id (the `read_result` meta-tool only knows
|
|
50
51
|
* `call_id`, not the content-hashed key `persistOutput` chose). Scans the driver's key list for
|
|
51
|
-
* the
|
|
52
|
+
* the hashed session-scoped call-key prefix; returns `undefined` if nothing was ever
|
|
52
53
|
* spooled for that call.
|
|
53
54
|
*/
|
|
54
|
-
findByCallId(callId: string): Promise<string | undefined>;
|
|
55
|
+
findByCallId(sessionId: string, callId: string): Promise<string | undefined>;
|
|
55
56
|
cleanup(maxAgeMs?: number): Promise<number>;
|
|
56
57
|
}
|
|
@@ -92,9 +92,16 @@ omitted: ${omitted} chars
|
|
|
92
92
|
wasSpooled: true,
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
callKey(sessionId, callId) {
|
|
96
|
+
// Session-scoped and hashed: the driver's key space is shared across sessions and outlives
|
|
97
|
+
// runs, while vendor call ids can be index-style ("call_0") and repeat — an unscoped key
|
|
98
|
+
// lets read_result in one session fetch another session's spooled output. Hashing also keeps
|
|
99
|
+
// untrusted call-id characters out of driver keys (parity with Node/Python).
|
|
100
|
+
return simpleHash(`${sessionId}\u0000${callId}`);
|
|
101
|
+
}
|
|
102
|
+
async persistOutput(sessionId, callId, content) {
|
|
96
103
|
const hash = simpleHash(content);
|
|
97
|
-
const key = `.spool/${callId}-${hash.slice(0, 16)}.txt`;
|
|
104
|
+
const key = `.spool/${this.callKey(sessionId, callId)}-${hash.slice(0, 16)}.txt`;
|
|
98
105
|
let promise = this.activeWrites.get(key);
|
|
99
106
|
if (!promise) {
|
|
100
107
|
promise = (async () => {
|
|
@@ -116,10 +123,10 @@ omitted: ${omitted} chars
|
|
|
116
123
|
/**
|
|
117
124
|
* O7: locate a spooled output by the tool call's id (the `read_result` meta-tool only knows
|
|
118
125
|
* `call_id`, not the content-hashed key `persistOutput` chose). Scans the driver's key list for
|
|
119
|
-
* the
|
|
126
|
+
* the hashed session-scoped call-key prefix; returns `undefined` if nothing was ever
|
|
120
127
|
* spooled for that call.
|
|
121
128
|
*/
|
|
122
|
-
async findByCallId(callId) {
|
|
129
|
+
async findByCallId(sessionId, callId) {
|
|
123
130
|
let keys;
|
|
124
131
|
try {
|
|
125
132
|
keys = await this.driver.list();
|
|
@@ -127,7 +134,7 @@ omitted: ${omitted} chars
|
|
|
127
134
|
catch {
|
|
128
135
|
return undefined;
|
|
129
136
|
}
|
|
130
|
-
const prefix = `.spool/${callId}-`;
|
|
137
|
+
const prefix = `.spool/${this.callKey(sessionId, callId)}-`;
|
|
131
138
|
const match = keys.find(k => k.startsWith(prefix) && k.endsWith('.txt'));
|
|
132
139
|
if (!match)
|
|
133
140
|
return undefined;
|
package/dist/runtime/runner.js
CHANGED
|
@@ -158,6 +158,12 @@ export class RuntimeRunner {
|
|
|
158
158
|
async *run(req) {
|
|
159
159
|
const prior = req.inheritEvents ?? await this.opts.sessionLog.read(req.sessionId);
|
|
160
160
|
const midRun = isMidRun(prior);
|
|
161
|
+
// Idempotent per session: an earlier run's `run_started` already carries these attachments
|
|
162
|
+
// (same-session retry attempt), so replay reconstructs them — recording and seeding again
|
|
163
|
+
// would double them in history. Deduping at the append keeps live and replay in agreement.
|
|
164
|
+
const attachments = req.attachments?.length && !attachmentsAlreadySeeded(prior, req.attachments)
|
|
165
|
+
? req.attachments
|
|
166
|
+
: undefined;
|
|
161
167
|
if (!midRun) {
|
|
162
168
|
await this.opts.sessionLog.append(req.sessionId, {
|
|
163
169
|
kind: "run_started",
|
|
@@ -166,10 +172,10 @@ export class RuntimeRunner {
|
|
|
166
172
|
criteria: req.criteria ?? [],
|
|
167
173
|
agent_id: this.opts.agentId,
|
|
168
174
|
system_prompt: this.opts.systemPrompt,
|
|
169
|
-
...(
|
|
175
|
+
...(attachments ? { attachments } : {}),
|
|
170
176
|
});
|
|
171
177
|
}
|
|
172
|
-
yield* this.execute(req.sessionId, req.goal, req.criteria ?? [], req.extensions, prior.length > 0 ? prior : undefined, midRun,
|
|
178
|
+
yield* this.execute(req.sessionId, req.goal, req.criteria ?? [], req.extensions, prior.length > 0 ? prior : undefined, midRun, attachments);
|
|
173
179
|
}
|
|
174
180
|
async *wake(sessionId, extensions) {
|
|
175
181
|
const events = await this.opts.sessionLog.read(sessionId);
|
|
@@ -352,7 +358,7 @@ export class RuntimeRunner {
|
|
|
352
358
|
let full;
|
|
353
359
|
if (full === undefined && this.opts.resultSpool) {
|
|
354
360
|
try {
|
|
355
|
-
full = await this.opts.resultSpool.findByCallId(callId);
|
|
361
|
+
full = await this.opts.resultSpool.findByCallId(sessionId, callId);
|
|
356
362
|
}
|
|
357
363
|
catch {
|
|
358
364
|
full = undefined;
|
|
@@ -801,7 +807,7 @@ export class RuntimeRunner {
|
|
|
801
807
|
let spoolRef;
|
|
802
808
|
let error;
|
|
803
809
|
try {
|
|
804
|
-
spoolRef = await spool.persistOutput(action.callId, action.output);
|
|
810
|
+
spoolRef = await spool.persistOutput(sessionId, action.callId, action.output);
|
|
805
811
|
}
|
|
806
812
|
catch (cause) {
|
|
807
813
|
error = formatToolError(cause);
|
|
@@ -2143,6 +2149,15 @@ function signalToKernelEvent(delivery) {
|
|
|
2143
2149
|
},
|
|
2144
2150
|
};
|
|
2145
2151
|
}
|
|
2152
|
+
/**
|
|
2153
|
+
* True when an earlier run in this session already seeded the same attachments. Replay
|
|
2154
|
+
* reconstructs the attachment message from that run's `run_started`, so recording and
|
|
2155
|
+
* live-seeding them again (a same-session retry attempt) would double them in history.
|
|
2156
|
+
*/
|
|
2157
|
+
function attachmentsAlreadySeeded(prior, attachments) {
|
|
2158
|
+
const wanted = JSON.stringify(attachments);
|
|
2159
|
+
return prior.some(({ event }) => event.kind === "run_started" && JSON.stringify(event.attachments ?? []) === wanted);
|
|
2160
|
+
}
|
|
2146
2161
|
/** Convert SDK ContentParts (camelCase mediaType) to kernel serde shape (media_type). */
|
|
2147
2162
|
function attachmentsToKernelMessage(parts) {
|
|
2148
2163
|
const content = parts.map(p => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepstrike/wasm",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"README.md"
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build:wasm": "wasm-pack build
|
|
13
|
+
"build:wasm": "wasm-pack build ../crates/deepstrike-wasm --target bundler --out-dir ../../wasm/pkg",
|
|
14
14
|
"build": "tsc",
|
|
15
15
|
"test": "node --experimental-vm-modules node_modules/.bin/jest"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@deepstrike/wasm-kernel": "0.2.
|
|
18
|
+
"@deepstrike/wasm-kernel": "0.2.44"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/jest": "^30.0.0",
|