@odla-ai/kg 0.3.2 → 0.4.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.
@@ -1,256 +0,0 @@
1
- import { Value, Op, AdminDb, SerializedAttr, Cardinality, SerializedSchema } from '@odla-ai/db';
2
- import { Ai } from '@odla-ai/ai';
3
-
4
- /**
5
- * The output of a connector: one acquired item. Exactly one of `text` or
6
- * `fragment` is set — `text` goes through LLM extraction, `fragment` is already
7
- * ontology-typed and goes straight to the graph writer (structured feeds).
8
- */
9
- interface RawItem {
10
- url: string;
11
- title: string;
12
- date?: string;
13
- sourceName: string;
14
- sourceKind: string;
15
- watch?: string | null;
16
- text?: string;
17
- fragment?: GraphFragment;
18
- }
19
- /** A graph node = an odla-db entity in a namespace, keyed by a natural key. */
20
- interface GraphNode {
21
- type: string;
22
- key: string;
23
- attrs: Record<string, Value>;
24
- }
25
- /** A graph edge = an odla-db `link` from one node to another by forward label. */
26
- interface GraphEdge {
27
- from: {
28
- type: string;
29
- key: string;
30
- };
31
- to: {
32
- type: string;
33
- key: string;
34
- };
35
- label: string;
36
- }
37
- /** The single shape the graph writer consumes, whatever produced it. */
38
- interface GraphFragment {
39
- nodes: GraphNode[];
40
- edges: GraphEdge[];
41
- }
42
- /** What an extractor turns a text RawItem into: a fragment plus a prose summary. */
43
- interface ExtractResult {
44
- fragment: GraphFragment;
45
- summary: string;
46
- }
47
- /** Provider-agnostic LLM usage accounting. */
48
- interface Usage {
49
- calls: number;
50
- inputTokens: number;
51
- outputTokens: number;
52
- }
53
- /** Create zeroed provider-agnostic usage totals for one pipeline run. */
54
- declare function emptyUsage(): Usage;
55
- /** Mutate an accumulator by adding call, input-token, and output-token totals. */
56
- declare function addUsage(into: Usage, more: Usage): void;
57
-
58
- /** node type → unique natural-key attribute name. */
59
- type NaturalKeys = Record<string, string>;
60
- /**
61
- * Pure fragment → ops mapping (no read/merge). Node upserts by Lookup natural
62
- * key, then links — nodes always before links so `link` targets resolve.
63
- * Used by tests and as the building block for the provenance path below.
64
- */
65
- declare function fragmentToOps(fragment: GraphFragment, keys: NaturalKeys): Op[];
66
- /**
67
- * Provenance-preserving write. Reads existing nodes by natural key (one batched
68
- * query), merges scalar attrs per the ontology's rules, drops human-owned
69
- * attrs, then writes merged node updates + all links in one atomic, idempotent
70
- * transaction. `mutationId` must be deterministic so odla-db can deduplicate
71
- * the write on retry; this does not make preceding reads or external effects
72
- * exactly-once.
73
- */
74
- declare function writeFragment(db: AdminDb, fragment: GraphFragment, ontology: Ontology, mutationId: string): Promise<{
75
- txId: number;
76
- ops: number;
77
- }>;
78
-
79
- /** How a scalar attribute is reconciled when a node is re-discovered. */
80
- type MergeRule = "replace" | "prefer" | "earliest" | "latest";
81
- type AttrType = SerializedAttr["type"];
82
- interface AttrSpec {
83
- type: AttrType;
84
- unique?: boolean;
85
- indexed?: boolean;
86
- optional?: boolean;
87
- /** The pipeline NEVER writes this attr (hand-edited in a UI); omitted from every update. */
88
- human?: boolean;
89
- /** Provenance rule for re-discovery. Default "replace". */
90
- merge?: MergeRule;
91
- /** Shown to the LLM when this attr appears in an extraction schema. */
92
- desc?: string;
93
- }
94
- interface EntitySpec {
95
- /** Unique attr used for Lookup upsert (MERGE key). Must be `unique` in attrs. */
96
- naturalKey: string;
97
- attrs: Record<string, AttrSpec>;
98
- /** FTS fields for fuzzy resolution (P5). */
99
- searchable?: string[];
100
- }
101
- interface EdgeSpec {
102
- from: string;
103
- to: string;
104
- forwardLabel: string;
105
- reverseLabel: string;
106
- forwardHas?: Cardinality;
107
- reverseHas?: Cardinality;
108
- }
109
- interface Ontology {
110
- entities: Record<string, EntitySpec>;
111
- edges: Record<string, EdgeSpec>;
112
- }
113
- /** node type → natural-key attr name (for the graph writer's Lookup refs). */
114
- declare function naturalKeysOf(o: Ontology): NaturalKeys;
115
- /** Attr name → merge rule, for every entity type (used by the provenance writer). */
116
- declare function mergeRulesOf(o: Ontology): Record<string, Record<string, MergeRule>>;
117
- /** Attr names the pipeline must never write, per entity type. */
118
- declare function humanAttrsOf(o: Ontology): Record<string, Set<string>>;
119
- /** Compile the ontology to an odla-db SerializedSchema to POST at /app/:id/schema. */
120
- declare function toSerializedSchema(o: Ontology): SerializedSchema;
121
-
122
- /**
123
- * The LLM seam, now a thin adapter over @odla-ai/ai (which was itself
124
- * generalized from this package's original Provider). Three verbs stay:
125
- * extract (forced structured tool call), search (web-search-enabled text),
126
- * write (plain generation). Callers never see vendor or oracle types.
127
- */
128
- type ProviderFamily = "claude" | "openai";
129
- /** Role → model tiers per family — config as data. `cheap` is for gate-style
130
- * calls, `extract` for structured extraction (and prose writing), `search`
131
- * for web-search-enabled calls. */
132
- declare const MODEL_TIERS: Record<ProviderFamily, {
133
- cheap: string;
134
- extract: string;
135
- search: string;
136
- }>;
137
- /** A forced structured tool call: schema in, validated object out. */
138
- interface ExtractCall {
139
- system: string;
140
- user: string;
141
- tool: {
142
- name: string;
143
- description?: string;
144
- parameters: Record<string, unknown>;
145
- };
146
- model?: string;
147
- maxTokens?: number;
148
- }
149
- /** A web-search-enabled call: the model searches and returns text (caller tolerant-parses). */
150
- interface SearchCall {
151
- system: string;
152
- user: string;
153
- model?: string;
154
- maxTokens?: number;
155
- }
156
- /** A plain text-generation call (no tools, no search) — e.g. digest prose. */
157
- interface WriteCall {
158
- system: string;
159
- user: string;
160
- model?: string;
161
- maxTokens?: number;
162
- }
163
- interface Provider {
164
- id: ProviderFamily;
165
- /** The underlying @odla-ai/ai client — escape hatch for advanced use. */
166
- ai: Ai;
167
- extract<T = unknown>(c: ExtractCall): Promise<{
168
- value: T;
169
- usage: Usage;
170
- }>;
171
- search(c: SearchCall): Promise<{
172
- text: string;
173
- usage: Usage;
174
- }>;
175
- write(c: WriteCall): Promise<{
176
- text: string;
177
- usage: Usage;
178
- }>;
179
- }
180
- interface LlmConfig {
181
- provider: ProviderFamily;
182
- anthropicKey?: string;
183
- openaiKey?: string;
184
- /** Inject a pre-built Ai (tests, custom catalog); keys are ignored when set. */
185
- ai?: Ai;
186
- }
187
- /** The library primitive: an explicit config in, the three-verb seam out. */
188
- declare function createProvider(cfg: LlmConfig): Provider;
189
- /** The env vars the provider factory reads — a structural slice, not the
190
- * worker Env, so any host (worker, script, test) can supply plain strings. */
191
- interface LlmEnv {
192
- LLM_PROVIDER?: string;
193
- ANTHROPIC_API_KEY?: string;
194
- OPENAI_API_KEY?: string;
195
- }
196
- /** Build the configured provider from host env, failing before use when its key is missing. */
197
- declare function getProvider(env: LlmEnv): Provider;
198
-
199
- /** Ambient services a connector may use. Host-agnostic: secrets come through
200
- * secret(), never a worker Env, so the library runs anywhere. */
201
- interface ConnectorContext {
202
- now: Date;
203
- fetchText(url: string): Promise<string>;
204
- secret(name: string): string | undefined;
205
- ontology: Ontology;
206
- /** The configured LLM provider (lazy — only web-search/discovery connectors need it). */
207
- provider(): Provider;
208
- }
209
- /**
210
- * The extensibility seam. A connector emits normalized RawItems — text-bearing
211
- * (→ LLM extraction) or fragment-bearing (structured → straight to the writer).
212
- * Adding a source = a new module implementing this + one registry line.
213
- */
214
- interface SourceConnector<Cfg = unknown> {
215
- id: string;
216
- capabilities: {
217
- fetch: boolean;
218
- discover?: boolean;
219
- structured: boolean;
220
- };
221
- parseConfig(raw: unknown): Cfg;
222
- fetch(cfg: Cfg, ctx: ConnectorContext): Promise<RawItem[]>;
223
- /** Web-search-style net-new discovery (P4). */
224
- discover?(cfg: Cfg, ctx: ConnectorContext): Promise<RawItem[]>;
225
- }
226
- /** One unit of work for the ingest workflow: which connector + its config. */
227
- interface ConnectorJob {
228
- kind: string;
229
- name: string;
230
- watch?: string | null;
231
- cfg: unknown;
232
- }
233
-
234
- /**
235
- * Sources are DATA, not code. Each entry names a connector (`kind`) + its config
236
- * + scheduling. Add a feed → add an entry; no redeploy of the pipeline. P5 moves
237
- * this into KV behind a /config admin endpoint so edits don't need a deploy at all.
238
- */
239
- interface SourceEntry {
240
- kind: string;
241
- name: string;
242
- enabled?: boolean;
243
- cadenceHours?: number;
244
- watch?: string | null;
245
- url?: string;
246
- query?: string;
247
- [key: string]: unknown;
248
- }
249
- /** Return source entries not explicitly disabled, preserving configured order. */
250
- declare function enabledSources(sources: SourceEntry[]): SourceEntry[];
251
- /** Enabled sources whose cadence lands on this UTC hour. */
252
- declare function jobsForHour(sources: SourceEntry[], hour: number): ConnectorJob[];
253
- /** Every enabled source, ignoring cadence (manual /trigger?kind=sources). */
254
- declare function allJobs(sources: SourceEntry[]): ConnectorJob[];
255
-
256
- export { type AttrSpec as A, type ConnectorContext as C, type ExtractResult as E, type GraphFragment as G, type LlmConfig as L, type MergeRule as M, type NaturalKeys as N, type Ontology as O, type Provider as P, type RawItem as R, type SourceConnector as S, type Usage as U, type WriteCall as W, type SourceEntry as a, type AttrType as b, type ConnectorJob as c, type EdgeSpec as d, type EntitySpec as e, type ExtractCall as f, type GraphEdge as g, type GraphNode as h, type LlmEnv as i, MODEL_TIERS as j, type ProviderFamily as k, type SearchCall as l, addUsage as m, allJobs as n, createProvider as o, emptyUsage as p, enabledSources as q, fragmentToOps as r, getProvider as s, humanAttrsOf as t, jobsForHour as u, mergeRulesOf as v, naturalKeysOf as w, toSerializedSchema as x, writeFragment as y };