stitchkit 0.102.0 → 0.103.1
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 +64 -0
- package/dist/agent-runtime/browser-control-contract.d.ts +1118 -0
- package/dist/agent-runtime/browser-control-contract.d.ts.map +1 -0
- package/dist/agent-runtime/browser-controller.d.ts +31 -0
- package/dist/agent-runtime/browser-controller.d.ts.map +1 -0
- package/dist/agent-runtime/harness-control.d.ts.map +1 -1
- package/dist/agent-runtime/harness-realtime.d.ts +25 -0
- package/dist/agent-runtime/harness-realtime.d.ts.map +1 -0
- package/dist/agent-runtime/harness-tools.d.ts +11 -0
- package/dist/agent-runtime/harness-tools.d.ts.map +1 -0
- package/dist/agent-runtime/react.d.ts +4 -0
- package/dist/agent-runtime/react.d.ts.map +1 -0
- package/dist/agent-runtime/run-assertions.d.ts +63 -0
- package/dist/agent-runtime/run-assertions.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-contract.d.ts +46 -7
- package/dist/application/diagnostic-journal-contract.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-frame.d.ts +9 -0
- package/dist/application/diagnostic-journal-frame.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-manager.d.ts.map +1 -1
- package/dist/application/diagnostic-journal-read-contract.d.ts +110 -0
- package/dist/application/diagnostic-journal-read-contract.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-reader.d.ts +13 -0
- package/dist/application/diagnostic-journal-reader.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-recovery.d.ts +4 -0
- package/dist/application/diagnostic-journal-recovery.d.ts.map +1 -0
- package/dist/application/diagnostic-journal-storage.d.ts +2 -0
- package/dist/application/diagnostic-journal-storage.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/browser.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/browser.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/browser.js +235 -0
- package/dist/entrypoints/agent-runtime/harness-tools.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/harness-tools.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/harness-tools.js +32 -0
- package/dist/entrypoints/agent-runtime/harness.js +11 -226
- package/dist/entrypoints/agent-runtime/react.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/react.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/react.js +8 -0
- package/dist/entrypoints/agent-runtime/realtime.d.ts +2 -0
- package/dist/entrypoints/agent-runtime/realtime.d.ts.map +1 -0
- package/dist/entrypoints/agent-runtime/realtime.js +159 -0
- package/dist/entrypoints/agent-runtime/testing.d.ts +1 -0
- package/dist/entrypoints/agent-runtime/testing.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/testing.js +67 -2
- package/dist/entrypoints/agent-runtime.js +23 -18
- package/dist/entrypoints/application/diagnostic-journal.d.ts +1 -0
- package/dist/entrypoints/application/diagnostic-journal.d.ts.map +1 -1
- package/dist/entrypoints/application/diagnostic-journal.js +213 -19
- package/dist/entrypoints/application.d.ts +1 -0
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +10 -2
- package/dist/entrypoints/cli.js +6 -6
- package/dist/entrypoints/index.js +15 -226
- package/dist/entrypoints/node.js +7 -5
- package/dist/entrypoints/observability.js +2 -2
- package/dist/entrypoints/react.js +2 -2
- package/dist/entrypoints/remote.js +3 -3
- package/dist/entrypoints/server.js +10 -8
- package/dist/entrypoints/testing.js +3 -3
- package/dist/entrypoints/tools/invoker.js +5 -5
- package/dist/entrypoints/tools.js +23 -34
- package/dist/entrypoints/tracking.js +2 -2
- package/dist/{index-d82d3xg4.js → index-0c419yx7.js} +1 -1
- package/dist/{index-dvwj1f43.js → index-0efgsyav.js} +1 -1
- package/dist/index-20yvtn9a.js +38 -0
- package/dist/{index-a9pd417t.js → index-5vyd0fkb.js} +1 -34
- package/dist/{index-r1z0rd9c.js → index-7n68nmc6.js} +1 -1
- package/dist/index-860vjkgm.js +48 -0
- package/dist/index-c9d05kvt.js +11 -0
- package/dist/{index-m9fndta6.js → index-ds7jdhep.js} +2 -2
- package/dist/index-jn9g8xdt.js +246 -0
- package/dist/{index-n9tyz8z3.js → index-kgmh97hf.js} +1 -1
- package/dist/{index-c6aagrbd.js → index-kkk1wzsq.js} +3 -3
- package/dist/index-nggfa2yn.js +34 -0
- package/dist/{index-m79yr938.js → index-pw99k9h5.js} +1 -10
- package/dist/index-qapzv4p5.js +54 -0
- package/dist/index-r34mvse1.js +225 -0
- package/dist/index-srs8hj9c.js +10 -0
- package/dist/index-vgkbcnkc.js +29 -0
- package/dist/{index-ewbaywk5.js → index-x1dkwx5x.js} +1 -1
- package/dist/{index-xkhk5d6g.js → index-xgc94hy6.js} +5 -48
- package/dist/{index-3ct7hhq6.js → index-xwq9j1sf.js} +6 -56
- package/dist/{index-hby4qhax.js → index-yex7eg1v.js} +4 -10
- package/dist/{index-1h6gtdrj.js → index-ygkka6zn.js} +1 -1
- package/dist/{index-zs4ms3th.js → index-z3pqcy7r.js} +7 -30
- package/dist/index-z94wht4y.js +156 -0
- package/dist/index-ze1eph1k.js +20 -0
- package/llms/agent-runtime-browser.txt +26 -0
- package/llms/agent-runtime-harness-tools.txt +25 -0
- package/llms/agent-runtime-harness.txt +140 -1
- package/llms/agent-runtime-react.txt +21 -0
- package/llms/agent-runtime-realtime.txt +30 -0
- package/llms/agent-runtime-testing.txt +6 -0
- package/llms/application-diagnostic-journal.txt +2 -0
- package/llms/application.2.txt +157 -267
- package/llms/application.3.txt +278 -0
- package/llms/application.txt +43 -158
- package/llms/stitchkit.txt +9 -5
- package/llms/{upgrading-0.75.0-0.102.0.txt → upgrading-0.75.0-0.103.0.txt} +32 -3
- package/llms/upgrading.txt +1 -1
- package/llms-full.txt +289 -9
- package/llms.txt +11 -7
- package/package.json +13 -1
- package/dist/index-h124epcf.js +0 -103
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord
|
|
3
|
+
} from "./index-9jfdm5tg.js";
|
|
4
|
+
|
|
5
|
+
// src/application/diagnostic-journal-frame.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var DiagnosticJournalFrameSchema2 = z.object({
|
|
8
|
+
schemaVersion: z.literal(1),
|
|
9
|
+
epoch: z.uuid(),
|
|
10
|
+
sequence: z.number().int().positive(),
|
|
11
|
+
event: z.json()
|
|
12
|
+
}).strict().readonly();
|
|
13
|
+
|
|
14
|
+
// src/application/diagnostic-journal-read-contract.ts
|
|
15
|
+
import { z as z2 } from "zod";
|
|
16
|
+
var ByteCountSchema = z2.number().int().nonnegative();
|
|
17
|
+
var LocationSchema = z2.object({
|
|
18
|
+
file: z2.string(),
|
|
19
|
+
offset: ByteCountSchema,
|
|
20
|
+
line: z2.number().int().positive()
|
|
21
|
+
});
|
|
22
|
+
var DiagnosticJournalAnomalySchema2 = LocationSchema.extend({
|
|
23
|
+
reason: z2.enum([
|
|
24
|
+
"nul-byte",
|
|
25
|
+
"unterminated-line",
|
|
26
|
+
"invalid-utf8",
|
|
27
|
+
"invalid-json",
|
|
28
|
+
"invalid-frame",
|
|
29
|
+
"invalid-event",
|
|
30
|
+
"oversized-line"
|
|
31
|
+
]),
|
|
32
|
+
position: z2.enum(["tail", "interior"]),
|
|
33
|
+
terminated: z2.boolean(),
|
|
34
|
+
skippedBytes: ByteCountSchema
|
|
35
|
+
}).strict().readonly();
|
|
36
|
+
function createDiagnosticJournalReadResultSchema2(eventSchema) {
|
|
37
|
+
return z2.discriminatedUnion("type", [
|
|
38
|
+
LocationSchema.extend({
|
|
39
|
+
type: z2.literal("frame"),
|
|
40
|
+
bytes: ByteCountSchema,
|
|
41
|
+
frame: DiagnosticJournalFrameSchema2.unwrap().extend({ event: eventSchema }).readonly()
|
|
42
|
+
}).strict().readonly(),
|
|
43
|
+
z2.object({ type: z2.literal("anomaly"), anomaly: DiagnosticJournalAnomalySchema2 }).strict().readonly()
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
var DiagnosticJournalRecoveryStatusSchema2 = z2.object({
|
|
47
|
+
filesChecked: ByteCountSchema,
|
|
48
|
+
anomalies: ByteCountSchema,
|
|
49
|
+
skippedBytes: ByteCountSchema,
|
|
50
|
+
firstAnomaly: DiagnosticJournalAnomalySchema2.optional(),
|
|
51
|
+
lastAnomaly: DiagnosticJournalAnomalySchema2.optional()
|
|
52
|
+
}).strict().readonly();
|
|
53
|
+
|
|
54
|
+
class DiagnosticJournalRecoveryError2 extends Error {
|
|
55
|
+
recovery;
|
|
56
|
+
constructor(recovery) {
|
|
57
|
+
super("Diagnostic journal tail recovery requires maxFiles >= 2; no data was removed");
|
|
58
|
+
this.recovery = recovery;
|
|
59
|
+
this.name = "DiagnosticJournalRecoveryError";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/application/diagnostic-journal-contract.ts
|
|
64
|
+
import { z as z3 } from "zod";
|
|
65
|
+
var PositiveSafeIntegerSchema = z3.number().int().positive();
|
|
66
|
+
var FileModeSchema = z3.number().int().min(0).max(511);
|
|
67
|
+
var DiagnosticJournalLimitsSchema2 = z3.object({
|
|
68
|
+
maxEventBytes: PositiveSafeIntegerSchema,
|
|
69
|
+
maxPendingItems: PositiveSafeIntegerSchema,
|
|
70
|
+
maxPendingBytes: PositiveSafeIntegerSchema,
|
|
71
|
+
maxFileBytes: PositiveSafeIntegerSchema,
|
|
72
|
+
maxFiles: PositiveSafeIntegerSchema
|
|
73
|
+
}).strict().readonly();
|
|
74
|
+
var DiagnosticJournalLockPolicySchema2 = z3.enum(["refuse", "reclaim-stale"]);
|
|
75
|
+
var DiagnosticJournalStateSchema2 = z3.enum(["open", "draining", "closed", "failed"]);
|
|
76
|
+
var DiagnosticJournalRefusalReasonSchema2 = z3.enum([
|
|
77
|
+
"closed",
|
|
78
|
+
"failed",
|
|
79
|
+
"invalid",
|
|
80
|
+
"oversized",
|
|
81
|
+
"item-capacity",
|
|
82
|
+
"byte-capacity"
|
|
83
|
+
]);
|
|
84
|
+
var DiagnosticJournalRefusalCountersSchema = z3.object({
|
|
85
|
+
closed: z3.number().int().nonnegative(),
|
|
86
|
+
failed: z3.number().int().nonnegative(),
|
|
87
|
+
invalid: z3.number().int().nonnegative(),
|
|
88
|
+
oversized: z3.number().int().nonnegative(),
|
|
89
|
+
"item-capacity": z3.number().int().nonnegative(),
|
|
90
|
+
"byte-capacity": z3.number().int().nonnegative()
|
|
91
|
+
}).strict().readonly();
|
|
92
|
+
var DiagnosticJournalFailurePhaseSchema2 = z3.enum(["write", "rotation", "close"]);
|
|
93
|
+
var DiagnosticJournalStatusSchema2 = z3.object({
|
|
94
|
+
state: DiagnosticJournalStateSchema2,
|
|
95
|
+
epoch: z3.uuid(),
|
|
96
|
+
limits: DiagnosticJournalLimitsSchema2,
|
|
97
|
+
lock: z3.object({
|
|
98
|
+
policy: DiagnosticJournalLockPolicySchema2,
|
|
99
|
+
reclaimedStale: z3.boolean()
|
|
100
|
+
}).strict().readonly(),
|
|
101
|
+
received: z3.number().int().nonnegative(),
|
|
102
|
+
accepted: z3.number().int().nonnegative(),
|
|
103
|
+
refused: z3.number().int().nonnegative(),
|
|
104
|
+
refusals: DiagnosticJournalRefusalCountersSchema,
|
|
105
|
+
written: z3.number().int().nonnegative(),
|
|
106
|
+
failedRecords: z3.number().int().nonnegative(),
|
|
107
|
+
pendingItems: z3.number().int().nonnegative(),
|
|
108
|
+
pendingBytes: z3.number().int().nonnegative(),
|
|
109
|
+
inFlight: z3.boolean(),
|
|
110
|
+
rotations: z3.number().int().nonnegative(),
|
|
111
|
+
rotationFailures: z3.number().int().nonnegative(),
|
|
112
|
+
partialTails: z3.number().int().nonnegative(),
|
|
113
|
+
currentFileBytes: z3.number().int().nonnegative(),
|
|
114
|
+
retainedFiles: z3.number().int().nonnegative(),
|
|
115
|
+
recovery: DiagnosticJournalRecoveryStatusSchema2.optional(),
|
|
116
|
+
lastAcceptedSequence: z3.number().int().positive().optional(),
|
|
117
|
+
lastWrittenSequence: z3.number().int().positive().optional(),
|
|
118
|
+
lastSettledSequence: z3.number().int().positive().optional(),
|
|
119
|
+
lastFailure: z3.object({
|
|
120
|
+
phase: DiagnosticJournalFailurePhaseSchema2,
|
|
121
|
+
sequence: z3.number().int().positive().optional()
|
|
122
|
+
}).strict().readonly().optional()
|
|
123
|
+
}).strict().readonly();
|
|
124
|
+
var DiagnosticJournalSubmitResultSchema2 = z3.discriminatedUnion("outcome", [
|
|
125
|
+
z3.object({
|
|
126
|
+
outcome: z3.literal("accepted"),
|
|
127
|
+
epoch: z3.uuid(),
|
|
128
|
+
sequence: z3.number().int().positive()
|
|
129
|
+
}).strict().readonly(),
|
|
130
|
+
z3.object({
|
|
131
|
+
outcome: z3.literal("refused"),
|
|
132
|
+
reason: DiagnosticJournalRefusalReasonSchema2
|
|
133
|
+
}).strict().readonly()
|
|
134
|
+
]);
|
|
135
|
+
var DiagnosticJournalWaitResultSchema2 = z3.object({
|
|
136
|
+
outcome: z3.enum(["settled", "timed-out", "cancelled"]),
|
|
137
|
+
state: DiagnosticJournalStateSchema2,
|
|
138
|
+
throughSequence: z3.number().int().nonnegative(),
|
|
139
|
+
settledSequence: z3.number().int().nonnegative()
|
|
140
|
+
}).strict().readonly();
|
|
141
|
+
var DiagnosticJournalCloseResultSchema2 = z3.object({
|
|
142
|
+
outcome: z3.enum(["closed", "timed-out", "cancelled"]),
|
|
143
|
+
state: DiagnosticJournalStateSchema2,
|
|
144
|
+
pendingItems: z3.number().int().nonnegative()
|
|
145
|
+
}).strict().readonly();
|
|
146
|
+
function parseDiagnosticJournalMode(mode) {
|
|
147
|
+
return FileModeSchema.parse(mode ?? 384);
|
|
148
|
+
}
|
|
149
|
+
function readDiagnosticJournalLockDiagnosis2(error) {
|
|
150
|
+
if (!isRecord(error))
|
|
151
|
+
return;
|
|
152
|
+
const diagnosis = error.journalLock;
|
|
153
|
+
return isRecord(diagnosis) ? diagnosis : undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { DiagnosticJournalFrameSchema2, DiagnosticJournalAnomalySchema2, createDiagnosticJournalReadResultSchema2, DiagnosticJournalRecoveryStatusSchema2, DiagnosticJournalRecoveryError2, DiagnosticJournalLimitsSchema2, DiagnosticJournalLockPolicySchema2, DiagnosticJournalStateSchema2, DiagnosticJournalRefusalReasonSchema2, DiagnosticJournalFailurePhaseSchema2, DiagnosticJournalStatusSchema2, DiagnosticJournalSubmitResultSchema2, DiagnosticJournalWaitResultSchema2, DiagnosticJournalCloseResultSchema2, parseDiagnosticJournalMode, readDiagnosticJournalLockDiagnosis2 };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/tools/lifecycle.ts
|
|
2
|
+
function composeToolLifecycle2(...hooks) {
|
|
3
|
+
return {
|
|
4
|
+
beforeHandle: async (ctx, endpoint) => {
|
|
5
|
+
for (const hook of hooks)
|
|
6
|
+
await hook?.beforeHandle?.(ctx, endpoint);
|
|
7
|
+
},
|
|
8
|
+
afterHandle: async (ctx, result, endpoint) => {
|
|
9
|
+
let current = result;
|
|
10
|
+
for (const hook of hooks) {
|
|
11
|
+
const transformed = await hook?.afterHandle?.(ctx, current, endpoint);
|
|
12
|
+
if (transformed !== undefined)
|
|
13
|
+
current = transformed;
|
|
14
|
+
}
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { composeToolLifecycle2 };
|
|
@@ -7,6 +7,7 @@ Contains: API reference: `stitchkit/agent-runtime/browser` (docs/api/reference.
|
|
|
7
7
|
|
|
8
8
|
Also read:
|
|
9
9
|
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
|
+
- see `llms/agent-runtime-harness.txt` for the Agent composition guide
|
|
10
11
|
|
|
11
12
|
==============================================================================
|
|
12
13
|
# API reference: `stitchkit/agent-runtime/browser` (docs/api/reference.md)
|
|
@@ -31,3 +32,28 @@ Use this entrypoint from client components and shared DTO packages. The full
|
|
|
31
32
|
`stitchkit/agent-runtime` entrypoint remains server-only.
|
|
32
33
|
|
|
33
34
|
---
|
|
35
|
+
|
|
36
|
+
### Browser control composition
|
|
37
|
+
|
|
38
|
+
`AgentBrowserRequestSchema` / `AgentBrowserRequest` derive from the trusted control
|
|
39
|
+
protocol but exclude runtime `context`. Submit permits only strict text/file parts;
|
|
40
|
+
file ownership and metadata policy are checked by server authorization. The shared
|
|
41
|
+
`agentControlRealtimeContract` owns `agent:control` acknowledgements and `agent:delivery`.
|
|
42
|
+
|
|
43
|
+
`createAgentController` / `AgentControllerConfig` take an existing Stitchkit
|
|
44
|
+
realtime `transport`, `conversationId`, `access` (`observe` or `control`), optional
|
|
45
|
+
`timeoutMs` (10000), `maxBufferedEvents` (256), `maxBufferedBytes` (1048576) and
|
|
46
|
+
`maxPendingRequests` (32). All bounds are positive safe integers. One controller owns one
|
|
47
|
+
attachment per conversation on that transport; share the controller between views.
|
|
48
|
+
|
|
49
|
+
`AgentController` exposes stable `subscribe`, `getSnapshot`, `request(command)` and async
|
|
50
|
+
`close`. `AgentBrowserCommand` uses the canonical operations, without request/conversation identity;
|
|
51
|
+
`submit` requires a caller-owned idempotency key. Unknown-outcome mutations are never
|
|
52
|
+
replayed automatically. `AgentControllerState` distinguishes connecting, ready,
|
|
53
|
+
disconnected, error and closed and retains the canonical full `view` plus safe error
|
|
54
|
+
code/message. Errors in automatic attach/refresh appear there. Reconnect attaches again
|
|
55
|
+
and reads a snapshot; snapshot gaps coalesce, stale generations cannot overwrite state,
|
|
56
|
+
and buffers/queues are bounded. Overflow or failed refresh is visible and requires
|
|
57
|
+
explicit recovery. Closing detaches without closing the shared transport or remote run.
|
|
58
|
+
|
|
59
|
+
See [agent composition](../guide/agent-composition.md) for a complete wiring example.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# stitchkit/agent-runtime/harness-tools — stitchkit docs slice
|
|
2
|
+
|
|
3
|
+
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
|
+
> `llms.txt` in this package.
|
|
5
|
+
|
|
6
|
+
Contains: API reference: `stitchkit/agent-runtime/harness-tools` (docs/api/reference.md)
|
|
7
|
+
|
|
8
|
+
Also read:
|
|
9
|
+
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
|
+
- see `llms/agent-runtime-harness.txt` for the Agent composition guide
|
|
11
|
+
|
|
12
|
+
==============================================================================
|
|
13
|
+
# API reference: `stitchkit/agent-runtime/harness-tools` (docs/api/reference.md)
|
|
14
|
+
==============================================================================
|
|
15
|
+
|
|
16
|
+
## `stitchkit/agent-runtime/harness-tools`
|
|
17
|
+
|
|
18
|
+
Optional evolving composition of the full `mountAgent` configuration with the runtime
|
|
19
|
+
fence. Its runtime peer is `ai`; its full tool presenter declarations also require
|
|
20
|
+
`@modelcontextprotocol/server`, as `stitchkit/tools` does. The base harness retains its
|
|
21
|
+
AI-only peer boundary. Existing custom tool callbacks need no new import.
|
|
22
|
+
|
|
23
|
+
| Export | Kind | Summary |
|
|
24
|
+
|--------|------|---------|
|
|
25
|
+
| `createAgentHarnessTools` / `AgentHarnessToolsConfig` | function / _type_ | async per-run full mount configuration (`services` plus all `AgentMountConfig` options); composes application lifecycle then runtime fence exactly once |
|
|
@@ -3,11 +3,150 @@
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: API reference: `stitchkit/agent-runtime/harness` (docs/api/reference.md)
|
|
6
|
+
Contains: Guide: Agent composition (docs/guide/agent-composition.md) · API reference: `stitchkit/agent-runtime/harness` (docs/api/reference.md)
|
|
7
7
|
|
|
8
8
|
Also read:
|
|
9
9
|
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
10
|
|
|
11
|
+
==============================================================================
|
|
12
|
+
# Guide: Agent composition (docs/guide/agent-composition.md)
|
|
13
|
+
==============================================================================
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
title: "Agent composition without a second runtime"
|
|
17
|
+
description: "Compose contract tools, authenticated realtime control, React views and exact-run behavioral checks."
|
|
18
|
+
type: architecture
|
|
19
|
+
status: active
|
|
20
|
+
created: 2026-09-30 22:45 +07:00
|
|
21
|
+
updated: 2026-09-30 23:03 +07:00
|
|
22
|
+
participants:
|
|
23
|
+
- role: authored
|
|
24
|
+
harness: Codex
|
|
25
|
+
model: GPT-6
|
|
26
|
+
at: 2026-09-30 22:45 +07:00
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# Compose an agent application
|
|
30
|
+
|
|
31
|
+
Use these pieces when an application wants the existing headless harness and a generic
|
|
32
|
+
conversation view. An application with its own AI SDK loop keeps `mountAgent`; a product
|
|
33
|
+
with custom message projections can keep its transport and UI. No consumer migration is
|
|
34
|
+
required. Model selection, storage, compaction, approvals and recovery stay with their
|
|
35
|
+
existing owners.
|
|
36
|
+
|
|
37
|
+
## Resources and tools
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import {
|
|
41
|
+
createAgentHarnessFileResources,
|
|
42
|
+
createHeadlessAgentHarness,
|
|
43
|
+
} from 'stitchkit/agent-runtime/harness';
|
|
44
|
+
import { createAgentHarnessTools } from 'stitchkit/agent-runtime/harness-tools';
|
|
45
|
+
|
|
46
|
+
const resources = createAgentHarnessFileResources({
|
|
47
|
+
roots: [{ id: 'guide', kind: 'instruction', path: instructionRoot }],
|
|
48
|
+
limits: { maxTotalBytes: 256 * 1024 },
|
|
49
|
+
});
|
|
50
|
+
const harness = createHeadlessAgentHarness({
|
|
51
|
+
protocol, store, models, promptBudget,
|
|
52
|
+
resources,
|
|
53
|
+
tools: createAgentHarnessTools(({ context, run }) => ({
|
|
54
|
+
services: [catalogService],
|
|
55
|
+
context: { ...context, messageId: run.assistantMessageId },
|
|
56
|
+
runtimeTools: resources.runtimeTools,
|
|
57
|
+
lifecycle: authorizeTools,
|
|
58
|
+
hooks: observeTools,
|
|
59
|
+
})),
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The factory composes application authorization then the runtime fence through `mountAgent`.
|
|
64
|
+
The optional harness-tools leaf preserves the complete tool types, including MCP presenter
|
|
65
|
+
declarations; install the same `ai` and `@modelcontextprotocol/server` peers as for
|
|
66
|
+
`stitchkit/tools`. The base harness stays AI-only. Every mount option remains available, including registry, runtime tools, extension,
|
|
67
|
+
coercion, output stripping, hooks and durability. Async per-run configuration is supported.
|
|
68
|
+
The original tools callback still accepts arbitrary typed AI SDK tools and prepareStep.
|
|
69
|
+
The resource reader is explicitly selected: filtered allowlists do not gain tools merely
|
|
70
|
+
because a loader exists. Root IDs, kinds, provenance and limits are unchanged.
|
|
71
|
+
|
|
72
|
+
## Server and browser
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { bindAgentHarnessRealtime } from 'stitchkit/agent-runtime/realtime';
|
|
76
|
+
|
|
77
|
+
const binding = bindAgentHarnessRealtime(harness, socket, {
|
|
78
|
+
async authorize({ identity, request, signal }) {
|
|
79
|
+
// socket.data comes from your verified Socket.IO handshake, not a browser context.
|
|
80
|
+
if (!await mayAccessConversation(identity, request, signal)) return null;
|
|
81
|
+
return { context: { userId: identity.userId } };
|
|
82
|
+
},
|
|
83
|
+
onError: reportServerError,
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`socket` is the existing `createSocketIOServer` handle, attached to `createServer` (Bun)
|
|
88
|
+
or the Node adapter. The access policy checks every operation, file/reference and metadata
|
|
89
|
+
as well as snapshot/event reads. Session handshake authentication alone is insufficient.
|
|
90
|
+
Conversation ownership and observer/controller roles are application policy; the canonical
|
|
91
|
+
control server additionally enforces its exclusive controller lease.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { createSocketIOClient } from 'stitchkit';
|
|
95
|
+
import { createAgentController } from 'stitchkit/agent-runtime/browser';
|
|
96
|
+
import { useAgent } from 'stitchkit/agent-runtime/react';
|
|
97
|
+
|
|
98
|
+
const transport = createSocketIOClient({ url: serverUrl, auth: sessionAuth });
|
|
99
|
+
const agent = createAgentController({ transport, conversationId, access: 'control' });
|
|
100
|
+
transport.connect();
|
|
101
|
+
|
|
102
|
+
function Conversation() {
|
|
103
|
+
const state = useAgent(agent);
|
|
104
|
+
const conversation = state.view.conversations[conversationId];
|
|
105
|
+
// Render canonical messages/parts, transient progress, approvals and state.error.
|
|
106
|
+
return <Transcript conversation={conversation} status={state.status} error={state.error} />;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
await agent.request({
|
|
110
|
+
operation: 'submit', idempotencyKey: crypto.randomUUID(),
|
|
111
|
+
parts: [{ type: 'text', text: 'Find available items' }],
|
|
112
|
+
});
|
|
113
|
+
await agent.request({ operation: 'interrupt', runId });
|
|
114
|
+
await agent.request({ operation: 'respond-approval', approvalId, approved: true });
|
|
115
|
+
await agent.close(); // leaves transport and harness alive
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Wait for `ready` before sending. Share a controller among views of the same conversation;
|
|
119
|
+
create it at session scope, not during React render. Unmount only unsubscribes the view.
|
|
120
|
+
To release the session, await `close`; to stop the application, separately close the
|
|
121
|
+
binding, transport and harness through the application's shutdown lifecycle. Closing a
|
|
122
|
+
view does not interrupt its remote run. Use explicit `interrupt` for cancellation.
|
|
123
|
+
|
|
124
|
+
Reconnect reattaches and reads durable state. Mutations are not retried automatically:
|
|
125
|
+
if an acknowledgement is lost, retain the original idempotency key. Incoming event
|
|
126
|
+
buffers and outgoing requests have finite limits; capacity/overflow/lease failures stay
|
|
127
|
+
visible. A server overflow deliberately disconnects the transport; reconnect explicitly.
|
|
128
|
+
|
|
129
|
+
## Check behavior, not just admission
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { inspectAgentRun } from 'stitchkit/agent-runtime/testing';
|
|
133
|
+
|
|
134
|
+
const ticket = harness.submit(input);
|
|
135
|
+
const admitted = await ticket.admission;
|
|
136
|
+
await ticket.result;
|
|
137
|
+
const result = inspectAgentRun(await harness.snapshot(input.conversationId), admitted.runId);
|
|
138
|
+
result.calledTool('catalog_search');
|
|
139
|
+
result.toolSucceeded('catalog_search');
|
|
140
|
+
result.notCalledTool('catalog_delete');
|
|
141
|
+
result.completed();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`calledTool` proves a call record (including an approved continuation linked through that
|
|
145
|
+
run’s exact input messages); `toolSucceeded` also needs a matching successful result.
|
|
146
|
+
`completed` requires successful terminal output with no pending approval. Prior runs,
|
|
147
|
+
provider/policy stops, failed calls and unfinished runs cannot satisfy those assertions.
|
|
148
|
+
The helper does not invoke a model or poll; the existing runtime ticket owns execution.
|
|
149
|
+
|
|
11
150
|
==============================================================================
|
|
12
151
|
# API reference: `stitchkit/agent-runtime/harness` (docs/api/reference.md)
|
|
13
152
|
==============================================================================
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# stitchkit/agent-runtime/react — stitchkit docs slice
|
|
2
|
+
|
|
3
|
+
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
|
+
> `llms.txt` in this package.
|
|
5
|
+
|
|
6
|
+
Contains: API reference: `stitchkit/agent-runtime/react` (docs/api/reference.md)
|
|
7
|
+
|
|
8
|
+
Also read:
|
|
9
|
+
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
|
+
- see `llms/agent-runtime-harness.txt` for the Agent composition guide
|
|
11
|
+
|
|
12
|
+
==============================================================================
|
|
13
|
+
# API reference: `stitchkit/agent-runtime/react` (docs/api/reference.md)
|
|
14
|
+
==============================================================================
|
|
15
|
+
|
|
16
|
+
## `stitchkit/agent-runtime/react`
|
|
17
|
+
|
|
18
|
+
Optional evolving React peer leaf. `useAgent` takes a controller and subscribes through
|
|
19
|
+
`useSyncExternalStore`, returning the same `AgentControllerState` as `getSnapshot()`.
|
|
20
|
+
Create and close the controller at application/session scope. Multiple components can
|
|
21
|
+
observe it; StrictMode and unmount release only the component's own subscription.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# stitchkit/agent-runtime/realtime — stitchkit docs slice
|
|
2
|
+
|
|
3
|
+
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
|
+
> `llms.txt` in this package.
|
|
5
|
+
|
|
6
|
+
Contains: API reference: `stitchkit/agent-runtime/realtime` (docs/api/reference.md)
|
|
7
|
+
|
|
8
|
+
Also read:
|
|
9
|
+
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
|
+
- see `llms/agent-runtime-harness.txt` for the Agent composition guide
|
|
11
|
+
|
|
12
|
+
==============================================================================
|
|
13
|
+
# API reference: `stitchkit/agent-runtime/realtime` (docs/api/reference.md)
|
|
14
|
+
==============================================================================
|
|
15
|
+
|
|
16
|
+
## `stitchkit/agent-runtime/realtime`
|
|
17
|
+
|
|
18
|
+
Optional evolving Socket.IO server binding. `bindAgentHarnessRealtime` takes `(harness, socket, config)` and returns `close()` for its subscriptions and control connections, without closing
|
|
19
|
+
socket or harness. `AgentHarnessRealtimeConfig` requires `authorize({ identity, request,
|
|
20
|
+
signal })`: return `{ context }` after verifying the session principal, conversation,
|
|
21
|
+
operation, files and metadata, or `null`. Identity is `socket.data` from the application's
|
|
22
|
+
verified handshake. Every request and event delivery is authorized. Observe access does
|
|
23
|
+
not grant mutation; controller leases and approval policy still belong to the harness.
|
|
24
|
+
|
|
25
|
+
`maxPendingEvents` and `maxPendingAttachments` forward to the canonical control server;
|
|
26
|
+
`maxPendingRequests` bounds in-flight authorization/control requests per socket (32);
|
|
27
|
+
`authorizationTimeoutMs` bounds each authorization (10000 ms). Honor its AbortSignal.
|
|
28
|
+
`onError` receives internal errors; peers receive generic denials. Revoking a conversation
|
|
29
|
+
releases only its attachment. Event overflow closes the socket; explicitly reconnect the
|
|
30
|
+
application transport. A transport's Engine.IO payload limit remains application-owned.
|
|
@@ -7,6 +7,7 @@ Contains: API reference: `stitchkit/agent-runtime/testing` (docs/api/reference.
|
|
|
7
7
|
|
|
8
8
|
Also read:
|
|
9
9
|
- see `llms/agent-runtime.txt` for the Agent application runtime guide
|
|
10
|
+
- see `llms/agent-runtime-harness.txt` for the Agent composition guide
|
|
10
11
|
|
|
11
12
|
==============================================================================
|
|
12
13
|
# API reference: `stitchkit/agent-runtime/testing` (docs/api/reference.md)
|
|
@@ -28,3 +29,8 @@ Credential-free provider and concurrency fixtures for Bun and Node tests.
|
|
|
28
29
|
| `runAgentStoreConformance` | function | reusable black-box duplicate/coalescing/stale/recovery contract for durable agent-store adapters |
|
|
29
30
|
| `AgentStoreConformanceConfig` | _type_ | `{ createStore(context), cleanup?(context) }` — the factory the contract runs against, plus a teardown that runs once whether the scenario passed or failed |
|
|
30
31
|
| `AgentStoreConformanceContext` | _type_ | `{ conversationIds }` — every conversation the scenario will mutate, handed over **before** the first mutation so an adapter can provision application-owned parent rows; a zero-argument factory stays valid |
|
|
32
|
+
|
|
33
|
+
`inspectAgentRun` takes `(snapshot, runId)` and returns `completed()`, `calledTool(name)`,
|
|
34
|
+
`notCalledTool(name)` and `toolSucceeded(name)` assertions over durable evidence for
|
|
35
|
+
that exact run. Completion requires terminal reason `success`, not `policy_stop` or
|
|
36
|
+
`provider_stop`, and no pending approval. Successful tools require matching call/result IDs.
|
|
@@ -17,6 +17,8 @@ Also read:
|
|
|
17
17
|
| Export | Kind | Summary |
|
|
18
18
|
|--------|------|---------|
|
|
19
19
|
| `createDiagnosticJournal` | function | the bounded local journal: a file lock, a spawn to diagnose a stale one, and framed writes |
|
|
20
|
+
| `readDiagnosticJournal` | function | bounded async stream of validated frames and explicit anomalies from finite snapshots of caller-selected files; I/O failures throw |
|
|
21
|
+
| `DiagnosticJournalReaderConfig` | _type_ | normalized absolute `paths`, owner `eventSchema`, positive safe-integer `maxLineBytes` and optional cancellation `signal` |
|
|
20
22
|
|
|
21
23
|
Its own entrypoint because of what it reaches — `node:child_process`,
|
|
22
24
|
`node:fs`, `node:os`, `node:util` — with `promisify(execFile)` evaluated while
|