@semiont/sdk 0.5.2 → 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 +39 -15
- package/dist/index.d.ts +19 -2
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,9 +14,9 @@ The SDK is **transport-agnostic**: it consumes the `ITransport` and `IContentTra
|
|
|
14
14
|
|
|
15
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
16
|
|
|
17
|
-
##
|
|
17
|
+
## Four ideas that hold the surface together
|
|
18
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.
|
|
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
20
|
|
|
21
21
|
### 1. Eight verbs
|
|
22
22
|
|
|
@@ -24,38 +24,62 @@ Every operation in the SDK belongs to one of eight *flows* — verbs that descri
|
|
|
24
24
|
|
|
25
25
|
| Verb | What it does | Example methods |
|
|
26
26
|
|---|---|---|
|
|
27
|
-
| **frame** | Define and evolve the schema vocabulary (entity types,
|
|
27
|
+
| **frame** | Define and evolve the schema vocabulary (entity types, tag schemas, future relation types) | `frame.addEntityType`, `frame.addEntityTypes`, `frame.addTagSchema` |
|
|
28
28
|
| **yield** | Introduce new resources into the system | `yield.resource`, `yield.fromAnnotation`, `yield.cloneToken` |
|
|
29
29
|
| **mark** | Add structured metadata to resources | `mark.annotation`, `mark.assist`, `mark.archive` |
|
|
30
30
|
| **match** | Search the corpus for candidate resources | `match.search` |
|
|
31
31
|
| **bind** | Resolve ambiguous references to specific resources | `bind.body`, `bind.initiate` |
|
|
32
32
|
| **gather** | Assemble related context around an annotation | `gather.annotation` |
|
|
33
|
-
| **browse** | Navigate, read, and observe | `browse.resource`, `browse.annotations`, `browse.click` |
|
|
33
|
+
| **browse** | Navigate, read, and observe | `browse.resource`, `browse.annotations`, `browse.entityTypes`, `browse.tagSchemas`, `browse.click` |
|
|
34
34
|
| **beckon** | Coordinate attention across participants | `beckon.hover`, `beckon.attention`, `beckon.sparkle` |
|
|
35
35
|
|
|
36
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
37
|
|
|
38
|
-
### 2.
|
|
38
|
+
### 2. One call, two ways to consume
|
|
39
39
|
|
|
40
|
-
|
|
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
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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.
|
|
48
58
|
|
|
49
|
-
|
|
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).
|
|
50
60
|
|
|
51
61
|
### 3. Collaboration primitives
|
|
52
62
|
|
|
53
|
-
The
|
|
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.
|
|
54
64
|
|
|
55
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.
|
|
56
66
|
|
|
57
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).
|
|
58
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.
|
|
82
|
+
|
|
59
83
|
## What's in the box
|
|
60
84
|
|
|
61
85
|
- **`SemiontClient`** — the verb-oriented coordinator over a wire transport.
|
|
@@ -166,7 +190,7 @@ Same `SemiontClient`, same verb namespaces — no network involved. There is no
|
|
|
166
190
|
|
|
167
191
|
## Worked examples
|
|
168
192
|
|
|
169
|
-
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
|
|
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).
|
|
170
194
|
|
|
171
195
|
```ts
|
|
172
196
|
// Browse — live queries; await yields the loaded value, subscribe yields
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import * as rxjs from 'rxjs';
|
|
|
2
2
|
import { Observable, BehaviorSubject, Subject } from 'rxjs';
|
|
3
3
|
export { firstValueFrom, lastValueFrom } from 'rxjs';
|
|
4
4
|
import * as _semiont_core from '@semiont/core';
|
|
5
|
-
import { ResourceId, components, UserDID, paths, BackendDownload, ProgressEvent, AnnotationId, BodyOperation, EventMap, ResourceDescriptor, Annotation, GraphConnection, Motivation, GatheredContext, JobId, ITransport, EventBus, IContentTransport, IBackendOperations, BaseUrl, AccessToken, SemiontError, ConnectionState, Selector } from '@semiont/core';
|
|
6
|
-
export { AccessToken, Annotation, AnnotationId, BaseUrl, BodyItem, BodyOperation, ConnectionState, EntityType, EventMap, GatheredContext, IContentTransport, ITransport, Logger, Motivation, RefreshToken, ResourceDescriptor, ResourceId, SemiontError, UserId, accessToken, annotationId, baseUrl, entityType, refreshToken, resourceId, userId } from '@semiont/core';
|
|
5
|
+
import { ResourceId, components, UserDID, paths, BackendDownload, ProgressEvent, AnnotationId, BodyOperation, EventMap, ResourceDescriptor, Annotation, TagSchema, GraphConnection, Motivation, GatheredContext, JobId, ITransport, EventBus, IContentTransport, IBackendOperations, BaseUrl, AccessToken, SemiontError, ConnectionState, Selector } from '@semiont/core';
|
|
6
|
+
export { AccessToken, Annotation, AnnotationId, BaseUrl, BodyItem, BodyOperation, ConnectionState, EntityType, EventMap, GatheredContext, IContentTransport, ITransport, Logger, Motivation, RefreshToken, ResourceDescriptor, ResourceId, SemiontError, TagCategory, TagSchema, UserId, accessToken, annotationId, baseUrl, entityType, refreshToken, resourceId, userId } from '@semiont/core';
|
|
7
7
|
export { APIError, HttpContentTransport, HttpTransport, HttpTransportConfig, TokenRefresher } from '@semiont/api-client';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -203,6 +203,8 @@ interface GenerationOptions {
|
|
|
203
203
|
storageUri: string;
|
|
204
204
|
context: GatheredContext;
|
|
205
205
|
prompt?: string;
|
|
206
|
+
/** Entity-type tags to stamp on the synthesized resource. Used both as a prompt bias for the generation worker and as the `entityTypes` set on the resulting resource (so `browse.resources({ entityType: ... })` queries can find it). */
|
|
207
|
+
entityTypes?: string[];
|
|
206
208
|
/** Annotation/resource body locale — language the generated resource is written in (typically the user's UI locale). */
|
|
207
209
|
language?: string;
|
|
208
210
|
/** Source-resource locale — language of the resource the annotation lives on, used in the prompt so the LLM understands embedded source-context snippets. BCP-47. */
|
|
@@ -297,6 +299,7 @@ interface BrowseNamespace$1 {
|
|
|
297
299
|
annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
|
|
298
300
|
annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
|
|
299
301
|
entityTypes(): CacheObservable<string[]>;
|
|
302
|
+
tagSchemas(): CacheObservable<TagSchema[]>;
|
|
300
303
|
referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
|
|
301
304
|
events(resourceId: ResourceId): CacheObservable<StoredEventResponse$1[]>;
|
|
302
305
|
resourceContent(resourceId: ResourceId): Promise<string>;
|
|
@@ -346,6 +349,16 @@ interface FrameNamespace$1 {
|
|
|
346
349
|
addEntityType(type: string): Promise<void>;
|
|
347
350
|
/** Add multiple entity types in one call. Convenience over a loop of `addEntityType`. */
|
|
348
351
|
addEntityTypes(types: string[]): Promise<void>;
|
|
352
|
+
/**
|
|
353
|
+
* Register a tag schema with the KB's runtime registry.
|
|
354
|
+
*
|
|
355
|
+
* Most-recent registration of a given `schema.id` wins; identical
|
|
356
|
+
* re-registrations are silent, differing content overwrites the
|
|
357
|
+
* existing entry and logs a warning. KBs typically call this at
|
|
358
|
+
* session/skill startup so the schema is available for `mark.assist`
|
|
359
|
+
* with motivation `tagging` and surfaces in `browse.tagSchemas()`.
|
|
360
|
+
*/
|
|
361
|
+
addTagSchema(schema: TagSchema): Promise<void>;
|
|
349
362
|
}
|
|
350
363
|
/**
|
|
351
364
|
* Mark — annotation CRUD, AI assist, resource lifecycle
|
|
@@ -551,6 +564,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
|
|
|
551
564
|
private readonly annotationDetailCache;
|
|
552
565
|
private readonly annotationResources;
|
|
553
566
|
private readonly entityTypesCache;
|
|
567
|
+
private readonly tagSchemasCache;
|
|
554
568
|
private readonly referencedByCache;
|
|
555
569
|
private readonly resourceEventsCache;
|
|
556
570
|
/** Filter-blob memory so `invalidateResourceLists` can replay per-key. */
|
|
@@ -571,6 +585,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
|
|
|
571
585
|
annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
|
|
572
586
|
annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
|
|
573
587
|
entityTypes(): CacheObservable<string[]>;
|
|
588
|
+
tagSchemas(): CacheObservable<TagSchema[]>;
|
|
574
589
|
referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
|
|
575
590
|
events(resourceId: ResourceId): CacheObservable<StoredEventResponse[]>;
|
|
576
591
|
resourceContent(resourceId: ResourceId): Promise<string>;
|
|
@@ -599,6 +614,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
|
|
|
599
614
|
invalidateResourceDetail(id: ResourceId): void;
|
|
600
615
|
invalidateResourceLists(): void;
|
|
601
616
|
invalidateEntityTypes(): void;
|
|
617
|
+
invalidateTagSchemas(): void;
|
|
602
618
|
invalidateReferencedBy(resourceId: ResourceId): void;
|
|
603
619
|
invalidateResourceEvents(resourceId: ResourceId): void;
|
|
604
620
|
updateAnnotationInPlace(resourceId: ResourceId, annotation: Annotation): void;
|
|
@@ -737,6 +753,7 @@ declare class FrameNamespace implements FrameNamespace$1 {
|
|
|
737
753
|
constructor(transport: ITransport);
|
|
738
754
|
addEntityType(type: string): Promise<void>;
|
|
739
755
|
addEntityTypes(types: string[]): Promise<void>;
|
|
756
|
+
addTagSchema(schema: TagSchema): Promise<void>;
|
|
740
757
|
}
|
|
741
758
|
|
|
742
759
|
type JobStatusResponse = components['schemas']['JobStatusResponse'];
|
package/dist/index.js
CHANGED
|
@@ -171,6 +171,7 @@ function createCache(fetchFn) {
|
|
|
171
171
|
|
|
172
172
|
// src/namespaces/browse.ts
|
|
173
173
|
var ENTITY_TYPES_KEY = "_";
|
|
174
|
+
var TAG_SCHEMAS_KEY = "_";
|
|
174
175
|
var BrowseNamespace = class {
|
|
175
176
|
constructor(transport, bus, content) {
|
|
176
177
|
this.transport = transport;
|
|
@@ -231,6 +232,16 @@ var BrowseNamespace = class {
|
|
|
231
232
|
);
|
|
232
233
|
return result.entityTypes;
|
|
233
234
|
});
|
|
235
|
+
this.tagSchemasCache = createCache(async () => {
|
|
236
|
+
const result = await busRequest(
|
|
237
|
+
this.transport,
|
|
238
|
+
"browse:tag-schemas-requested",
|
|
239
|
+
{},
|
|
240
|
+
"browse:tag-schemas-result",
|
|
241
|
+
"browse:tag-schemas-failed"
|
|
242
|
+
);
|
|
243
|
+
return result.tagSchemas;
|
|
244
|
+
});
|
|
234
245
|
this.referencedByCache = createCache(async (resourceId2) => {
|
|
235
246
|
const result = await busRequest(
|
|
236
247
|
this.transport,
|
|
@@ -274,6 +285,7 @@ var BrowseNamespace = class {
|
|
|
274
285
|
annotationDetailCache;
|
|
275
286
|
annotationResources = /* @__PURE__ */ new Map();
|
|
276
287
|
entityTypesCache;
|
|
288
|
+
tagSchemasCache;
|
|
277
289
|
referencedByCache;
|
|
278
290
|
resourceEventsCache;
|
|
279
291
|
/** Filter-blob memory so `invalidateResourceLists` can replay per-key. */
|
|
@@ -316,6 +328,9 @@ var BrowseNamespace = class {
|
|
|
316
328
|
entityTypes() {
|
|
317
329
|
return CacheObservable.from(this.entityTypesCache.observe(ENTITY_TYPES_KEY));
|
|
318
330
|
}
|
|
331
|
+
tagSchemas() {
|
|
332
|
+
return CacheObservable.from(this.tagSchemasCache.observe(TAG_SCHEMAS_KEY));
|
|
333
|
+
}
|
|
319
334
|
referencedBy(resourceId2) {
|
|
320
335
|
return CacheObservable.from(this.referencedByCache.observe(resourceId2));
|
|
321
336
|
}
|
|
@@ -400,6 +415,9 @@ var BrowseNamespace = class {
|
|
|
400
415
|
invalidateEntityTypes() {
|
|
401
416
|
this.entityTypesCache.invalidate(ENTITY_TYPES_KEY);
|
|
402
417
|
}
|
|
418
|
+
invalidateTagSchemas() {
|
|
419
|
+
this.tagSchemasCache.invalidate(TAG_SCHEMAS_KEY);
|
|
420
|
+
}
|
|
403
421
|
invalidateReferencedBy(resourceId2) {
|
|
404
422
|
this.referencedByCache.invalidate(resourceId2);
|
|
405
423
|
}
|
|
@@ -476,6 +494,7 @@ var BrowseNamespace = class {
|
|
|
476
494
|
for (const rId of this.referencedByCache.keys()) this.invalidateReferencedBy(rId);
|
|
477
495
|
}
|
|
478
496
|
this.invalidateEntityTypes();
|
|
497
|
+
this.invalidateTagSchemas();
|
|
479
498
|
});
|
|
480
499
|
this.on("mark:delete-ok", (event) => {
|
|
481
500
|
this.removeAnnotationDetail(annotationId(event.annotationId));
|
|
@@ -511,6 +530,7 @@ var BrowseNamespace = class {
|
|
|
511
530
|
this.on("mark:archived", this.onArchiveToggled);
|
|
512
531
|
this.on("mark:unarchived", this.onArchiveToggled);
|
|
513
532
|
this.on("frame:entity-type-added", () => this.invalidateEntityTypes());
|
|
533
|
+
this.on("frame:tag-schema-added", () => this.invalidateTagSchemas());
|
|
514
534
|
}
|
|
515
535
|
};
|
|
516
536
|
var MarkNamespace = class {
|
|
@@ -543,6 +563,7 @@ var MarkNamespace = class {
|
|
|
543
563
|
let done = false;
|
|
544
564
|
let pollTimer = null;
|
|
545
565
|
let pollInterval = null;
|
|
566
|
+
let unsubscribeResource = this.transport.subscribeToResource(resourceId2);
|
|
546
567
|
const cleanup = () => {
|
|
547
568
|
done = true;
|
|
548
569
|
if (pollTimer) {
|
|
@@ -553,6 +574,10 @@ var MarkNamespace = class {
|
|
|
553
574
|
clearInterval(pollInterval);
|
|
554
575
|
pollInterval = null;
|
|
555
576
|
}
|
|
577
|
+
if (unsubscribeResource) {
|
|
578
|
+
unsubscribeResource();
|
|
579
|
+
unsubscribeResource = null;
|
|
580
|
+
}
|
|
556
581
|
};
|
|
557
582
|
const resetPollTimer = (jobId) => {
|
|
558
583
|
if (pollTimer) clearTimeout(pollTimer);
|
|
@@ -867,6 +892,7 @@ var YieldNamespace = class {
|
|
|
867
892
|
let done = false;
|
|
868
893
|
let pollTimer = null;
|
|
869
894
|
let pollInterval = null;
|
|
895
|
+
let unsubscribeResource = this.transport.subscribeToResource(resourceId2);
|
|
870
896
|
const cleanup = () => {
|
|
871
897
|
done = true;
|
|
872
898
|
if (pollTimer) {
|
|
@@ -877,6 +903,10 @@ var YieldNamespace = class {
|
|
|
877
903
|
clearInterval(pollInterval);
|
|
878
904
|
pollInterval = null;
|
|
879
905
|
}
|
|
906
|
+
if (unsubscribeResource) {
|
|
907
|
+
unsubscribeResource();
|
|
908
|
+
unsubscribeResource = null;
|
|
909
|
+
}
|
|
880
910
|
};
|
|
881
911
|
const resetPollTimer = (jid) => {
|
|
882
912
|
if (pollTimer) clearTimeout(pollTimer);
|
|
@@ -950,6 +980,7 @@ var YieldNamespace = class {
|
|
|
950
980
|
referenceId: annotationId2,
|
|
951
981
|
title: options.title,
|
|
952
982
|
prompt: options.prompt,
|
|
983
|
+
entityTypes: options.entityTypes,
|
|
953
984
|
language: options.language,
|
|
954
985
|
sourceLanguage: options.sourceLanguage,
|
|
955
986
|
temperature: options.temperature,
|
|
@@ -1041,6 +1072,9 @@ var FrameNamespace = class {
|
|
|
1041
1072
|
await this.transport.emit("frame:add-entity-type", { tag });
|
|
1042
1073
|
}
|
|
1043
1074
|
}
|
|
1075
|
+
async addTagSchema(schema) {
|
|
1076
|
+
await this.transport.emit("frame:add-tag-schema", { schema });
|
|
1077
|
+
}
|
|
1044
1078
|
};
|
|
1045
1079
|
|
|
1046
1080
|
// src/namespaces/job.ts
|