stitchkit 0.68.8 → 0.68.10
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/agent-runtime/deferred-tool-search.d.ts +8 -0
- package/dist/agent-runtime/deferred-tool-search.d.ts.map +1 -0
- package/dist/agent-runtime/deferred-tool-selection.d.ts +15 -0
- package/dist/agent-runtime/deferred-tool-selection.d.ts.map +1 -0
- package/dist/agent-runtime/deferred-tool-types.d.ts +131 -0
- package/dist/agent-runtime/deferred-tool-types.d.ts.map +1 -0
- package/dist/agent-runtime/deferred-tools-internal.d.ts +10 -0
- package/dist/agent-runtime/deferred-tools-internal.d.ts.map +1 -0
- package/dist/agent-runtime/deferred-tools.d.ts +4 -0
- package/dist/agent-runtime/deferred-tools.d.ts.map +1 -0
- package/dist/agent-runtime/run-execution.d.ts.map +1 -1
- package/dist/agent-runtime-openrouter.js +1 -1
- package/dist/agent-runtime.d.ts +1 -0
- package/dist/agent-runtime.d.ts.map +1 -1
- package/dist/agent-runtime.js +471 -73
- package/dist/cli.js +7 -8
- package/dist/contract/index.js +2 -2
- package/dist/{index-vkk06pv1.js → index-22by16v6.js} +57 -9
- package/dist/{index-hmfpjnh7.js → index-22tjt2rk.js} +2 -2
- package/dist/{index-1bmpkhj2.js → index-2t6zt5cg.js} +9 -134
- package/dist/index-bt5179zb.js +99 -0
- package/dist/index-eqqyd9v8.js +130 -0
- package/dist/{index-51a19y3v.js → index-f24xg2cw.js} +2 -2
- package/dist/{index-j2nq04z6.js → index-f6n5n7nz.js} +1 -1
- package/dist/{index-9t2tdk1x.js → index-grgvpbch.js} +3 -5
- package/dist/{index-n34x0q5e.js → index-hb0mncmj.js} +3 -3
- package/dist/{index-6tqys26z.js → index-hcx9yypn.js} +4 -4
- package/dist/{index-z575awm9.js → index-hxh98zbm.js} +2 -2
- package/dist/{index-bmmtz6r9.js → index-pgsyp3xh.js} +1 -1
- package/dist/index-qyrqwr4c.js +41 -0
- package/dist/{index-r5s4wqb5.js → index-t23p2b68.js} +1 -1
- package/dist/{index-3ydx9j01.js → index-xyvxez9r.js} +3 -3
- package/dist/{index-04agqrs8.js → index-y2ctppmg.js} +72 -6
- package/dist/index.js +2 -2
- package/dist/internal/typed.d.ts +8 -0
- package/dist/internal/typed.d.ts.map +1 -1
- package/dist/node.js +5 -5
- package/dist/observability/index.js +4 -4
- package/dist/react.js +1 -1
- package/dist/remote.js +4 -4
- package/dist/server/index.js +7 -7
- package/dist/testing.js +5 -6
- package/dist/tool-invoker.js +6 -8
- package/dist/tools/internal/surface-projector.d.ts +7 -0
- package/dist/tools/internal/surface-projector.d.ts.map +1 -1
- package/dist/tools.js +34 -115
- package/llms-full.txt +150 -4
- package/package.json +1 -1
- package/dist/index-6djpbnda.js +0 -56
- package/dist/index-88yyydag.js +0 -75
- package/dist/index-smpbdg6k.js +0 -27
- /package/dist/{index-tss6bk5c.js → index-ksp6e2ye.js} +0 -0
package/dist/tools.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
redact
|
|
3
|
-
} from "./index-
|
|
3
|
+
} from "./index-22tjt2rk.js";
|
|
4
|
+
import {
|
|
5
|
+
buildToolManifest,
|
|
6
|
+
mountAgent
|
|
7
|
+
} from "./index-bt5179zb.js";
|
|
4
8
|
import {
|
|
5
9
|
signJwt,
|
|
6
10
|
verifyPkce
|
|
7
|
-
} from "./index-
|
|
11
|
+
} from "./index-xyvxez9r.js";
|
|
8
12
|
import {
|
|
9
13
|
DEFAULT_CORS_ALLOW_HEADERS,
|
|
10
14
|
DEFAULT_PROCESS_SIGNALS,
|
|
@@ -12,39 +16,39 @@ import {
|
|
|
12
16
|
defaultSignalSource,
|
|
13
17
|
guardSignalCallback,
|
|
14
18
|
reportSignalError
|
|
15
|
-
} from "./index-
|
|
19
|
+
} from "./index-hxh98zbm.js";
|
|
16
20
|
import {
|
|
17
21
|
createToolInvoker
|
|
18
|
-
} from "./index-
|
|
22
|
+
} from "./index-grgvpbch.js";
|
|
19
23
|
import {
|
|
20
24
|
WaitTimeoutError,
|
|
21
|
-
collectToolSurface,
|
|
22
25
|
createCli,
|
|
23
|
-
createRuntimeToolFactory,
|
|
24
26
|
defineCliCommand,
|
|
25
|
-
defineRuntimeTool,
|
|
26
27
|
fetchGuarded,
|
|
27
28
|
fetchPinnedDocument,
|
|
28
29
|
readCapped,
|
|
29
30
|
runWaitOperation
|
|
30
|
-
} from "./index-
|
|
31
|
+
} from "./index-2t6zt5cg.js";
|
|
31
32
|
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from "./index-
|
|
33
|
+
collectToolSurface,
|
|
34
|
+
createRuntimeToolFactory,
|
|
35
|
+
defineRuntimeTool
|
|
36
|
+
} from "./index-eqqyd9v8.js";
|
|
36
37
|
import {
|
|
37
38
|
ToolExecutionControlError,
|
|
38
39
|
coerceJsonArgs,
|
|
40
|
+
collectTools,
|
|
41
|
+
createToolRunner,
|
|
39
42
|
executeToolMethod,
|
|
43
|
+
formatToolError,
|
|
40
44
|
isToolExecutionControlError,
|
|
41
45
|
toolResultFromError
|
|
42
|
-
} from "./index-
|
|
46
|
+
} from "./index-y2ctppmg.js";
|
|
43
47
|
import {
|
|
44
48
|
getRequestContext,
|
|
45
49
|
getTraceId,
|
|
46
50
|
runWithRequestContext
|
|
47
|
-
} from "./index-
|
|
51
|
+
} from "./index-f24xg2cw.js";
|
|
48
52
|
import {
|
|
49
53
|
ManagedFileError
|
|
50
54
|
} from "./index-bfcpjw20.js";
|
|
@@ -59,17 +63,16 @@ import {
|
|
|
59
63
|
prepareProjectedMcpTools,
|
|
60
64
|
presentationMetadata,
|
|
61
65
|
validateMcpRoundPolicy
|
|
62
|
-
} from "./index-
|
|
63
|
-
import"./index-6djpbnda.js";
|
|
66
|
+
} from "./index-22by16v6.js";
|
|
64
67
|
import"./index-cby4ar3v.js";
|
|
65
68
|
import {
|
|
66
69
|
defineContract,
|
|
67
70
|
normalizeError,
|
|
68
71
|
resolvePropagationContext
|
|
69
|
-
} from "./index-
|
|
72
|
+
} from "./index-pgsyp3xh.js";
|
|
70
73
|
import {
|
|
71
74
|
isRecord
|
|
72
|
-
} from "./index-
|
|
75
|
+
} from "./index-qyrqwr4c.js";
|
|
73
76
|
import {
|
|
74
77
|
AppError,
|
|
75
78
|
STITCH_ERROR_STATUS
|
|
@@ -78,77 +81,6 @@ import {
|
|
|
78
81
|
ManagedFilePathSchema,
|
|
79
82
|
ManagedFileRefSchema
|
|
80
83
|
} from "./index-6k1937bx.js";
|
|
81
|
-
|
|
82
|
-
// src/tools/agent.ts
|
|
83
|
-
import { jsonSchema, tool } from "ai";
|
|
84
|
-
function mountAgent(services, config = {}) {
|
|
85
|
-
const serviceList = Array.isArray(services) ? services : [services];
|
|
86
|
-
const tools = {};
|
|
87
|
-
const runTool = createToolRunner({
|
|
88
|
-
source: "agent",
|
|
89
|
-
extend: config.extend,
|
|
90
|
-
context: config.context,
|
|
91
|
-
hooks: config.hooks,
|
|
92
|
-
lifecycle: config.lifecycle,
|
|
93
|
-
errorHint: config.errorHint,
|
|
94
|
-
coerceJsonArgs: config.coerceJsonArgs,
|
|
95
|
-
onOutputStrip: config.onOutputStrip
|
|
96
|
-
});
|
|
97
|
-
for (const entry of collectToolSurface({
|
|
98
|
-
surface: { services: serviceList, runtimeTools: config.runtimeTools },
|
|
99
|
-
transport: "AGENT",
|
|
100
|
-
extend: config.extend,
|
|
101
|
-
flattenUnionInput: config.flattenUnionInput
|
|
102
|
-
})) {
|
|
103
|
-
const { mountable } = entry;
|
|
104
|
-
const inputSchema = jsonSchema(mountable.presentationSchema, {
|
|
105
|
-
validate: async (value) => isRecord(value) ? { success: true, value } : { success: false, error: new Error("Tool arguments must be an object") }
|
|
106
|
-
});
|
|
107
|
-
const execute = async (rawArgs, options) => {
|
|
108
|
-
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
109
|
-
try {
|
|
110
|
-
const result = await runTool(mountable, args, { signal: options.abortSignal });
|
|
111
|
-
if (result.ok)
|
|
112
|
-
return result.data;
|
|
113
|
-
return formatToolError(result, mountable.name, config.errorHint);
|
|
114
|
-
} catch (err) {
|
|
115
|
-
if (isToolExecutionControlError(err))
|
|
116
|
-
throw err;
|
|
117
|
-
return formatToolError(toolResultFromError(err), mountable.name, config.errorHint);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const presenter = entry.kind === "runtime" ? entry.definition.present?.agent : undefined;
|
|
121
|
-
if (entry.kind === "runtime" && presenter) {
|
|
122
|
-
const { definition } = entry;
|
|
123
|
-
const output = definition.output;
|
|
124
|
-
if (!output) {
|
|
125
|
-
throw new Error(`Runtime tool "${definition.name}" presenter requires an output schema`);
|
|
126
|
-
}
|
|
127
|
-
tools[definition.name] = tool({
|
|
128
|
-
description: definition.description,
|
|
129
|
-
inputSchema,
|
|
130
|
-
outputSchema: output,
|
|
131
|
-
execute,
|
|
132
|
-
toModelOutput: async ({ output: rawOutput }) => {
|
|
133
|
-
const parsed = output.safeParse(rawOutput);
|
|
134
|
-
if (!parsed.success) {
|
|
135
|
-
return { type: "text", value: JSON.stringify(rawOutput) };
|
|
136
|
-
}
|
|
137
|
-
return presenter(parsed.data);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
} else {
|
|
141
|
-
const output = entry.kind === "runtime" ? entry.definition.output : undefined;
|
|
142
|
-
tools[mountable.name] = tool({
|
|
143
|
-
description: mountable.method.desc,
|
|
144
|
-
inputSchema,
|
|
145
|
-
...output && { outputSchema: output },
|
|
146
|
-
execute
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return tools;
|
|
151
|
-
}
|
|
152
84
|
// src/tools/async-operation.ts
|
|
153
85
|
import { z } from "zod";
|
|
154
86
|
|
|
@@ -1003,19 +935,6 @@ function listToolNames(surface) {
|
|
|
1003
935
|
function listContractToolNames(contracts) {
|
|
1004
936
|
return listToolNames({ services: contracts.map(contractOnlyService) });
|
|
1005
937
|
}
|
|
1006
|
-
// src/tools/manifest.ts
|
|
1007
|
-
function buildToolManifest(config) {
|
|
1008
|
-
return collectToolSurface({
|
|
1009
|
-
surface: config,
|
|
1010
|
-
transport: config.transport,
|
|
1011
|
-
extend: config.extend,
|
|
1012
|
-
flattenUnionInput: config.flattenUnionInput
|
|
1013
|
-
}).map(({ mountable }) => ({
|
|
1014
|
-
name: mountable.name,
|
|
1015
|
-
description: mountable.method.desc,
|
|
1016
|
-
inputSchema: mountable.presentationSchema
|
|
1017
|
-
}));
|
|
1018
|
-
}
|
|
1019
938
|
// src/tools/mcp.ts
|
|
1020
939
|
import {
|
|
1021
940
|
createRequestStateCodec,
|
|
@@ -1178,23 +1097,23 @@ async function argumentsDigest(args) {
|
|
|
1178
1097
|
binary += String.fromCodePoint(byte);
|
|
1179
1098
|
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
1180
1099
|
}
|
|
1181
|
-
function operationIdentity(
|
|
1100
|
+
function operationIdentity(tool) {
|
|
1182
1101
|
return {
|
|
1183
|
-
toolName:
|
|
1184
|
-
serviceName:
|
|
1185
|
-
action:
|
|
1186
|
-
method:
|
|
1187
|
-
...
|
|
1102
|
+
toolName: tool.name,
|
|
1103
|
+
serviceName: tool.method.serviceName,
|
|
1104
|
+
action: tool.method.key,
|
|
1105
|
+
method: tool.method.method,
|
|
1106
|
+
...tool.method.scope !== undefined && { scope: tool.method.scope }
|
|
1188
1107
|
};
|
|
1189
1108
|
}
|
|
1190
1109
|
function sameIdentity(left, right) {
|
|
1191
1110
|
return left.toolName === right.toolName && left.serviceName === right.serviceName && left.action === right.action && left.method === right.method && left.scope === right.scope;
|
|
1192
1111
|
}
|
|
1193
|
-
async function runRoundSuccess(
|
|
1112
|
+
async function runRoundSuccess(tool, rawArgs, runTool, context) {
|
|
1194
1113
|
return runTool({
|
|
1195
|
-
...
|
|
1114
|
+
...tool,
|
|
1196
1115
|
method: {
|
|
1197
|
-
...
|
|
1116
|
+
...tool.method,
|
|
1198
1117
|
outputSchema: undefined,
|
|
1199
1118
|
handler: () => {
|
|
1200
1119
|
return;
|
|
@@ -1202,11 +1121,11 @@ async function runRoundSuccess(tool2, rawArgs, runTool, context) {
|
|
|
1202
1121
|
}
|
|
1203
1122
|
}, rawArgs, context);
|
|
1204
1123
|
}
|
|
1205
|
-
async function runRoundFailure(
|
|
1124
|
+
async function runRoundFailure(tool, rawArgs, runTool, context, code, message) {
|
|
1206
1125
|
return runTool({
|
|
1207
|
-
...
|
|
1126
|
+
...tool,
|
|
1208
1127
|
method: {
|
|
1209
|
-
...
|
|
1128
|
+
...tool.method,
|
|
1210
1129
|
outputSchema: undefined,
|
|
1211
1130
|
handler: () => {
|
|
1212
1131
|
throw new AppError(code, message, 400);
|
|
@@ -1402,7 +1321,7 @@ function mountPreparedRuntimeMcp(server, tools, config) {
|
|
|
1402
1321
|
}
|
|
1403
1322
|
server.registerTool(definition.name, toolConfig, async (rawArgs, mcpContext) => runInMcpRequestContext(mcpContext, definition.name, async () => {
|
|
1404
1323
|
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
1405
|
-
const runTool = (
|
|
1324
|
+
const runTool = (tool, toolArgs, roundContext) => executeToolMethod(tool.method, definition.name, toolArgs, { ...config.context, ...roundContext, source: "mcp" }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(definition.name, paths) : undefined);
|
|
1406
1325
|
const round = await resolveMcpRound({
|
|
1407
1326
|
tool: mountable,
|
|
1408
1327
|
rawArgs: args,
|
package/llms-full.txt
CHANGED
|
@@ -3533,6 +3533,36 @@ const exportOperation = defineAsyncOperation({
|
|
|
3533
3533
|
const runtimeTools = exportOperation.runtimeTools
|
|
3534
3534
|
```
|
|
3535
3535
|
|
|
3536
|
+
#### Durable application-owned execution
|
|
3537
|
+
|
|
3538
|
+
The executable reference
|
|
3539
|
+
[`durable-async-operation-harness.ts`](../../packages/core/examples/durable-async-operation-harness.ts)
|
|
3540
|
+
shows the complete boundary behind that surface. It composes
|
|
3541
|
+
`defineAsyncOperationContract`, `defineAsyncOperation`, `createApplication`,
|
|
3542
|
+
`createBoundedAdmission`, managed shutdown and `createAgentToolFenceLifecycle`
|
|
3543
|
+
around an injected store and provider.
|
|
3544
|
+
|
|
3545
|
+
The store transactionally owns the idempotency key **and normalized request
|
|
3546
|
+
hash**. Reusing both returns the existing operation; reusing the key with a
|
|
3547
|
+
different hash conflicts. Every mutation is an expected-revision CAS. Before an
|
|
3548
|
+
external call, the application persists a unique attempt/effect key and marks
|
|
3549
|
+
the dispatch `possibly-dispatched`; a lost response is therefore reconciled by
|
|
3550
|
+
that key after restart and is never treated as permission to submit the effect
|
|
3551
|
+
again. Provider acknowledgement, progress, cancellation intent, result and
|
|
3552
|
+
artifact references remain durable application state.
|
|
3553
|
+
|
|
3554
|
+
Agent tool fencing and operation idempotency are separate guarantees. The fence
|
|
3555
|
+
prevents a stale run owner from crossing an effect boundary; the transactional
|
|
3556
|
+
idempotency record makes a repeated current call converge on one operation.
|
|
3557
|
+
Neither replaces the other.
|
|
3558
|
+
|
|
3559
|
+
Stitchkit deliberately does **not** own the durable queue, operation database,
|
|
3560
|
+
lease renewal, provider retry/reconciliation protocol, asset catalog or domain
|
|
3561
|
+
states. The process-local application resource stops admission and drains
|
|
3562
|
+
accepted work; unresolved durable records survive shutdown for the next
|
|
3563
|
+
recovery pass. The packed consumer lane executes this composition from the
|
|
3564
|
+
published package on Bun and Node.
|
|
3565
|
+
|
|
3536
3566
|
Every follow-up repeats `authorize`; an opaque id is never authority. Aborting
|
|
3537
3567
|
`wait` only stops waiting and never calls optional domain `cancel`.
|
|
3538
3568
|
|
|
@@ -3682,6 +3712,16 @@ fails first on duplicate contract/runtime names. There is no runtime-only
|
|
|
3682
3712
|
manifest helper or public mount adapter: the framework owns merging and schema
|
|
3683
3713
|
projection.
|
|
3684
3714
|
|
|
3715
|
+
Applications using Stitchkit's durable runtime can compose this manifest with
|
|
3716
|
+
bounded per-run activation through `createDeferredAgentToolSurface` from
|
|
3717
|
+
`stitchkit/agent-runtime`. It keeps selected calls as direct `mountAgent` tools
|
|
3718
|
+
rather than routing them through a generic executor. Search receipts live in
|
|
3719
|
+
ordinary durable tool-result history, so recovery restores activation and a
|
|
3720
|
+
queued successor cannot inherit it. See
|
|
3721
|
+
[Bounded deferred tool catalogs](./agent-runtime.md#bounded-deferred-tool-catalogs)
|
|
3722
|
+
and ADR 0129. Raw `mountAgent`, `mountMcp` and `buildToolManifest` behavior is
|
|
3723
|
+
unchanged.
|
|
3724
|
+
|
|
3685
3725
|
`listToolNames` remains diagnostic and reports `kind: 'contract' | 'runtime'`
|
|
3686
3726
|
for every identity. `summarizeTransports` returns `contractServices`,
|
|
3687
3727
|
`runtimeTools`, aggregate `totals`, and a `sources` breakdown. Runtime tools
|
|
@@ -3733,7 +3773,7 @@ description: Configure Stitchkit's optional durable history, stream loop, run co
|
|
|
3733
3773
|
type: architecture
|
|
3734
3774
|
status: active
|
|
3735
3775
|
created: 2026-08-22
|
|
3736
|
-
updated: 2026-08-
|
|
3776
|
+
updated: 2026-08-29
|
|
3737
3777
|
---
|
|
3738
3778
|
|
|
3739
3779
|
# Agent application runtime
|
|
@@ -3888,6 +3928,69 @@ await ticket.accepted
|
|
|
3888
3928
|
const terminal = await ticket.result
|
|
3889
3929
|
```
|
|
3890
3930
|
|
|
3931
|
+
## Bounded deferred tool catalogs
|
|
3932
|
+
|
|
3933
|
+
Use `createDeferredAgentToolSurface` when a measured large catalog makes
|
|
3934
|
+
sending every schema on every provider step expensive. The controller mounts
|
|
3935
|
+
the complete executable surface in process, but initially advertises only its
|
|
3936
|
+
search tool, explicit `alwaysOn` tools and bounded policy pins:
|
|
3937
|
+
|
|
3938
|
+
```ts
|
|
3939
|
+
import { createDeferredAgentToolSurface } from 'stitchkit/agent-runtime'
|
|
3940
|
+
import { composeToolLifecycle } from 'stitchkit/tools'
|
|
3941
|
+
|
|
3942
|
+
const deferred = createDeferredAgentToolSurface({
|
|
3943
|
+
surfaces: {
|
|
3944
|
+
member: { services: memberServices, runtimeTools, alwaysOn: ['ask_user'] },
|
|
3945
|
+
broadcast: { services: broadcastServices, runtimeTools },
|
|
3946
|
+
},
|
|
3947
|
+
selectSurface: ({ context }) => context.mode,
|
|
3948
|
+
pins: ({ context }) => context.skillTools,
|
|
3949
|
+
search: {
|
|
3950
|
+
name: 'tool_search',
|
|
3951
|
+
maxQueryBytes: 1_024,
|
|
3952
|
+
maxResults: 8,
|
|
3953
|
+
maxResultBytes: 8_192,
|
|
3954
|
+
select: ({ query, manifest }) => rankCatalog(query, manifest),
|
|
3955
|
+
},
|
|
3956
|
+
activation: {
|
|
3957
|
+
maxSelectedTools: 8,
|
|
3958
|
+
maxActiveTools: 16,
|
|
3959
|
+
maxSchemaBytes: 32_768,
|
|
3960
|
+
},
|
|
3961
|
+
observe: event => recordDeferredToolEvidence(event),
|
|
3962
|
+
})
|
|
3963
|
+
|
|
3964
|
+
const runtime = createAgentRuntime({
|
|
3965
|
+
// protocol, store, models and prompt...
|
|
3966
|
+
tools: runContext => deferred.mount(runContext, {
|
|
3967
|
+
context: runContext.context,
|
|
3968
|
+
lifecycle: composeToolLifecycle(authLifecycle, runContext.toolFenceLifecycle),
|
|
3969
|
+
}),
|
|
3970
|
+
loop: { prepareStep: deferred.prepareStep(applicationPrepareStep) },
|
|
3971
|
+
})
|
|
3972
|
+
```
|
|
3973
|
+
|
|
3974
|
+
The built-in selector deterministically ranks exact name, prefix/token and
|
|
3975
|
+
description matches. A custom async selector returns names only; unknown and
|
|
3976
|
+
duplicate output is removed against the local canonical manifest. Search never
|
|
3977
|
+
executes the selected operation and never returns its schema. A later provider
|
|
3978
|
+
step receives the real selected tools by name, so their direct lifecycle,
|
|
3979
|
+
fencing, hooks, errors and `present.agent` output remain unchanged.
|
|
3980
|
+
|
|
3981
|
+
Selection is a versioned receipt in the ordinary durable tool-result history.
|
|
3982
|
+
The latest valid same-run search replaces the earlier selection; parallel
|
|
3983
|
+
searches in one step merge in call order. Recovery reconstructs it, while a
|
|
3984
|
+
different run or finite surface cannot inherit it. Known inactive calls take a
|
|
3985
|
+
recoverable `SEARCH_REQUIRED` search round; unknown names still fail.
|
|
3986
|
+
|
|
3987
|
+
Every ceiling is required. `maxSchemaBytes` measures UTF-8 bytes over canonical
|
|
3988
|
+
name, description and presentation schema. It is useful for before/after
|
|
3989
|
+
comparison, but provider serialization and tokenization differ: use existing
|
|
3990
|
+
provider-reported input usage and cost to decide whether the extra search round
|
|
3991
|
+
is beneficial. Controller evidence intentionally omits query text, prompts,
|
|
3992
|
+
arguments and application context. → ADR 0129.
|
|
3993
|
+
|
|
3891
3994
|
### Executable headless harness and capability map
|
|
3892
3995
|
|
|
3893
3996
|
[`packages/core/examples/headless-agent-harness.ts`](../../packages/core/examples/headless-agent-harness.ts)
|
|
@@ -4348,6 +4451,43 @@ These are post-commit notifications, not a transactional outbox: a process can
|
|
|
4348
4451
|
crash between the database commit and `publish`. Reconnect should load canonical
|
|
4349
4452
|
state. Exactly-once external delivery remains an application-owned outbox.
|
|
4350
4453
|
|
|
4454
|
+
### External channel ingress and delivery
|
|
4455
|
+
|
|
4456
|
+
The executable
|
|
4457
|
+
[`external-channel-harness.ts`](../../packages/core/examples/external-channel-harness.ts)
|
|
4458
|
+
is the reference composition for webhooks, polling transports and local-device
|
|
4459
|
+
adapters. Its generic boundary injects a runtime, durable store and delivery
|
|
4460
|
+
adapter; the optional
|
|
4461
|
+
[`external-channel-grammy.ts`](../../packages/core/examples/external-channel-grammy.ts)
|
|
4462
|
+
attaches the same ingress function to grammY polling or webhook lifecycle
|
|
4463
|
+
without putting provider types in the agent runtime.
|
|
4464
|
+
|
|
4465
|
+
Inbound update identity, principal resolution, conversation mapping and reply
|
|
4466
|
+
target are application policy. Persist and deduplicate the update before
|
|
4467
|
+
`runtime.submit`, use the stored idempotency key on crash recovery, then persist
|
|
4468
|
+
the admitted `runId`. A duplicate arriving after restart resolves to that same
|
|
4469
|
+
mapping instead of creating another model turn.
|
|
4470
|
+
|
|
4471
|
+
For output, choose `terminal-only` or `streaming` explicitly. Stable durable
|
|
4472
|
+
`eventId` values and transient `(runtimeEpoch, sequence)` identities become
|
|
4473
|
+
outbox keys; the application store assigns causal ordinals. A bounded channel
|
|
4474
|
+
is only a process-local wakeup and never the durable authority. Before sending,
|
|
4475
|
+
persist one of these states:
|
|
4476
|
+
|
|
4477
|
+
| State | Recovery action |
|
|
4478
|
+
| --- | --- |
|
|
4479
|
+
| `not-dispatched` | may dispatch once |
|
|
4480
|
+
| `possibly-dispatched` | reconcile with the adapter or remain unresolved |
|
|
4481
|
+
| `acknowledged` | deduplicate; delivery is complete |
|
|
4482
|
+
|
|
4483
|
+
The agent `terminal` event and the adapter's delivery receipt are intentionally
|
|
4484
|
+
different records. A successful run does not prove that a reply reached its
|
|
4485
|
+
channel, and a delivery failure never rewrites the canonical agent result.
|
|
4486
|
+
Shutdown stops ingress, drains accepted process-local work and leaves ambiguous
|
|
4487
|
+
outbox records visible for a later reconciliation pass. Stitchkit does not own
|
|
4488
|
+
a channel database, durable broker, provider payload schema or application
|
|
4489
|
+
identity policy.
|
|
4490
|
+
|
|
4351
4491
|
Durable event IDs are derived from run, event type and snapshot version. Use
|
|
4352
4492
|
`advanceAgentRuntimeEventCursor` to classify delivery.
|
|
4353
4493
|
|
|
@@ -11616,6 +11756,12 @@ Server-only optional application runtime. See the
|
|
|
11616
11756
|
| Export | Kind | Summary |
|
|
11617
11757
|
|--------|------|---------|
|
|
11618
11758
|
| `createAgentRuntime` | function | compose durable acceptance, stream loop, checkpoints, coordination, managed tools and winner-only terminal publication; reconciles same-owner terminal/interrupt/head CAS races before releasing the lane |
|
|
11759
|
+
| `createDeferredAgentToolSurface` | function | bounded canonical catalog search plus durable same-run activation of direct `mountAgent` tools; supports one immutable surface or a finite identity-specific registry |
|
|
11760
|
+
| `DeferredAgentToolSearchInputSchema` / `DeferredAgentToolMatchSchema` / `DeferredAgentToolReceiptSchema` | schema | bounded search input, public match and versioned durable selection receipt |
|
|
11761
|
+
| `DeferredAgentToolSurfaceConfig` / `DeferredAgentToolCommonConfig` / `DeferredAgentToolSurfaceDefinition` / `DeferredAgentToolController` | _type_ | finite catalogs, selector, pin, budget and `mount`/`prepareStep` composition contracts |
|
|
11762
|
+
| `DeferredAgentRuntimeToolDefinition` / `DeferredAgentToolMountConfig` | _type_ | peer-free Agent-only runtime definition and canonical mount configuration accepted by the controller |
|
|
11763
|
+
| `DeferredAgentToolManifestEntry` / `DeferredAgentToolSearchContext` / `DeferredAgentToolReceipt` | _type_ | canonical selector input and inferred durable receipt records |
|
|
11764
|
+
| `DeferredAgentToolEvent` | _type_ | PII-free search/step evidence with surface, provenance, counts, canonical schema bytes and ceilings |
|
|
11619
11765
|
| `defineAgentProtocol` | function | declare context, input metadata, canonical parts and optional pre-CAS terminal acceptance (`allow-empty`, `require-output` or callback) |
|
|
11620
11766
|
| `hasAgentTerminalOutput` | function | generic `require-output` predicate for non-blank text, generated files, structured provider parts and explicit tool-only policy stops |
|
|
11621
11767
|
| `AgentMessageSchema` / `AgentRunSchema` / `AgentSnapshotSchema` | schema | versioned canonical engine records |
|
|
@@ -11646,7 +11792,7 @@ Server-only optional application runtime. See the
|
|
|
11646
11792
|
| `AgentSessionCloseOptions` | _type_ | `gracePeriodMs` for natural settlement, then abort, then `forceTimeoutMs` for bounded settlement after it |
|
|
11647
11793
|
| `AgentSessionCloseResult` | _type_ | what `close()` achieved: `settled`, or `timedOut` with `remaining` runs still in flight. Only omitting `forceTimeoutMs` guarantees nothing is in flight on return |
|
|
11648
11794
|
| `AgentHistoryProjectionOptions` | _type_ | storage-neutral file resolver, explicit unresolved-file behavior, and how an interrupted turn reaches the model (`interruptedAssistant`) |
|
|
11649
|
-
| `createAgentToolFenceLifecycle` | function | pre-effect and post-effect run ownership fence for `mountAgent
|
|
11795
|
+
| `createAgentToolFenceLifecycle` | function | pre-effect and post-effect run ownership fence for `mountAgent`; compose beside application idempotency for [durable operations](../guide/mcp-and-agents.md#durable-application-owned-execution) |
|
|
11650
11796
|
| `AgentRuntimeEventSchema` | schema | transient stream lifecycle plus post-commit admission/checkpoint/run-state/terminal projections |
|
|
11651
11797
|
| `createAgentObservability` | function | separate agent-run sink over the shared bounded observability lifecycle |
|
|
11652
11798
|
|
|
@@ -12035,8 +12181,8 @@ runtime-tool runner, plus deliberate raw MCP adapters over the same mechanics.
|
|
|
12035
12181
|
| `NativeToolIdentity` | _type_ | pathless service/action/scope/meta identity; semantic method is factory-owned |
|
|
12036
12182
|
| `ManagedWaitRender` | _type_ | optional managed wait terminal text and failure classification |
|
|
12037
12183
|
| `UploadToolInputSchema` | constant | fixed `{ path: string }` input schema for `defineUploadTool` |
|
|
12038
|
-
| `defineAsyncOperation` | function | runtime-only start/status/wait plus configured cancel/result/artifacts definitions |
|
|
12039
|
-
| `defineAsyncOperationContract` | function | define one canonical Zod-first HTTP contract for start/status/wait plus optional capabilities |
|
|
12184
|
+
| `defineAsyncOperation` | function | runtime-only start/status/wait plus configured cancel/result/artifacts definitions; see the [durable application-owned recipe](../guide/mcp-and-agents.md#durable-application-owned-execution) |
|
|
12185
|
+
| `defineAsyncOperationContract` | function | define one canonical Zod-first HTTP contract for start/status/wait plus optional capabilities; execution and recovery remain application-owned |
|
|
12040
12186
|
| `bindContractAsyncOperation` | function | bind literal methods from an existing contract without creating another HTTP surface |
|
|
12041
12187
|
| `createAsyncOperationSnapshotSchema` | function | canonical pending/running/succeeded/failed/cancelled Zod snapshot |
|
|
12042
12188
|
| `AsyncOperationCancelResultSchema` | constant | validated accepted/already_terminal/rejected cancellation result |
|
package/package.json
CHANGED
package/dist/index-6djpbnda.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
toJsonSchema
|
|
3
|
-
} from "./index-cby4ar3v.js";
|
|
4
|
-
|
|
5
|
-
// src/tools/schema.ts
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
function objectShapeKeys(schema) {
|
|
8
|
-
return schema instanceof z.ZodObject ? Object.keys(schema.shape) : [];
|
|
9
|
-
}
|
|
10
|
-
function keyPolicyOf(schema) {
|
|
11
|
-
return schema.def.catchall;
|
|
12
|
-
}
|
|
13
|
-
function rebuildObject(source, shape) {
|
|
14
|
-
return withKeyPolicy(z.object(shape), keyPolicyOf(source));
|
|
15
|
-
}
|
|
16
|
-
function withKeyPolicy(object, policy) {
|
|
17
|
-
if (policy === undefined)
|
|
18
|
-
return object;
|
|
19
|
-
return object.catchall(representable(policy));
|
|
20
|
-
}
|
|
21
|
-
function representable(policy) {
|
|
22
|
-
if (policy instanceof z.ZodNever || policy instanceof z.ZodUnknown)
|
|
23
|
-
return policy;
|
|
24
|
-
if (!(policy instanceof z.ZodType))
|
|
25
|
-
return z.unknown();
|
|
26
|
-
try {
|
|
27
|
-
toJsonSchema(policy, "input");
|
|
28
|
-
return policy;
|
|
29
|
-
} catch {
|
|
30
|
-
return z.unknown();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function mergeSchemas(paramsSchema, inputSchema) {
|
|
34
|
-
if (paramsSchema && !(paramsSchema instanceof z.ZodObject)) {
|
|
35
|
-
throw new Error("Tool params schema must be a z.object()");
|
|
36
|
-
}
|
|
37
|
-
const paramsObject = paramsSchema instanceof z.ZodObject ? paramsSchema : undefined;
|
|
38
|
-
if (!inputSchema) {
|
|
39
|
-
return paramsObject ?? z.object({});
|
|
40
|
-
}
|
|
41
|
-
if (inputSchema instanceof z.ZodObject) {
|
|
42
|
-
if (paramsObject) {
|
|
43
|
-
const conflicts = Object.keys(paramsObject.shape).filter((key) => (key in inputSchema.shape));
|
|
44
|
-
if (conflicts.length > 0) {
|
|
45
|
-
throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return rebuildObject(inputSchema, {
|
|
49
|
-
...paramsObject?.shape ?? {},
|
|
50
|
-
...inputSchema.shape
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return paramsObject ? z.intersection(paramsObject, inputSchema) : inputSchema;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { objectShapeKeys, rebuildObject, mergeSchemas };
|
package/dist/index-88yyydag.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
executeToolMethod
|
|
3
|
-
} from "./index-04agqrs8.js";
|
|
4
|
-
import {
|
|
5
|
-
assertToolExtensionCompatible,
|
|
6
|
-
projectToolSurface
|
|
7
|
-
} from "./index-vkk06pv1.js";
|
|
8
|
-
import {
|
|
9
|
-
mergeSchemas,
|
|
10
|
-
rebuildObject
|
|
11
|
-
} from "./index-6djpbnda.js";
|
|
12
|
-
|
|
13
|
-
// src/tools/mount.ts
|
|
14
|
-
import { z } from "zod";
|
|
15
|
-
function applyExtend(base, extra) {
|
|
16
|
-
if (base instanceof z.ZodObject) {
|
|
17
|
-
assertToolExtensionCompatible(base, extra);
|
|
18
|
-
return rebuildObject(base, { ...extra, ...base.shape });
|
|
19
|
-
}
|
|
20
|
-
return z.intersection(z.object(extra), base);
|
|
21
|
-
}
|
|
22
|
-
function contractToolMountable(projected, extend) {
|
|
23
|
-
const method = projected.source;
|
|
24
|
-
const baseArgumentSchema = mergeSchemas(method.paramsSchema, method.inputSchema);
|
|
25
|
-
const argumentSchema = projected.shouldExtend && extend ? applyExtend(baseArgumentSchema, extend.schema) : baseArgumentSchema;
|
|
26
|
-
return {
|
|
27
|
-
method,
|
|
28
|
-
name: projected.name,
|
|
29
|
-
argumentSchema,
|
|
30
|
-
presentationSchema: projected.presentationSchema,
|
|
31
|
-
shouldExtend: projected.shouldExtend
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function collectTools(service, transport, config = {}) {
|
|
35
|
-
const { extend, flattenUnionInput = false, assertNames = true } = config;
|
|
36
|
-
const tools = [];
|
|
37
|
-
for (const projected of projectToolSurface({ services: [service] }, transport === "HTTP" ? "AGENT" : transport, {
|
|
38
|
-
extend,
|
|
39
|
-
flattenUnionInput,
|
|
40
|
-
assertNames,
|
|
41
|
-
assertUniqueNames: false
|
|
42
|
-
})) {
|
|
43
|
-
if (projected.kind !== "contract")
|
|
44
|
-
continue;
|
|
45
|
-
tools.push(contractToolMountable(projected, extend));
|
|
46
|
-
}
|
|
47
|
-
return tools;
|
|
48
|
-
}
|
|
49
|
-
function createToolRunner(config) {
|
|
50
|
-
const extension = config.extend ? {
|
|
51
|
-
schema: z.object(config.extend.schema),
|
|
52
|
-
resolve: config.extend.resolve
|
|
53
|
-
} : undefined;
|
|
54
|
-
return async function runOneToolCall(tool, rawArgs, context) {
|
|
55
|
-
return executeToolMethod(tool.method, tool.name, rawArgs, { ...config.context, ...context, source: config.source }, config.hooks, config.lifecycle, config.coerceJsonArgs ?? true, config.onOutputStrip ? (paths) => config.onOutputStrip?.(tool.name, paths) : undefined, tool.shouldExtend ? extension : undefined);
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function formatToolError(result, toolName, errorHint) {
|
|
59
|
-
const err = { error: result.code };
|
|
60
|
-
if (result.details)
|
|
61
|
-
err.details = result.details;
|
|
62
|
-
const hints = [];
|
|
63
|
-
if (result.hint)
|
|
64
|
-
hints.push(result.hint);
|
|
65
|
-
if (errorHint && toolName) {
|
|
66
|
-
const global = errorHint(toolName, result.code);
|
|
67
|
-
if (global)
|
|
68
|
-
hints.push(global);
|
|
69
|
-
}
|
|
70
|
-
if (hints.length > 0)
|
|
71
|
-
err._hint = hints.join(" ");
|
|
72
|
-
return err;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export { contractToolMountable, collectTools, createToolRunner, formatToolError };
|
package/dist/index-smpbdg6k.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// src/internal/typed.ts
|
|
2
|
-
function typedEntries(value) {
|
|
3
|
-
return Object.entries(value);
|
|
4
|
-
}
|
|
5
|
-
function isRecord(value) {
|
|
6
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
-
}
|
|
8
|
-
function callRuntimeHandler(handler, context) {
|
|
9
|
-
if (typeof handler !== "function") {
|
|
10
|
-
throw new TypeError("Runtime handler must be a function");
|
|
11
|
-
}
|
|
12
|
-
return Reflect.apply(handler, undefined, [context]);
|
|
13
|
-
}
|
|
14
|
-
function transportResult(value) {
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
17
|
-
function mapObject(source, mapper) {
|
|
18
|
-
const result = {};
|
|
19
|
-
for (const [key, value] of typedEntries(source)) {
|
|
20
|
-
const mapped = mapper(key, value);
|
|
21
|
-
if (mapped !== undefined)
|
|
22
|
-
result[key] = mapped;
|
|
23
|
-
}
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { typedEntries, isRecord, callRuntimeHandler, transportResult, mapObject };
|
|
File without changes
|