index-timing.mjs
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠ breaking
2 days ago
| 1 | /** |
| 2 | * Per-request timing instrumentation for POST /api/v1/index in hub/bridge/server.mjs. |
| 3 | * |
| 4 | * Why this exists: when a hosted re-index hits the Netlify sync-function timeout (~26–30 s |
| 5 | * before this PR; ~60 s after), the gateway logs a generic 30 s duration but neither side |
| 6 | * tells us which sub-step (canister export, embed loop, blob persist, etc.) dominated. |
| 7 | * Without that signal we cannot tell whether the bottleneck is provider latency |
| 8 | * (DeepInfra batch embed), the canister export, or the Netlify Blobs vector persist — |
| 9 | * all of which require different fixes (parallelize embed, async/background, etc.). |
| 10 | * |
| 11 | * Logs a single JSON object per step under a stable `type` so Netlify / Datadog filters |
| 12 | * can scrape reliably. No PII beyond vault_id + sanitized canister_uid (already in use). |
| 13 | * |
| 14 | * Pure module: side-effect is the injected logger only (default console.log). |
| 15 | */ |
| 16 | |
| 17 | /** |
| 18 | * @param {object} [opts] |
| 19 | * @param {string|null} [opts.vaultId] |
| 20 | * @param {string|null} [opts.canisterUid] |
| 21 | * @param {(line: string) => void} [opts.logger] - Defaults to console.log; injected for tests. |
| 22 | * @param {() => number} [opts.now] - Defaults to Date.now; injected for tests. |
| 23 | * @returns {{ step: (name: string, extra?: object) => number, finish: (extra?: object) => number, totalMs: () => number }} |
| 24 | */ |
| 25 | export function createIndexTimer({ vaultId = null, canisterUid = null, logger = console.log, now = Date.now } = {}) { |
| 26 | const t0 = now(); |
| 27 | let last = t0; |
| 28 | let stepCount = 0; |
| 29 | let finished = false; |
| 30 | |
| 31 | function step(name, extra = {}) { |
| 32 | if (finished) return 0; |
| 33 | if (typeof name !== 'string' || !name) { |
| 34 | throw new Error('createIndexTimer.step requires a non-empty name'); |
| 35 | } |
| 36 | const t = now(); |
| 37 | const ms = t - last; |
| 38 | const totalMs = t - t0; |
| 39 | last = t; |
| 40 | stepCount++; |
| 41 | const line = { |
| 42 | type: 'knowtation_index_step', |
| 43 | ts: new Date(t).toISOString(), |
| 44 | vault_id: vaultId, |
| 45 | canister_uid: canisterUid, |
| 46 | step: name, |
| 47 | ms, |
| 48 | total_ms: totalMs, |
| 49 | ...extra, |
| 50 | }; |
| 51 | logger(JSON.stringify(line)); |
| 52 | return ms; |
| 53 | } |
| 54 | |
| 55 | function finish(extra = {}) { |
| 56 | if (finished) return now() - t0; |
| 57 | finished = true; |
| 58 | const t = now(); |
| 59 | const totalMs = t - t0; |
| 60 | const line = { |
| 61 | type: 'knowtation_index_done', |
| 62 | ts: new Date(t).toISOString(), |
| 63 | vault_id: vaultId, |
| 64 | canister_uid: canisterUid, |
| 65 | total_ms: totalMs, |
| 66 | step_count: stepCount, |
| 67 | ...extra, |
| 68 | }; |
| 69 | logger(JSON.stringify(line)); |
| 70 | return totalMs; |
| 71 | } |
| 72 | |
| 73 | function totalMs() { |
| 74 | return now() - t0; |
| 75 | } |
| 76 | |
| 77 | return { step, finish, totalMs }; |
| 78 | } |
File History
2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠
2 days ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6
docs: accept Calendar Events v0 spec with Phase 0 security …
Human
2 days ago