@shpitdev/convex-cliproxy-observability 0.3.5 → 0.3.7
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 +20 -0
- package/README.md +2 -2
- package/dist/capture/content-health.d.ts +29 -0
- package/dist/capture/content-health.d.ts.map +1 -0
- package/dist/capture/content-health.js +29 -0
- package/dist/capture/content-health.js.map +1 -0
- package/dist/capture/index.d.ts +26 -2
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +99 -7
- package/dist/capture/index.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -0
- package/dist/client.js.map +1 -1
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/ingest.d.ts +13 -0
- package/dist/component/ingest.d.ts.map +1 -1
- package/dist/component/ingest.js +4 -0
- package/dist/component/ingest.js.map +1 -1
- package/dist/model-call/index.d.ts +3 -1
- package/dist/model-call/index.d.ts.map +1 -1
- package/dist/model-call/index.js.map +1 -1
- package/dist/projection.d.ts +6 -3
- package/dist/projection.d.ts.map +1 -1
- package/dist/projection.js +55 -7
- package/dist/projection.js.map +1 -1
- package/dist/protocols/body-parts.d.ts +19 -0
- package/dist/protocols/body-parts.d.ts.map +1 -0
- package/dist/protocols/body-parts.js +56 -0
- package/dist/protocols/body-parts.js.map +1 -0
- package/dist/protocols/checkpoint.d.ts +16 -1
- package/dist/protocols/checkpoint.d.ts.map +1 -1
- package/dist/protocols/checkpoint.js +69 -24
- package/dist/protocols/checkpoint.js.map +1 -1
- package/dist/protocols/index.d.ts +3 -1
- package/dist/protocols/index.d.ts.map +1 -1
- package/dist/protocols/index.js +2 -0
- package/dist/protocols/index.js.map +1 -1
- package/dist/protocols/stock-block.d.ts +3 -0
- package/dist/protocols/stock-block.d.ts.map +1 -0
- package/dist/protocols/stock-block.js +17 -0
- package/dist/protocols/stock-block.js.map +1 -0
- package/package.json +1 -1
- package/src/capture/content-health.ts +32 -0
- package/src/capture/index.ts +139 -9
- package/src/client.ts +3 -0
- package/src/component/_generated/api.ts +5 -6
- package/src/component/_generated/component.ts +6 -6
- package/src/component/ingest.ts +3 -0
- package/src/model-call/index.ts +3 -1
- package/src/projection.ts +71 -16
- package/src/protocols/body-parts.ts +58 -0
- package/src/protocols/checkpoint.ts +76 -22
- package/src/protocols/index.ts +4 -1
- package/src/protocols/stock-block.ts +18 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/protocols/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/protocols/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stock-block.d.ts","sourceRoot":"","sources":["../../src/protocols/stock-block.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,SAAS,UAAU,EAAE,CAavB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Recover stock parser boundaries without altering the captured bytes. */
|
|
2
|
+
export function expandStockHookBlock(body, lengths) {
|
|
3
|
+
if (!Array.isArray(lengths) || lengths.length === 0 || lengths.length > 1024)
|
|
4
|
+
throw new Error("invalid stock hook block lengths");
|
|
5
|
+
const pieces = [];
|
|
6
|
+
let offset = 0;
|
|
7
|
+
for (const length of lengths) {
|
|
8
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > body.byteLength - offset)
|
|
9
|
+
throw new Error("invalid stock hook block length");
|
|
10
|
+
pieces.push(body.subarray(offset, offset + length));
|
|
11
|
+
offset += length;
|
|
12
|
+
}
|
|
13
|
+
if (offset !== body.byteLength)
|
|
14
|
+
throw new Error("stock hook block byte mismatch");
|
|
15
|
+
return pieces;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=stock-block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stock-block.js","sourceRoot":"","sources":["../../src/protocols/stock-block.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,UAAU,oBAAoB,CAClC,IAAgB,EAChB,OAA0B;IAE1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI;QAC1E,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,UAAU,GAAG,MAAM;YAClF,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;QACpD,MAAM,IAAI,MAAM,CAAC;IACnB,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shpitdev/convex-cliproxy-observability",
|
|
3
3
|
"description": "Private stock CLIProxy capture, protocol projections, and bounded model-call reads.",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.7",
|
|
5
5
|
"author": "Anand Pant",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": "github:anandpant/convex-components",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
|
|
3
|
+
/** Local durable ACK counts. They do not claim remote persistence or projection. */
|
|
4
|
+
export const contentHealthValidator = v.object({
|
|
5
|
+
observedBytes: v.number(),
|
|
6
|
+
committedBytes: v.number(),
|
|
7
|
+
lostBytes: v.number(),
|
|
8
|
+
unconfirmedBytes: v.number(),
|
|
9
|
+
unknownLosses: v.number(),
|
|
10
|
+
/** Native 0.2.5: enrolled calls that could not start a scope. Optional for older senders. */
|
|
11
|
+
missedCalls: v.optional(v.number()),
|
|
12
|
+
streamCallbacks: v.number(),
|
|
13
|
+
incompleteCalls: v.number(),
|
|
14
|
+
capacityRejections: v.number(),
|
|
15
|
+
retainedChargedBytes: v.number(),
|
|
16
|
+
peakChargedBytes: v.number(),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export function validContentHealth(value: unknown): boolean {
|
|
20
|
+
if (value === undefined) return true;
|
|
21
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
22
|
+
const counters = value as Record<string, unknown>;
|
|
23
|
+
const fields = Object.keys(contentHealthValidator.fields);
|
|
24
|
+
return (
|
|
25
|
+
Object.keys(counters).every((key) => fields.includes(key)) &&
|
|
26
|
+
fields.every((key) => key === "missedCalls" || key in counters) &&
|
|
27
|
+
Object.values(counters).every(
|
|
28
|
+
(n) => typeof n === "number" && Number.isSafeInteger(n) && n >= 0,
|
|
29
|
+
) &&
|
|
30
|
+
(counters.retainedChargedBytes as number) <= (counters.peakChargedBytes as number)
|
|
31
|
+
);
|
|
32
|
+
}
|
package/src/capture/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { expandStockHookBlock } from "../protocols/stock-block.js";
|
|
1
2
|
import type { ExactCorrelation } from "../model-call/index.js";
|
|
2
3
|
export const MAX_ENVELOPE_BYTES = 2 * 1024 * 1024;
|
|
3
4
|
export const MAX_CONTENT_BYTES = 1024 * 1024;
|
|
5
|
+
/** One split body spans at most the producer's 256 shared data-record slots. */
|
|
6
|
+
export const MAX_BODY_PARTS = 256;
|
|
4
7
|
const id = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,199}$/;
|
|
5
8
|
const routes = new Set([
|
|
6
9
|
"GET /v1/models",
|
|
@@ -9,12 +12,26 @@ const routes = new Set([
|
|
|
9
12
|
"POST /v1/responses",
|
|
10
13
|
"POST /v1/chat/completions",
|
|
11
14
|
]);
|
|
15
|
+
/**
|
|
16
|
+
* Native 0.2.5 splits a body larger than `MAX_CONTENT_BYTES` into exact ordered
|
|
17
|
+
* parts with consecutive sequences. Every part but the last holds exactly
|
|
18
|
+
* `MAX_CONTENT_BYTES`; `offset` is `index * MAX_CONTENT_BYTES`. Concatenate in
|
|
19
|
+
* index order and verify `totalBytes`/`totalSha256` (see `/protocols`
|
|
20
|
+
* `BodyPartAssembler`). A split stream callback is one stock callback.
|
|
21
|
+
*/
|
|
22
|
+
export type BodyPartV1 = {
|
|
23
|
+
index: number;
|
|
24
|
+
count: number;
|
|
25
|
+
offset: number;
|
|
26
|
+
totalBytes: number;
|
|
27
|
+
totalSha256: string;
|
|
28
|
+
};
|
|
12
29
|
export type CaptureObservationV1 = {
|
|
13
30
|
schemaVersion: 1;
|
|
14
31
|
pluginVersion: string;
|
|
15
32
|
/** Historical redacted observations retain their original policy label. */
|
|
16
33
|
redactionVersion?: string;
|
|
17
|
-
capturePolicy?: "hook-body-v1";
|
|
34
|
+
capturePolicy?: "hook-body-v1" | "hook-content-block-v1";
|
|
18
35
|
destinationId: string;
|
|
19
36
|
instanceId: string;
|
|
20
37
|
pluginBootId: string;
|
|
@@ -45,7 +62,12 @@ export type CaptureObservationV1 = {
|
|
|
45
62
|
stockChunkIndex?: number;
|
|
46
63
|
body?: string;
|
|
47
64
|
observedBodyBytes?: number;
|
|
48
|
-
bodyFraming?:
|
|
65
|
+
bodyFraming?:
|
|
66
|
+
"stock_json_chunk" | "stock_sse_candidate" | "stock_hook_chunk" | "stock_hook_block";
|
|
67
|
+
stockHookChunkLengths?: number[];
|
|
68
|
+
bodyPart?: BodyPartV1;
|
|
69
|
+
lostContentBytes?: number;
|
|
70
|
+
captureIncomplete?: boolean;
|
|
49
71
|
contentSha256: string;
|
|
50
72
|
contentBytes: number;
|
|
51
73
|
completionOutcome?: string;
|
|
@@ -135,6 +157,10 @@ export async function validateObservation(
|
|
|
135
157
|
"correlation",
|
|
136
158
|
"correlationConflicts",
|
|
137
159
|
"stockChunkIndex",
|
|
160
|
+
"stockHookChunkLengths",
|
|
161
|
+
"bodyPart",
|
|
162
|
+
"lostContentBytes",
|
|
163
|
+
"captureIncomplete",
|
|
138
164
|
"body",
|
|
139
165
|
"observedBodyBytes",
|
|
140
166
|
"bodyFraming",
|
|
@@ -234,11 +260,17 @@ export async function validateObservation(
|
|
|
234
260
|
if (o[field] !== undefined && (typeof o[field] !== "string" || o[field]!.length > 256))
|
|
235
261
|
throw new Error("invalid optional metadata");
|
|
236
262
|
}
|
|
237
|
-
if (
|
|
263
|
+
if (
|
|
264
|
+
!o.pluginVersion ||
|
|
265
|
+
(!o.redactionVersion &&
|
|
266
|
+
o.capturePolicy !== "hook-body-v1" &&
|
|
267
|
+
o.capturePolicy !== "hook-content-block-v1")
|
|
268
|
+
)
|
|
238
269
|
throw new Error("capture versions required");
|
|
239
270
|
if (
|
|
240
271
|
o.capturePolicy !== undefined &&
|
|
241
|
-
(
|
|
272
|
+
(!["hook-body-v1", "hook-content-block-v1"].includes(o.capturePolicy) ||
|
|
273
|
+
o.redactionVersion !== undefined)
|
|
242
274
|
)
|
|
243
275
|
throw new Error("invalid capture policy");
|
|
244
276
|
if (
|
|
@@ -248,11 +280,17 @@ export async function validateObservation(
|
|
|
248
280
|
o.metadataOmissions.some((x) => typeof x !== "string" || x.length > 64))
|
|
249
281
|
)
|
|
250
282
|
throw new Error("invalid metadata omissions");
|
|
251
|
-
if (
|
|
283
|
+
if (
|
|
284
|
+
o.error !== undefined &&
|
|
285
|
+
(typeof o.error !== "string" ||
|
|
286
|
+
new TextEncoder().encode(o.error).length >
|
|
287
|
+
(o.capturePolicy === "hook-content-block-v1" ? MAX_CONTENT_BYTES : 4096))
|
|
288
|
+
)
|
|
252
289
|
throw new Error("invalid error detail");
|
|
253
290
|
if (
|
|
254
291
|
(o.kind === "request_after_auth" || o.bodyFraming === "stock_hook_chunk") &&
|
|
255
|
-
o.capturePolicy !== "hook-body-v1"
|
|
292
|
+
o.capturePolicy !== "hook-body-v1" &&
|
|
293
|
+
o.capturePolicy !== "hook-content-block-v1"
|
|
256
294
|
)
|
|
257
295
|
throw new Error("raw hook policy required");
|
|
258
296
|
if (
|
|
@@ -263,14 +301,52 @@ export async function validateObservation(
|
|
|
263
301
|
throw new Error("raw hook provenance required");
|
|
264
302
|
if (
|
|
265
303
|
o.kind === "completion" &&
|
|
266
|
-
!["succeeded", "failed", "canceled", "rejected"].includes(o.completionOutcome ?? "")
|
|
304
|
+
!["succeeded", "failed", "canceled", "rejected"].includes(o.completionOutcome ?? "") &&
|
|
305
|
+
!(
|
|
306
|
+
o.capturePolicy === "hook-content-block-v1" &&
|
|
307
|
+
o.captureIncomplete === true &&
|
|
308
|
+
o.completionOutcome === undefined &&
|
|
309
|
+
["capture_shutdown_incomplete", "scope_expired"].includes(o.gap ?? "")
|
|
310
|
+
)
|
|
267
311
|
)
|
|
268
312
|
throw new Error("invalid completion outcome");
|
|
269
313
|
if (
|
|
270
314
|
o.bodyFraming !== undefined &&
|
|
271
|
-
!["stock_json_chunk", "stock_sse_candidate", "stock_hook_chunk"].includes(
|
|
315
|
+
!["stock_json_chunk", "stock_sse_candidate", "stock_hook_chunk", "stock_hook_block"].includes(
|
|
316
|
+
o.bodyFraming,
|
|
317
|
+
)
|
|
272
318
|
)
|
|
273
319
|
throw new Error("invalid body framing");
|
|
320
|
+
const body = decodeBody(o);
|
|
321
|
+
if (o.bodyPart !== undefined) validateBodyPart(o, body);
|
|
322
|
+
if (o.bodyFraming === "stock_hook_block") {
|
|
323
|
+
if (o.capturePolicy !== "hook-content-block-v1" || o.kind !== "stream_chunk")
|
|
324
|
+
throw new Error("stock block policy required");
|
|
325
|
+
expandStockHookBlock(body, o.stockHookChunkLengths ?? []);
|
|
326
|
+
} else if (o.stockHookChunkLengths !== undefined) {
|
|
327
|
+
throw new Error("unexpected stock block lengths");
|
|
328
|
+
}
|
|
329
|
+
if (
|
|
330
|
+
o.capturePolicy === "hook-content-block-v1" &&
|
|
331
|
+
(o.bodyFromSequence !== undefined ||
|
|
332
|
+
(o.kind === "stream_chunk" && o.bodyFraming !== "stock_hook_block"))
|
|
333
|
+
)
|
|
334
|
+
throw new Error("content block provenance required");
|
|
335
|
+
if (
|
|
336
|
+
o.lostContentBytes !== undefined &&
|
|
337
|
+
(o.capturePolicy !== "hook-content-block-v1" ||
|
|
338
|
+
!Number.isSafeInteger(o.lostContentBytes) ||
|
|
339
|
+
o.lostContentBytes < 0 ||
|
|
340
|
+
(o.lostContentBytes > 0 && o.captureIncomplete !== true))
|
|
341
|
+
)
|
|
342
|
+
throw new Error("invalid content loss count");
|
|
343
|
+
if (
|
|
344
|
+
o.captureIncomplete !== undefined &&
|
|
345
|
+
(o.capturePolicy !== "hook-content-block-v1" ||
|
|
346
|
+
typeof o.captureIncomplete !== "boolean" ||
|
|
347
|
+
(o.captureIncomplete && !o.gap))
|
|
348
|
+
)
|
|
349
|
+
throw new Error("invalid incomplete capture");
|
|
274
350
|
if (
|
|
275
351
|
o.observedBodyBytes !== undefined &&
|
|
276
352
|
(!Number.isSafeInteger(o.observedBodyBytes) ||
|
|
@@ -287,7 +363,6 @@ export async function validateObservation(
|
|
|
287
363
|
o.observedErrorBytes > MAX_ENVELOPE_BYTES)
|
|
288
364
|
)
|
|
289
365
|
throw new Error("invalid observed diagnostic size");
|
|
290
|
-
const body = decodeBody(o);
|
|
291
366
|
if ((await sha256(body)) !== o.contentSha256) throw new Error("content digest mismatch");
|
|
292
367
|
return {
|
|
293
368
|
observation: o,
|
|
@@ -298,6 +373,53 @@ export async function validateObservation(
|
|
|
298
373
|
};
|
|
299
374
|
}
|
|
300
375
|
|
|
376
|
+
const partKinds = new Set(["request", "request_after_auth", "response", "stream_chunk"]);
|
|
377
|
+
function validateBodyPart(o: CaptureObservationV1, body: Uint8Array) {
|
|
378
|
+
const part: unknown = o.bodyPart;
|
|
379
|
+
const keys = ["index", "count", "offset", "totalBytes", "totalSha256"];
|
|
380
|
+
if (
|
|
381
|
+
!part ||
|
|
382
|
+
typeof part !== "object" ||
|
|
383
|
+
Array.isArray(part) ||
|
|
384
|
+
Object.keys(part).length !== keys.length ||
|
|
385
|
+
!keys.every((key) => key in part)
|
|
386
|
+
)
|
|
387
|
+
throw new Error("invalid body part");
|
|
388
|
+
const { index, count, offset, totalBytes, totalSha256 } = part as BodyPartV1;
|
|
389
|
+
if (
|
|
390
|
+
o.capturePolicy !== "hook-content-block-v1" ||
|
|
391
|
+
!partKinds.has(o.kind) ||
|
|
392
|
+
![index, count, offset, totalBytes].every(Number.isSafeInteger) ||
|
|
393
|
+
count < 2 ||
|
|
394
|
+
count > MAX_BODY_PARTS ||
|
|
395
|
+
index < 0 ||
|
|
396
|
+
index >= count ||
|
|
397
|
+
offset !== index * MAX_CONTENT_BYTES ||
|
|
398
|
+
totalBytes <= (count - 1) * MAX_CONTENT_BYTES ||
|
|
399
|
+
totalBytes > count * MAX_CONTENT_BYTES ||
|
|
400
|
+
body.byteLength !== Math.min(MAX_CONTENT_BYTES, totalBytes - offset) ||
|
|
401
|
+
typeof totalSha256 !== "string" ||
|
|
402
|
+
!/^[a-f0-9]{64}$/.test(totalSha256)
|
|
403
|
+
)
|
|
404
|
+
throw new Error("invalid body part");
|
|
405
|
+
}
|
|
406
|
+
type PartPosition = Pick<CaptureObservationV1, "kind" | "sequence" | "bodyPart">;
|
|
407
|
+
/** True when `next` is the part that must follow `previous` in one split body. */
|
|
408
|
+
export function continuesBodyPart(previous: PartPosition, next: PartPosition) {
|
|
409
|
+
const a = previous.bodyPart;
|
|
410
|
+
const b = next.bodyPart;
|
|
411
|
+
return (
|
|
412
|
+
!!a &&
|
|
413
|
+
!!b &&
|
|
414
|
+
next.kind === previous.kind &&
|
|
415
|
+
next.sequence === previous.sequence + 1 &&
|
|
416
|
+
b.index === a.index + 1 &&
|
|
417
|
+
b.count === a.count &&
|
|
418
|
+
b.totalBytes === a.totalBytes &&
|
|
419
|
+
b.totalSha256 === a.totalSha256
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
301
423
|
/** One immutable NDJSON segment batches observations: no per-token Convex writes. */
|
|
302
424
|
export type CaptureSegmentV1 = {
|
|
303
425
|
schemaVersion: 1;
|
|
@@ -368,6 +490,14 @@ export async function validateSegment(
|
|
|
368
490
|
)
|
|
369
491
|
)
|
|
370
492
|
throw new Error("inconsistent segment lifecycle");
|
|
493
|
+
// Parts of one split body are consecutive; neighbors within a segment must chain.
|
|
494
|
+
for (const [index, o] of observations.entries()) {
|
|
495
|
+
const previous = observations[index - 1];
|
|
496
|
+
if (!previous) continue;
|
|
497
|
+
const open = previous.bodyPart && previous.bodyPart.index < previous.bodyPart.count - 1;
|
|
498
|
+
if ((open || (o.bodyPart && o.bodyPart.index > 0)) && !continuesBodyPart(previous, o))
|
|
499
|
+
throw new Error("body part order mismatch");
|
|
500
|
+
}
|
|
371
501
|
const callId = await callIdentity(first);
|
|
372
502
|
const identity = await sha256(
|
|
373
503
|
new TextEncoder().encode(
|
package/src/client.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validContentHealth } from "./capture/content-health.js";
|
|
1
2
|
import { validCapacity } from "./capture/capacity.js";
|
|
2
3
|
import type {
|
|
3
4
|
GenericActionCtx,
|
|
@@ -223,9 +224,11 @@ export async function handleCliproxyCaptureRequest(
|
|
|
223
224
|
expiredScopesTotal: candidate.expiredScopesTotal,
|
|
224
225
|
activeCalls: candidate.activeCalls,
|
|
225
226
|
...(candidate.capacity === undefined ? {} : { capacity: candidate.capacity }),
|
|
227
|
+
...(candidate.content === undefined ? {} : { content: candidate.content }),
|
|
226
228
|
};
|
|
227
229
|
if (
|
|
228
230
|
!validCapacity(candidate.capacity) ||
|
|
231
|
+
!validContentHealth(candidate.content) ||
|
|
229
232
|
typeof args.startedAt !== "string" ||
|
|
230
233
|
typeof args.observedAt !== "string" ||
|
|
231
234
|
!Number.isFinite(Date.parse(args.startedAt)) ||
|
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type * as ingest from "../ingest.js";
|
|
4
4
|
import type * as queries from "../queries.js";
|
|
5
|
-
import type {
|
|
6
|
-
ApiFromModules,
|
|
7
|
-
FilterApi,
|
|
8
|
-
FunctionReference,
|
|
9
|
-
} from "convex/server";
|
|
5
|
+
import type { ApiFromModules, FilterApi, FunctionReference } from "convex/server";
|
|
10
6
|
import { anyApi, componentsGeneric } from "convex/server";
|
|
11
7
|
|
|
12
8
|
const fullApi: ApiFromModules<{
|
|
@@ -15,5 +11,8 @@ const fullApi: ApiFromModules<{
|
|
|
15
11
|
}> = anyApi as any;
|
|
16
12
|
|
|
17
13
|
export const api: FilterApi<typeof fullApi, FunctionReference<any, "public">> = anyApi as any;
|
|
18
|
-
export const internal: FilterApi<
|
|
14
|
+
export const internal: FilterApi<
|
|
15
|
+
typeof fullApi,
|
|
16
|
+
FunctionReference<any, "internal">
|
|
17
|
+
> = anyApi as any;
|
|
19
18
|
export const components = componentsGeneric() as unknown as {};
|
|
@@ -10,9 +10,9 @@ type ComponentQuery<Registered, Name extends string | undefined> =
|
|
|
10
10
|
: never;
|
|
11
11
|
|
|
12
12
|
type PublicQueries<Module, Name extends string | undefined> = {
|
|
13
|
-
[
|
|
14
|
-
? Key
|
|
15
|
-
|
|
13
|
+
[
|
|
14
|
+
Key in keyof Module as Module[Key] extends RegisteredQuery<"public", any, any> ? Key : never
|
|
15
|
+
]: ComponentQuery<Module[Key], Name>;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
type ComponentMutation<Registered, Name extends string | undefined> =
|
|
@@ -21,9 +21,9 @@ type ComponentMutation<Registered, Name extends string | undefined> =
|
|
|
21
21
|
: never;
|
|
22
22
|
|
|
23
23
|
type PublicMutations<Module, Name extends string | undefined> = {
|
|
24
|
-
[
|
|
25
|
-
? Key
|
|
26
|
-
|
|
24
|
+
[
|
|
25
|
+
Key in keyof Module as Module[Key] extends RegisteredMutation<"public", any, any> ? Key : never
|
|
26
|
+
]: ComponentMutation<Module[Key], Name>;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
export type ComponentApi<Name extends string | undefined = string | undefined> = {
|
package/src/component/ingest.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { contentHealthValidator, validContentHealth } from "../capture/content-health.js";
|
|
1
2
|
import { capacityValidator, validCapacity } from "../capture/capacity.js";
|
|
2
3
|
import { v } from "convex/values";
|
|
3
4
|
import { mutation } from "./_generated/server.js";
|
|
@@ -268,10 +269,12 @@ export const recordHealth = mutation({
|
|
|
268
269
|
expiredScopesTotal: v.number(),
|
|
269
270
|
activeCalls: v.number(),
|
|
270
271
|
capacity: v.optional(capacityValidator),
|
|
272
|
+
content: v.optional(contentHealthValidator),
|
|
271
273
|
},
|
|
272
274
|
handler: async (ctx, args) => {
|
|
273
275
|
bounded(JSON.stringify(args), 4096);
|
|
274
276
|
if (!validCapacity(args.capacity)) throw new Error("invalid capture capacity");
|
|
277
|
+
if (!validContentHealth(args.content)) throw new Error("invalid content health");
|
|
275
278
|
const at = Date.parse(args.observedAt);
|
|
276
279
|
if (!Number.isFinite(at) || !Number.isFinite(Date.parse(args.startedAt)))
|
|
277
280
|
throw new Error("invalid health time");
|
package/src/model-call/index.ts
CHANGED
|
@@ -126,7 +126,9 @@ export type ModelCallV1 = {
|
|
|
126
126
|
parserVersion: string;
|
|
127
127
|
pluginVersion?: string;
|
|
128
128
|
redactionVersion?: string;
|
|
129
|
-
capturePolicy?: "hook-body-v1";
|
|
129
|
+
capturePolicy?: "hook-body-v1" | "hook-content-block-v1";
|
|
130
|
+
incomplete?: boolean;
|
|
131
|
+
lostContentBytes?: number;
|
|
130
132
|
lastObservedAt?: string;
|
|
131
133
|
};
|
|
132
134
|
receivedAt: number;
|
package/src/projection.ts
CHANGED
|
@@ -1,19 +1,65 @@
|
|
|
1
1
|
import type { GenericActionCtx, GenericDataModel } from "convex/server";
|
|
2
2
|
import type { CliproxyObservability } from "./client.js";
|
|
3
3
|
import { resolveCallBlob, type PrivateCaptureStorage } from "./content/index.js";
|
|
4
|
-
import { sha256, type CaptureObservationV1 } from "./capture/index.js";
|
|
5
|
-
import {
|
|
4
|
+
import { decodeBody, sha256, type CaptureObservationV1 } from "./capture/index.js";
|
|
5
|
+
import {
|
|
6
|
+
MAX_PROJECTED_SPLIT_BYTES,
|
|
7
|
+
applyObservation,
|
|
8
|
+
type ProjectionCheckpoint,
|
|
9
|
+
} from "./protocols/checkpoint.js";
|
|
10
|
+
import { BodyPartAssembler } from "./protocols/body-parts.js";
|
|
6
11
|
import type { ModelCallV1 } from "./model-call/index.js";
|
|
12
|
+
type ProjectionContext = Pick<GenericActionCtx<GenericDataModel>, "runQuery" | "runMutation">;
|
|
13
|
+
type ProjectionOptions = {
|
|
14
|
+
client: CliproxyObservability;
|
|
15
|
+
storage: PrivateCaptureStorage;
|
|
16
|
+
destinationId: string;
|
|
17
|
+
callId: string;
|
|
18
|
+
};
|
|
19
|
+
const segmentLines = (content: Uint8Array) =>
|
|
20
|
+
new TextDecoder("utf-8", { fatal: true }).decode(content).split("\n").filter(Boolean);
|
|
21
|
+
/**
|
|
22
|
+
* A split body spans several immutable segments and projection pages. Re-read
|
|
23
|
+
* its owned segments from the first part and return the exact verified body.
|
|
24
|
+
*/
|
|
25
|
+
async function reassembleSplitBody(
|
|
26
|
+
ctx: ProjectionContext,
|
|
27
|
+
options: ProjectionOptions,
|
|
28
|
+
fromSegment: number,
|
|
29
|
+
final: CaptureObservationV1,
|
|
30
|
+
): Promise<Uint8Array> {
|
|
31
|
+
const parts = new BodyPartAssembler();
|
|
32
|
+
const first = final.sequence - final.bodyPart!.index;
|
|
33
|
+
let after = fromSegment - 1;
|
|
34
|
+
while (after < final.sequence) {
|
|
35
|
+
const page = await ctx.runQuery(options.client.component.queries.pageEventSegments, {
|
|
36
|
+
destinationId: options.destinationId,
|
|
37
|
+
callId: options.callId,
|
|
38
|
+
afterSequence: after,
|
|
39
|
+
limit: 8,
|
|
40
|
+
});
|
|
41
|
+
if (!page.segments.length || page.segments[0]!.sequence !== after + 1)
|
|
42
|
+
throw new Error("split body segment unavailable");
|
|
43
|
+
for (const segment of page.segments) {
|
|
44
|
+
if (segment.sequence > final.sequence) break;
|
|
45
|
+
const content = await resolveCallBlob(
|
|
46
|
+
options.storage,
|
|
47
|
+
[segment.reference],
|
|
48
|
+
segment.reference,
|
|
49
|
+
);
|
|
50
|
+
for (const line of segmentLines(content)) {
|
|
51
|
+
const o = JSON.parse(line) as CaptureObservationV1;
|
|
52
|
+
if (o.sequence < first || o.sequence > final.sequence) continue;
|
|
53
|
+
const whole = await parts.push(o, decodeBody(o));
|
|
54
|
+
if (whole) return whole;
|
|
55
|
+
}
|
|
56
|
+
after = segment.throughSequence;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error("split body incomplete");
|
|
60
|
+
}
|
|
7
61
|
/** Project at most two immutable segments. Host schedules the next page when `more` is true. */
|
|
8
|
-
export async function projectPendingSegments(
|
|
9
|
-
ctx: Pick<GenericActionCtx<GenericDataModel>, "runQuery" | "runMutation">,
|
|
10
|
-
options: {
|
|
11
|
-
client: CliproxyObservability;
|
|
12
|
-
storage: PrivateCaptureStorage;
|
|
13
|
-
destinationId: string;
|
|
14
|
-
callId: string;
|
|
15
|
-
},
|
|
16
|
-
) {
|
|
62
|
+
export async function projectPendingSegments(ctx: ProjectionContext, options: ProjectionOptions) {
|
|
17
63
|
const { client, destinationId, callId } = options;
|
|
18
64
|
const state = await ctx.runQuery(client.component.queries.getProcessingState, {
|
|
19
65
|
destinationId,
|
|
@@ -51,11 +97,20 @@ export async function projectPendingSegments(
|
|
|
51
97
|
[segment.reference],
|
|
52
98
|
segment.reference,
|
|
53
99
|
);
|
|
54
|
-
for (const line of
|
|
55
|
-
.
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
|
|
100
|
+
for (const line of segmentLines(content)) {
|
|
101
|
+
const o = JSON.parse(line) as CaptureObservationV1;
|
|
102
|
+
const part = o.bodyPart;
|
|
103
|
+
if (part?.index === 0) checkpoint.bodyPartSegment = segment.sequence;
|
|
104
|
+
if (part && part.index === part.count - 1) {
|
|
105
|
+
if (checkpoint.bodyPartSegment === undefined) throw new Error("split body start missing");
|
|
106
|
+
const whole =
|
|
107
|
+
part.totalBytes > MAX_PROJECTED_SPLIT_BYTES
|
|
108
|
+
? null
|
|
109
|
+
: await reassembleSplitBody(ctx, options, checkpoint.bodyPartSegment, o);
|
|
110
|
+
applyObservation(call, checkpoint, o, whole);
|
|
111
|
+
delete checkpoint.bodyPartSegment;
|
|
112
|
+
} else applyObservation(call, checkpoint, o);
|
|
113
|
+
}
|
|
59
114
|
through = segment.throughSequence;
|
|
60
115
|
}
|
|
61
116
|
if (through === state.projectedThroughSequence)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_BODY_PARTS,
|
|
3
|
+
MAX_CONTENT_BYTES,
|
|
4
|
+
continuesBodyPart,
|
|
5
|
+
sha256,
|
|
6
|
+
type CaptureObservationV1,
|
|
7
|
+
} from "../capture/index.js";
|
|
8
|
+
import { expandStockHookBlock } from "./stock-block.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reassembles native 0.2.5 split bodies from validated observations read in
|
|
12
|
+
* sequence order. `push` returns a whole observation's body unchanged, nothing
|
|
13
|
+
* for an earlier part, and the exact original body at the final part once its
|
|
14
|
+
* length and SHA-256 match. Interleaved, missing or reordered parts throw.
|
|
15
|
+
*/
|
|
16
|
+
export class BodyPartAssembler {
|
|
17
|
+
#open?: { previous: CaptureObservationV1; body: Uint8Array; written: number };
|
|
18
|
+
/** `maxBytes` bounds the buffer one split body may allocate. */
|
|
19
|
+
constructor(readonly maxBytes = MAX_BODY_PARTS * MAX_CONTENT_BYTES) {}
|
|
20
|
+
/** A split body has started but its final part has not been pushed. */
|
|
21
|
+
get pending(): boolean {
|
|
22
|
+
return this.#open !== undefined;
|
|
23
|
+
}
|
|
24
|
+
async push(o: CaptureObservationV1, body: Uint8Array): Promise<Uint8Array | undefined> {
|
|
25
|
+
const part = o.bodyPart;
|
|
26
|
+
const open = this.#open;
|
|
27
|
+
if (!part) {
|
|
28
|
+
if (open) throw new Error("body part interrupted");
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
if (part.index === 0) {
|
|
32
|
+
if (open) throw new Error("body part interrupted");
|
|
33
|
+
if (part.totalBytes > this.maxBytes) throw new Error("body part read limit");
|
|
34
|
+
this.#open = { previous: o, body: new Uint8Array(part.totalBytes), written: 0 };
|
|
35
|
+
} else if (!open || !continuesBodyPart(open.previous, o)) {
|
|
36
|
+
throw new Error("body part order mismatch");
|
|
37
|
+
}
|
|
38
|
+
const current = this.#open!;
|
|
39
|
+
if (part.offset !== current.written || body.byteLength > part.totalBytes - current.written)
|
|
40
|
+
throw new Error("body part offset mismatch");
|
|
41
|
+
current.body.set(body, part.offset);
|
|
42
|
+
current.written += body.byteLength;
|
|
43
|
+
current.previous = o;
|
|
44
|
+
if (part.index < part.count - 1) return undefined;
|
|
45
|
+
this.#open = undefined;
|
|
46
|
+
if (current.written !== part.totalBytes || (await sha256(current.body)) !== part.totalSha256)
|
|
47
|
+
throw new Error("body part digest mismatch");
|
|
48
|
+
return current.body;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Stock callbacks in a block, or the one callback a split stream body carries. */
|
|
53
|
+
export function stockHookPieces(
|
|
54
|
+
o: Pick<CaptureObservationV1, "bodyPart" | "stockHookChunkLengths">,
|
|
55
|
+
body: Uint8Array,
|
|
56
|
+
): readonly Uint8Array[] {
|
|
57
|
+
return o.bodyPart ? [body] : expandStockHookBlock(body, o.stockHookChunkLengths ?? []);
|
|
58
|
+
}
|