@cat-factory/server 0.191.2 → 0.193.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/dist/app.d.ts.map +1 -1
- package/dist/app.js +18 -0
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.d.ts +41 -0
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.d.ts.map +1 -0
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.js +82 -0
- package/dist/modules/foundationalServices/FoundationalBuiltinsController.js.map +1 -0
- package/dist/modules/telemetry/TelemetryReadController.d.ts +37 -0
- package/dist/modules/telemetry/TelemetryReadController.d.ts.map +1 -0
- package/dist/modules/telemetry/TelemetryReadController.js +225 -0
- package/dist/modules/telemetry/TelemetryReadController.js.map +1 -0
- package/dist/persistence/foundationalBuiltins.d.ts +47 -0
- package/dist/persistence/foundationalBuiltins.d.ts.map +1 -0
- package/dist/persistence/foundationalBuiltins.js +112 -0
- package/dist/persistence/foundationalBuiltins.js.map +1 -0
- package/dist/persistence/mappers.d.ts +0 -2
- package/dist/persistence/mappers.d.ts.map +1 -1
- package/dist/persistence/mappers.js +9 -101
- package/dist/persistence/mappers.js.map +1 -1
- package/dist/telemetry/machineTelemetryRead.d.ts +297 -0
- package/dist/telemetry/machineTelemetryRead.d.ts.map +1 -0
- package/dist/telemetry/machineTelemetryRead.js +256 -0
- package/dist/telemetry/machineTelemetryRead.js.map +1 -0
- package/package.json +10 -10
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { AgentContextSnapshot, AgentContextSnapshotIndex, AgentSearchQuery, LlmCallMetric, LlmCallMetricPage, LlmCallMetricSummary } from '@cat-factory/kernel';
|
|
2
|
+
/**
|
|
3
|
+
* The closed set of telemetry reads a mothership will serve, and the bound each one is held to.
|
|
4
|
+
*
|
|
5
|
+
* Every entry is a READ, is scoped to ONE run (or one row of one), and has a size a caller can
|
|
6
|
+
* compute BEFORE the request — the same rule the remote debugging surface obeys
|
|
7
|
+
* (backend/docs/debug-api.md). `listByExecution` appears nowhere: it takes no cursor, so a node
|
|
8
|
+
* asking a long run for "everything" is exactly the un-resumable bulk read this bucket forbids.
|
|
9
|
+
* The read-through answers those methods by DRAINING the paged reads below.
|
|
10
|
+
*
|
|
11
|
+
* `provisioningLogRepository` and `subscriptionQuotaCycleRepository` are absent on purpose: they
|
|
12
|
+
* are local-first and deliberately never ingested (a provisioned environment outlives the run that
|
|
13
|
+
* created it, so "a finished run's rows" does not identify its log; a quota cycle keys on
|
|
14
|
+
* laptop-held credentials). The mothership holds nothing to read through TO.
|
|
15
|
+
*/
|
|
16
|
+
export declare const TELEMETRY_READ_METHODS: {
|
|
17
|
+
readonly llmCallMetricRepository: {
|
|
18
|
+
/** Whole-body page of a run's calls — what the observability panel and the export drain. */
|
|
19
|
+
readonly listRunPage: {
|
|
20
|
+
readonly args: 'runQuery';
|
|
21
|
+
readonly maxArgs: 1;
|
|
22
|
+
readonly limit: 'query.limit';
|
|
23
|
+
readonly maxLimit: 100;
|
|
24
|
+
readonly timeoutMs: 30000;
|
|
25
|
+
};
|
|
26
|
+
/** The debug surface's sliced page. */
|
|
27
|
+
readonly listPage: {
|
|
28
|
+
readonly args: 'runQuery';
|
|
29
|
+
readonly maxArgs: 1;
|
|
30
|
+
readonly limit: 'query.limit';
|
|
31
|
+
readonly maxLimit: 200;
|
|
32
|
+
readonly maxBodyChars: 262144;
|
|
33
|
+
readonly timeoutMs: 20000;
|
|
34
|
+
};
|
|
35
|
+
/** One call by id, bodies sliced to the caller's window. */
|
|
36
|
+
readonly get: {
|
|
37
|
+
readonly args: 'id';
|
|
38
|
+
readonly maxArgs: 2;
|
|
39
|
+
readonly limit: null;
|
|
40
|
+
readonly maxBodyChars: 262144;
|
|
41
|
+
readonly timeoutMs: 20000;
|
|
42
|
+
};
|
|
43
|
+
/** The `(agentKind, phase)` aggregate every rollup folds over — no rows, no bodies. */
|
|
44
|
+
readonly summarizeByExecution: {
|
|
45
|
+
readonly args: 'id';
|
|
46
|
+
readonly maxArgs: 1;
|
|
47
|
+
readonly limit: null;
|
|
48
|
+
readonly timeoutMs: 5000;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
readonly agentContextSnapshotRepository: {
|
|
52
|
+
/**
|
|
53
|
+
* Whole-body page of a run's dispatches. Capped SMALL, and this is the one entry where the
|
|
54
|
+
* cap is about bytes rather than rows: a snapshot carries the composed prompt plus every
|
|
55
|
+
* injected context file, so the recorder's own per-row ceiling is megabytes.
|
|
56
|
+
*/
|
|
57
|
+
readonly listRunPage: {
|
|
58
|
+
readonly args: 'runQuery';
|
|
59
|
+
readonly maxArgs: 1;
|
|
60
|
+
readonly limit: 'query.limit';
|
|
61
|
+
readonly maxLimit: 3;
|
|
62
|
+
readonly timeoutMs: 30000;
|
|
63
|
+
};
|
|
64
|
+
/** Identity + sizes only, never a body. */
|
|
65
|
+
readonly listIndex: {
|
|
66
|
+
readonly args: 'runQuery';
|
|
67
|
+
readonly maxArgs: 1;
|
|
68
|
+
readonly limit: 'query.limit';
|
|
69
|
+
readonly maxLimit: 200;
|
|
70
|
+
readonly timeoutMs: 10000;
|
|
71
|
+
};
|
|
72
|
+
readonly get: {
|
|
73
|
+
readonly args: 'id';
|
|
74
|
+
readonly maxArgs: 1;
|
|
75
|
+
readonly limit: null;
|
|
76
|
+
readonly timeoutMs: 20000;
|
|
77
|
+
};
|
|
78
|
+
readonly countByExecution: {
|
|
79
|
+
readonly args: 'id';
|
|
80
|
+
readonly maxArgs: 1;
|
|
81
|
+
readonly limit: null;
|
|
82
|
+
readonly timeoutMs: 5000;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
readonly agentSearchQueryRepository: {
|
|
86
|
+
/** Whole rows, but they carry no unbounded body (the query text is capped at capture). */
|
|
87
|
+
readonly listPage: {
|
|
88
|
+
readonly args: 'runQuery';
|
|
89
|
+
readonly maxArgs: 1;
|
|
90
|
+
readonly limit: 'query.limit';
|
|
91
|
+
readonly maxLimit: 500;
|
|
92
|
+
readonly timeoutMs: 10000;
|
|
93
|
+
};
|
|
94
|
+
readonly countByExecution: {
|
|
95
|
+
readonly args: 'id';
|
|
96
|
+
readonly maxArgs: 1;
|
|
97
|
+
readonly limit: null;
|
|
98
|
+
readonly timeoutMs: 5000;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* How one entry of {@link TELEMETRY_READ_METHODS} is bounded — on all three axes a caller has to
|
|
104
|
+
* be able to size BEFORE the request: the arguments it may pass, the rows and bytes it may ask
|
|
105
|
+
* back, and how long it may wait.
|
|
106
|
+
*/
|
|
107
|
+
export interface TelemetryReadBound {
|
|
108
|
+
/**
|
|
109
|
+
* The shape `args` must have, checked before the call is dispatched so a malformed query is a
|
|
110
|
+
* 422 rather than a 500 raised deep inside a repository's SQL. `'runQuery'` takes one object
|
|
111
|
+
* carrying a non-empty `executionId`; `'id'` takes a non-empty string.
|
|
112
|
+
*/
|
|
113
|
+
args: 'runQuery' | 'id';
|
|
114
|
+
/** How many positional arguments may follow the STAMPED workspace. */
|
|
115
|
+
maxArgs: number;
|
|
116
|
+
/**
|
|
117
|
+
* Where the row cap lives — `'query.limit'` for the `(workspaceId, query)` shape, or null for a
|
|
118
|
+
* read that returns one row or one aggregate and so has no cap to check.
|
|
119
|
+
*/
|
|
120
|
+
limit: 'query.limit' | null;
|
|
121
|
+
maxLimit?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Ceiling on a per-body slice budget. Where this is set the budget is REQUIRED, for the same
|
|
124
|
+
* reason an unstated `limit` is refused: "whole bodies" computes no size, and a read whose size
|
|
125
|
+
* cannot be computed before the request has no place on this surface. A caller that wanted the
|
|
126
|
+
* whole body asks for this ceiling explicitly and reads {@link LlmCallBodySlice.totalChars} to
|
|
127
|
+
* see whether it got all of it.
|
|
128
|
+
*/
|
|
129
|
+
maxBodyChars?: number;
|
|
130
|
+
/**
|
|
131
|
+
* Round-trip budget, sized to what the read actually moves rather than to one global default.
|
|
132
|
+
* It matters because these reads are not all equally patient: the `(agentKind, phase)` aggregate
|
|
133
|
+
* is folded onto every step settlement by `RunStateMachine.attachStepMetrics`, which awaits it
|
|
134
|
+
* on the emit path, so an unreachable mothership must cost that emit seconds rather than the
|
|
135
|
+
* half-minute a megabyte-scale snapshot page is rightly allowed.
|
|
136
|
+
*/
|
|
137
|
+
timeoutMs: number;
|
|
138
|
+
}
|
|
139
|
+
/** A repository name {@link TELEMETRY_READ_METHODS} serves. */
|
|
140
|
+
export type TelemetryReadRepository = keyof typeof TELEMETRY_READ_METHODS;
|
|
141
|
+
/**
|
|
142
|
+
* The per-body slice budget `repo.method` REQUIRES, or null where it takes none.
|
|
143
|
+
*
|
|
144
|
+
* The read-through calls this to fill in a window its own caller left open: a point read with no
|
|
145
|
+
* window means "the whole bodies" to the port, which is exactly the unstated size this surface
|
|
146
|
+
* refuses, so the fallback asks for the declared ceiling instead of being refused. The slice is
|
|
147
|
+
* self-describing (`totalChars` beside the text), so a body longer than the ceiling reports itself
|
|
148
|
+
* as cut rather than passing as whole.
|
|
149
|
+
*/
|
|
150
|
+
export declare function telemetryReadBodyCap(repo: TelemetryReadRepository, method: string): number | null;
|
|
151
|
+
/**
|
|
152
|
+
* Page sizes the laptop-side drain STARTS at. Each is at or below its method's `maxLimit` and
|
|
153
|
+
* sized for the rows that sink typically holds — not for its worst case, which no fixed page size
|
|
154
|
+
* could serve: three whole snapshots at the capture ceiling are ~12 MiB before JSON escaping, and
|
|
155
|
+
* a hundred whole calls ~150 MiB. A page that overruns {@link MAX_TELEMETRY_READ_CHARS} is
|
|
156
|
+
* therefore a ROUTINE condition on a run with large prompts, and the drain halves and retries
|
|
157
|
+
* rather than failing (see {@link TelemetryReadTooLargeError}). Snapshots start at 1 because
|
|
158
|
+
* there is no batching win in a sink whose rows are megabytes apiece.
|
|
159
|
+
*/
|
|
160
|
+
export declare const TELEMETRY_READ_PAGE_SIZES: {
|
|
161
|
+
readonly metrics: 100;
|
|
162
|
+
readonly snapshots: 1;
|
|
163
|
+
readonly searchQueries: 500;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Upper bound on one read RESPONSE (characters). The per-method caps bound row COUNT; this bounds
|
|
167
|
+
* the axis a single pathological row moves. Over it the mothership REFUSES rather than truncating:
|
|
168
|
+
* a shortened page would leave the node paging on a cursor drawn from rows the mothership silently
|
|
169
|
+
* dropped, which loses the tail with nothing left to notice.
|
|
170
|
+
*
|
|
171
|
+
* It is DERIVED from the capture ceilings rather than picked, and the derivation is the property
|
|
172
|
+
* that makes the drain's halving terminate: the backstop is wide enough for the largest SINGLE row
|
|
173
|
+
* either body-bearing sink can store, worst-case escaped, so a request for one row can never be
|
|
174
|
+
* refused for size. Halving therefore always reaches a page that fits, instead of bottoming out at
|
|
175
|
+
* 1 and failing a run permanently — which is what an 8,000,000 constant did, being narrower than a
|
|
176
|
+
* single maximal snapshot (4 MiB × 2 = 8,388,608).
|
|
177
|
+
*
|
|
178
|
+
* `telemetryRead.spec.ts` pins the inequality against BOTH sinks' ceilings, so raising a capture
|
|
179
|
+
* cap without widening this fails a test rather than a developer's panel.
|
|
180
|
+
*/
|
|
181
|
+
export declare const MAX_TELEMETRY_READ_CHARS: number;
|
|
182
|
+
/**
|
|
183
|
+
* The largest a single row of a body-bearing sink can serialize to, worst-case escaped. Exported
|
|
184
|
+
* so the conformity assertion in `telemetryRead.spec.ts` states the inequality in one place rather
|
|
185
|
+
* than restating the arithmetic.
|
|
186
|
+
*
|
|
187
|
+
* An LLM call carries three capped bodies ({@link MAX_BODY_CHARS} each: prompt delta, response,
|
|
188
|
+
* reasoning); a snapshot carries one shared budget across both prompts, every fragment and every
|
|
189
|
+
* injected file.
|
|
190
|
+
*/
|
|
191
|
+
export declare const MAX_TELEMETRY_READ_ROW_CHARS: number;
|
|
192
|
+
/**
|
|
193
|
+
* One bounded telemetry read, posted to `POST /internal/telemetry/read`.
|
|
194
|
+
*
|
|
195
|
+
* `workspaceId` is the SCOPE, not an argument: the mothership binds it to the token's accounts
|
|
196
|
+
* and then PREPENDS it as the call's first argument, so `args` carries everything AFTER it. A
|
|
197
|
+
* node therefore cannot address a workspace it cannot already reach even by naming one in `args`
|
|
198
|
+
* — the same stamping property the ingest applies to a row's `workspaceId`.
|
|
199
|
+
*/
|
|
200
|
+
export interface TelemetryReadRequest {
|
|
201
|
+
workspaceId: string;
|
|
202
|
+
repo: TelemetryReadRepository;
|
|
203
|
+
method: string;
|
|
204
|
+
/** The call's arguments AFTER `workspaceId`. JSON-serializable by construction. */
|
|
205
|
+
args: unknown[];
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The read's result. Plain JSON rather than the persistence RPC's tagged envelope: every method
|
|
209
|
+
* in the table returns an array, a number or a nullable row, so there is no `undefined`/`null`
|
|
210
|
+
* distinction to preserve and no in-place `rev` to write back.
|
|
211
|
+
*/
|
|
212
|
+
export type TelemetryReadResponse = {
|
|
213
|
+
ok: true;
|
|
214
|
+
value: unknown;
|
|
215
|
+
} | {
|
|
216
|
+
ok: false;
|
|
217
|
+
error: {
|
|
218
|
+
code: string;
|
|
219
|
+
message: string;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
/** The typed results the read-through expects back, per method. */
|
|
223
|
+
export interface TelemetryReadResults {
|
|
224
|
+
'llmCallMetricRepository.listRunPage': LlmCallMetric[];
|
|
225
|
+
'llmCallMetricRepository.listPage': LlmCallMetricPage[];
|
|
226
|
+
'llmCallMetricRepository.get': LlmCallMetricPage | null;
|
|
227
|
+
'llmCallMetricRepository.summarizeByExecution': LlmCallMetricSummary[];
|
|
228
|
+
'agentContextSnapshotRepository.listRunPage': AgentContextSnapshot[];
|
|
229
|
+
'agentContextSnapshotRepository.listIndex': AgentContextSnapshotIndex[];
|
|
230
|
+
'agentContextSnapshotRepository.get': AgentContextSnapshot | null;
|
|
231
|
+
'agentContextSnapshotRepository.countByExecution': number;
|
|
232
|
+
'agentSearchQueryRepository.listPage': AgentSearchQuery[];
|
|
233
|
+
'agentSearchQueryRepository.countByExecution': number;
|
|
234
|
+
}
|
|
235
|
+
/** The client half: performs one bounded telemetry read against the mothership. */
|
|
236
|
+
export interface MachineTelemetryReadClient {
|
|
237
|
+
/**
|
|
238
|
+
* Perform `request`. REJECTS on any failure — transport, HTTP, an unreachable mothership, or a
|
|
239
|
+
* node with no machine token — and never resolves to an empty result standing in for one.
|
|
240
|
+
*
|
|
241
|
+
* That contract is the whole point. The caller is a rendering surface that fell back here
|
|
242
|
+
* BECAUSE its local store held nothing, so an empty resolution would be reported to the reader
|
|
243
|
+
* as "this run spent nothing / captured nothing" — the exact false-zero the read-through
|
|
244
|
+
* exists to remove. A rejection surfaces as a failed panel, which is the honest answer.
|
|
245
|
+
*/
|
|
246
|
+
read(request: TelemetryReadRequest): Promise<unknown>;
|
|
247
|
+
}
|
|
248
|
+
export interface HttpMachineTelemetryReadClientOptions {
|
|
249
|
+
baseUrl: string;
|
|
250
|
+
/** The machine token, as a fixed string OR a provider read per request (may return null). */
|
|
251
|
+
token: string | (() => string | null);
|
|
252
|
+
fetchImpl?: typeof fetch;
|
|
253
|
+
/**
|
|
254
|
+
* Abort the round-trip after this long, OVERRIDING the per-method budget the request's own
|
|
255
|
+
* {@link TelemetryReadBound.timeoutMs} would otherwise supply. For tests and for a deployment
|
|
256
|
+
* that has to widen every read at once; leave it unset in production so an aggregate folded onto
|
|
257
|
+
* the emit path keeps its short budget while a snapshot page keeps its long one.
|
|
258
|
+
*/
|
|
259
|
+
timeoutMs?: number;
|
|
260
|
+
}
|
|
261
|
+
/** The `error.code` a mothership uses for a response that overran {@link MAX_TELEMETRY_READ_CHARS}. */
|
|
262
|
+
export declare const TELEMETRY_READ_TOO_LARGE_CODE = "response_too_large";
|
|
263
|
+
/**
|
|
264
|
+
* The refusal a caller can DO something about: the rows it asked for were within their row cap but
|
|
265
|
+
* serialized past the byte backstop, so the same cursor with a smaller page will fit.
|
|
266
|
+
*
|
|
267
|
+
* Distinct from every other refusal precisely so the drain can tell "ask for less" from "you asked
|
|
268
|
+
* for something you may not have" (an over-cap limit, an unknown method — client bugs, where
|
|
269
|
+
* retrying smaller would just fail more slowly). Retrying is CORRECT rather than a clamp in
|
|
270
|
+
* disguise: the keyset cursor only ever advances over rows actually received, so a narrower page
|
|
271
|
+
* loses nothing, where the server silently shortening one would.
|
|
272
|
+
*/
|
|
273
|
+
export declare class TelemetryReadTooLargeError extends Error {
|
|
274
|
+
constructor(message: string);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* A fetch-based {@link MachineTelemetryReadClient} posting to a mothership's
|
|
278
|
+
* `POST /internal/telemetry/read` with the node's machine token. Same auth contract as
|
|
279
|
+
* `HttpMachineTelemetryClient` (a fixed token OR a per-request provider, so a token cached after
|
|
280
|
+
* boot by the mothership login flow is picked up without a restart).
|
|
281
|
+
*/
|
|
282
|
+
export declare class HttpMachineTelemetryReadClient implements MachineTelemetryReadClient {
|
|
283
|
+
private readonly opts;
|
|
284
|
+
constructor(opts: HttpMachineTelemetryReadClientOptions);
|
|
285
|
+
read(request: TelemetryReadRequest): Promise<unknown>;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Thrown when the node holds no machine token yet, so the read could not be attempted.
|
|
289
|
+
*
|
|
290
|
+
* Distinct from a transport failure only so a caller can report the benign, self-healing case
|
|
291
|
+
* ("finish the mothership login") differently from a broken one. Both are rejections, for the
|
|
292
|
+
* reason {@link MachineTelemetryReadClient.read} states.
|
|
293
|
+
*/
|
|
294
|
+
export declare class MachineTokenUnavailableForReadError extends Error {
|
|
295
|
+
constructor();
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=machineTelemetryRead.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineTelemetryRead.d.ts","sourceRoot":"","sources":["../../src/telemetry/machineTelemetryRead.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { MAX_AGENT_CONTEXT_TOTAL_CHARS, MAX_BODY_CHARS } from '@cat-factory/orchestration';
|
|
2
|
+
// Mothership-mode telemetry READ-THROUGH (docs/initiatives/mothership-mode.md, PR 5 — the last
|
|
3
|
+
// piece of the telemetry bucket).
|
|
4
|
+
//
|
|
5
|
+
// The capture half writes a mothership-mode node's telemetry to a `node:sqlite` store on the
|
|
6
|
+
// laptop; the ingest half carries a quiesced run's rows UP so hosted teammates can read them and
|
|
7
|
+
// they outlive the node's short local retention window. What both leave open is the read coming
|
|
8
|
+
// back DOWN. Three runs render wrong on a mothership-mode node today, and none reports a problem:
|
|
9
|
+
//
|
|
10
|
+
// - a run this node drove whose LOCAL rows have already been pruned (the mothership holds them,
|
|
11
|
+
// the laptop no longer does),
|
|
12
|
+
// - a run somebody ELSE drove — a hosted teammate, or another laptop. Its telemetry was never
|
|
13
|
+
// local at all, and in mothership mode the node's SPA shows the whole org's board, so this is
|
|
14
|
+
// the common case rather than the exotic one, and
|
|
15
|
+
// - a run the prune took only PART of, which renders a short list and an understated token total
|
|
16
|
+
// instead of a blank panel — the same false picture, with rows in it to make it convincing.
|
|
17
|
+
// The laptop side (`telemetryReadThrough.ts`) is where that one is detected; what this module
|
|
18
|
+
// owes it is a read that can fetch the missing remainder on the same cursor.
|
|
19
|
+
//
|
|
20
|
+
// This module is the runtime-neutral spine of the read: the closed table of bounded reads the
|
|
21
|
+
// mothership will serve, the wire envelope, and the fetch client the laptop asks through.
|
|
22
|
+
//
|
|
23
|
+
// It is a DEDICATED `/internal/*` endpoint rather than allow-listed persistence-RPC methods, for
|
|
24
|
+
// the same reason the ingest is (ADR 0009), plus one specific to reads: the drift guard asserts
|
|
25
|
+
// that a `LOCAL_FIRST_PERSISTENCE_REPOSITORIES` repository appears in no `REMOTE_PERSISTENCE_METHODS`
|
|
26
|
+
// entry, because the persistence registry resolves a repository WHOLE — naming one there would
|
|
27
|
+
// route its hot-path WRITES over the network, which is the entire thing this bucket exists to
|
|
28
|
+
// prevent. A separate table, reached only by the read-through decorator, keeps that invariant
|
|
29
|
+
// intact while still letting a rendering surface reach the mothership's copy.
|
|
30
|
+
/**
|
|
31
|
+
* The closed set of telemetry reads a mothership will serve, and the bound each one is held to.
|
|
32
|
+
*
|
|
33
|
+
* Every entry is a READ, is scoped to ONE run (or one row of one), and has a size a caller can
|
|
34
|
+
* compute BEFORE the request — the same rule the remote debugging surface obeys
|
|
35
|
+
* (backend/docs/debug-api.md). `listByExecution` appears nowhere: it takes no cursor, so a node
|
|
36
|
+
* asking a long run for "everything" is exactly the un-resumable bulk read this bucket forbids.
|
|
37
|
+
* The read-through answers those methods by DRAINING the paged reads below.
|
|
38
|
+
*
|
|
39
|
+
* `provisioningLogRepository` and `subscriptionQuotaCycleRepository` are absent on purpose: they
|
|
40
|
+
* are local-first and deliberately never ingested (a provisioned environment outlives the run that
|
|
41
|
+
* created it, so "a finished run's rows" does not identify its log; a quota cycle keys on
|
|
42
|
+
* laptop-held credentials). The mothership holds nothing to read through TO.
|
|
43
|
+
*/
|
|
44
|
+
export const TELEMETRY_READ_METHODS = {
|
|
45
|
+
llmCallMetricRepository: {
|
|
46
|
+
/** Whole-body page of a run's calls — what the observability panel and the export drain. */
|
|
47
|
+
listRunPage: {
|
|
48
|
+
args: 'runQuery',
|
|
49
|
+
maxArgs: 1,
|
|
50
|
+
limit: 'query.limit',
|
|
51
|
+
maxLimit: 100,
|
|
52
|
+
timeoutMs: 30_000,
|
|
53
|
+
},
|
|
54
|
+
/** The debug surface's sliced page. */
|
|
55
|
+
listPage: {
|
|
56
|
+
args: 'runQuery',
|
|
57
|
+
maxArgs: 1,
|
|
58
|
+
limit: 'query.limit',
|
|
59
|
+
maxLimit: 200,
|
|
60
|
+
maxBodyChars: 262_144,
|
|
61
|
+
timeoutMs: 20_000,
|
|
62
|
+
},
|
|
63
|
+
/** One call by id, bodies sliced to the caller's window. */
|
|
64
|
+
get: { args: 'id', maxArgs: 2, limit: null, maxBodyChars: 262_144, timeoutMs: 20_000 },
|
|
65
|
+
/** The `(agentKind, phase)` aggregate every rollup folds over — no rows, no bodies. */
|
|
66
|
+
summarizeByExecution: { args: 'id', maxArgs: 1, limit: null, timeoutMs: 5_000 },
|
|
67
|
+
},
|
|
68
|
+
agentContextSnapshotRepository: {
|
|
69
|
+
/**
|
|
70
|
+
* Whole-body page of a run's dispatches. Capped SMALL, and this is the one entry where the
|
|
71
|
+
* cap is about bytes rather than rows: a snapshot carries the composed prompt plus every
|
|
72
|
+
* injected context file, so the recorder's own per-row ceiling is megabytes.
|
|
73
|
+
*/
|
|
74
|
+
listRunPage: {
|
|
75
|
+
args: 'runQuery',
|
|
76
|
+
maxArgs: 1,
|
|
77
|
+
limit: 'query.limit',
|
|
78
|
+
maxLimit: 3,
|
|
79
|
+
timeoutMs: 30_000,
|
|
80
|
+
},
|
|
81
|
+
/** Identity + sizes only, never a body. */
|
|
82
|
+
listIndex: {
|
|
83
|
+
args: 'runQuery',
|
|
84
|
+
maxArgs: 1,
|
|
85
|
+
limit: 'query.limit',
|
|
86
|
+
maxLimit: 200,
|
|
87
|
+
timeoutMs: 10_000,
|
|
88
|
+
},
|
|
89
|
+
get: { args: 'id', maxArgs: 1, limit: null, timeoutMs: 20_000 },
|
|
90
|
+
countByExecution: { args: 'id', maxArgs: 1, limit: null, timeoutMs: 5_000 },
|
|
91
|
+
},
|
|
92
|
+
agentSearchQueryRepository: {
|
|
93
|
+
/** Whole rows, but they carry no unbounded body (the query text is capped at capture). */
|
|
94
|
+
listPage: {
|
|
95
|
+
args: 'runQuery',
|
|
96
|
+
maxArgs: 1,
|
|
97
|
+
limit: 'query.limit',
|
|
98
|
+
maxLimit: 500,
|
|
99
|
+
timeoutMs: 10_000,
|
|
100
|
+
},
|
|
101
|
+
countByExecution: { args: 'id', maxArgs: 1, limit: null, timeoutMs: 5_000 },
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* The per-body slice budget `repo.method` REQUIRES, or null where it takes none.
|
|
106
|
+
*
|
|
107
|
+
* The read-through calls this to fill in a window its own caller left open: a point read with no
|
|
108
|
+
* window means "the whole bodies" to the port, which is exactly the unstated size this surface
|
|
109
|
+
* refuses, so the fallback asks for the declared ceiling instead of being refused. The slice is
|
|
110
|
+
* self-describing (`totalChars` beside the text), so a body longer than the ceiling reports itself
|
|
111
|
+
* as cut rather than passing as whole.
|
|
112
|
+
*/
|
|
113
|
+
export function telemetryReadBodyCap(repo, method) {
|
|
114
|
+
const methods = TELEMETRY_READ_METHODS[repo];
|
|
115
|
+
if (!Object.hasOwn(methods, method))
|
|
116
|
+
return null;
|
|
117
|
+
return methods[method]?.maxBodyChars ?? null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Page sizes the laptop-side drain STARTS at. Each is at or below its method's `maxLimit` and
|
|
121
|
+
* sized for the rows that sink typically holds — not for its worst case, which no fixed page size
|
|
122
|
+
* could serve: three whole snapshots at the capture ceiling are ~12 MiB before JSON escaping, and
|
|
123
|
+
* a hundred whole calls ~150 MiB. A page that overruns {@link MAX_TELEMETRY_READ_CHARS} is
|
|
124
|
+
* therefore a ROUTINE condition on a run with large prompts, and the drain halves and retries
|
|
125
|
+
* rather than failing (see {@link TelemetryReadTooLargeError}). Snapshots start at 1 because
|
|
126
|
+
* there is no batching win in a sink whose rows are megabytes apiece.
|
|
127
|
+
*/
|
|
128
|
+
export const TELEMETRY_READ_PAGE_SIZES = {
|
|
129
|
+
metrics: 100,
|
|
130
|
+
snapshots: 1,
|
|
131
|
+
searchQueries: 500,
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Worst-case inflation from JSON string escaping: a body of nothing but `"` or control characters
|
|
135
|
+
* serializes to two characters each. Real bodies sit far below this, but the backstop below has to
|
|
136
|
+
* hold for the pathological one — that is what it is FOR.
|
|
137
|
+
*/
|
|
138
|
+
const JSON_ESCAPE_WORST_CASE = 2;
|
|
139
|
+
/**
|
|
140
|
+
* Room for one row's non-body fields — ids, timestamps, token counts, a snapshot's fragment and
|
|
141
|
+
* context-file paths/titles/URLs, and the response envelope itself. Generous on purpose: it is
|
|
142
|
+
* the slack in the inequality that makes {@link MAX_TELEMETRY_READ_CHARS} provably sufficient.
|
|
143
|
+
*/
|
|
144
|
+
const ROW_METADATA_HEADROOM = 512 * 1024;
|
|
145
|
+
/**
|
|
146
|
+
* Upper bound on one read RESPONSE (characters). The per-method caps bound row COUNT; this bounds
|
|
147
|
+
* the axis a single pathological row moves. Over it the mothership REFUSES rather than truncating:
|
|
148
|
+
* a shortened page would leave the node paging on a cursor drawn from rows the mothership silently
|
|
149
|
+
* dropped, which loses the tail with nothing left to notice.
|
|
150
|
+
*
|
|
151
|
+
* It is DERIVED from the capture ceilings rather than picked, and the derivation is the property
|
|
152
|
+
* that makes the drain's halving terminate: the backstop is wide enough for the largest SINGLE row
|
|
153
|
+
* either body-bearing sink can store, worst-case escaped, so a request for one row can never be
|
|
154
|
+
* refused for size. Halving therefore always reaches a page that fits, instead of bottoming out at
|
|
155
|
+
* 1 and failing a run permanently — which is what an 8,000,000 constant did, being narrower than a
|
|
156
|
+
* single maximal snapshot (4 MiB × 2 = 8,388,608).
|
|
157
|
+
*
|
|
158
|
+
* `telemetryRead.spec.ts` pins the inequality against BOTH sinks' ceilings, so raising a capture
|
|
159
|
+
* cap without widening this fails a test rather than a developer's panel.
|
|
160
|
+
*/
|
|
161
|
+
export const MAX_TELEMETRY_READ_CHARS = MAX_AGENT_CONTEXT_TOTAL_CHARS * JSON_ESCAPE_WORST_CASE + ROW_METADATA_HEADROOM;
|
|
162
|
+
/**
|
|
163
|
+
* The largest a single row of a body-bearing sink can serialize to, worst-case escaped. Exported
|
|
164
|
+
* so the conformity assertion in `telemetryRead.spec.ts` states the inequality in one place rather
|
|
165
|
+
* than restating the arithmetic.
|
|
166
|
+
*
|
|
167
|
+
* An LLM call carries three capped bodies ({@link MAX_BODY_CHARS} each: prompt delta, response,
|
|
168
|
+
* reasoning); a snapshot carries one shared budget across both prompts, every fragment and every
|
|
169
|
+
* injected file.
|
|
170
|
+
*/
|
|
171
|
+
export const MAX_TELEMETRY_READ_ROW_CHARS = Math.max(MAX_BODY_CHARS * 3, MAX_AGENT_CONTEXT_TOTAL_CHARS) * JSON_ESCAPE_WORST_CASE;
|
|
172
|
+
/**
|
|
173
|
+
* Fallback round-trip budget for a method the table does not name. Unreachable through the
|
|
174
|
+
* read-through (its calls are all table entries), so this only covers a hand-built request.
|
|
175
|
+
*/
|
|
176
|
+
const DEFAULT_TIMEOUT_MS = 20_000;
|
|
177
|
+
/** The `error.code` a mothership uses for a response that overran {@link MAX_TELEMETRY_READ_CHARS}. */
|
|
178
|
+
export const TELEMETRY_READ_TOO_LARGE_CODE = 'response_too_large';
|
|
179
|
+
/**
|
|
180
|
+
* The refusal a caller can DO something about: the rows it asked for were within their row cap but
|
|
181
|
+
* serialized past the byte backstop, so the same cursor with a smaller page will fit.
|
|
182
|
+
*
|
|
183
|
+
* Distinct from every other refusal precisely so the drain can tell "ask for less" from "you asked
|
|
184
|
+
* for something you may not have" (an over-cap limit, an unknown method — client bugs, where
|
|
185
|
+
* retrying smaller would just fail more slowly). Retrying is CORRECT rather than a clamp in
|
|
186
|
+
* disguise: the keyset cursor only ever advances over rows actually received, so a narrower page
|
|
187
|
+
* loses nothing, where the server silently shortening one would.
|
|
188
|
+
*/
|
|
189
|
+
export class TelemetryReadTooLargeError extends Error {
|
|
190
|
+
constructor(message) {
|
|
191
|
+
super(message);
|
|
192
|
+
this.name = 'TelemetryReadTooLargeError';
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* A fetch-based {@link MachineTelemetryReadClient} posting to a mothership's
|
|
197
|
+
* `POST /internal/telemetry/read` with the node's machine token. Same auth contract as
|
|
198
|
+
* `HttpMachineTelemetryClient` (a fixed token OR a per-request provider, so a token cached after
|
|
199
|
+
* boot by the mothership login flow is picked up without a restart).
|
|
200
|
+
*/
|
|
201
|
+
export class HttpMachineTelemetryReadClient {
|
|
202
|
+
opts;
|
|
203
|
+
constructor(opts) {
|
|
204
|
+
this.opts = opts;
|
|
205
|
+
}
|
|
206
|
+
async read(request) {
|
|
207
|
+
const token = typeof this.opts.token === 'function' ? this.opts.token() : this.opts.token;
|
|
208
|
+
// No token yet (a node booted before the mothership login): there is nothing to read from,
|
|
209
|
+
// and this THROWS rather than returning an empty result for the reason the port states — a
|
|
210
|
+
// fallback that answers empty reports a false zero to whoever is looking at the panel.
|
|
211
|
+
if (!token)
|
|
212
|
+
throw new MachineTokenUnavailableForReadError();
|
|
213
|
+
const fetchImpl = this.opts.fetchImpl ?? fetch;
|
|
214
|
+
const res = await fetchImpl(`${this.opts.baseUrl.replace(/\/$/, '')}/internal/telemetry/read`, {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },
|
|
217
|
+
body: JSON.stringify(request),
|
|
218
|
+
signal: AbortSignal.timeout(this.opts.timeoutMs ?? timeoutFor(request)),
|
|
219
|
+
});
|
|
220
|
+
const body = (await res.json().catch(() => null));
|
|
221
|
+
if (!body || !('ok' in body)) {
|
|
222
|
+
throw new Error(`mothership telemetry read failed with HTTP ${res.status}`);
|
|
223
|
+
}
|
|
224
|
+
if (!body.ok) {
|
|
225
|
+
const refusal = `${body.error.code} ${body.error.message}`;
|
|
226
|
+
// The one refusal a caller can act on rather than report — see the error's own note.
|
|
227
|
+
if (body.error.code === TELEMETRY_READ_TOO_LARGE_CODE) {
|
|
228
|
+
throw new TelemetryReadTooLargeError(`mothership telemetry read refused: ${refusal}`);
|
|
229
|
+
}
|
|
230
|
+
throw new Error(`mothership telemetry read refused: ${refusal}`);
|
|
231
|
+
}
|
|
232
|
+
return body.value;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** The round-trip budget `request`'s method declares, or the fallback for one off the table. */
|
|
236
|
+
function timeoutFor(request) {
|
|
237
|
+
const methods = Object.hasOwn(TELEMETRY_READ_METHODS, request.repo)
|
|
238
|
+
? TELEMETRY_READ_METHODS[request.repo]
|
|
239
|
+
: undefined;
|
|
240
|
+
const bound = methods && Object.hasOwn(methods, request.method) ? methods[request.method] : null;
|
|
241
|
+
return bound?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Thrown when the node holds no machine token yet, so the read could not be attempted.
|
|
245
|
+
*
|
|
246
|
+
* Distinct from a transport failure only so a caller can report the benign, self-healing case
|
|
247
|
+
* ("finish the mothership login") differently from a broken one. Both are rejections, for the
|
|
248
|
+
* reason {@link MachineTelemetryReadClient.read} states.
|
|
249
|
+
*/
|
|
250
|
+
export class MachineTokenUnavailableForReadError extends Error {
|
|
251
|
+
constructor() {
|
|
252
|
+
super('no machine token: node has not completed the mothership login yet');
|
|
253
|
+
this.name = 'MachineTokenUnavailableForReadError';
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=machineTelemetryRead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machineTelemetryRead.js","sourceRoot":"","sources":["../../src/telemetry/machineTelemetryRead.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,6BAA6B,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAE1F,+FAA+F;AAC/F,kCAAkC;AAClC,EAAE;AACF,6FAA6F;AAC7F,iGAAiG;AACjG,gGAAgG;AAChG,kGAAkG;AAClG,EAAE;AACF,kGAAkG;AAClG,kCAAkC;AAClC,gGAAgG;AAChG,kGAAkG;AAClG,sDAAsD;AACtD,mGAAmG;AACnG,gGAAgG;AAChG,kGAAkG;AAClG,iFAAiF;AACjF,EAAE;AACF,8FAA8F;AAC9F,0FAA0F;AAC1F,EAAE;AACF,iGAAiG;AACjG,gGAAgG;AAChG,sGAAsG;AACtG,+FAA+F;AAC/F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,uBAAuB,EAAE;QACvB,4FAA4F;QAC5F,WAAW,EAAE;YACX,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,MAAM;SAClB;QACD,uCAAuC;QACvC,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,GAAG;YACb,YAAY,EAAE,OAAO;YACrB,SAAS,EAAE,MAAM;SAClB;QACD,4DAA4D;QAC5D,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE;QACtF,uFAAuF;QACvF,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;KAChF;IACD,8BAA8B,EAAE;QAC9B;;;;WAIG;QACH,WAAW,EAAE;YACX,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,MAAM;SAClB;QACD,2CAA2C;QAC3C,SAAS,EAAE;YACT,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,MAAM;SAClB;QACD,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE;QAC/D,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;KAC5E;IACD,0BAA0B,EAAE;QAC1B,0FAA0F;QAC1F,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,GAAG;YACb,SAAS,EAAE,MAAM;SAClB;QACD,gBAAgB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;KAC5E;CACoE,CAAA;AA2CvE;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA6B,EAAE,MAAc;IAChF,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAuC,CAAA;IAClF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAChD,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,IAAI,IAAI,CAAA;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,CAAC;IACZ,aAAa,EAAE,GAAG;CACV,CAAA;AAEV;;;;GAIG;AACH,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEhC;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAA;AAExC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,6BAA6B,GAAG,sBAAsB,GAAG,qBAAqB,CAAA;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,4BAA4B,GACvC,IAAI,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,EAAE,6BAA6B,CAAC,GAAG,sBAAsB,CAAA;AAqEtF;;;GAGG;AACH,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAEjC,uGAAuG;AACvG,MAAM,CAAC,MAAM,6BAA6B,GAAG,oBAAoB,CAAA;AAEjE;;;;;;;;;GASG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAA;IAC1C,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,8BAA8B;IACZ,IAAI;IAAjC,YAA6B,IAA2C;oBAA3C,IAAI;IAA0C,CAAC;IAE5E,KAAK,CAAC,IAAI,CAAC,OAA6B;QACtC,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAA;QACzF,2FAA2F;QAC3F,2FAA2F;QAC3F,uFAAuF;QACvF,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,mCAAmC,EAAE,CAAA;QAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;QAC9C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,0BAA0B,EAAE;YAC7F,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;YACjF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;SACxE,CAAC,CAAA;QACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAiC,CAAA;QACjF,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,8CAA8C,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;QAC7E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;YAC1D,qFAAqF;YACrF,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE,CAAC;gBACtD,MAAM,IAAI,0BAA0B,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAA;YACvF,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAA;QAClE,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;CACF;AAED,gGAAgG;AAChG,SAAS,UAAU,CAAC,OAA6B;IAC/C,MAAM,OAAO,GAAmD,MAAM,CAAC,MAAM,CAC3E,sBAAsB,EACtB,OAAO,CAAC,IAAI,CACb;QACC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC;QACtC,CAAC,CAAC,SAAS,CAAA;IACb,MAAM,KAAK,GAAG,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAChG,OAAO,KAAK,EAAE,SAAS,IAAI,kBAAkB,CAAA;AAC/C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,mCAAoC,SAAQ,KAAK;IAC5D;QACE,KAAK,CAAC,mEAAmE,CAAC,CAAA;QAC1E,IAAI,CAAC,IAAI,GAAG,qCAAqC,CAAA;IACnD,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.193.0",
|
|
4
4
|
"description": "Runtime-neutral HTTP layer for the Agent Architecture Board: the Hono controllers, middleware (auth/authz/CORS/error), request helpers and the gateway seams shared by every deployment facade (Cloudflare Worker, Node service).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
"@toad-contracts/core": "0.4.0",
|
|
28
28
|
"@toad-contracts/hono": "0.3.2",
|
|
29
29
|
"@toad-contracts/valibot": "0.5.0",
|
|
30
|
-
"hono": "^4.12.
|
|
30
|
+
"hono": "^4.12.33",
|
|
31
31
|
"pino": "^10.3.1",
|
|
32
32
|
"valibot": "^1.4.2",
|
|
33
|
-
"@cat-factory/agents": "0.
|
|
34
|
-
"@cat-factory/contracts": "0.210.
|
|
35
|
-
"@cat-factory/integrations": "0.116.
|
|
36
|
-
"@cat-factory/kernel": "0.
|
|
37
|
-
"@cat-factory/orchestration": "0.
|
|
38
|
-
"@cat-factory/prompt-fragments": "0.15.
|
|
39
|
-
"@cat-factory/spend": "0.12.
|
|
33
|
+
"@cat-factory/agents": "0.104.1",
|
|
34
|
+
"@cat-factory/contracts": "0.210.1",
|
|
35
|
+
"@cat-factory/integrations": "0.116.2",
|
|
36
|
+
"@cat-factory/kernel": "0.213.0",
|
|
37
|
+
"@cat-factory/orchestration": "0.185.0",
|
|
38
|
+
"@cat-factory/prompt-fragments": "0.15.35",
|
|
39
|
+
"@cat-factory/spend": "0.12.144"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@types/node": "^26.1.
|
|
42
|
+
"@types/node": "^26.1.2",
|
|
43
43
|
"typescript": "7.0.2",
|
|
44
44
|
"undici": "^8.9.0",
|
|
45
45
|
"vitest": "^4.1.10"
|