impel-cli 0.20.13 → 0.20.14
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/RELEASE_NOTES.md +10 -0
- package/package.json +1 -1
- package/src/nativeAgentTransport.js +58 -6
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.14 — Opaque direct-answer continuations
|
|
4
|
+
|
|
5
|
+
- Returns a minimal local continuation locator for read-only direct answers,
|
|
6
|
+
so wrapper models no longer need to copy policy or request fingerprints.
|
|
7
|
+
- Resolves the locator against integrity-validated tenant-local state and the
|
|
8
|
+
MCP server's fixed agent binding; durable and write-capable handles retain
|
|
9
|
+
their full fail-closed validation.
|
|
10
|
+
- Adds a regression test for the production case where Claude shortened a
|
|
11
|
+
request fingerprint while preserving the invocation id.
|
|
12
|
+
|
|
3
13
|
## 0.20.13 — Allocation publication race
|
|
4
14
|
|
|
5
15
|
- Retries allocation when a competing process moves the published lock between
|
package/package.json
CHANGED
|
@@ -31,6 +31,7 @@ export {
|
|
|
31
31
|
NATIVE_AGENT_RUN_TOOL,
|
|
32
32
|
};
|
|
33
33
|
export const NATIVE_AGENT_HANDLE_SCHEMA = "impel.native-agent-run.v1";
|
|
34
|
+
export const NATIVE_AGENT_CONTINUATION_SCHEMA = "impel.native-agent-continuation.v1";
|
|
34
35
|
export const NATIVE_AGENT_RESULT_SCHEMA = "impel.native-agent-result.v1";
|
|
35
36
|
export const NATIVE_AGENT_RECOVERY_SCHEMA = "impel.native-agent-recovery.v1";
|
|
36
37
|
|
|
@@ -390,7 +391,21 @@ function handleForState(state) {
|
|
|
390
391
|
};
|
|
391
392
|
}
|
|
392
393
|
|
|
394
|
+
function continuationForState(state) {
|
|
395
|
+
return {
|
|
396
|
+
schema: NATIVE_AGENT_CONTINUATION_SCHEMA,
|
|
397
|
+
invocationId: state.invocationId,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
393
401
|
function normalizeHandle(value) {
|
|
402
|
+
if (value?.schema === NATIVE_AGENT_CONTINUATION_SCHEMA) {
|
|
403
|
+
exactObject(value, ["schema", "invocationId"], "native-agent continuation");
|
|
404
|
+
if (typeof value.invocationId !== "string" || !SAFE_INVOCATION_RE.test(value.invocationId)) {
|
|
405
|
+
throw new Error("native-agent continuation invocationId is invalid");
|
|
406
|
+
}
|
|
407
|
+
return { ...value };
|
|
408
|
+
}
|
|
394
409
|
exactObject(value, [
|
|
395
410
|
"schema",
|
|
396
411
|
"tenantId",
|
|
@@ -1564,6 +1579,18 @@ export class NativeAgentCompositeTransport {
|
|
|
1564
1579
|
}
|
|
1565
1580
|
|
|
1566
1581
|
validateBoundState(state, handle) {
|
|
1582
|
+
if (handle.schema === NATIVE_AGENT_CONTINUATION_SCHEMA) {
|
|
1583
|
+
if (state.startMode !== "answer") {
|
|
1584
|
+
throw new Error("native-agent continuation does not identify a direct-answer run");
|
|
1585
|
+
}
|
|
1586
|
+
if (state.tenantId !== this.tenantId
|
|
1587
|
+
|| state.agentId !== this.agentId
|
|
1588
|
+
|| state.scopeParam !== this.scopeParam
|
|
1589
|
+
|| state.policyFingerprint !== this.policyFingerprint) {
|
|
1590
|
+
throw new Error("native-agent continuation does not match this fixed binding");
|
|
1591
|
+
}
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1567
1594
|
const expected = {
|
|
1568
1595
|
tenantId: this.tenantId,
|
|
1569
1596
|
agentId: this.agentId,
|
|
@@ -1780,7 +1807,9 @@ export class NativeAgentCompositeTransport {
|
|
|
1780
1807
|
runId: state.upstreamRunId,
|
|
1781
1808
|
};
|
|
1782
1809
|
}
|
|
1783
|
-
return result
|
|
1810
|
+
return result?.schema === NATIVE_AGENT_HANDLE_SCHEMA
|
|
1811
|
+
? continuationForState(state)
|
|
1812
|
+
: result;
|
|
1784
1813
|
} catch (error) {
|
|
1785
1814
|
if (!state) throw error;
|
|
1786
1815
|
if (lock) {
|
|
@@ -1790,7 +1819,7 @@ export class NativeAgentCompositeTransport {
|
|
|
1790
1819
|
// The persisted handle remains authoritative after a lost lease.
|
|
1791
1820
|
}
|
|
1792
1821
|
}
|
|
1793
|
-
return
|
|
1822
|
+
return continuationForState(state);
|
|
1794
1823
|
} finally {
|
|
1795
1824
|
lock?.release();
|
|
1796
1825
|
attachment.dispose();
|
|
@@ -1811,11 +1840,14 @@ export class NativeAgentCompositeTransport {
|
|
|
1811
1840
|
// upstream byte is sent.
|
|
1812
1841
|
lock = this.acquireLock(state.invocationId);
|
|
1813
1842
|
if (!lock) return handleForState(state);
|
|
1814
|
-
|
|
1843
|
+
const result = await this.attach(state, prepared, {
|
|
1815
1844
|
signal: attachment.signal,
|
|
1816
1845
|
onProgress,
|
|
1817
1846
|
lock,
|
|
1818
1847
|
});
|
|
1848
|
+
return state.startMode === "answer" && result?.schema === NATIVE_AGENT_HANDLE_SCHEMA
|
|
1849
|
+
? continuationForState(state)
|
|
1850
|
+
: result;
|
|
1819
1851
|
} catch (error) {
|
|
1820
1852
|
// Once state exists, cancellation or the local attachment deadline must
|
|
1821
1853
|
// hand the caller the only handle that can resume it.
|
|
@@ -1834,7 +1866,7 @@ export class NativeAgentCompositeTransport {
|
|
|
1834
1866
|
exactObject(args, ["handle"], "resume_native_agent_run arguments");
|
|
1835
1867
|
if (!Object.hasOwn(args, "handle")) throw new Error("resume_native_agent_run requires a handle");
|
|
1836
1868
|
const handle = normalizeHandle(args.handle);
|
|
1837
|
-
if (handle.tenantId !== this.tenantId) {
|
|
1869
|
+
if (handle.schema === NATIVE_AGENT_HANDLE_SCHEMA && handle.tenantId !== this.tenantId) {
|
|
1838
1870
|
throw new Error("native-agent run handle does not match this fixed tenant");
|
|
1839
1871
|
}
|
|
1840
1872
|
this.ensureRoots();
|
|
@@ -2130,7 +2162,7 @@ export class NativeAgentCompositeTransport {
|
|
|
2130
2162
|
result = resultForState(state);
|
|
2131
2163
|
if (result.schema === NATIVE_AGENT_RESULT_SCHEMA) return result;
|
|
2132
2164
|
}
|
|
2133
|
-
return handleForState(state);
|
|
2165
|
+
return state.startMode === "answer" ? continuationForState(state) : handleForState(state);
|
|
2134
2166
|
} catch (error) {
|
|
2135
2167
|
if (!state.upstreamRunId) throw error;
|
|
2136
2168
|
try {
|
|
@@ -2167,6 +2199,19 @@ const HANDLE_SCHEMA = {
|
|
|
2167
2199
|
},
|
|
2168
2200
|
};
|
|
2169
2201
|
|
|
2202
|
+
const ANSWER_RESUME_SCHEMA = {
|
|
2203
|
+
type: "object",
|
|
2204
|
+
additionalProperties: false,
|
|
2205
|
+
required: ["schema", "invocationId"],
|
|
2206
|
+
properties: {
|
|
2207
|
+
...HANDLE_SCHEMA.properties,
|
|
2208
|
+
schema: {
|
|
2209
|
+
type: "string",
|
|
2210
|
+
enum: [NATIVE_AGENT_CONTINUATION_SCHEMA, NATIVE_AGENT_HANDLE_SCHEMA],
|
|
2211
|
+
},
|
|
2212
|
+
},
|
|
2213
|
+
};
|
|
2214
|
+
|
|
2170
2215
|
export function nativeAgentCompositeTools({ mode = "durable" } = {}) {
|
|
2171
2216
|
if (!["durable", "recovery", "answer"].includes(mode)) throw new Error("invalid native-agent MCP mode");
|
|
2172
2217
|
const answerTool = {
|
|
@@ -2233,7 +2278,14 @@ export function nativeAgentCompositeTools({ mode = "durable" } = {}) {
|
|
|
2233
2278
|
// continuation handle. Once that handle exists, resume is the only valid
|
|
2234
2279
|
// next action; exposing recovery here gives the wrapper model an
|
|
2235
2280
|
// unnecessary branch and can add a fifth inference round to healthy runs.
|
|
2236
|
-
|
|
2281
|
+
const resumeTool = tools.find(({ name }) => name === NATIVE_AGENT_RESUME_TOOL);
|
|
2282
|
+
return [answerTool, {
|
|
2283
|
+
...resumeTool,
|
|
2284
|
+
inputSchema: {
|
|
2285
|
+
...resumeTool.inputSchema,
|
|
2286
|
+
properties: { handle: ANSWER_RESUME_SCHEMA },
|
|
2287
|
+
},
|
|
2288
|
+
}];
|
|
2237
2289
|
}
|
|
2238
2290
|
return mode === "recovery" ? tools.filter(({ name }) => name !== NATIVE_AGENT_RUN_TOOL) : tools;
|
|
2239
2291
|
}
|