@retinue/agentkit 0.1.0 → 0.3.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/README.md +59 -277
- package/dist/adapters/audio/openai.d.ts +36 -0
- package/dist/adapters/audio/openai.js +136 -0
- package/dist/adapters/bullmq/lock.d.ts +26 -2
- package/dist/adapters/embeddings/openai.d.ts +45 -0
- package/dist/adapters/embeddings/openai.js +109 -0
- package/dist/adapters/memory/connections.d.ts +10 -0
- package/dist/adapters/memory/connections.js +87 -0
- package/dist/adapters/memory/graph.d.ts +17 -0
- package/dist/adapters/memory/graph.js +267 -0
- package/dist/adapters/memory/index.d.ts +3 -0
- package/dist/adapters/memory/index.js +3 -0
- package/dist/adapters/memory/rate-limit.d.ts +14 -0
- package/dist/adapters/memory/rate-limit.js +28 -0
- package/dist/adapters/memory/runtime.js +0 -0
- package/dist/adapters/postgres/connections.d.ts +15 -0
- package/dist/adapters/postgres/connections.js +134 -0
- package/dist/adapters/postgres/graph.d.ts +24 -0
- package/dist/adapters/postgres/graph.js +325 -0
- package/dist/adapters/postgres/index.d.ts +2 -0
- package/dist/adapters/postgres/index.js +2 -0
- package/dist/adapters/postgres/migrations.js +198 -0
- package/dist/adapters/postgres/run-store.js +26 -2
- package/dist/adapters/postgres/schema.d.ts +61 -2
- package/dist/adapters/postgres/schema.js +95 -10
- package/dist/adapters/redis/index.d.ts +1 -0
- package/dist/adapters/redis/index.js +1 -0
- package/dist/adapters/redis/rate-limit.d.ts +46 -0
- package/dist/adapters/redis/rate-limit.js +55 -0
- package/dist/adapters/supabase/index.d.ts +15 -0
- package/dist/adapters/supabase/index.js +15 -0
- package/dist/adapters/supabase/rls.js +33 -0
- package/dist/agents/agent.d.ts +99 -1
- package/dist/agents/agent.js +215 -16
- package/dist/agents/define.js +24 -4
- package/dist/agents/engine.d.ts +48 -0
- package/dist/agents/engine.js +370 -13
- package/dist/audio/index.d.ts +151 -0
- package/dist/audio/index.js +183 -0
- package/dist/capabilities/index.d.ts +5 -1
- package/dist/capabilities/index.js +23 -0
- package/dist/capabilities/runtime.d.ts +8 -0
- package/dist/connections/cipher.d.ts +103 -0
- package/dist/connections/cipher.js +141 -0
- package/dist/connections/index.d.ts +156 -0
- package/dist/connections/index.js +72 -0
- package/dist/connections/oauth/client.d.ts +84 -0
- package/dist/connections/oauth/client.js +141 -0
- package/dist/connections/oauth/index.d.ts +166 -0
- package/dist/connections/oauth/index.js +226 -0
- package/dist/connections/oauth/service.d.ts +90 -0
- package/dist/connections/oauth/service.js +132 -0
- package/dist/connections/pause.d.ts +68 -0
- package/dist/connections/pause.js +97 -0
- package/dist/connections/resolver.d.ts +59 -0
- package/dist/connections/resolver.js +138 -0
- package/dist/connections/resume.d.ts +64 -0
- package/dist/connections/resume.js +99 -0
- package/dist/connections/vault-cipher.d.ts +95 -0
- package/dist/connections/vault-cipher.js +206 -0
- package/dist/core/budget.d.ts +55 -0
- package/dist/core/budget.js +56 -0
- package/dist/core/content-parts.d.ts +26 -2
- package/dist/core/content-parts.js +1 -0
- package/dist/core/context.d.ts +25 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.js +15 -0
- package/dist/core/events.d.ts +110 -2
- package/dist/core/events.js +33 -2
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/validation.js +19 -0
- package/dist/documents/index.d.ts +14 -0
- package/dist/documents/parsers/text.d.ts +16 -0
- package/dist/documents/parsers/text.js +54 -2
- package/dist/entries/connections.d.ts +10 -0
- package/dist/entries/connections.js +10 -0
- package/dist/entries/guardrails.d.ts +14 -0
- package/dist/entries/guardrails.js +14 -0
- package/dist/entries/knowledge.d.ts +17 -0
- package/dist/entries/knowledge.js +16 -0
- package/dist/entries/mcp-server.d.ts +9 -0
- package/dist/entries/mcp-server.js +9 -0
- package/dist/entries/runtime.d.ts +10 -0
- package/dist/entries/runtime.js +8 -0
- package/dist/entries/testing.d.ts +28 -0
- package/dist/entries/testing.js +28 -0
- package/dist/graphql/resolvers.d.ts +7 -1
- package/dist/graphql/resolvers.js +20 -0
- package/dist/graphql/schema.d.ts +1 -1
- package/dist/graphql/schema.js +44 -0
- package/dist/guardrails/index.d.ts +115 -0
- package/dist/guardrails/index.js +108 -0
- package/dist/guardrails/moderation.d.ts +53 -0
- package/dist/guardrails/moderation.js +75 -0
- package/dist/guardrails/pii.d.ts +75 -0
- package/dist/guardrails/pii.js +193 -0
- package/dist/knowledge/communities.d.ts +166 -0
- package/dist/knowledge/communities.js +377 -0
- package/dist/knowledge/graph-global.d.ts +153 -0
- package/dist/knowledge/graph-global.js +246 -0
- package/dist/knowledge/graph-retrieval.d.ts +150 -0
- package/dist/knowledge/graph-retrieval.js +303 -0
- package/dist/knowledge/graph.d.ts +223 -0
- package/dist/knowledge/graph.js +369 -0
- package/dist/knowledge/index.d.ts +25 -0
- package/dist/knowledge/index.js +37 -1
- package/dist/knowledge/navigate.d.ts +89 -0
- package/dist/knowledge/navigate.js +107 -0
- package/dist/knowledge/retrieval.d.ts +98 -5
- package/dist/knowledge/retrieval.js +158 -28
- package/dist/mcp-server/index.d.ts +168 -0
- package/dist/mcp-server/index.js +175 -0
- package/dist/models/extraction.d.ts +73 -0
- package/dist/models/extraction.js +118 -0
- package/dist/models/index.d.ts +40 -1
- package/dist/models/index.js +22 -1
- package/dist/models/pricing.d.ts +2 -0
- package/dist/models/pricing.js +17 -1
- package/dist/models/provider-factory.js +9 -7
- package/dist/models/streaming.d.ts +111 -1
- package/dist/models/streaming.js +184 -3
- package/dist/persistence/index.d.ts +230 -0
- package/dist/persistence/index.js +2 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +12 -0
- package/dist/runtime/worker.d.ts +36 -1
- package/dist/runtime/worker.js +37 -4
- package/dist/security/checklist.js +55 -0
- package/dist/security/findings.js +18 -9
- package/dist/server/bin.d.ts +19 -0
- package/dist/server/bin.js +226 -0
- package/dist/server/boot.d.ts +20 -2
- package/dist/server/boot.js +29 -3
- package/dist/server/cli.d.ts +13 -0
- package/dist/server/cli.js +7 -4
- package/dist/server/doctor.d.ts +74 -0
- package/dist/server/doctor.js +280 -0
- package/dist/skills/catalogue.d.ts +49 -0
- package/dist/skills/catalogue.js +61 -0
- package/dist/skills/context.d.ts +61 -0
- package/dist/skills/context.js +107 -0
- package/dist/skills/index.d.ts +2 -0
- package/dist/skills/index.js +2 -0
- package/dist/telemetry/spans.js +17 -0
- package/dist/testing/conformance/artifact-exports.d.ts +20 -0
- package/dist/testing/conformance/artifact-exports.js +172 -0
- package/dist/testing/conformance/artifacts.d.ts +11 -0
- package/dist/testing/conformance/artifacts.js +316 -0
- package/dist/testing/conformance/audio.d.ts +38 -0
- package/dist/testing/conformance/audio.js +145 -0
- package/dist/testing/conformance/capability.d.ts +23 -0
- package/dist/testing/conformance/capability.js +27 -0
- package/dist/testing/conformance/checkpoint-store.d.ts +15 -0
- package/dist/testing/conformance/checkpoint-store.js +72 -0
- package/dist/testing/conformance/connections.d.ts +14 -0
- package/dist/testing/conformance/connections.js +171 -0
- package/dist/testing/conformance/conversation-store.d.ts +10 -0
- package/dist/testing/conformance/conversation-store.js +60 -0
- package/dist/testing/conformance/evaluation.d.ts +10 -0
- package/dist/testing/conformance/evaluation.js +295 -0
- package/dist/testing/conformance/files.d.ts +19 -0
- package/dist/testing/conformance/files.js +454 -0
- package/dist/testing/conformance/flows.d.ts +16 -0
- package/dist/testing/conformance/flows.js +193 -0
- package/dist/testing/conformance/graph.d.ts +22 -0
- package/dist/testing/conformance/graph.js +500 -0
- package/dist/testing/conformance/hitl.d.ts +25 -0
- package/dist/testing/conformance/hitl.js +523 -0
- package/dist/testing/conformance/index.d.ts +163 -0
- package/dist/testing/conformance/index.js +321 -0
- package/dist/testing/conformance/invariants.d.ts +23 -0
- package/dist/testing/conformance/invariants.js +80 -0
- package/dist/testing/conformance/knowledge.d.ts +41 -0
- package/dist/testing/conformance/knowledge.js +592 -0
- package/dist/testing/conformance/parents.d.ts +50 -0
- package/dist/testing/conformance/parents.js +39 -0
- package/dist/testing/conformance/rate-limit.d.ts +25 -0
- package/dist/testing/conformance/rate-limit.js +71 -0
- package/dist/testing/conformance/records.d.ts +36 -0
- package/dist/testing/conformance/records.js +400 -0
- package/dist/testing/conformance/rollups.d.ts +30 -0
- package/dist/testing/conformance/rollups.js +425 -0
- package/dist/testing/conformance/run-coordinator.d.ts +27 -0
- package/dist/testing/conformance/run-coordinator.js +150 -0
- package/dist/testing/conformance/run-event-log.d.ts +9 -0
- package/dist/testing/conformance/run-event-log.js +138 -0
- package/dist/testing/conformance/run-store.d.ts +12 -0
- package/dist/testing/conformance/run-store.js +294 -0
- package/dist/testing/conformance/session-state.d.ts +38 -0
- package/dist/testing/conformance/session-state.js +198 -0
- package/dist/testing/conformance/usage-limits.d.ts +10 -0
- package/dist/testing/conformance/usage-limits.js +309 -0
- package/dist/testing/conformance.d.ts +8 -0
- package/dist/testing/conformance.js +8 -0
- package/dist/testing/memory-backend.d.ts +39 -0
- package/dist/testing/memory-backend.js +41 -0
- package/dist/testing/pglite.d.ts +55 -0
- package/dist/testing/pglite.js +78 -0
- package/dist/testing/stub-model.d.ts +58 -0
- package/dist/testing/stub-model.js +71 -0
- package/dist/testing/supabase-storage-double.d.ts +35 -0
- package/dist/testing/supabase-storage-double.js +101 -0
- package/dist/toolkit/files.d.ts +125 -0
- package/dist/toolkit/files.js +320 -0
- package/dist/toolkit/http.d.ts +27 -0
- package/dist/toolkit/http.js +48 -0
- package/dist/toolkit/index.d.ts +31 -1
- package/dist/toolkit/index.js +26 -1
- package/dist/toolkit/mime.d.ts +97 -0
- package/dist/toolkit/mime.js +233 -0
- package/dist/toolkit/sandbox.d.ts +119 -0
- package/dist/toolkit/sandbox.js +239 -0
- package/dist/toolkit/ssrf.d.ts +139 -0
- package/dist/toolkit/ssrf.js +349 -0
- package/dist/toolkit/vendor.d.ts +91 -0
- package/dist/toolkit/vendor.js +153 -0
- package/dist/toolkit/web.d.ts +13 -0
- package/dist/toolkit/web.js +7 -1
- package/dist/tools/budget.d.ts +28 -0
- package/dist/tools/budget.js +35 -0
- package/dist/tools/credentials.d.ts +316 -0
- package/dist/tools/credentials.js +369 -0
- package/dist/tools/define.d.ts +45 -0
- package/dist/tools/define.js +26 -0
- package/dist/tools/find.d.ts +109 -0
- package/dist/tools/find.js +210 -0
- package/dist/tools/index.d.ts +35 -2
- package/dist/tools/index.js +11 -0
- package/dist/tools/library/audio.d.ts +63 -0
- package/dist/tools/library/audio.js +148 -0
- package/dist/tools/library/fs.d.ts +24 -0
- package/dist/tools/library/fs.js +102 -0
- package/dist/tools/library/index.d.ts +37 -2
- package/dist/tools/library/index.js +47 -0
- package/dist/tools/library/shell.d.ts +45 -0
- package/dist/tools/library/shell.js +70 -0
- package/dist/tools/meta-tools.js +8 -0
- package/dist/tools/registry.d.ts +146 -0
- package/dist/tools/registry.js +250 -4
- package/dist/usage/index.d.ts +21 -0
- package/dist/usage/index.js +1 -0
- package/dist/usage/rate-limit.d.ts +122 -0
- package/dist/usage/rate-limit.js +131 -0
- package/dist/usage/recorder.js +3 -0
- package/package.json +33 -2
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared storage conformance suite — `docs/02` "Conformance suite", widened by #91.
|
|
3
|
+
*
|
|
4
|
+
* Every storage adapter must pass the same harnesses, so "swap the database" is a verified property
|
|
5
|
+
* rather than a claim. Before #91 this suite covered one port of nineteen, which is how #20
|
|
6
|
+
* ("PostgreSQL adapter") could satisfy its own acceptance criterion — *"passes the full conformance
|
|
7
|
+
* suite"* — with a single table implemented.
|
|
8
|
+
*
|
|
9
|
+
* An adapter package supplies factories; it writes no test bodies. Not part of the published build
|
|
10
|
+
* (`src/testing/**` is excluded in tsconfig); imported by tests only.
|
|
11
|
+
*
|
|
12
|
+
* `REGISTERED_PORTS` below is the coverage ledger the guard test in
|
|
13
|
+
* `src/__tests__/conformance-coverage.test.ts` checks, so a port cannot gain methods without also
|
|
14
|
+
* gaining a harness.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./capability.js";
|
|
17
|
+
export * from "./parents.js";
|
|
18
|
+
export * from "./conversation-store.js";
|
|
19
|
+
export * from "./run-store.js";
|
|
20
|
+
export * from "./run-event-log.js";
|
|
21
|
+
export * from "./checkpoint-store.js";
|
|
22
|
+
export * from "./run-coordinator.js";
|
|
23
|
+
export * from "./session-state.js";
|
|
24
|
+
export * from "./records.js";
|
|
25
|
+
export * from "./hitl.js";
|
|
26
|
+
export * from "./files.js";
|
|
27
|
+
export * from "./artifacts.js";
|
|
28
|
+
export * from "./artifact-exports.js";
|
|
29
|
+
export * from "./knowledge.js";
|
|
30
|
+
export * from "./rollups.js";
|
|
31
|
+
export * from "./usage-limits.js";
|
|
32
|
+
export * from "./rate-limit.js";
|
|
33
|
+
export * from "./connections.js";
|
|
34
|
+
export * from "./evaluation.js";
|
|
35
|
+
export * from "./invariants.js";
|
|
36
|
+
/** A port with methods, and the harness that verifies it. */
|
|
37
|
+
export type PortCoverage = {
|
|
38
|
+
readonly port: string;
|
|
39
|
+
readonly harness: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Ports that have methods and therefore must have a harness. Kept as data so the guard test can
|
|
43
|
+
* compare it against the interfaces actually exported by the port modules.
|
|
44
|
+
*/
|
|
45
|
+
export declare const REGISTERED_PORTS: readonly PortCoverage[];
|
|
46
|
+
/**
|
|
47
|
+
* Registered ports whose harness is **not** required to assert cross-tenant isolation, with the
|
|
48
|
+
* reason. Everything else must: governing principle 1 says every tenant-sensitive operation receives
|
|
49
|
+
* an explicit tenant context, and the `AgentStore` leak #91 found proves the type system alone does
|
|
50
|
+
* not enforce it — a store can accept `TenantScope` and quietly ignore it.
|
|
51
|
+
*
|
|
52
|
+
* Keep this list as short as the truth allows. An entry here is a claim that the port has nothing
|
|
53
|
+
* tenant-scoped to leak, not that testing it would be inconvenient.
|
|
54
|
+
*/
|
|
55
|
+
export declare const ISOLATION_EXEMPT_PORTS: readonly {
|
|
56
|
+
readonly port: string;
|
|
57
|
+
readonly reason: string;
|
|
58
|
+
}[];
|
|
59
|
+
/**
|
|
60
|
+
* Method-less placeholder interfaces, deliberately without a harness. An empty harness would pass
|
|
61
|
+
* vacuously and read as coverage, so the guard test instead fails if one of these gains a method —
|
|
62
|
+
* turning "we forgot to widen the suite" into a build failure. Each lands with its own SPEC:
|
|
63
|
+
* `EvaluationStore` #141, `KnowledgeStore`/`VectorIndex`/`KeywordIndex` #135–#136, `ArtifactStore` #133.
|
|
64
|
+
*
|
|
65
|
+
* `FileMetadataStore` left this list in #129, which is the mechanism working as intended: it gained methods
|
|
66
|
+
* and the guard would have failed had a harness not come with them.
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* Ports declared with no methods yet.
|
|
70
|
+
*
|
|
71
|
+
* Empty as of #141, and the list stays: the guard that fails when a placeholder gains methods without a harness
|
|
72
|
+
* is what stopped `KnowledgeStore` and `EvaluationStore` from quietly shipping untested, and deleting it once
|
|
73
|
+
* the list is empty would remove the check that catches the next one.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PLACEHOLDER_PORTS: readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* Infrastructure ports that are not storage. Their real adapters land with REQ-015 (#105 BullMQ
|
|
78
|
+
* dispatcher, #106 Redis lock), at which point they join `REGISTERED_PORTS`. Listed so the omission
|
|
79
|
+
* is recorded rather than silent.
|
|
80
|
+
*/
|
|
81
|
+
export declare const DEFERRED_INFRASTRUCTURE_PORTS: readonly string[];
|
|
82
|
+
/**
|
|
83
|
+
* Exported interfaces in the scanned port modules that are not storage at all, so a storage
|
|
84
|
+
* conformance harness would be meaningless for them. Classified explicitly rather than filtered by
|
|
85
|
+
* a name pattern, so adding one is a decision someone made on purpose.
|
|
86
|
+
*/
|
|
87
|
+
export declare const NON_STORAGE_PORTS: readonly string[];
|
|
88
|
+
/**
|
|
89
|
+
* The port modules the coverage guard scans. Every exported interface in these files must appear in
|
|
90
|
+
* exactly one of the four lists above; an unclassified one fails the guard, which is what forces a
|
|
91
|
+
* new port to come with a harness or an explicit, reasoned exemption.
|
|
92
|
+
*/
|
|
93
|
+
export declare const SCANNED_PORT_MODULES: readonly string[];
|
|
94
|
+
/** The adapters the conformance matrix reports on. */
|
|
95
|
+
export declare const MATRIX_ADAPTERS: readonly ["memory", "postgres", "supabase"];
|
|
96
|
+
export type MatrixAdapter = (typeof MATRIX_ADAPTERS)[number];
|
|
97
|
+
/**
|
|
98
|
+
* Which ports each adapter implements today, and — for each it does not — the SPEC that will add
|
|
99
|
+
* it. This is the data behind the matrix's `NOT-IMPLEMENTED` cell and behind AC-3 of #92.
|
|
100
|
+
*
|
|
101
|
+
* The distinction that matters: a **classified** absence (listed here with a tracking issue) is a
|
|
102
|
+
* known gap and is allowed; an **unclassified** absence (a registered port missing from both lists)
|
|
103
|
+
* is an omission and fails the build. Without that split, either the matrix is permanently red until
|
|
104
|
+
* #100 lands, or a forgotten adapter silently reads as covered — and #20 closing green against
|
|
105
|
+
* "passes the full conformance suite" is what the second failure mode looks like in practice.
|
|
106
|
+
*/
|
|
107
|
+
export type AdapterCoverage = {
|
|
108
|
+
readonly adapter: MatrixAdapter;
|
|
109
|
+
readonly implemented: readonly string[];
|
|
110
|
+
readonly notImplemented: readonly {
|
|
111
|
+
readonly port: string;
|
|
112
|
+
readonly trackedBy: string;
|
|
113
|
+
}[];
|
|
114
|
+
/**
|
|
115
|
+
* Ports this adapter should **never** implement, with the reason.
|
|
116
|
+
*
|
|
117
|
+
* Distinct from `notImplemented`, which means "not yet, tracked by an issue". #129 forced the
|
|
118
|
+
* distinction: `FileContentStore` holds file bytes, and a relational adapter storing them would be the
|
|
119
|
+
* base64-in-`jsonb` antipattern #102 rejected when it declined to make `blobs` a pointer table.
|
|
120
|
+
*
|
|
121
|
+
* Listing it as pending would be a lie the matrix repeats forever, and leaving it out would be an
|
|
122
|
+
* unclassified absence the guard rejects. So it is a third answer, with a reason — the same shape as
|
|
123
|
+
* `ISOLATION_EXEMPT_PORTS`, and kept as short as the truth allows.
|
|
124
|
+
*/
|
|
125
|
+
readonly notApplicable?: readonly {
|
|
126
|
+
readonly port: string;
|
|
127
|
+
readonly reason: string;
|
|
128
|
+
}[];
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Ports Supabase implements itself rather than inheriting from Postgres (#129).
|
|
132
|
+
*
|
|
133
|
+
* The first entry in this list is a real change to what "Supabase" means here: for nineteen ports it was
|
|
134
|
+
* Postgres under another name, asserted by object identity. File bytes break that, and they break it for a
|
|
135
|
+
* good reason rather than by drift — object storage is a different service. Named here so the alias test can
|
|
136
|
+
* assert identity for everything *except* these, instead of being relaxed to let any port off.
|
|
137
|
+
*/
|
|
138
|
+
export declare const SUPABASE_NATIVE: readonly string[];
|
|
139
|
+
/**
|
|
140
|
+
* The ports `adapters/supabase/index.ts` aliases from the Postgres adapter — all of them as of #104.
|
|
141
|
+
*
|
|
142
|
+
* Derived from `REGISTERED_PORTS` rather than listed, now that the answer is "all", so a newly
|
|
143
|
+
* registered port cannot quietly become an unclassified Supabase gap. The alias identity itself is
|
|
144
|
+
* asserted per port in `supabase-conformance.test.ts`, which is what keeps this honest: if an alias
|
|
145
|
+
* were repointed to a second implementation, that test fails rather than this list going stale.
|
|
146
|
+
*/
|
|
147
|
+
/**
|
|
148
|
+
* Ports Supabase will never implement — #248.
|
|
149
|
+
*
|
|
150
|
+
* Read by all three columns (`implemented` via the alias derivation, `notImplemented`, `notApplicable`) so they
|
|
151
|
+
* cannot disagree. The alias derivation below defaults a new port to "aliased", and its own comment says a
|
|
152
|
+
* future exemption "has to be stated" — this is where.
|
|
153
|
+
*/
|
|
154
|
+
export declare const SUPABASE_NOT_APPLICABLE: readonly string[];
|
|
155
|
+
export declare const ADAPTER_COVERAGE: readonly AdapterCoverage[];
|
|
156
|
+
/**
|
|
157
|
+
* The harness sources the isolation guard reads. Listed explicitly rather than globbed so a harness
|
|
158
|
+
* file that is added but never wired in shows up as a missing harness rather than being skipped.
|
|
159
|
+
*/
|
|
160
|
+
export declare const HARNESS_MODULES: readonly string[];
|
|
161
|
+
export * from "./graph.js";
|
|
162
|
+
export * from "./flows.js";
|
|
163
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared storage conformance suite — `docs/02` "Conformance suite", widened by #91.
|
|
3
|
+
*
|
|
4
|
+
* Every storage adapter must pass the same harnesses, so "swap the database" is a verified property
|
|
5
|
+
* rather than a claim. Before #91 this suite covered one port of nineteen, which is how #20
|
|
6
|
+
* ("PostgreSQL adapter") could satisfy its own acceptance criterion — *"passes the full conformance
|
|
7
|
+
* suite"* — with a single table implemented.
|
|
8
|
+
*
|
|
9
|
+
* An adapter package supplies factories; it writes no test bodies. Not part of the published build
|
|
10
|
+
* (`src/testing/**` is excluded in tsconfig); imported by tests only.
|
|
11
|
+
*
|
|
12
|
+
* `REGISTERED_PORTS` below is the coverage ledger the guard test in
|
|
13
|
+
* `src/__tests__/conformance-coverage.test.ts` checks, so a port cannot gain methods without also
|
|
14
|
+
* gaining a harness.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./capability.js";
|
|
17
|
+
export * from "./parents.js";
|
|
18
|
+
export * from "./conversation-store.js";
|
|
19
|
+
export * from "./run-store.js";
|
|
20
|
+
export * from "./run-event-log.js";
|
|
21
|
+
export * from "./checkpoint-store.js";
|
|
22
|
+
export * from "./run-coordinator.js";
|
|
23
|
+
export * from "./session-state.js";
|
|
24
|
+
export * from "./records.js";
|
|
25
|
+
export * from "./hitl.js";
|
|
26
|
+
export * from "./files.js";
|
|
27
|
+
export * from "./artifacts.js";
|
|
28
|
+
export * from "./artifact-exports.js";
|
|
29
|
+
export * from "./knowledge.js";
|
|
30
|
+
export * from "./rollups.js";
|
|
31
|
+
export * from "./usage-limits.js";
|
|
32
|
+
export * from "./rate-limit.js";
|
|
33
|
+
export * from "./connections.js";
|
|
34
|
+
export * from "./evaluation.js";
|
|
35
|
+
export * from "./invariants.js";
|
|
36
|
+
/**
|
|
37
|
+
* Ports that have methods and therefore must have a harness. Kept as data so the guard test can
|
|
38
|
+
* compare it against the interfaces actually exported by the port modules.
|
|
39
|
+
*/
|
|
40
|
+
export const REGISTERED_PORTS = [
|
|
41
|
+
{ port: "ConversationStore", harness: "conversationStoreConformance" },
|
|
42
|
+
// #187, #186. Both have harnesses, and both are tenant-scoped — a flow's definition and its execution are as
|
|
43
|
+
// much a tenant's data as a conversation is.
|
|
44
|
+
{ port: "FlowDefinitionStore", harness: "flowDefinitionStoreConformance" },
|
|
45
|
+
{ port: "FlowExecutionStore", harness: "flowExecutionStoreConformance" },
|
|
46
|
+
{ port: "SessionStateStore", harness: "sessionStateStoreConformance" },
|
|
47
|
+
{ port: "ConversationBindingStore", harness: "conversationBindingStoreConformance" },
|
|
48
|
+
{ port: "ConversationRunCoordinator", harness: "conversationRunCoordinatorConformance" },
|
|
49
|
+
{ port: "ThreadSummaryStore", harness: "threadSummaryStoreConformance" },
|
|
50
|
+
{ port: "RunStore", harness: "runStoreConformance" },
|
|
51
|
+
{ port: "MessageStore", harness: "messageStoreConformance" },
|
|
52
|
+
{ port: "AgentStore", harness: "agentStoreConformance" },
|
|
53
|
+
{ port: "SkillStore", harness: "skillStoreConformance" },
|
|
54
|
+
/**
|
|
55
|
+
* #248. Not storage in the matrix sense — it is a counter, and its real adapter is Redis, so it has no
|
|
56
|
+
* Postgres or Supabase implementation and never will. Registered anyway because it *has* methods and a
|
|
57
|
+
* contract worth holding: the harness runs against the in-memory store and against a real Redis.
|
|
58
|
+
*/
|
|
59
|
+
{ port: "RateLimitStore", harness: "rateLimitStoreConformance" },
|
|
60
|
+
/** #261. Tenant-scoped storage like any other, holding a sealed blob it cannot read. */
|
|
61
|
+
{ port: "ConnectionStore", harness: "connectionStoreConformance" },
|
|
62
|
+
{ port: "InteractionStore", harness: "interactionStoreConformance" },
|
|
63
|
+
{ port: "ApprovalGrantStore", harness: "approvalGrantStoreConformance" },
|
|
64
|
+
{ port: "CheckpointStore", harness: "checkpointStoreConformance" },
|
|
65
|
+
{ port: "UsageStore", harness: "usageStoreConformance" },
|
|
66
|
+
{ port: "BlobStore", harness: "blobStoreConformance" },
|
|
67
|
+
{ port: "UnitOfWork", harness: "unitOfWorkConformance" },
|
|
68
|
+
{ port: "RunEventLog", harness: "runEventLogConformance" },
|
|
69
|
+
{ port: "IdempotencyStore", harness: "idempotencyStoreConformance" },
|
|
70
|
+
{ port: "PrincipalMemoryStore", harness: "principalMemoryStoreConformance" },
|
|
71
|
+
{ port: "McpConnectionStore", harness: "mcpConnectionStoreConformance" },
|
|
72
|
+
{ port: "FileMetadataStore", harness: "fileMetadataStoreConformance" },
|
|
73
|
+
{ port: "FileContentStore", harness: "fileContentStoreConformance" },
|
|
74
|
+
{ port: "ArtifactStore", harness: "artifactStoreConformance" },
|
|
75
|
+
{ port: "ArtifactExportStore", harness: "artifactExportStoreConformance" },
|
|
76
|
+
{ port: "KnowledgeStore", harness: "knowledgeStoreConformance" },
|
|
77
|
+
{ port: "VectorIndex", harness: "vectorIndexConformance" },
|
|
78
|
+
{ port: "KeywordIndex", harness: "keywordIndexConformance" },
|
|
79
|
+
/** #271. Ordinary rows, so it needs no pgvector — a deployment without the extension still runs graph-local. */
|
|
80
|
+
{ port: "GraphStore", harness: "graphStoreConformance" },
|
|
81
|
+
{ port: "UsageRollupStore", harness: "usageRollupStoreConformance" },
|
|
82
|
+
{ port: "UsageLimitStore", harness: "usageLimitStoreConformance" },
|
|
83
|
+
{ port: "EvaluationStore", harness: "evaluationStoreConformance" },
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* Registered ports whose harness is **not** required to assert cross-tenant isolation, with the
|
|
87
|
+
* reason. Everything else must: governing principle 1 says every tenant-sensitive operation receives
|
|
88
|
+
* an explicit tenant context, and the `AgentStore` leak #91 found proves the type system alone does
|
|
89
|
+
* not enforce it — a store can accept `TenantScope` and quietly ignore it.
|
|
90
|
+
*
|
|
91
|
+
* Keep this list as short as the truth allows. An entry here is a claim that the port has nothing
|
|
92
|
+
* tenant-scoped to leak, not that testing it would be inconvenient.
|
|
93
|
+
*/
|
|
94
|
+
export const ISOLATION_EXEMPT_PORTS = [
|
|
95
|
+
{
|
|
96
|
+
port: "UnitOfWork",
|
|
97
|
+
reason: "run<T>(fn) takes no tenant parameter and holds no data of its own, so there is nothing " +
|
|
98
|
+
"tenant-scoped to isolate. The stores it wraps are each covered by their own harness.",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
/**
|
|
102
|
+
* Method-less placeholder interfaces, deliberately without a harness. An empty harness would pass
|
|
103
|
+
* vacuously and read as coverage, so the guard test instead fails if one of these gains a method —
|
|
104
|
+
* turning "we forgot to widen the suite" into a build failure. Each lands with its own SPEC:
|
|
105
|
+
* `EvaluationStore` #141, `KnowledgeStore`/`VectorIndex`/`KeywordIndex` #135–#136, `ArtifactStore` #133.
|
|
106
|
+
*
|
|
107
|
+
* `FileMetadataStore` left this list in #129, which is the mechanism working as intended: it gained methods
|
|
108
|
+
* and the guard would have failed had a harness not come with them.
|
|
109
|
+
*/
|
|
110
|
+
/**
|
|
111
|
+
* Ports declared with no methods yet.
|
|
112
|
+
*
|
|
113
|
+
* Empty as of #141, and the list stays: the guard that fails when a placeholder gains methods without a harness
|
|
114
|
+
* is what stopped `KnowledgeStore` and `EvaluationStore` from quietly shipping untested, and deleting it once
|
|
115
|
+
* the list is empty would remove the check that catches the next one.
|
|
116
|
+
*/
|
|
117
|
+
export const PLACEHOLDER_PORTS = [];
|
|
118
|
+
/**
|
|
119
|
+
* Infrastructure ports that are not storage. Their real adapters land with REQ-015 (#105 BullMQ
|
|
120
|
+
* dispatcher, #106 Redis lock), at which point they join `REGISTERED_PORTS`. Listed so the omission
|
|
121
|
+
* is recorded rather than silent.
|
|
122
|
+
*/
|
|
123
|
+
export const DEFERRED_INFRASTRUCTURE_PORTS = ["JobDispatcher", "DistributedLockStore"];
|
|
124
|
+
/**
|
|
125
|
+
* Exported interfaces in the scanned port modules that are not storage at all, so a storage
|
|
126
|
+
* conformance harness would be meaningless for them. Classified explicitly rather than filtered by
|
|
127
|
+
* a name pattern, so adding one is a decision someone made on purpose.
|
|
128
|
+
*/
|
|
129
|
+
export const NON_STORAGE_PORTS = [
|
|
130
|
+
"CapabilityAware", // adapter self-description, consumed *by* the suite
|
|
131
|
+
"RealtimePublisher", // fan-out transport, not durable storage
|
|
132
|
+
"McpClient", // outbound protocol client
|
|
133
|
+
"RateLimitObserver", // a refusal sink, like QuotaObserver — nothing durable to verify
|
|
134
|
+
];
|
|
135
|
+
/**
|
|
136
|
+
* The port modules the coverage guard scans. Every exported interface in these files must appear in
|
|
137
|
+
* exactly one of the four lists above; an unclassified one fails the guard, which is what forces a
|
|
138
|
+
* new port to come with a harness or an explicit, reasoned exemption.
|
|
139
|
+
*/
|
|
140
|
+
export const SCANNED_PORT_MODULES = [
|
|
141
|
+
"src/persistence/index.ts",
|
|
142
|
+
"src/core/events.ts",
|
|
143
|
+
"src/idempotency/index.ts",
|
|
144
|
+
"src/principal-memory/index.ts",
|
|
145
|
+
"src/mcp/provider.ts",
|
|
146
|
+
"src/runtime/index.ts",
|
|
147
|
+
// Added by #248. A port declared in a module nobody scans escapes this ledger entirely, which is how
|
|
148
|
+
// `RateLimitStore` would have shipped with no coverage record at all — the omission being invisible rather
|
|
149
|
+
// than listed is exactly what `PLACEHOLDER_PORTS` and `DEFERRED_INFRASTRUCTURE_PORTS` exist to prevent.
|
|
150
|
+
"src/usage/rate-limit.ts",
|
|
151
|
+
// #261.
|
|
152
|
+
"src/connections/index.ts",
|
|
153
|
+
];
|
|
154
|
+
/** The adapters the conformance matrix reports on. */
|
|
155
|
+
export const MATRIX_ADAPTERS = ["memory", "postgres", "supabase"];
|
|
156
|
+
/**
|
|
157
|
+
* Why the **relational** adapter does not implement `FileContentStore`.
|
|
158
|
+
*
|
|
159
|
+
* Postgres alone. Supabase has a real home for file bytes — Supabase Storage, `adapters/supabase/storage.ts`
|
|
160
|
+
* — so claiming an exemption there would be claiming a gap that does not exist. The exemption is about the
|
|
161
|
+
* relational column, not about the deployment.
|
|
162
|
+
*/
|
|
163
|
+
const RELATIONAL_CONTENT_EXEMPTION = {
|
|
164
|
+
port: "FileContentStore",
|
|
165
|
+
reason: "File bytes belong in object storage. A relational adapter holding them means base64 in a column — the " +
|
|
166
|
+
"antipattern #102 rejected when it declined to make `blobs` a pointer table, and the reason #129 split " +
|
|
167
|
+
"metadata from content in the first place. Object-storage adapters implement this port instead.",
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Ports Supabase implements itself rather than inheriting from Postgres (#129).
|
|
171
|
+
*
|
|
172
|
+
* The first entry in this list is a real change to what "Supabase" means here: for nineteen ports it was
|
|
173
|
+
* Postgres under another name, asserted by object identity. File bytes break that, and they break it for a
|
|
174
|
+
* good reason rather than by drift — object storage is a different service. Named here so the alias test can
|
|
175
|
+
* assert identity for everything *except* these, instead of being relaxed to let any port off.
|
|
176
|
+
*/
|
|
177
|
+
export const SUPABASE_NATIVE = ["FileContentStore"];
|
|
178
|
+
/**
|
|
179
|
+
* The ports `adapters/supabase/index.ts` aliases from the Postgres adapter — all of them as of #104.
|
|
180
|
+
*
|
|
181
|
+
* Derived from `REGISTERED_PORTS` rather than listed, now that the answer is "all", so a newly
|
|
182
|
+
* registered port cannot quietly become an unclassified Supabase gap. The alias identity itself is
|
|
183
|
+
* asserted per port in `supabase-conformance.test.ts`, which is what keeps this honest: if an alias
|
|
184
|
+
* were repointed to a second implementation, that test fails rather than this list going stale.
|
|
185
|
+
*/
|
|
186
|
+
/**
|
|
187
|
+
* Ports Supabase will never implement — #248.
|
|
188
|
+
*
|
|
189
|
+
* Read by all three columns (`implemented` via the alias derivation, `notImplemented`, `notApplicable`) so they
|
|
190
|
+
* cannot disagree. The alias derivation below defaults a new port to "aliased", and its own comment says a
|
|
191
|
+
* future exemption "has to be stated" — this is where.
|
|
192
|
+
*/
|
|
193
|
+
export const SUPABASE_NOT_APPLICABLE = ["RateLimitStore"];
|
|
194
|
+
const SUPABASE_ALIASED = REGISTERED_PORTS.map((p) => p.port).filter(
|
|
195
|
+
// `FileContentStore` is the one registered port the Postgres adapter does not implement, so there is
|
|
196
|
+
// nothing for Supabase to alias. Filtered from the derivation rather than removed from it, so a future
|
|
197
|
+
// port still defaults to "aliased" and a future exemption has to be stated.
|
|
198
|
+
(port) => !SUPABASE_NATIVE.includes(port) && !SUPABASE_NOT_APPLICABLE.includes(port));
|
|
199
|
+
/** Ports with no Postgres store yet, each against the SPEC that adds it (REQ-010→013). */
|
|
200
|
+
const POSTGRES_PENDING = [];
|
|
201
|
+
export const ADAPTER_COVERAGE = [
|
|
202
|
+
{
|
|
203
|
+
adapter: "memory",
|
|
204
|
+
// The reference implementation: it implements every port, which is what makes it the baseline
|
|
205
|
+
// the other adapters are compared against.
|
|
206
|
+
implemented: REGISTERED_PORTS.map((p) => p.port),
|
|
207
|
+
notImplemented: [],
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
adapter: "postgres",
|
|
211
|
+
implemented: [
|
|
212
|
+
"ConversationStore",
|
|
213
|
+
// #261 — the store holds a sealed blob it cannot read.
|
|
214
|
+
"ConnectionStore",
|
|
215
|
+
// #187, #186 — both harnesses run against the Postgres adapter in `postgres-conformance.test.ts`.
|
|
216
|
+
"FlowDefinitionStore",
|
|
217
|
+
"FlowExecutionStore",
|
|
218
|
+
"RunStore",
|
|
219
|
+
"RunEventLog",
|
|
220
|
+
"CheckpointStore",
|
|
221
|
+
"MessageStore",
|
|
222
|
+
"AgentStore",
|
|
223
|
+
"ConversationBindingStore",
|
|
224
|
+
"SessionStateStore",
|
|
225
|
+
"ThreadSummaryStore",
|
|
226
|
+
"ConversationRunCoordinator",
|
|
227
|
+
"UnitOfWork",
|
|
228
|
+
"InteractionStore",
|
|
229
|
+
"ApprovalGrantStore",
|
|
230
|
+
"UsageStore",
|
|
231
|
+
"IdempotencyStore",
|
|
232
|
+
"SkillStore",
|
|
233
|
+
"McpConnectionStore",
|
|
234
|
+
"PrincipalMemoryStore",
|
|
235
|
+
"BlobStore",
|
|
236
|
+
"FileMetadataStore",
|
|
237
|
+
"ArtifactStore",
|
|
238
|
+
"ArtifactExportStore",
|
|
239
|
+
"KnowledgeStore",
|
|
240
|
+
"VectorIndex",
|
|
241
|
+
"KeywordIndex",
|
|
242
|
+
// #271. Unlike the three above it needs no pgvector, so it runs on PGlite in the default local suite.
|
|
243
|
+
"GraphStore",
|
|
244
|
+
"UsageRollupStore",
|
|
245
|
+
"UsageLimitStore",
|
|
246
|
+
"EvaluationStore",
|
|
247
|
+
],
|
|
248
|
+
notImplemented: POSTGRES_PENDING,
|
|
249
|
+
notApplicable: [
|
|
250
|
+
{
|
|
251
|
+
port: "RateLimitStore",
|
|
252
|
+
reason: "A rate limiter is a counter on the hot path of every admission, and its correctness rests on an " +
|
|
253
|
+
"atomic increment-with-expiry. A relational adapter would mean a write and a row-lock per admitted " +
|
|
254
|
+
"run, plus a sweep for expired windows — slower than the thing it protects. Redis has the primitive; " +
|
|
255
|
+
"this port has a Redis adapter and an in-memory one for tests, and needs no third (#248).",
|
|
256
|
+
}, RELATIONAL_CONTENT_EXEMPTION
|
|
257
|
+
],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
adapter: "supabase",
|
|
261
|
+
// `createSupabaseConversationStore` is an alias re-export of the Postgres store
|
|
262
|
+
// (`adapters/supabase/index.ts`), so Supabase inherits Postgres's coverage rather than being a
|
|
263
|
+
// second implementation. #104 brings the remaining stores across with RLS applied.
|
|
264
|
+
//
|
|
265
|
+
// Derived rather than listed: a Postgres store landing (#93 → #102) must not silently become a
|
|
266
|
+
// Supabase claim, but it must not become an *unclassified* absence either. Deriving the gap from
|
|
267
|
+
// what this adapter actually aliases keeps the column honest as Postgres fills in.
|
|
268
|
+
//
|
|
269
|
+
// `FileContentStore` joins as of #129 — implemented, not aliased and not exempt. Supabase Storage is a
|
|
270
|
+
// real second implementation, which is why the alias assertion exempts it by name rather than the
|
|
271
|
+
// coverage column claiming a gap Supabase does not have.
|
|
272
|
+
implemented: [...SUPABASE_ALIASED, ...SUPABASE_NATIVE],
|
|
273
|
+
/**
|
|
274
|
+
* Derived, and the derivation has to know about `notApplicable` too — #248.
|
|
275
|
+
*
|
|
276
|
+
* Filtering only on aliased/native put every never-applicable port into the gap column *as well as* the
|
|
277
|
+
* not-applicable one, and the guard rightly refused to let a port be claimed both ways. The subtraction is
|
|
278
|
+
* the point of deriving: a port that will never exist here is not a gap tracked by #104.
|
|
279
|
+
*/
|
|
280
|
+
notImplemented: REGISTERED_PORTS.filter((p) => !SUPABASE_ALIASED.includes(p.port) &&
|
|
281
|
+
!SUPABASE_NATIVE.includes(p.port) &&
|
|
282
|
+
!SUPABASE_NOT_APPLICABLE.includes(p.port)).map((p) => ({ port: p.port, trackedBy: "#104" })),
|
|
283
|
+
notApplicable: [
|
|
284
|
+
{
|
|
285
|
+
port: "RateLimitStore",
|
|
286
|
+
reason: "A rate limiter is a counter on the hot path of every admission, and its correctness rests on an " +
|
|
287
|
+
"atomic increment-with-expiry. A relational adapter would mean a write and a row-lock per admitted " +
|
|
288
|
+
"run, plus a sweep for expired windows — slower than the thing it protects. Redis has the primitive; " +
|
|
289
|
+
"this port has a Redis adapter and an in-memory one for tests, and needs no third (#248).",
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
];
|
|
294
|
+
/**
|
|
295
|
+
* The harness sources the isolation guard reads. Listed explicitly rather than globbed so a harness
|
|
296
|
+
* file that is added but never wired in shows up as a missing harness rather than being skipped.
|
|
297
|
+
*/
|
|
298
|
+
export const HARNESS_MODULES = [
|
|
299
|
+
"src/testing/conformance/rate-limit.ts",
|
|
300
|
+
"src/testing/conformance/connections.ts",
|
|
301
|
+
"src/testing/conformance/conversation-store.ts",
|
|
302
|
+
"src/testing/conformance/flows.ts",
|
|
303
|
+
"src/testing/conformance/run-store.ts",
|
|
304
|
+
"src/testing/conformance/run-event-log.ts",
|
|
305
|
+
"src/testing/conformance/checkpoint-store.ts",
|
|
306
|
+
"src/testing/conformance/run-coordinator.ts",
|
|
307
|
+
"src/testing/conformance/session-state.ts",
|
|
308
|
+
"src/testing/conformance/records.ts",
|
|
309
|
+
"src/testing/conformance/hitl.ts",
|
|
310
|
+
"src/testing/conformance/files.ts",
|
|
311
|
+
"src/testing/conformance/artifacts.ts",
|
|
312
|
+
"src/testing/conformance/artifact-exports.ts",
|
|
313
|
+
"src/testing/conformance/knowledge.ts",
|
|
314
|
+
"src/testing/conformance/graph.ts",
|
|
315
|
+
"src/testing/conformance/rollups.ts",
|
|
316
|
+
"src/testing/conformance/usage-limits.ts",
|
|
317
|
+
"src/testing/conformance/evaluation.ts",
|
|
318
|
+
];
|
|
319
|
+
export * from "./graph.js";
|
|
320
|
+
export * from "./flows.js";
|
|
321
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-port invariants — the ones no single-port harness can catch, because each store is
|
|
3
|
+
* individually correct and the defect lives in the relationship between two of them.
|
|
4
|
+
*
|
|
5
|
+
* These are the failures that produced the crash-recovery/event-log desync found in the REQ-005
|
|
6
|
+
* review: the log and the checkpoint were each self-consistent, and the pair was not.
|
|
7
|
+
*/
|
|
8
|
+
import type { RunEventLog } from "../../core/events.js";
|
|
9
|
+
import type { CheckpointStore, RunStore, UsageStore } from "../../persistence/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Split so an adapter can run the invariants it *can* run (#95). Postgres has runs, events and
|
|
12
|
+
* checkpoints after #95 but no `UsageStore` until #100 — requiring all four would have left the
|
|
13
|
+
* checkpoint-vs-log-head invariant unverified on the very adapter it matters for. `usage` is
|
|
14
|
+
* therefore optional, and the usage-dependent case reports why it stood down rather than vanishing.
|
|
15
|
+
*/
|
|
16
|
+
export type InvariantFixture = {
|
|
17
|
+
readonly runs: RunStore;
|
|
18
|
+
readonly events: RunEventLog;
|
|
19
|
+
readonly checkpoints: CheckpointStore;
|
|
20
|
+
readonly usage?: UsageStore;
|
|
21
|
+
};
|
|
22
|
+
export declare function crossPortInvariants(makeFixture: () => InvariantFixture): void;
|
|
23
|
+
//# sourceMappingURL=invariants.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-port invariants — the ones no single-port harness can catch, because each store is
|
|
3
|
+
* individually correct and the defect lives in the relationship between two of them.
|
|
4
|
+
*
|
|
5
|
+
* These are the failures that produced the crash-recovery/event-log desync found in the REQ-005
|
|
6
|
+
* review: the log and the checkpoint were each self-consistent, and the pair was not.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from "vitest";
|
|
9
|
+
import { asId } from "../../core/ids.js";
|
|
10
|
+
import { emptyCheckpoint } from "../../runtime/checkpoint.js";
|
|
11
|
+
const T1 = asId("conf-tenant-1");
|
|
12
|
+
const CONVO = asId("conf-convo-1");
|
|
13
|
+
const AGENT = asId("conf-agent-1");
|
|
14
|
+
const RUN = asId("conf-run-1");
|
|
15
|
+
const NOW = "2020-01-01T00:00:00.000Z";
|
|
16
|
+
const lifecycle = (sequence) => ({
|
|
17
|
+
type: "run.checkpointed",
|
|
18
|
+
runId: RUN,
|
|
19
|
+
sequence,
|
|
20
|
+
occurredAt: NOW,
|
|
21
|
+
});
|
|
22
|
+
export function crossPortInvariants(makeFixture) {
|
|
23
|
+
describe("cross-port invariants", () => {
|
|
24
|
+
it("a run's events are ordered and gapless from 1 to the head", async () => {
|
|
25
|
+
const { runs, events } = makeFixture();
|
|
26
|
+
await runs.create({ tenantId: T1, id: RUN, conversationId: CONVO, agentId: AGENT, agentVersion: 1 });
|
|
27
|
+
for (const s of [1, 2, 3, 4])
|
|
28
|
+
await events.append({ tenantId: T1, event: lifecycle(s) });
|
|
29
|
+
const all = await events.listAfter({ tenantId: T1, runId: RUN, after: 0 });
|
|
30
|
+
const sequences = all.map((e) => e.sequence);
|
|
31
|
+
expect(sequences).toEqual([1, 2, 3, 4]);
|
|
32
|
+
expect(await events.latestSequence({ tenantId: T1, runId: RUN })).toBe(sequences[sequences.length - 1]);
|
|
33
|
+
});
|
|
34
|
+
it("a checkpoint never references a sequence beyond the event-log head", async () => {
|
|
35
|
+
const { runs, events, checkpoints } = makeFixture();
|
|
36
|
+
await runs.create({ tenantId: T1, id: RUN, conversationId: CONVO, agentId: AGENT, agentVersion: 1 });
|
|
37
|
+
for (const s of [1, 2, 3])
|
|
38
|
+
await events.append({ tenantId: T1, event: lifecycle(s) });
|
|
39
|
+
await checkpoints.save({ tenantId: T1, checkpoint: { ...emptyCheckpoint(RUN, NOW), sequence: 3 } });
|
|
40
|
+
const head = await events.latestSequence({ tenantId: T1, runId: RUN });
|
|
41
|
+
const checkpoint = await checkpoints.latest({ tenantId: T1, runId: RUN });
|
|
42
|
+
// Recovery reads the checkpoint then replays from the log. A checkpoint ahead of the head means
|
|
43
|
+
// the worker would resume past events that were never durably written.
|
|
44
|
+
expect(checkpoint?.sequence ?? 0).toBeLessThanOrEqual(head);
|
|
45
|
+
});
|
|
46
|
+
it("every usage event resolves to a run that exists", async () => {
|
|
47
|
+
const { runs, usage } = makeFixture();
|
|
48
|
+
if (!usage) {
|
|
49
|
+
// A named, visible stand-down: this adapter has no UsageStore yet (#100 for Postgres). The
|
|
50
|
+
// assertion below documents the gap so it reads as "not applicable here", never as passing.
|
|
51
|
+
expect(usage).toBeUndefined();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await runs.create({ tenantId: T1, id: RUN, conversationId: CONVO, agentId: AGENT, agentVersion: 1 });
|
|
55
|
+
const event = {
|
|
56
|
+
id: "u1",
|
|
57
|
+
tenantId: T1,
|
|
58
|
+
runId: RUN,
|
|
59
|
+
stepId: "step-1",
|
|
60
|
+
modelId: "claude-opus-5",
|
|
61
|
+
inputTokens: 10,
|
|
62
|
+
outputTokens: 5,
|
|
63
|
+
cachedInputTokens: 0,
|
|
64
|
+
costMinorUnits: 7,
|
|
65
|
+
currency: "EUR",
|
|
66
|
+
occurredAt: NOW,
|
|
67
|
+
};
|
|
68
|
+
await usage.append({ tenantId: T1, event });
|
|
69
|
+
const page = await usage.listByRun({ tenantId: T1, runId: RUN, limit: 10 });
|
|
70
|
+
for (const recorded of page.items) {
|
|
71
|
+
expect(await runs.findById({ tenantId: T1, id: recorded.runId })).not.toBeNull();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
it("the event-log head does not advance for a run that was never created", async () => {
|
|
75
|
+
const { events } = makeFixture();
|
|
76
|
+
expect(await events.latestSequence({ tenantId: T1, runId: asId("never-created") })).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=invariants.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `KnowledgeStore` and `VectorIndex` conformance (#135) — AC-6.
|
|
3
|
+
*
|
|
4
|
+
* Two harnesses over one fixture, because on pgvector both ports are one table and a suite that opened them
|
|
5
|
+
* separately would never exercise the case that matters: a search seeing what a write just wrote.
|
|
6
|
+
*
|
|
7
|
+
* Both harnesses are gated on the `vector-search` capability. An adapter that cannot hold vectors — Postgres
|
|
8
|
+
* without pgvector installed, which includes the PGlite the suite runs on by default — declares nothing and
|
|
9
|
+
* every case registers as a *named* skip rather than vanishing from the report. `gatedIt` exists for exactly
|
|
10
|
+
* this: an invisible skip is indistinguishable from coverage.
|
|
11
|
+
*
|
|
12
|
+
* The search cases assert the **contract**, not recall. pgvector's HNSW index is *approximate*, so
|
|
13
|
+
* "the nearest chunk comes first" is something the production adapter is permitted to miss on a large corpus —
|
|
14
|
+
* asserting it here would make the harness fail for a reason that is not a bug. What is asserted is what must
|
|
15
|
+
* hold exactly at any size: tenant isolation, permission filtering, the limit, score ordering among returned
|
|
16
|
+
* hits, and that no vector ever comes back. Recall is measured separately against a fixed query set.
|
|
17
|
+
*/
|
|
18
|
+
import { type AdapterDeclaration } from "./capability.js";
|
|
19
|
+
import type { EmbeddingModelRef, KeywordIndex, KnowledgeStore, VectorIndex } from "../../persistence/index.js";
|
|
20
|
+
/** 1536, because that is what the pgvector schema declares and a vector of another length is rejected. */
|
|
21
|
+
export declare const CONFORMANCE_DIMENSIONS = 1536;
|
|
22
|
+
export declare const MODEL: EmbeddingModelRef;
|
|
23
|
+
/**
|
|
24
|
+
* A deterministic vector pointing mostly along one axis.
|
|
25
|
+
*
|
|
26
|
+
* Deterministic because a recall figure that moves between runs is a figure nobody can act on, and axis-aligned
|
|
27
|
+
* because it makes "closer" obvious: a query along axis 3 must rank the chunk built on axis 3 first, with no
|
|
28
|
+
* dependence on floating-point luck.
|
|
29
|
+
*/
|
|
30
|
+
export declare const axisVector: (axis: number, magnitude?: number) => readonly number[];
|
|
31
|
+
/** Both ports over the same backing store, which is how pgvector provides them. */
|
|
32
|
+
export type KnowledgeFixture = {
|
|
33
|
+
readonly store: KnowledgeStore;
|
|
34
|
+
readonly index: VectorIndex;
|
|
35
|
+
/** Present once #136's keyword index exists; the harness for it is gated on the same capability. */
|
|
36
|
+
readonly keyword?: KeywordIndex;
|
|
37
|
+
};
|
|
38
|
+
export declare function knowledgeStoreConformance(make: () => KnowledgeFixture | Promise<KnowledgeFixture>, declaration?: AdapterDeclaration): void;
|
|
39
|
+
export declare function vectorIndexConformance(make: () => KnowledgeFixture | Promise<KnowledgeFixture>, declaration?: AdapterDeclaration): void;
|
|
40
|
+
export declare function keywordIndexConformance(make: () => KnowledgeFixture | Promise<KnowledgeFixture>, declaration?: AdapterDeclaration): void;
|
|
41
|
+
//# sourceMappingURL=knowledge.d.ts.map
|