@odla-ai/kg 0.2.3 → 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/dist/chunk-V3N2GRYU.js +73 -0
- package/dist/chunk-V3N2GRYU.js.map +1 -0
- package/dist/index.cjs +136 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -250
- package/dist/index.d.ts +44 -250
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -1
- package/dist/sources-nJyD0JUP.d.cts +256 -0
- package/dist/sources-nJyD0JUP.d.ts +256 -0
- package/dist/temporal/index.cjs +881 -0
- package/dist/temporal/index.cjs.map +1 -0
- package/dist/temporal/index.d.cts +553 -0
- package/dist/temporal/index.d.ts +553 -0
- package/dist/temporal/index.js +799 -0
- package/dist/temporal/index.js.map +1 -0
- package/package.json +11 -6
- package/llms.txt +0 -536
package/llms.txt
DELETED
|
@@ -1,536 +0,0 @@
|
|
|
1
|
-
# @odla-ai/kg — LLM context
|
|
2
|
-
|
|
3
|
-
> Ontology-driven knowledge-graph builder: pluggable source connectors, LLM extraction against a config-as-data ontology, and a provenance-preserving graph writer persisting into odla-db.
|
|
4
|
-
|
|
5
|
-
> ⚠️ **Early access — pre-1.0.** Agents work from bounded runbooks; humans
|
|
6
|
-
> approve credentials, production changes, releases, and merges. APIs and exact
|
|
7
|
-
> package availability can change. Review the documented guarantees and
|
|
8
|
-
> limitations; this software is MIT-licensed and provided without warranty.
|
|
9
|
-
|
|
10
|
-
An ontology-driven **knowledge-graph builder**. Pluggable source connectors pull
|
|
11
|
-
from the web and data feeds, an LLM extracts entities + relationships against a
|
|
12
|
-
**config-as-data ontology**, and a provenance-preserving graph writer persists
|
|
13
|
-
the result into [odla-db](https://www.npmjs.com/package/@odla-ai/db).
|
|
14
|
-
|
|
15
|
-
The library is host-agnostic: it runs in Cloudflare Workers, Node, or tests —
|
|
16
|
-
the host supplies the database client, LLM keys, and a KV-like store. The
|
|
17
|
-
public platform and package manuals describe how to compose it with Workflows,
|
|
18
|
-
scheduled triggers, an HTTP API, and a viewer UI.
|
|
19
|
-
|
|
20
|
-
## Architecture
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
Connector ──RawItem[]──▶ Extraction ──GraphFragment──▶ writeFragment ──Op[]──▶ odla-db
|
|
24
|
-
(how data (LLM forced-tool (ontology-typed (Lookup upserts +
|
|
25
|
-
was acquired) OR pure mapper) nodes + edges) links, idempotent)
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
- **`RawItem`** — a connector emits either `text` (→ LLM extraction) or a
|
|
29
|
-
ready-made `fragment` (structured feeds bypass the LLM).
|
|
30
|
-
- **`GraphFragment`** — ontology-typed `nodes[]` + `edges[]`; the single shape
|
|
31
|
-
the writer consumes, whatever produced it.
|
|
32
|
-
- **`Ontology`** — data, not code. It compiles to the odla-db schema
|
|
33
|
-
(`toSerializedSchema`), the writer's natural-key + merge-rule maps
|
|
34
|
-
(`naturalKeysOf`, `mergeRulesOf`, `humanAttrsOf`), and by convention the
|
|
35
|
-
extractor's tool schema.
|
|
36
|
-
|
|
37
|
-
Add a source → implement `SourceConnector` + one registry line. Add an
|
|
38
|
-
entity/edge type → edit the ontology data. Neither touches the pipeline.
|
|
39
|
-
|
|
40
|
-
## Usage
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
import { init } from "@odla-ai/db";
|
|
44
|
-
import {
|
|
45
|
-
Store, getProvider, makeContext, ingestFresh, writeFragment,
|
|
46
|
-
toSerializedSchema, type Ontology, type PipelineDeps,
|
|
47
|
-
} from "@odla-ai/kg";
|
|
48
|
-
|
|
49
|
-
// 1. Your ontology is ordinary application-owned data.
|
|
50
|
-
const ontology: Ontology = { entities: { /* … */ }, edges: { /* … */ } };
|
|
51
|
-
|
|
52
|
-
// 2. Wire the host services once. Env-var keys work standalone…
|
|
53
|
-
const db = init({ appId, adminToken, endpoint });
|
|
54
|
-
const provider = getProvider({ LLM_PROVIDER: "claude", ANTHROPIC_API_KEY: key });
|
|
55
|
-
// …but platform apps should bring a configured Ai instead (no LLM keys in
|
|
56
|
-
// worker env): createProvider({ provider: "claude", ai }) with the ai from
|
|
57
|
-
// @odla-ai/ai's initFromPlatform. The
|
|
58
|
-
// platform's default model is ignored here; kg's MODEL_TIERS govern verbs.
|
|
59
|
-
const deps: PipelineDeps = { db, provider, ontology, extract: myExtractor, store: new Store(kv) };
|
|
60
|
-
|
|
61
|
-
// 3. Run items through the shared pipeline (or call writeFragment directly).
|
|
62
|
-
await ingestFresh(step, deps, freshItems, "ingest");
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Key seams the host supplies:
|
|
66
|
-
|
|
67
|
-
- **`PipelineDeps`** — db (`AdminDb`), LLM `Provider`, the ontology, the
|
|
68
|
-
extractor (your domain craft), and a `Store` over any `KVLike`.
|
|
69
|
-
- **`ContextConfig`** (→ `makeContext`) — what connectors see: ontology, lazy
|
|
70
|
-
provider, named secrets.
|
|
71
|
-
- **`StepLike`** — a structural view of Cloudflare's `WorkflowStep`
|
|
72
|
-
(`asStepLike(step)`); any `do(name, cfg?, fn)` runner works, including a
|
|
73
|
-
plain inline runner in tests.
|
|
74
|
-
|
|
75
|
-
## Built-in connectors
|
|
76
|
-
|
|
77
|
-
`rss`, `url`, `gdelt` (text → LLM extraction) · `fred`, `edgar` (structured →
|
|
78
|
-
straight to the writer) · `web-search` (LLM web-search discovery) · `gov-data`
|
|
79
|
-
(template proving a new source needs no pipeline change).
|
|
80
|
-
|
|
81
|
-
## Provenance & merging
|
|
82
|
-
|
|
83
|
-
`writeFragment` reads existing nodes by natural key (one batched query), merges
|
|
84
|
-
scalar attrs per the ontology's rules (`replace` / `prefer` / `earliest` /
|
|
85
|
-
`latest`), never writes `human`-owned attrs, and commits nodes-then-links in a
|
|
86
|
-
single idempotent transaction (deterministic `mutationId`).
|
|
87
|
-
|
|
88
|
-
## API reference (generated from dist/index.d.ts, v0.2.3)
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { Value, Op, AdminDb, SerializedAttr, Cardinality, SerializedSchema, Entity } from '@odla-ai/db';
|
|
92
|
-
import { Ai } from '@odla-ai/ai';
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* The output of a connector: one acquired item. Exactly one of `text` or
|
|
96
|
-
* `fragment` is set — `text` goes through LLM extraction, `fragment` is already
|
|
97
|
-
* ontology-typed and goes straight to the graph writer (structured feeds).
|
|
98
|
-
*/
|
|
99
|
-
interface RawItem {
|
|
100
|
-
url: string;
|
|
101
|
-
title: string;
|
|
102
|
-
date?: string;
|
|
103
|
-
sourceName: string;
|
|
104
|
-
sourceKind: string;
|
|
105
|
-
watch?: string | null;
|
|
106
|
-
text?: string;
|
|
107
|
-
fragment?: GraphFragment;
|
|
108
|
-
}
|
|
109
|
-
/** A graph node = an odla-db entity in a namespace, keyed by a natural key. */
|
|
110
|
-
interface GraphNode {
|
|
111
|
-
type: string;
|
|
112
|
-
key: string;
|
|
113
|
-
attrs: Record<string, Value>;
|
|
114
|
-
}
|
|
115
|
-
/** A graph edge = an odla-db `link` from one node to another by forward label. */
|
|
116
|
-
interface GraphEdge {
|
|
117
|
-
from: {
|
|
118
|
-
type: string;
|
|
119
|
-
key: string;
|
|
120
|
-
};
|
|
121
|
-
to: {
|
|
122
|
-
type: string;
|
|
123
|
-
key: string;
|
|
124
|
-
};
|
|
125
|
-
label: string;
|
|
126
|
-
}
|
|
127
|
-
/** The single shape the graph writer consumes, whatever produced it. */
|
|
128
|
-
interface GraphFragment {
|
|
129
|
-
nodes: GraphNode[];
|
|
130
|
-
edges: GraphEdge[];
|
|
131
|
-
}
|
|
132
|
-
/** What an extractor turns a text RawItem into: a fragment plus a prose summary. */
|
|
133
|
-
interface ExtractResult {
|
|
134
|
-
fragment: GraphFragment;
|
|
135
|
-
summary: string;
|
|
136
|
-
}
|
|
137
|
-
/** Provider-agnostic LLM usage accounting. */
|
|
138
|
-
interface Usage {
|
|
139
|
-
calls: number;
|
|
140
|
-
inputTokens: number;
|
|
141
|
-
outputTokens: number;
|
|
142
|
-
}
|
|
143
|
-
/** Create zeroed provider-agnostic usage totals for one pipeline run. */
|
|
144
|
-
declare function emptyUsage(): Usage;
|
|
145
|
-
/** Mutate an accumulator by adding call, input-token, and output-token totals. */
|
|
146
|
-
declare function addUsage(into: Usage, more: Usage): void;
|
|
147
|
-
|
|
148
|
-
/** node type → unique natural-key attribute name. */
|
|
149
|
-
type NaturalKeys = Record<string, string>;
|
|
150
|
-
/**
|
|
151
|
-
* Pure fragment → ops mapping (no read/merge). Node upserts by Lookup natural
|
|
152
|
-
* key, then links — nodes always before links so `link` targets resolve.
|
|
153
|
-
* Used by tests and as the building block for the provenance path below.
|
|
154
|
-
*/
|
|
155
|
-
declare function fragmentToOps(fragment: GraphFragment, keys: NaturalKeys): Op[];
|
|
156
|
-
/**
|
|
157
|
-
* Provenance-preserving write. Reads existing nodes by natural key (one batched
|
|
158
|
-
* query), merges scalar attrs per the ontology's rules, drops human-owned
|
|
159
|
-
* attrs, then writes merged node updates + all links in one atomic, idempotent
|
|
160
|
-
* transaction. `mutationId` must be deterministic so odla-db can deduplicate
|
|
161
|
-
* the write on retry; this does not make preceding reads or external effects
|
|
162
|
-
* exactly-once.
|
|
163
|
-
*/
|
|
164
|
-
declare function writeFragment(db: AdminDb, fragment: GraphFragment, ontology: Ontology, mutationId: string): Promise<{
|
|
165
|
-
txId: number;
|
|
166
|
-
ops: number;
|
|
167
|
-
}>;
|
|
168
|
-
|
|
169
|
-
/** How a scalar attribute is reconciled when a node is re-discovered. */
|
|
170
|
-
type MergeRule = "replace" | "prefer" | "earliest" | "latest";
|
|
171
|
-
type AttrType = SerializedAttr["type"];
|
|
172
|
-
interface AttrSpec {
|
|
173
|
-
type: AttrType;
|
|
174
|
-
unique?: boolean;
|
|
175
|
-
indexed?: boolean;
|
|
176
|
-
optional?: boolean;
|
|
177
|
-
/** The pipeline NEVER writes this attr (hand-edited in a UI); omitted from every update. */
|
|
178
|
-
human?: boolean;
|
|
179
|
-
/** Provenance rule for re-discovery. Default "replace". */
|
|
180
|
-
merge?: MergeRule;
|
|
181
|
-
/** Shown to the LLM when this attr appears in an extraction schema. */
|
|
182
|
-
desc?: string;
|
|
183
|
-
}
|
|
184
|
-
interface EntitySpec {
|
|
185
|
-
/** Unique attr used for Lookup upsert (MERGE key). Must be `unique` in attrs. */
|
|
186
|
-
naturalKey: string;
|
|
187
|
-
attrs: Record<string, AttrSpec>;
|
|
188
|
-
/** FTS fields for fuzzy resolution (P5). */
|
|
189
|
-
searchable?: string[];
|
|
190
|
-
}
|
|
191
|
-
interface EdgeSpec {
|
|
192
|
-
from: string;
|
|
193
|
-
to: string;
|
|
194
|
-
forwardLabel: string;
|
|
195
|
-
reverseLabel: string;
|
|
196
|
-
forwardHas?: Cardinality;
|
|
197
|
-
reverseHas?: Cardinality;
|
|
198
|
-
}
|
|
199
|
-
interface Ontology {
|
|
200
|
-
entities: Record<string, EntitySpec>;
|
|
201
|
-
edges: Record<string, EdgeSpec>;
|
|
202
|
-
}
|
|
203
|
-
/** node type → natural-key attr name (for the graph writer's Lookup refs). */
|
|
204
|
-
declare function naturalKeysOf(o: Ontology): NaturalKeys;
|
|
205
|
-
/** Attr name → merge rule, for every entity type (used by the provenance writer). */
|
|
206
|
-
declare function mergeRulesOf(o: Ontology): Record<string, Record<string, MergeRule>>;
|
|
207
|
-
/** Attr names the pipeline must never write, per entity type. */
|
|
208
|
-
declare function humanAttrsOf(o: Ontology): Record<string, Set<string>>;
|
|
209
|
-
/** Compile the ontology to an odla-db SerializedSchema to POST at /app/:id/schema. */
|
|
210
|
-
declare function toSerializedSchema(o: Ontology): SerializedSchema;
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Reconcile one scalar attribute when a node is re-discovered. Port of agnacl's
|
|
214
|
-
* provenance rules (utils/markdown.ts). Empty incoming never clobbers; empty
|
|
215
|
-
* existing is filled. Ordering rules compare stringwise (ISO dates sort right).
|
|
216
|
-
*/
|
|
217
|
-
declare function mergeScalar(rule: MergeRule, existing: Value | undefined, incoming: Value | undefined): Value | undefined;
|
|
218
|
-
/**
|
|
219
|
-
* Merge an incoming attr set into an existing one per the type's rules. `human`
|
|
220
|
-
* attrs are excluded upstream (never in `incoming`); this only reconciles what
|
|
221
|
-
* the pipeline owns. Returns the attrs to write (update leaves unlisted attrs intact).
|
|
222
|
-
*/
|
|
223
|
-
declare function mergeAttrs(rules: Record<string, MergeRule>, existing: Record<string, Value>, incoming: Record<string, Value>): Record<string, Value>;
|
|
224
|
-
|
|
225
|
-
/** FTS5 search over a namespace's text fields (odla-db QueryOpts.search). */
|
|
226
|
-
declare function searchEntities(db: AdminDb, type: string, q: string, limit?: number): Promise<Entity[]>;
|
|
227
|
-
/**
|
|
228
|
-
* Resolve a name to an existing entity's natural key via FTS — for merging a
|
|
229
|
-
* re-discovery that slugified differently. Conservative: only returns a hit when
|
|
230
|
-
* the top match's name/key normalizes identically to the query.
|
|
231
|
-
*/
|
|
232
|
-
declare function resolveName(db: AdminDb, type: string, keyAttr: string, name: string): Promise<string | null>;
|
|
233
|
-
/**
|
|
234
|
-
* Canonicalize a fragment's searchable nodes against existing entities via FTS,
|
|
235
|
-
* remapping node keys (and the edges that reference them) to the canonical key.
|
|
236
|
-
* Used on the lower-volume discovery/enrich paths, not high-volume ingest.
|
|
237
|
-
*/
|
|
238
|
-
declare function canonicalizeFragment(db: AdminDb, fragment: GraphFragment, ontology: Ontology): Promise<GraphFragment>;
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* The LLM seam, now a thin adapter over @odla-ai/ai (which was itself
|
|
242
|
-
* generalized from this package's original Provider). Three verbs stay:
|
|
243
|
-
* extract (forced structured tool call), search (web-search-enabled text),
|
|
244
|
-
* write (plain generation). Callers never see vendor or oracle types.
|
|
245
|
-
*/
|
|
246
|
-
type ProviderFamily = "claude" | "openai";
|
|
247
|
-
/** Role → model tiers per family — config as data. `cheap` is for gate-style
|
|
248
|
-
* calls, `extract` for structured extraction (and prose writing), `search`
|
|
249
|
-
* for web-search-enabled calls. */
|
|
250
|
-
declare const MODEL_TIERS: Record<ProviderFamily, {
|
|
251
|
-
cheap: string;
|
|
252
|
-
extract: string;
|
|
253
|
-
search: string;
|
|
254
|
-
}>;
|
|
255
|
-
/** A forced structured tool call: schema in, validated object out. */
|
|
256
|
-
interface ExtractCall {
|
|
257
|
-
system: string;
|
|
258
|
-
user: string;
|
|
259
|
-
tool: {
|
|
260
|
-
name: string;
|
|
261
|
-
description?: string;
|
|
262
|
-
parameters: Record<string, unknown>;
|
|
263
|
-
};
|
|
264
|
-
model?: string;
|
|
265
|
-
maxTokens?: number;
|
|
266
|
-
}
|
|
267
|
-
/** A web-search-enabled call: the model searches and returns text (caller tolerant-parses). */
|
|
268
|
-
interface SearchCall {
|
|
269
|
-
system: string;
|
|
270
|
-
user: string;
|
|
271
|
-
model?: string;
|
|
272
|
-
maxTokens?: number;
|
|
273
|
-
}
|
|
274
|
-
/** A plain text-generation call (no tools, no search) — e.g. digest prose. */
|
|
275
|
-
interface WriteCall {
|
|
276
|
-
system: string;
|
|
277
|
-
user: string;
|
|
278
|
-
model?: string;
|
|
279
|
-
maxTokens?: number;
|
|
280
|
-
}
|
|
281
|
-
interface Provider {
|
|
282
|
-
id: ProviderFamily;
|
|
283
|
-
/** The underlying @odla-ai/ai client — escape hatch for advanced use. */
|
|
284
|
-
ai: Ai;
|
|
285
|
-
extract<T = unknown>(c: ExtractCall): Promise<{
|
|
286
|
-
value: T;
|
|
287
|
-
usage: Usage;
|
|
288
|
-
}>;
|
|
289
|
-
search(c: SearchCall): Promise<{
|
|
290
|
-
text: string;
|
|
291
|
-
usage: Usage;
|
|
292
|
-
}>;
|
|
293
|
-
write(c: WriteCall): Promise<{
|
|
294
|
-
text: string;
|
|
295
|
-
usage: Usage;
|
|
296
|
-
}>;
|
|
297
|
-
}
|
|
298
|
-
interface LlmConfig {
|
|
299
|
-
provider: ProviderFamily;
|
|
300
|
-
anthropicKey?: string;
|
|
301
|
-
openaiKey?: string;
|
|
302
|
-
/** Inject a pre-built Ai (tests, custom catalog); keys are ignored when set. */
|
|
303
|
-
ai?: Ai;
|
|
304
|
-
}
|
|
305
|
-
/** The library primitive: an explicit config in, the three-verb seam out. */
|
|
306
|
-
declare function createProvider(cfg: LlmConfig): Provider;
|
|
307
|
-
/** The env vars the provider factory reads — a structural slice, not the
|
|
308
|
-
* worker Env, so any host (worker, script, test) can supply plain strings. */
|
|
309
|
-
interface LlmEnv {
|
|
310
|
-
LLM_PROVIDER?: string;
|
|
311
|
-
ANTHROPIC_API_KEY?: string;
|
|
312
|
-
OPENAI_API_KEY?: string;
|
|
313
|
-
}
|
|
314
|
-
/** Build the configured provider from host env, failing before use when its key is missing. */
|
|
315
|
-
declare function getProvider(env: LlmEnv): Provider;
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Tolerant JSON extraction from LLM prose — web-search models return JSON inside
|
|
319
|
-
* explanatory text. Ported from agnacl services/enrichment.ts.
|
|
320
|
-
*/
|
|
321
|
-
declare function extractJson<T = unknown>(text: string): T | null;
|
|
322
|
-
/** Tolerantly parse the first JSON-array-shaped span in model prose, or return an empty array. */
|
|
323
|
-
declare function extractJsonArray<T = unknown>(text: string): T[];
|
|
324
|
-
|
|
325
|
-
/** Ambient services a connector may use. Host-agnostic: secrets come through
|
|
326
|
-
* secret(), never a worker Env, so the library runs anywhere. */
|
|
327
|
-
interface ConnectorContext {
|
|
328
|
-
now: Date;
|
|
329
|
-
fetchText(url: string): Promise<string>;
|
|
330
|
-
secret(name: string): string | undefined;
|
|
331
|
-
ontology: Ontology;
|
|
332
|
-
/** The configured LLM provider (lazy — only web-search/discovery connectors need it). */
|
|
333
|
-
provider(): Provider;
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* The extensibility seam. A connector emits normalized RawItems — text-bearing
|
|
337
|
-
* (→ LLM extraction) or fragment-bearing (structured → straight to the writer).
|
|
338
|
-
* Adding a source = a new module implementing this + one registry line.
|
|
339
|
-
*/
|
|
340
|
-
interface SourceConnector<Cfg = unknown> {
|
|
341
|
-
id: string;
|
|
342
|
-
capabilities: {
|
|
343
|
-
fetch: boolean;
|
|
344
|
-
discover?: boolean;
|
|
345
|
-
structured: boolean;
|
|
346
|
-
};
|
|
347
|
-
parseConfig(raw: unknown): Cfg;
|
|
348
|
-
fetch(cfg: Cfg, ctx: ConnectorContext): Promise<RawItem[]>;
|
|
349
|
-
/** Web-search-style net-new discovery (P4). */
|
|
350
|
-
discover?(cfg: Cfg, ctx: ConnectorContext): Promise<RawItem[]>;
|
|
351
|
-
}
|
|
352
|
-
/** One unit of work for the ingest workflow: which connector + its config. */
|
|
353
|
-
interface ConnectorJob {
|
|
354
|
-
kind: string;
|
|
355
|
-
name: string;
|
|
356
|
-
watch?: string | null;
|
|
357
|
-
cfg: unknown;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/** Resolve a built-in source connector by its stable registry id. */
|
|
361
|
-
declare function getConnector(id: string): SourceConnector | undefined;
|
|
362
|
-
/** List registered connector ids in deterministic insertion order. */
|
|
363
|
-
declare function connectorIds(): string[];
|
|
364
|
-
/** Everything a ConnectorContext needs, supplied by the host (worker, script, test). */
|
|
365
|
-
interface ContextConfig {
|
|
366
|
-
ontology: Ontology;
|
|
367
|
-
provider: () => Provider;
|
|
368
|
-
/** Named secrets (API keys, user agents) — e.g. the worker Env, or a plain object. */
|
|
369
|
-
secrets?: Record<string, string | undefined>;
|
|
370
|
-
now?: Date;
|
|
371
|
-
}
|
|
372
|
-
/** Create a host-supplied connector context with lazy provider construction. */
|
|
373
|
-
declare function makeContext(cfg: ContextConfig): ConnectorContext;
|
|
374
|
-
|
|
375
|
-
/** Fetch one URL → a text-bearing RawItem. Used both directly (/trigger) and as a connector. */
|
|
376
|
-
declare function fetchUrl(url: string): Promise<RawItem>;
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Sources are DATA, not code. Each entry names a connector (`kind`) + its config
|
|
380
|
-
* + scheduling. Add a feed → add an entry; no redeploy of the pipeline. P5 moves
|
|
381
|
-
* this into KV behind a /config admin endpoint so edits don't need a deploy at all.
|
|
382
|
-
*/
|
|
383
|
-
interface SourceEntry {
|
|
384
|
-
kind: string;
|
|
385
|
-
name: string;
|
|
386
|
-
enabled?: boolean;
|
|
387
|
-
cadenceHours?: number;
|
|
388
|
-
watch?: string | null;
|
|
389
|
-
url?: string;
|
|
390
|
-
query?: string;
|
|
391
|
-
[key: string]: unknown;
|
|
392
|
-
}
|
|
393
|
-
/** Return source entries not explicitly disabled, preserving configured order. */
|
|
394
|
-
declare function enabledSources(sources: SourceEntry[]): SourceEntry[];
|
|
395
|
-
/** Enabled sources whose cadence lands on this UTC hour. */
|
|
396
|
-
declare function jobsForHour(sources: SourceEntry[], hour: number): ConnectorJob[];
|
|
397
|
-
/** Every enabled source, ignoring cadence (manual /trigger?kind=sources). */
|
|
398
|
-
declare function allJobs(sources: SourceEntry[]): ConnectorJob[];
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* The slice of a KV store the pipeline needs. Cloudflare's KVNamespace
|
|
402
|
-
* satisfies it structurally; tests pass an in-memory map. Keeping the library
|
|
403
|
-
* off Workers types is what lets it publish as a plain isomorphic package.
|
|
404
|
-
*/
|
|
405
|
-
interface KVLike {
|
|
406
|
-
get(key: string): Promise<string | null>;
|
|
407
|
-
put(key: string, value: string, opts?: {
|
|
408
|
-
expirationTtl?: number;
|
|
409
|
-
}): Promise<void>;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Operational state in KV (never the graph itself — that lives in odla-db).
|
|
413
|
-
* Ported/trimmed from agnacl services/kv.ts: seen-URL dedup + lastrun stamps.
|
|
414
|
-
*/
|
|
415
|
-
declare class Store {
|
|
416
|
-
private kv;
|
|
417
|
-
constructor(kv: KVLike);
|
|
418
|
-
private seenKey;
|
|
419
|
-
hasSeen(url: string): Promise<boolean>;
|
|
420
|
-
markSeen(url: string): Promise<void>;
|
|
421
|
-
/** Drop items whose URL we've already processed (checked BEFORE any LLM work). */
|
|
422
|
-
filterNew(items: RawItem[]): Promise<RawItem[]>;
|
|
423
|
-
setLastRun(kind: string, at?: string): Promise<void>;
|
|
424
|
-
getLastRun(kind: string): Promise<string | null>;
|
|
425
|
-
/** Per-entity enrichment cooldown so we don't re-search the same node constantly. */
|
|
426
|
-
isEnrichCooling(key: string): Promise<boolean>;
|
|
427
|
-
markEnriched(key: string): Promise<void>;
|
|
428
|
-
/** Runtime source config (edit without redeploy). null = fall back to the static SOURCES. */
|
|
429
|
-
getConfigSources(): Promise<SourceEntry[] | null>;
|
|
430
|
-
setConfigSources(list: SourceEntry[]): Promise<void>;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Cloudflare Workflow hardening — ported verbatim from agnacl
|
|
435
|
-
* (utils/workflow-helpers.ts). resilientStep adds structured error logging
|
|
436
|
-
* without changing retry semantics; the step configs replace the engine's slow
|
|
437
|
-
* default retry with fast exponential backoff.
|
|
438
|
-
*/
|
|
439
|
-
declare function resilientStep<T>(stepName: string, fn: () => Promise<T>): Promise<T>;
|
|
440
|
-
/** I/O-bound steps: KV reads, feed fetches. */
|
|
441
|
-
declare const IO_STEP_CONFIG: {
|
|
442
|
-
retries: {
|
|
443
|
-
limit: number;
|
|
444
|
-
delay: "5 seconds";
|
|
445
|
-
backoff: "exponential";
|
|
446
|
-
};
|
|
447
|
-
timeout: "2 minutes";
|
|
448
|
-
};
|
|
449
|
-
/** Graph write steps. */
|
|
450
|
-
declare const COMMIT_STEP_CONFIG: {
|
|
451
|
-
retries: {
|
|
452
|
-
limit: number;
|
|
453
|
-
delay: "3 seconds";
|
|
454
|
-
backoff: "exponential";
|
|
455
|
-
};
|
|
456
|
-
timeout: "90 seconds";
|
|
457
|
-
};
|
|
458
|
-
/** LLM generation steps (can be slow). */
|
|
459
|
-
declare const LLM_STEP_CONFIG: {
|
|
460
|
-
retries: {
|
|
461
|
-
limit: number;
|
|
462
|
-
delay: "5 seconds";
|
|
463
|
-
backoff: "exponential";
|
|
464
|
-
};
|
|
465
|
-
timeout: "3 minutes";
|
|
466
|
-
};
|
|
467
|
-
/** Retry/timeout shape of the step configs above. */
|
|
468
|
-
interface StepConfig {
|
|
469
|
-
retries?: {
|
|
470
|
-
limit: number;
|
|
471
|
-
delay: string;
|
|
472
|
-
backoff?: string;
|
|
473
|
-
};
|
|
474
|
-
timeout?: string;
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
* Structural view of Cloudflare's WorkflowStep. WorkflowStep.do constrains its
|
|
478
|
-
* result to Rpc.Serializable<T>, which cannot terminate (TS2589) on the
|
|
479
|
-
* recursive Value type now that the @odla/* workspace packages give
|
|
480
|
-
* @odla-ai/db's re-exports real definitions. A live WorkflowStep satisfies
|
|
481
|
-
* this shape at runtime; widen through asStepLike at the workflow boundary.
|
|
482
|
-
*/
|
|
483
|
-
interface StepLike {
|
|
484
|
-
do<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
485
|
-
do<T>(name: string, config: StepConfig, fn: () => Promise<T>): Promise<T>;
|
|
486
|
-
}
|
|
487
|
-
/** Widen a WorkflowStep to StepLike (type-level only, no runtime cost). */
|
|
488
|
-
declare function asStepLike(step: unknown): StepLike;
|
|
489
|
-
|
|
490
|
-
/** Everything the shared ingest loop needs, supplied by the host. The
|
|
491
|
-
* extractor is the ontology's domain craft (e.g. the OSINT extractor); the
|
|
492
|
-
* library stays ontology-agnostic. */
|
|
493
|
-
interface PipelineDeps {
|
|
494
|
-
db: AdminDb;
|
|
495
|
-
provider: Provider;
|
|
496
|
-
ontology: Ontology;
|
|
497
|
-
extract: (provider: Provider, item: RawItem) => Promise<ExtractResult | null>;
|
|
498
|
-
store: Store;
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Shared per-item processing: each RawItem is its own step (non-blocking,
|
|
502
|
-
* replay-cached). Structured items (fragment) skip the LLM; text items extract.
|
|
503
|
-
* `resolve` FTS-canonicalizes new nodes against existing ones (discovery path).
|
|
504
|
-
* Used by both the ingest (fetch) and discover (web-search) workflows.
|
|
505
|
-
*/
|
|
506
|
-
declare function ingestFresh(step: StepLike, deps: PipelineDeps, fresh: RawItem[], kind: string, resolve?: boolean): Promise<void>;
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Identity + dedup helpers. The slug / urlHash a node resolves to IS its
|
|
510
|
-
* natural key for Lookup-based upserts, so these must be stable and pure.
|
|
511
|
-
* Ported from agnacl (utils/markdown.ts slugify, services/kv.ts normalizeUrl).
|
|
512
|
-
*/
|
|
513
|
-
/** NFKD-normalize, strip accents, lowercase, non-alphanumerics → "-", cap 60. */
|
|
514
|
-
declare function slugify(input: string): string;
|
|
515
|
-
/** Drop tracking params, hash, and trailing slash so the same page maps to one key. */
|
|
516
|
-
declare function normalizeUrl(raw: string): string;
|
|
517
|
-
/** Stable short key for a URL (FNV-1a 32-bit, base36). Used as the `signal` natural key. */
|
|
518
|
-
declare function urlHash(raw: string): string;
|
|
519
|
-
/**
|
|
520
|
-
* Reject descriptive phrases masquerading as people ("three craftsmen",
|
|
521
|
-
* "the founders"). A real name is 2-4 capitalized tokens, no digits.
|
|
522
|
-
* Ported from agnacl utils/names.ts (isLikelyPersonName).
|
|
523
|
-
*/
|
|
524
|
-
declare function isLikelyPersonName(name: string): boolean;
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Dependency-free HTML → text extraction (Workers-isolate friendly: no DOM/jsdom).
|
|
528
|
-
* Ported from agnacl services/content-extractor.ts.
|
|
529
|
-
*/
|
|
530
|
-
/** Strip scripts/styles/tags and collapse whitespace; cap length. */
|
|
531
|
-
declare function htmlToText(html: string, maxChars?: number): string;
|
|
532
|
-
/** Fetch a URL and return readable text. Best-effort: returns "" on any failure. */
|
|
533
|
-
declare function fetchText(url: string, maxChars?: number): Promise<string>;
|
|
534
|
-
|
|
535
|
-
export { type AttrSpec, type AttrType, COMMIT_STEP_CONFIG, type ConnectorContext, type ConnectorJob, type ContextConfig, type EdgeSpec, type EntitySpec, type ExtractCall, type ExtractResult, type GraphEdge, type GraphFragment, type GraphNode, IO_STEP_CONFIG, type KVLike, LLM_STEP_CONFIG, type LlmConfig, type LlmEnv, MODEL_TIERS, type MergeRule, type NaturalKeys, type Ontology, type PipelineDeps, type Provider, type ProviderFamily, type RawItem, type SearchCall, type SourceConnector, type SourceEntry, type StepConfig, type StepLike, Store, type Usage, type WriteCall, addUsage, allJobs, asStepLike, canonicalizeFragment, connectorIds, createProvider, emptyUsage, enabledSources, extractJson, extractJsonArray, fetchText, fetchUrl, fragmentToOps, getConnector, getProvider, htmlToText, humanAttrsOf, ingestFresh, isLikelyPersonName, jobsForHour, makeContext, mergeAttrs, mergeRulesOf, mergeScalar, naturalKeysOf, normalizeUrl, resilientStep, resolveName, searchEntities, slugify, toSerializedSchema, urlHash, writeFragment };
|
|
536
|
-
```
|