@semiont/sdk 0.5.1 → 0.5.3
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 +116 -22
- package/dist/index.d.ts +468 -582
- package/dist/index.js +387 -1020
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,17 +6,105 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/@semiont/sdk)
|
|
7
7
|
[](https://github.com/The-AI-Alliance/semiont/blob/main/LICENSE)
|
|
8
8
|
|
|
9
|
-
The
|
|
9
|
+
The TypeScript SDK for [Semiont](https://github.com/The-AI-Alliance/semiont) — a programmable surface for **collaborative knowledge work**. Whether you're building a browser app where humans annotate documents and propose links, an AI agent that gathers context and matches candidate references, a daemon that ingests new sources, or a one-shot script that queries an established knowledge base, you reach the same verb namespaces, the same collaboration primitives, the same lifecycle observables.
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The eight flows — *frame, yield, mark, match, bind, gather, browse, beckon* — describe what participants *do* when they work with a shared corpus. The first seven act on content; Frame acts on the schema layer (the conceptual vocabulary the others operate within). The SDK exposes them uniformly across surfaces. A human in a browser hovers an annotation; an AI agent at the other end of the bus sees the hover and reacts; a daemon ingests new text and every connected participant sees the corpus grow live. Humans and AI agents are peers — the SDK does not distinguish.
|
|
12
|
+
|
|
13
|
+
The SDK is **transport-agnostic**: it consumes the `ITransport` and `IContentTransport` contracts from [`@semiont/core`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/core). For HTTP backends, the canonical wire adapter is re-exported here for convenience. For in-process operation (CLI, agentic worker, embedded use), use `LocalTransport` from [`@semiont/make-meaning`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/make-meaning).
|
|
14
|
+
|
|
15
|
+
> **Where this doc fits.** This README is the *typed-surface reference* — what's in `@semiont/sdk`, how the namespaces are organized, what return shapes to expect. For the *protocol-level architectural framing* (the eight flows, the three programmable surfaces — CLI, SDK, Skills — the core tenets, the per-flow contracts), start with [`docs/protocol/README.md`](https://github.com/The-AI-Alliance/semiont/blob/main/docs/protocol/README.md). Daemon authors stitching multiple packages together also want the [skill packs](https://github.com/The-AI-Alliance/semiont/tree/main/docs/protocol/skills) — `semiont-session` for watcher daemons, `semiont-worker` for job-claim daemons, `semiont-wiki` for the end-to-end annotation pipeline.
|
|
16
|
+
|
|
17
|
+
## Four ideas that hold the surface together
|
|
18
|
+
|
|
19
|
+
The SDK is wider than a typical client library because the domain is — collaborative knowledge work over a shared corpus, with humans and AI agents as peers. Four framings make the API tractable; once you've seen them, the rest is predictable.
|
|
20
|
+
|
|
21
|
+
### 1. Eight verbs
|
|
22
|
+
|
|
23
|
+
Every operation in the SDK belongs to one of eight *flows* — verbs that describe what a participant *does* with a shared corpus. The flows are the entire vocabulary of the protocol; learn them once and the surface stays small.
|
|
24
|
+
|
|
25
|
+
| Verb | What it does | Example methods |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| **frame** | Define and evolve the schema vocabulary (entity types, tag schemas, future relation types) | `frame.addEntityType`, `frame.addEntityTypes`, `frame.addTagSchema` |
|
|
28
|
+
| **yield** | Introduce new resources into the system | `yield.resource`, `yield.fromAnnotation`, `yield.cloneToken` |
|
|
29
|
+
| **mark** | Add structured metadata to resources | `mark.annotation`, `mark.assist`, `mark.archive` |
|
|
30
|
+
| **match** | Search the corpus for candidate resources | `match.search` |
|
|
31
|
+
| **bind** | Resolve ambiguous references to specific resources | `bind.body`, `bind.initiate` |
|
|
32
|
+
| **gather** | Assemble related context around an annotation | `gather.annotation` |
|
|
33
|
+
| **browse** | Navigate, read, and observe | `browse.resource`, `browse.annotations`, `browse.entityTypes`, `browse.tagSchemas`, `browse.click` |
|
|
34
|
+
| **beckon** | Coordinate attention across participants | `beckon.hover`, `beckon.attention`, `beckon.sparkle` |
|
|
35
|
+
|
|
36
|
+
Each flow is a namespace on `SemiontClient` (`client.mark.X(...)`, `client.gather.X(...)`, ...). The verb is the unit of mental model — a method call belongs to a flow, not to a noun. Frame is the schema-layer flow — content flows operate within the vocabulary Frame manages. Per-flow contracts live in [`docs/protocol/flows`](https://github.com/The-AI-Alliance/semiont/tree/main/docs/protocol/flows).
|
|
37
|
+
|
|
38
|
+
### 2. One call, two ways to consume
|
|
39
|
+
|
|
40
|
+
Most data-fetching libraries make you choose between Promise-shaped and Observable-shaped at the import line. The SDK doesn't. Every long-lived value comes back as an `Observable` that *also* implements `PromiseLike<T>` — `await` it for the final value, `.subscribe(...)` it for progress events or live updates, from the same call.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// One-shot consumer — never imports rxjs
|
|
44
|
+
const resource = await client.browse.resource(rId);
|
|
45
|
+
const result = await client.match.search(rId, refId, ctx);
|
|
46
|
+
|
|
47
|
+
// Reactive consumer — same call, .subscribe instead of await
|
|
48
|
+
client.browse.resource(rId).subscribe((r) => {
|
|
49
|
+
if (r === undefined) showSkeleton();
|
|
50
|
+
else render(r);
|
|
51
|
+
});
|
|
52
|
+
client.match.search(rId, refId, ctx).subscribe((event) => {
|
|
53
|
+
if (event.kind === 'progress') updateProgress(event.data);
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A script that just wants the final value never imports anything from `rxjs`. A browser app rendering loading state subscribes to the same shape. The reactive substrate is preserved as a load-bearing architectural choice; the user-facing surface looks Promise-shaped when that's all the caller needs.
|
|
58
|
+
|
|
59
|
+
Methods return one of: `Promise<T>` (atomic backend ops), an awaitable `Observable<T>` subclass (`StreamObservable<T>` for bounded progress streams, `CacheObservable<T>` for live queries with stale-while-revalidate), or `void` (collaboration signals — see #3). Per-method assignments and the typing discipline are in [`docs/REACTIVE-MODEL.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/REACTIVE-MODEL.md).
|
|
60
|
+
|
|
61
|
+
### 3. Collaboration primitives
|
|
62
|
+
|
|
63
|
+
The `void`-returning third category — collaboration signals — is the SDK's distinctive contribution to multi-participant coordination. They look fire-and-forget at the call site; on the bus they fan out across every participant.
|
|
64
|
+
|
|
65
|
+
A human in a browser hovers an annotation (`beckon.hover(annotationId)`); an AI agent at the other end of the bus sees `beckon:hover` and reacts. An agent emits a sparkle (`beckon.sparkle(annotationId)`); the human's UI lights up the indicated annotation. A frontend state unit emits `mark.changeShape('rectangle')`; a different participant subscribed to `mark:shape-changed` reacts.
|
|
66
|
+
|
|
67
|
+
This is *protocol-level* coordination — not browser-app fluff, not bolted-on presence — and it sits on the same typed namespace surface as data operations. Observers reach the same signals via `session.subscribe(channel, handler)` or `client.bus.get(channel)`. Three legitimate paths to the bus are documented in [`docs/REACTIVE-MODEL.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/REACTIVE-MODEL.md#three-paths-to-the-bus).
|
|
68
|
+
|
|
69
|
+
### 4. Transport agnosticism
|
|
70
|
+
|
|
71
|
+
`SemiontClient` is constructed against the `ITransport` and `IContentTransport` interfaces from `@semiont/core` — not against any particular wire. The same SDK surface runs over HTTP, in-process, or any future transport that satisfies the interface. None of the eight verb namespaces or the flow state machines reach for transport-specific features.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// HTTP — connect to a remote backend
|
|
75
|
+
const client = await SemiontClient.signInHttp({ baseUrl, email, password });
|
|
76
|
+
|
|
77
|
+
// In-process — same surface, no network
|
|
78
|
+
const client = new SemiontClient(localTransport, localContentTransport);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`KnowledgeBase` carries a uniform shape regardless of transport (only the nested `endpoint` varies — `{ kind: 'http', host, port, protocol }` or `{ kind: 'local', kbId }`). Code that doesn't *construct* transports — your scripts, the verb namespaces, the flow state machines — never inspects which kind it has. Tests can run against an in-process transport for speed; daemons can embed the backend; the same domain code drives both.
|
|
12
82
|
|
|
13
83
|
## What's in the box
|
|
14
84
|
|
|
15
85
|
- **`SemiontClient`** — the verb-oriented coordinator over a wire transport.
|
|
16
86
|
- **Verb namespaces** — `browse`, `mark`, `bind`, `gather`, `match`, `yield`, `beckon`, `job`, `auth`, `admin`. Typed methods that wrap the bus protocol; consumers never touch raw channel strings.
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
87
|
+
- **Collaboration primitives** — fire-and-forget signals on the verb namespaces (`beckon.hover`, `bind.initiate`, `mark.changeShape`, `browse.click`, ...) coordinate attention and intent across participants. Not afterthoughts, not browser-app fluff: they're how a multi-participant session stays coherent.
|
|
88
|
+
- **Session layer** — `SemiontSession` (per-KB authentication, token refresh, lifecycle), `SemiontBrowser` (multi-KB orchestration), and `SessionStorage` adapters (`InMemorySessionStorage`, plus a browser-backed one in `@semiont/react-ui`).
|
|
89
|
+
- **Flow state machines** — RxJS-based factories (`createMarkStateUnit`, `createGatherStateUnit`, `createMatchStateUnit`, `createYieldStateUnit`, `createBeckonStateUnit`) that wrap each long-running flow with `loading$` / `error$` / progress observables. UI-shape-agnostic — any consumer (browser, terminal, mobile, daemon) can subscribe.
|
|
90
|
+
- **`WorkerBus`** — the transport-neutral channel-bus interface that worker-side adapters consume. Domain-specific worker adapters live with their domain — `createJobClaimAdapter` and `createJobQueueStateUnit` in [`@semiont/jobs`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/jobs); `createSmelterActorStateUnit` in [`@semiont/make-meaning`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/make-meaning) — and consume `WorkerBus` from here.
|
|
91
|
+
- **Helpers** — `bus-request` (correlation-ID request/reply), the cache primitive backing live queries, and `createSearchPipeline` (debounced-search RxJS pipeline).
|
|
92
|
+
|
|
93
|
+
Page-shaped state machines (admin tables, compose page, resource viewer page, etc.) live in [`@semiont/react-ui`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/react-ui), alongside the components that render them. Those are framework-neutral but tied to the Semiont web frontend's specific page taxonomy; they don't apply to non-web consumers.
|
|
94
|
+
|
|
95
|
+
## For non-web consumers (TUI, mobile, daemon, agent)
|
|
96
|
+
|
|
97
|
+
`@semiont/sdk` is the only package a non-web Semiont consumer needs. From it you get:
|
|
98
|
+
|
|
99
|
+
- `SemiontClient` + the eight verb namespaces (`frame`, `browse`, `mark`, `bind`, `gather`, `match`, `yield`, `beckon`)
|
|
100
|
+
- Three infrastructure namespaces (`auth`, `admin`, `job`) when constructed with backend operations
|
|
101
|
+
- `SemiontSession` for long-running token refresh + persistence
|
|
102
|
+
- `SemiontBrowser` for multi-KB orchestration (transport-agnostic; takes a `SessionFactory`)
|
|
103
|
+
- The five flow state machines above
|
|
104
|
+
- The transport-neutral `WorkerBus` interface (worker adapters live in their domain packages — `@semiont/jobs`, `@semiont/make-meaning`)
|
|
105
|
+
- Branded ID types, the unified error hierarchy, the `TransportErrorCode` neutral vocabulary
|
|
106
|
+
|
|
107
|
+
Nothing page-shaped, nothing web-shell-shaped. A TUI, mobile reader, daemon, or AI agent installs `@semiont/sdk` alone (plus a transport package — `@semiont/api-client` for HTTP, `@semiont/make-meaning` for in-process).
|
|
20
108
|
|
|
21
109
|
## Installation
|
|
22
110
|
|
|
@@ -26,12 +114,12 @@ npm install @semiont/sdk
|
|
|
26
114
|
|
|
27
115
|
## Quick start (HTTP)
|
|
28
116
|
|
|
29
|
-
For one-shot scripts, `SemiontClient.
|
|
117
|
+
For one-shot scripts, `SemiontClient.signInHttp(...)` is the credentials-first one-line construction:
|
|
30
118
|
|
|
31
119
|
```ts
|
|
32
120
|
import { SemiontClient } from '@semiont/sdk';
|
|
33
121
|
|
|
34
|
-
const semiont = await SemiontClient.
|
|
122
|
+
const semiont = await SemiontClient.signInHttp({
|
|
35
123
|
baseUrl: 'http://localhost:4000',
|
|
36
124
|
email: 'me@example.com',
|
|
37
125
|
password: 'pwd',
|
|
@@ -43,7 +131,7 @@ console.log(resources);
|
|
|
43
131
|
semiont.dispose();
|
|
44
132
|
```
|
|
45
133
|
|
|
46
|
-
For long-running scripts that need to survive token expiry, use `SemiontSession.
|
|
134
|
+
For long-running scripts that need to survive token expiry, use `SemiontSession.signInHttp(...)` — same credentials shape, plus proactive refresh, validation, storage-adapter wiring, and disposal. `kb` is required; its `id` is the storage key for this session, so distinct scripts must use distinct ids:
|
|
47
135
|
|
|
48
136
|
```ts
|
|
49
137
|
import { SemiontSession, InMemorySessionStorage, type KnowledgeBase } from '@semiont/sdk';
|
|
@@ -51,13 +139,11 @@ import { SemiontSession, InMemorySessionStorage, type KnowledgeBase } from '@sem
|
|
|
51
139
|
const kb: KnowledgeBase = {
|
|
52
140
|
id: 'my-watcher',
|
|
53
141
|
label: 'My Watcher',
|
|
54
|
-
protocol: 'http',
|
|
55
|
-
host: 'localhost',
|
|
56
|
-
port: 4000,
|
|
57
142
|
email: 'me@example.com',
|
|
143
|
+
endpoint: { kind: 'http', host: 'localhost', port: 4000, protocol: 'http' },
|
|
58
144
|
};
|
|
59
145
|
|
|
60
|
-
const session = await SemiontSession.
|
|
146
|
+
const session = await SemiontSession.signInHttp({
|
|
61
147
|
kb,
|
|
62
148
|
storage: new InMemorySessionStorage(),
|
|
63
149
|
baseUrl: 'http://localhost:4000',
|
|
@@ -72,6 +158,8 @@ const resources = await session.client.browse.resources({ limit: 10 });
|
|
|
72
158
|
await session.dispose();
|
|
73
159
|
```
|
|
74
160
|
|
|
161
|
+
`KnowledgeBase` is uniform regardless of transport kind; the variation lives in the nested `endpoint` (currently `{ kind: 'http', host, port, protocol }` or `{ kind: 'local', kbId }`). Code that doesn't construct transports — your scripts, the verb namespaces, the flow state machines — never inspects `endpoint`.
|
|
162
|
+
|
|
75
163
|
If you already have an access token (CLI cached-token path, env-var token, embedded auth flow), use `SemiontClient.fromHttp({ baseUrl, token })` or `SemiontSession.fromHttp({ baseUrl, token, storage, kb, refresh, ... })` to skip the auth round-trip.
|
|
76
164
|
|
|
77
165
|
## Quick start (in-process)
|
|
@@ -100,9 +188,9 @@ const client = new SemiontClient(
|
|
|
100
188
|
|
|
101
189
|
Same `SemiontClient`, same verb namespaces — no network involved. There is no `fromLocal` factory because the in-process transport's dependencies (knowledgeSystem, eventBus, userId) are not boilerplate the SDK can hide.
|
|
102
190
|
|
|
103
|
-
##
|
|
191
|
+
## Worked examples
|
|
104
192
|
|
|
105
|
-
|
|
193
|
+
The eight verb namespaces hang off `SemiontClient`, plus three infrastructure namespaces (`auth`, `admin`, `job`) when the client was constructed with backend operations. Each example below uses one of the return shapes mentioned above; the per-method assignment table is in [`docs/REACTIVE-MODEL.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/REACTIVE-MODEL.md#method-by-method-assignment).
|
|
106
194
|
|
|
107
195
|
```ts
|
|
108
196
|
// Browse — live queries; await yields the loaded value, subscribe yields
|
|
@@ -111,30 +199,36 @@ const resources = await client.browse.resources({ limit: 10 });
|
|
|
111
199
|
client.browse.resource(resourceId).subscribe(/* ... */);
|
|
112
200
|
|
|
113
201
|
// Mark / Bind — atomic operations return Promise<T>.
|
|
114
|
-
|
|
202
|
+
// `mark.annotation` takes the W3C-shaped input directly; the resourceId
|
|
203
|
+
// is derived from `input.target.source` and returned as a branded id.
|
|
204
|
+
const { annotationId } = await client.mark.annotation(annotationInput);
|
|
115
205
|
await client.bind.body(rid, aid, [{ op: 'add', item: { /* W3C body */ } }]);
|
|
116
206
|
|
|
117
207
|
// Gather / Match — bounded streams; await yields the final value, subscribe
|
|
118
208
|
// yields every progress emission.
|
|
119
|
-
const ctx = await client.gather.annotation(
|
|
209
|
+
const ctx = await client.gather.annotation(rid, aid);
|
|
120
210
|
client.match.search(rid, refId, ctx, { limit: 10 }).subscribe(/* ... */);
|
|
121
211
|
|
|
122
|
-
// Yield — author new resources.
|
|
212
|
+
// Yield — author new resources. Returns an UploadObservable; await yields
|
|
213
|
+
// { resourceId }, subscribe yields the upload-progress lifecycle.
|
|
123
214
|
const { resourceId } = await client.yield.resource({
|
|
124
215
|
name, file, format, storageUri,
|
|
125
216
|
});
|
|
126
217
|
|
|
127
|
-
// Beckon —
|
|
218
|
+
// Beckon, Bind, Browse, Mark — collaboration signals (void). Fire-and-
|
|
219
|
+
// forget; fan out to other participants over the bus.
|
|
128
220
|
client.beckon.hover(annotationId);
|
|
221
|
+
client.bind.initiate({ annotationId });
|
|
222
|
+
client.browse.click(annotationId, 'linking');
|
|
129
223
|
```
|
|
130
224
|
|
|
131
|
-
The verb-by-verb walkthroughs live in [docs/flows](https://github.com/The-AI-Alliance/semiont/tree/main/docs/flows).
|
|
132
|
-
|
|
133
|
-
`.pipe(...)` returns a plain `Observable<T>` — once you compose with RxJS operators you've explicitly entered RxJS land, and `lastValueFrom` from `rxjs` is the right bridge. The `firstValueFrom`/`lastValueFrom` re-exports from `@semiont/sdk` stay available for that case.
|
|
225
|
+
The verb-by-verb walkthroughs live in [docs/protocol/flows](https://github.com/The-AI-Alliance/semiont/tree/main/docs/protocol/flows). The per-namespace API reference with concrete examples for each method lives in [`docs/Usage.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/Usage.md).
|
|
134
226
|
|
|
135
227
|
## Documentation
|
|
136
228
|
|
|
137
229
|
- [`docs/Usage.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/Usage.md) — per-namespace tour with concrete examples for Browse, Mark, Bind, Gather, Match, Yield, Beckon, Auth, Admin, Job, plus SSE and error handling.
|
|
230
|
+
- [`docs/REACTIVE-MODEL.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/REACTIVE-MODEL.md) — the Promise-shape-over-Observable design: how `await` works on the SDK's return values without learning RxJS, and where RxJS is still visible by design.
|
|
231
|
+
- [`docs/STATE-UNITS.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/STATE-UNITS.md) — the foundational pattern behind the flow state machines, worker adapters, and search pipeline: closure-based factories, RxJS-shaped surface, dispose lifecycle, and the axioms every new state unit honors.
|
|
138
232
|
- [`docs/CACHE-SEMANTICS.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/CACHE-SEMANTICS.md) — the cache primitive's behavioral contract.
|
|
139
233
|
- [`docs/protocol/TRANSPORT-CONTRACT.md`](https://github.com/The-AI-Alliance/semiont/blob/main/docs/protocol/TRANSPORT-CONTRACT.md) — the transport interface every `ITransport` must honor.
|
|
140
234
|
|
|
@@ -154,4 +248,4 @@ Apache-2.0 — see [LICENSE](https://github.com/The-AI-Alliance/semiont/blob/mai
|
|
|
154
248
|
- [`@semiont/api-client`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/api-client) — HTTP transport (`HttpTransport`, `HttpContentTransport`)
|
|
155
249
|
- [`@semiont/make-meaning`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/make-meaning) — in-process transport (`LocalTransport`) and the actor model behind it
|
|
156
250
|
- [`@semiont/observability`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/observability) — OpenTelemetry tracing the SDK propagates across the bus
|
|
157
|
-
- [`@semiont/react-ui`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/react-ui) — React bindings (`
|
|
251
|
+
- [`@semiont/react-ui`](https://github.com/The-AI-Alliance/semiont/tree/main/packages/react-ui) — React bindings (`useStateUnit`, web `SessionStorage`)
|