@abloatai/ablo 0.9.1 → 0.9.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/AGENTS.md +84 -0
- package/CHANGELOG.md +40 -0
- package/README.md +53 -27
- package/dist/BaseSyncedStore.d.ts +2 -36
- package/dist/BaseSyncedStore.js +11 -55
- package/dist/NetworkMonitor.js +4 -1
- package/dist/SyncClient.d.ts +22 -5
- package/dist/SyncClient.js +77 -0
- package/dist/SyncEngineContext.js +5 -1
- package/dist/agent/index.js +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/cli.cjs +302645 -0
- package/dist/client/Ablo.d.ts +19 -52
- package/dist/client/Ablo.js +30 -106
- package/dist/client/ApiClient.d.ts +1 -113
- package/dist/client/ApiClient.js +39 -238
- package/dist/client/auth.js +32 -2
- package/dist/client/createInternalComponents.js +1 -1
- package/dist/client/createModelProxy.d.ts +9 -0
- package/dist/client/createModelProxy.js +34 -10
- package/dist/client/httpClient.d.ts +5 -6
- package/dist/client/httpClient.js +2 -3
- package/dist/client/index.d.ts +1 -1
- package/dist/client/persistence.d.ts +6 -1
- package/dist/client/persistence.js +1 -1
- package/dist/client/registerDataSource.d.ts +4 -4
- package/dist/client/registerDataSource.js +39 -31
- package/dist/client/writeOptionsSchema.d.ts +50 -0
- package/dist/client/writeOptionsSchema.js +57 -0
- package/dist/core/index.d.ts +18 -26
- package/dist/core/index.js +22 -46
- package/dist/errorCodes.d.ts +13 -0
- package/dist/errorCodes.js +19 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -1
- package/dist/interfaces/index.d.ts +14 -4
- package/dist/mutators/UndoManager.d.ts +48 -5
- package/dist/mutators/UndoManager.js +166 -1
- package/dist/react/AbloProvider.d.ts +18 -8
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/useUndoScope.js +7 -0
- package/dist/schema/ddl.js +2 -1
- package/dist/schema/field.js +2 -1
- package/dist/schema/serialize.js +2 -1
- package/dist/server/commit.d.ts +4 -5
- package/dist/server/storage-mode.d.ts +7 -0
- package/dist/server/storage-mode.js +6 -0
- package/dist/source/adapters/drizzle.js +3 -2
- package/dist/source/adapters/kysely.d.ts +68 -0
- package/dist/source/adapters/kysely.js +210 -0
- package/dist/source/adapters/memory.js +2 -1
- package/dist/source/adapters/prisma.js +3 -2
- package/dist/source/index.js +2 -1
- package/dist/transactions/TransactionQueue.d.ts +6 -7
- package/dist/transactions/TransactionQueue.js +33 -9
- package/dist/types/streams.d.ts +2 -1
- package/dist/utils/duration.js +3 -2
- package/dist/wire/frames.d.ts +6 -8
- package/docs/api.md +1 -1
- package/docs/cli.md +17 -4
- package/docs/client-behavior.md +1 -1
- package/docs/data-sources.md +129 -125
- package/docs/examples/ai-sdk-tool.md +11 -5
- package/docs/examples/existing-python-backend.md +26 -4
- package/docs/examples/nextjs.md +3 -2
- package/docs/examples/scoped-agent.md +38 -11
- package/docs/guarantees.md +2 -2
- package/docs/identity.md +86 -59
- package/docs/index.md +2 -2
- package/docs/integration-guide.md +89 -61
- package/docs/mcp.md +1 -1
- package/docs/quickstart.md +84 -37
- package/docs/react.md +39 -28
- package/docs/schema-contract.md +2 -4
- package/llms-full.txt +360 -0
- package/llms.txt +30 -18
- package/package.json +23 -3
package/dist/client/Ablo.d.ts
CHANGED
|
@@ -28,22 +28,6 @@ import type { IntentStream, IntentWaitOptions, PresenceStream, Snapshot } from '
|
|
|
28
28
|
import type { ParticipantManager } from '../sync/participants.js';
|
|
29
29
|
import type { ActiveIntent, Duration, Intent, TargetRange } from '../types/streams.js';
|
|
30
30
|
import { type AbloApi, type AbloApiClientOptions, type AbloApiIntents } from './ApiClient.js';
|
|
31
|
-
/**
|
|
32
|
-
* Handle returned by `engine.beginTurn()`. While alive, every commit
|
|
33
|
-
* automatically carries this turn's id on the wire. Call `close(stats?)`
|
|
34
|
-
* when the turn finishes, or `dispose()` to abandon without recording
|
|
35
|
-
* usage. Idempotent.
|
|
36
|
-
*/
|
|
37
|
-
export interface Turn {
|
|
38
|
-
readonly turnId: string;
|
|
39
|
-
close(stats?: {
|
|
40
|
-
readonly costInputTokens?: number;
|
|
41
|
-
readonly costOutputTokens?: number;
|
|
42
|
-
readonly costComputeMs?: number;
|
|
43
|
-
}): Promise<void>;
|
|
44
|
-
dispose(): void;
|
|
45
|
-
[Symbol.asyncDispose](): Promise<void>;
|
|
46
|
-
}
|
|
47
31
|
/**
|
|
48
32
|
* Async function that resolves an apiKey at request time. Use for
|
|
49
33
|
* credential rotation — rotate from a vault, refresh from session
|
|
@@ -137,7 +121,7 @@ export interface AbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
137
121
|
* Local persistence mode. Pass `indexeddb` only when you want offline
|
|
138
122
|
* queueing and a reload-surviving browser cache.
|
|
139
123
|
*
|
|
140
|
-
* @default '
|
|
124
|
+
* @default 'memory'
|
|
141
125
|
*/
|
|
142
126
|
persistence?: AbloPersistence;
|
|
143
127
|
/**
|
|
@@ -266,7 +250,7 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
266
250
|
/** ObjectPool size limit (default: 10000) */
|
|
267
251
|
maxPoolSize?: number;
|
|
268
252
|
/**
|
|
269
|
-
* Local persistence mode. Defaults to `
|
|
253
|
+
* Local persistence mode. Defaults to `memory` so Ablo behaves like a
|
|
270
254
|
* point solution for shared state instead of silently bolting IndexedDB
|
|
271
255
|
* durability onto every browser consumer.
|
|
272
256
|
*
|
|
@@ -278,7 +262,7 @@ export interface InternalAbloOptions<S extends SchemaRecord = SchemaRecord> {
|
|
|
278
262
|
offline?: boolean;
|
|
279
263
|
/**
|
|
280
264
|
* @deprecated Internal/testing escape hatch. Use `persistence` in
|
|
281
|
-
* production code. `true` maps to `
|
|
265
|
+
* production code. `true` maps to `memory`; `false` maps to
|
|
282
266
|
* `indexeddb` in browsers.
|
|
283
267
|
*/
|
|
284
268
|
inMemory?: boolean;
|
|
@@ -479,6 +463,15 @@ export interface CommitCreateOptions {
|
|
|
479
463
|
readonly idempotencyKey?: string | null;
|
|
480
464
|
readonly readAt?: number | null;
|
|
481
465
|
readonly onStale?: 'reject' | 'force' | 'flag' | 'merge' | null;
|
|
466
|
+
/**
|
|
467
|
+
* A claim handle from `ablo.<model>.claim({ id })` (or the HTTP claim
|
|
468
|
+
* surface). Same vocabulary as the per-model writes: the handle's
|
|
469
|
+
* snapshot watermark becomes the batch `readAt` default and `onStale`
|
|
470
|
+
* defaults to `'reject'`, so a commit that follows a claim is guarded
|
|
471
|
+
* against concurrent edits without re-stating the watermark by hand.
|
|
472
|
+
* Explicit `readAt`/`onStale` on the options win.
|
|
473
|
+
*/
|
|
474
|
+
readonly claim?: ClaimHandle<Record<string, unknown>> | null;
|
|
482
475
|
readonly operation?: CommitOperationInput;
|
|
483
476
|
readonly operations?: readonly CommitOperationInput[];
|
|
484
477
|
readonly wait?: CommitWait;
|
|
@@ -809,10 +802,13 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
809
802
|
*/
|
|
810
803
|
readonly presence: PresenceStream;
|
|
811
804
|
/**
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
805
|
+
* @internal — the public coordination API is `ablo.<model>.claim`. This
|
|
806
|
+
* accessor is the internal stream `claim` is built on; it is NOT part of the
|
|
807
|
+
* supported public surface and will be moved off the public type (it currently
|
|
808
|
+
* stays only because internal SDK modules are still typed against it).
|
|
809
|
+
*
|
|
810
|
+
* Cooperative-mutex layer over presence — announce "I'm about to do X on Y" so
|
|
811
|
+
* peers can yield before colliding. Same socket as entity sync.
|
|
816
812
|
*/
|
|
817
813
|
readonly intents: IntentResource;
|
|
818
814
|
/**
|
|
@@ -861,18 +857,6 @@ export type Ablo<S extends SchemaRecord> = {
|
|
|
861
857
|
snapshot<ModelName extends keyof S & string>(entities: {
|
|
862
858
|
readonly [M in ModelName]: string | readonly string[];
|
|
863
859
|
}): Snapshot<Schema<S>, ModelName>;
|
|
864
|
-
/**
|
|
865
|
-
* Open a turn — every commit issued while the returned handle is
|
|
866
|
-
* alive carries `caused_by_task_id` on the wire so the server
|
|
867
|
-
* stamps it onto each delta. Powers `agent_tasks` audit trails.
|
|
868
|
-
* Server: `POST /api/agent/turn` with the capability bearer.
|
|
869
|
-
*/
|
|
870
|
-
beginTurn(options: {
|
|
871
|
-
readonly prompt: string;
|
|
872
|
-
readonly parentTaskId?: string;
|
|
873
|
-
readonly surface?: string;
|
|
874
|
-
readonly metadata?: Record<string, unknown>;
|
|
875
|
-
}): Promise<Turn>;
|
|
876
860
|
/**
|
|
877
861
|
* The internal BaseSyncedStore. Implements SyncStoreContract — pass to
|
|
878
862
|
* SyncContext.Provider so the SDK's useModel/useModels/useMutations hooks
|
|
@@ -973,17 +957,6 @@ export declare namespace Ablo {
|
|
|
973
957
|
type Options<S extends SchemaRecord = SchemaRecord> = AbloOptions<S>;
|
|
974
958
|
type Api = AbloApi;
|
|
975
959
|
type ApiIntents = AbloApiIntents;
|
|
976
|
-
type Agent = import('./ApiClient.js').Agent;
|
|
977
|
-
type AgentOptions = import('./ApiClient.js').AgentOptions;
|
|
978
|
-
type AgentRunOptions = import('./ApiClient.js').AgentRunOptions;
|
|
979
|
-
type AgentRunStatus = import('./ApiClient.js').AgentRunStatus;
|
|
980
|
-
type AgentRunResult<T> = import('./ApiClient.js').AgentRunResult<T>;
|
|
981
|
-
type AgentRunContext = import('./ApiClient.js').AgentRunContext;
|
|
982
|
-
type AgentModelClient<T = Record<string, unknown>> = import('./ApiClient.js').AgentModelClient<T>;
|
|
983
|
-
type AgentModelReadOptions = import('./ApiClient.js').AgentModelReadOptions;
|
|
984
|
-
type AgentModelMutationOptions = import('./ApiClient.js').AgentModelMutationOptions;
|
|
985
|
-
type AgentIntentOptions = import('./ApiClient.js').AgentIntentOptions;
|
|
986
|
-
type AgentIntentInput = import('./ApiClient.js').AgentIntentInput;
|
|
987
960
|
type Capability = import('./ApiClient.js').Capability;
|
|
988
961
|
type CapabilityCreateOptions = import('./ApiClient.js').CapabilityCreateOptions;
|
|
989
962
|
type CapabilityRecord = import('./ApiClient.js').CapabilityRecord;
|
|
@@ -991,11 +964,6 @@ export declare namespace Ablo {
|
|
|
991
964
|
type CapabilityRevocation = import('./ApiClient.js').CapabilityRevocation;
|
|
992
965
|
type CapabilityRotateOptions = import('./ApiClient.js').CapabilityRotateOptions;
|
|
993
966
|
type RotatedCapability = import('./ApiClient.js').RotatedCapability;
|
|
994
|
-
type Task = import('./ApiClient.js').Task;
|
|
995
|
-
type TaskCreateOptions = import('./ApiClient.js').TaskCreateOptions;
|
|
996
|
-
type TaskCloseOptions = import('./ApiClient.js').TaskCloseOptions;
|
|
997
|
-
type TaskCloseResult = import('./ApiClient.js').TaskCloseResult;
|
|
998
|
-
type TaskResource = import('./ApiClient.js').TaskResource;
|
|
999
967
|
type IfClaimedPolicy = import('./Ablo.js').IfClaimedPolicy;
|
|
1000
968
|
type ClaimedOptions = import('./Ablo.js').ClaimedOptions;
|
|
1001
969
|
type EntityRef = _Streams.EntityRef;
|
|
@@ -1011,7 +979,6 @@ export declare namespace Ablo {
|
|
|
1011
979
|
type IntentRejection = _Streams.IntentRejection;
|
|
1012
980
|
type IntentLost = _Streams.IntentLost;
|
|
1013
981
|
type Snapshot<TSchema extends _SchemaTypes.Schema = _SchemaTypes.Schema, K extends keyof TSchema['models'] = keyof TSchema['models']> = _Streams.Snapshot<TSchema, K>;
|
|
1014
|
-
type Turn = import('./Ablo.js').Turn;
|
|
1015
982
|
namespace Auth {
|
|
1016
983
|
type Principal = _Streams.Principal;
|
|
1017
984
|
type Session = _Streams.SessionRef;
|
package/dist/client/Ablo.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* await sync.reports.delete({ id: reportId });
|
|
20
20
|
*/
|
|
21
21
|
import { z } from 'zod';
|
|
22
|
-
import { AbloClaimedError, AbloError, AbloAuthenticationError, AbloConnectionError, AbloValidationError, translateHttpError,
|
|
22
|
+
import { AbloClaimedError, AbloError, AbloAuthenticationError, AbloConnectionError, AbloValidationError, translateHttpError, toAbloError } from '../errors.js';
|
|
23
23
|
import { LoadStrategy, PropertyType } from '../types/index.js';
|
|
24
24
|
import { initSyncEngine } from '../context.js';
|
|
25
25
|
import { noopObservability, browserOnlineStatus, defaultSessionErrorDetector, noopAnalytics, } from '../SyncEngineContext.js';
|
|
@@ -41,6 +41,7 @@ import { assertBrowserSafety, readProcessEnv, resolveApiKey, resolveApiKeyValue,
|
|
|
41
41
|
import { registerDataSource } from './registerDataSource.js';
|
|
42
42
|
import { shouldUseInMemoryPersistence, } from './persistence.js';
|
|
43
43
|
import { createModelProxy } from './createModelProxy.js';
|
|
44
|
+
import { assertWriteOptions } from './writeOptionsSchema.js';
|
|
44
45
|
// ── Config derivation from schema ─────────────────────────────────────────
|
|
45
46
|
/**
|
|
46
47
|
* Compute a create-priority map from schema `belongsTo` relations using
|
|
@@ -812,13 +813,6 @@ export function Ablo(options) {
|
|
|
812
813
|
// becomes null, so the first Ablo's commits start throwing
|
|
813
814
|
// `ws_not_ready` forever (terminal AgentJob writes hang on retry).
|
|
814
815
|
syncClient.getTransactionQueue().setMutationExecutor(executor);
|
|
815
|
-
// Active turn id, set by `beginTurn(...)`, cleared on close. While
|
|
816
|
-
// set, every batch commit attaches `causedByTaskId` so server
|
|
817
|
-
// delta rows get stamped with it. Single-turn-at-a-time per Ablo
|
|
818
|
-
// — opening a second turn overwrites the active id without closing
|
|
819
|
-
// the prior. Callers who need parallel turns construct multiple
|
|
820
|
-
// Ablo instances, matching the SyncAgent semantics.
|
|
821
|
-
let activeTurnId = null;
|
|
822
816
|
// Presence + intent streams — built eagerly so `engine.presence`
|
|
823
817
|
// and `engine.intents` return the same reference for the engine's
|
|
824
818
|
// lifetime. The transport doesn't exist yet (BaseSyncedStore.initialize
|
|
@@ -1072,6 +1066,12 @@ export function Ablo(options) {
|
|
|
1072
1066
|
return intent;
|
|
1073
1067
|
return intent?.id;
|
|
1074
1068
|
}
|
|
1069
|
+
function isClaimHandleValue(value) {
|
|
1070
|
+
return (typeof value === 'object' &&
|
|
1071
|
+
value !== null &&
|
|
1072
|
+
value.object === 'claim' &&
|
|
1073
|
+
typeof value.claimId === 'string');
|
|
1074
|
+
}
|
|
1075
1075
|
function normalizeCommitOperation(op, defaults) {
|
|
1076
1076
|
const model = op.model ?? op.target?.model;
|
|
1077
1077
|
if (!model) {
|
|
@@ -1348,10 +1348,26 @@ export function Ablo(options) {
|
|
|
1348
1348
|
const commits = {
|
|
1349
1349
|
async create(commitOptions) {
|
|
1350
1350
|
await ready();
|
|
1351
|
+
// Same runtime contract as the per-model writes — one schema.
|
|
1352
|
+
assertWriteOptions({
|
|
1353
|
+
idempotencyKey: commitOptions.idempotencyKey,
|
|
1354
|
+
readAt: commitOptions.readAt,
|
|
1355
|
+
onStale: commitOptions.onStale,
|
|
1356
|
+
wait: commitOptions.wait,
|
|
1357
|
+
intent: commitOptions.intent,
|
|
1358
|
+
}, 'commits.create');
|
|
1351
1359
|
const clientTxId = createClientTxId(commitOptions.idempotencyKey);
|
|
1352
|
-
|
|
1360
|
+
// A claim handle supplies the batch stale-guard defaults — same
|
|
1361
|
+
// semantics as `ablo.<model>.update({ id, data, claim })`, so the
|
|
1362
|
+
// two write doors speak one claim vocabulary. Explicit options win.
|
|
1363
|
+
const claim = commitOptions.claim ?? null;
|
|
1364
|
+
const operations = normalizeCommitOperations({
|
|
1365
|
+
...commitOptions,
|
|
1366
|
+
readAt: commitOptions.readAt ?? claim?.readAt ?? null,
|
|
1367
|
+
onStale: commitOptions.onStale ?? (claim?.readAt !== undefined ? 'reject' : null),
|
|
1368
|
+
});
|
|
1353
1369
|
const wait = commitOptions.wait ?? 'confirmed';
|
|
1354
|
-
const intentId = normalizeIntentId(commitOptions.intent);
|
|
1370
|
+
const intentId = normalizeIntentId(commitOptions.intent) ?? claim?.claimId;
|
|
1355
1371
|
void intentId; // The current wire clears intents by entity after commit.
|
|
1356
1372
|
// Route through the TransactionQueue's commit lane so the call
|
|
1357
1373
|
// tolerates WS disconnects: the envelope stays in memory until
|
|
@@ -1363,9 +1379,7 @@ export function Ablo(options) {
|
|
|
1363
1379
|
// SyncClient we already hold from createInternalComponents —
|
|
1364
1380
|
// no need to leak an accessor through BaseSyncedStore.
|
|
1365
1381
|
const queue = syncClient.getTransactionQueue();
|
|
1366
|
-
queue.enqueueCommit(clientTxId, operations
|
|
1367
|
-
causedByTaskId: activeTurnId,
|
|
1368
|
-
});
|
|
1382
|
+
queue.enqueueCommit(clientTxId, operations);
|
|
1369
1383
|
if (wait === 'queued') {
|
|
1370
1384
|
return { id: clientTxId, status: 'queued' };
|
|
1371
1385
|
}
|
|
@@ -1431,6 +1445,7 @@ export function Ablo(options) {
|
|
|
1431
1445
|
idempotencyKey: params.idempotencyKey,
|
|
1432
1446
|
readAt: params.readAt,
|
|
1433
1447
|
onStale: params.onStale,
|
|
1448
|
+
...(isClaimHandleValue(params.claim) ? { claim: params.claim } : {}),
|
|
1434
1449
|
wait: params.wait,
|
|
1435
1450
|
operations: [
|
|
1436
1451
|
{
|
|
@@ -1449,6 +1464,7 @@ export function Ablo(options) {
|
|
|
1449
1464
|
idempotencyKey: params.idempotencyKey,
|
|
1450
1465
|
readAt: params.readAt,
|
|
1451
1466
|
onStale: params.onStale,
|
|
1467
|
+
...(isClaimHandleValue(params.claim) ? { claim: params.claim } : {}),
|
|
1452
1468
|
wait: params.wait,
|
|
1453
1469
|
operations: [
|
|
1454
1470
|
{
|
|
@@ -1467,6 +1483,7 @@ export function Ablo(options) {
|
|
|
1467
1483
|
idempotencyKey: params.idempotencyKey,
|
|
1468
1484
|
readAt: params.readAt,
|
|
1469
1485
|
onStale: params.onStale,
|
|
1486
|
+
...(isClaimHandleValue(params.claim) ? { claim: params.claim } : {}),
|
|
1470
1487
|
wait: params.wait,
|
|
1471
1488
|
operations: [
|
|
1472
1489
|
{
|
|
@@ -1638,99 +1655,6 @@ export function Ablo(options) {
|
|
|
1638
1655
|
entities,
|
|
1639
1656
|
});
|
|
1640
1657
|
},
|
|
1641
|
-
// ── Turn handles ────────────────────────────────────────────────
|
|
1642
|
-
//
|
|
1643
|
-
// Open a turn — every commit issued while the returned handle is
|
|
1644
|
-
// alive carries `caused_by_task_id` on the wire so the server
|
|
1645
|
-
// stamps it onto each delta. The product surface this powers:
|
|
1646
|
-
// `agent_tasks` audit trails ("which AI prompt produced this
|
|
1647
|
-
// mutation"), parent/child turn chains, cost accounting per turn.
|
|
1648
|
-
//
|
|
1649
|
-
// POST /api/agent/turn (capability bearer) → returns turnId.
|
|
1650
|
-
// POST /api/agent/turn/:id/close (capability bearer) → records
|
|
1651
|
-
// final cost stats. Idempotent.
|
|
1652
|
-
async beginTurn(beginOptions) {
|
|
1653
|
-
const baseUrl = url.replace(/\/+$/, '');
|
|
1654
|
-
const turnUrl = `${baseUrl.replace(/^ws/, 'http')}/api/agent/turn`;
|
|
1655
|
-
const headers = authCredentials.withAuthHeaders({ 'Content-Type': 'application/json' });
|
|
1656
|
-
const res = await fetch(turnUrl, {
|
|
1657
|
-
method: 'POST',
|
|
1658
|
-
headers,
|
|
1659
|
-
body: JSON.stringify({
|
|
1660
|
-
prompt: beginOptions.prompt,
|
|
1661
|
-
parentTaskId: beginOptions.parentTaskId,
|
|
1662
|
-
surface: beginOptions.surface,
|
|
1663
|
-
metadata: beginOptions.metadata,
|
|
1664
|
-
}),
|
|
1665
|
-
});
|
|
1666
|
-
if (!res.ok) {
|
|
1667
|
-
const text = await res.text().catch(() => '');
|
|
1668
|
-
let parsed = text;
|
|
1669
|
-
if (text) {
|
|
1670
|
-
try {
|
|
1671
|
-
parsed = JSON.parse(text);
|
|
1672
|
-
}
|
|
1673
|
-
catch {
|
|
1674
|
-
/* keep raw text */
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
// Preserve the server's structured envelope (code/message/doc_url) when
|
|
1678
|
-
// present; fall back to turn_open_failed for a bare/non-Ablo body.
|
|
1679
|
-
throw hasWireCode(parsed)
|
|
1680
|
-
? translateHttpError(res.status, parsed, res.headers.get('x-request-id') ?? undefined)
|
|
1681
|
-
: new AbloError(`beginTurn failed: ${res.status} ${text}`, {
|
|
1682
|
-
code: 'turn_open_failed',
|
|
1683
|
-
httpStatus: res.status,
|
|
1684
|
-
});
|
|
1685
|
-
}
|
|
1686
|
-
const json = (await res.json());
|
|
1687
|
-
const turnId = json.turnId;
|
|
1688
|
-
activeTurnId = turnId;
|
|
1689
|
-
let closed = false;
|
|
1690
|
-
const close = async (stats) => {
|
|
1691
|
-
if (closed)
|
|
1692
|
-
return;
|
|
1693
|
-
closed = true;
|
|
1694
|
-
if (activeTurnId === turnId)
|
|
1695
|
-
activeTurnId = null;
|
|
1696
|
-
const closeUrl = `${turnUrl}/${encodeURIComponent(turnId)}/close`;
|
|
1697
|
-
const closeRes = await fetch(closeUrl, {
|
|
1698
|
-
method: 'POST',
|
|
1699
|
-
headers,
|
|
1700
|
-
body: JSON.stringify({
|
|
1701
|
-
costInputTokens: stats?.costInputTokens ?? 0,
|
|
1702
|
-
costOutputTokens: stats?.costOutputTokens ?? 0,
|
|
1703
|
-
costComputeMs: stats?.costComputeMs ?? 0,
|
|
1704
|
-
}),
|
|
1705
|
-
});
|
|
1706
|
-
if (!closeRes.ok) {
|
|
1707
|
-
const text = await closeRes.text().catch(() => '');
|
|
1708
|
-
let parsed = text;
|
|
1709
|
-
if (text) {
|
|
1710
|
-
try {
|
|
1711
|
-
parsed = JSON.parse(text);
|
|
1712
|
-
}
|
|
1713
|
-
catch {
|
|
1714
|
-
/* keep raw text */
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
throw hasWireCode(parsed)
|
|
1718
|
-
? translateHttpError(closeRes.status, parsed, closeRes.headers.get('x-request-id') ?? undefined)
|
|
1719
|
-
: new AbloError(`closeTurn failed: ${closeRes.status} ${text}`, {
|
|
1720
|
-
code: 'turn_close_failed',
|
|
1721
|
-
httpStatus: closeRes.status,
|
|
1722
|
-
});
|
|
1723
|
-
}
|
|
1724
|
-
};
|
|
1725
|
-
const dispose = () => {
|
|
1726
|
-
if (closed)
|
|
1727
|
-
return;
|
|
1728
|
-
closed = true;
|
|
1729
|
-
if (activeTurnId === turnId)
|
|
1730
|
-
activeTurnId = null;
|
|
1731
|
-
};
|
|
1732
|
-
return { turnId, close, dispose, [Symbol.asyncDispose]: () => close() };
|
|
1733
|
-
},
|
|
1734
1658
|
};
|
|
1735
1659
|
return engine;
|
|
1736
1660
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* IndexedDB, no WebSocket. It maps the public Model / Claim / Commit
|
|
6
6
|
* nouns directly to HTTP routes on sync-server.
|
|
7
7
|
*/
|
|
8
|
-
import type { AbloOptions,
|
|
8
|
+
import type { AbloOptions, CommitResource, IntentCreateOptions, IntentHandle, IntentWaitOptions, ModelClient, ModelClaim, ModelTarget } from './Ablo.js';
|
|
9
9
|
import type { Duration } from '../utils/duration.js';
|
|
10
10
|
export type AbloApiClientOptions = Omit<AbloOptions, 'schema'> & {
|
|
11
11
|
readonly schema?: null | undefined;
|
|
@@ -115,127 +115,15 @@ export interface CapabilityResource {
|
|
|
115
115
|
*/
|
|
116
116
|
mint(options: CapabilityCreateOptions): Promise<Capability>;
|
|
117
117
|
}
|
|
118
|
-
export interface TaskCreateOptions {
|
|
119
|
-
readonly prompt: string;
|
|
120
|
-
readonly parentTaskId?: string;
|
|
121
|
-
readonly surface?: string;
|
|
122
|
-
readonly metadata?: Record<string, unknown>;
|
|
123
|
-
}
|
|
124
|
-
export interface TaskCloseOptions {
|
|
125
|
-
readonly costInputTokens?: number;
|
|
126
|
-
readonly costOutputTokens?: number;
|
|
127
|
-
readonly costComputeMs?: number;
|
|
128
|
-
}
|
|
129
|
-
export interface Task {
|
|
130
|
-
readonly id: string;
|
|
131
|
-
readonly turnId: string;
|
|
132
|
-
readonly promptHash?: string;
|
|
133
|
-
readonly openedAt?: string;
|
|
134
|
-
close(stats?: TaskCloseOptions): Promise<TaskCloseResult>;
|
|
135
|
-
}
|
|
136
|
-
export interface TaskCloseResult {
|
|
137
|
-
readonly id: string;
|
|
138
|
-
readonly turnId: string;
|
|
139
|
-
readonly closed: boolean;
|
|
140
|
-
readonly alreadyClosed?: boolean;
|
|
141
|
-
readonly endedAt?: string;
|
|
142
|
-
}
|
|
143
|
-
export interface TaskResource {
|
|
144
|
-
create(options: TaskCreateOptions): Promise<Task>;
|
|
145
|
-
close(id: string, stats?: TaskCloseOptions): Promise<TaskCloseResult>;
|
|
146
|
-
/**
|
|
147
|
-
* Alias for `create`. Kept for the agent-run vocabulary; `create` is
|
|
148
|
-
* the canonical SDK verb.
|
|
149
|
-
*/
|
|
150
|
-
open(options: TaskCreateOptions): Promise<Task>;
|
|
151
|
-
}
|
|
152
|
-
export interface AgentOptions {
|
|
153
|
-
readonly can: readonly string[];
|
|
154
|
-
readonly syncGroups?: readonly string[];
|
|
155
|
-
readonly label?: string;
|
|
156
|
-
readonly userMeta?: Record<string, unknown>;
|
|
157
|
-
/**
|
|
158
|
-
* Internal lease for the run capability. Most callers should omit it.
|
|
159
|
-
* The SDK revokes the capability when `run` finishes; the lease exists
|
|
160
|
-
* to clean up crashed or abandoned runs.
|
|
161
|
-
*/
|
|
162
|
-
readonly lease?: Duration;
|
|
163
|
-
readonly leaseSeconds?: number;
|
|
164
|
-
}
|
|
165
|
-
export interface AgentRunOptions extends TaskCreateOptions {
|
|
166
|
-
readonly signal?: AbortSignal;
|
|
167
|
-
readonly costInputTokens?: number;
|
|
168
|
-
readonly costOutputTokens?: number;
|
|
169
|
-
readonly costComputeMs?: number;
|
|
170
|
-
}
|
|
171
|
-
export type AgentRunStatus = 'done' | 'failed' | 'cancelled';
|
|
172
|
-
export interface AgentRunDone<T> {
|
|
173
|
-
readonly status: 'done';
|
|
174
|
-
readonly task: Task;
|
|
175
|
-
readonly value: T;
|
|
176
|
-
}
|
|
177
|
-
export interface AgentRunFailed {
|
|
178
|
-
readonly status: 'failed';
|
|
179
|
-
readonly task?: Task;
|
|
180
|
-
readonly error: unknown;
|
|
181
|
-
}
|
|
182
|
-
export interface AgentRunCancelled {
|
|
183
|
-
readonly status: 'cancelled';
|
|
184
|
-
readonly task?: Task;
|
|
185
|
-
readonly error?: unknown;
|
|
186
|
-
}
|
|
187
|
-
export type AgentRunResult<T> = AgentRunDone<T> | AgentRunFailed | AgentRunCancelled;
|
|
188
|
-
export interface AgentIntentOptions {
|
|
189
|
-
readonly action: string;
|
|
190
|
-
readonly field?: string;
|
|
191
|
-
readonly ttl?: Duration;
|
|
192
|
-
readonly target?: Partial<ModelTarget>;
|
|
193
|
-
}
|
|
194
|
-
export type AgentIntentInput = string | AgentIntentOptions;
|
|
195
|
-
export interface AgentModelReadOptions extends ModelReadOptions {
|
|
196
|
-
}
|
|
197
|
-
export interface AgentModelMutationOptions extends Omit<ModelMutationOptions, 'intent'> {
|
|
198
|
-
readonly intent?: AgentIntentInput | {
|
|
199
|
-
readonly id: string;
|
|
200
|
-
} | null;
|
|
201
|
-
}
|
|
202
|
-
export interface AgentModelClient<T = Record<string, unknown>> {
|
|
203
|
-
retrieve(params: AgentModelReadOptions & {
|
|
204
|
-
readonly id: string;
|
|
205
|
-
}): Promise<ModelRead<T>>;
|
|
206
|
-
create(params: AgentModelMutationOptions & {
|
|
207
|
-
readonly data: Record<string, unknown>;
|
|
208
|
-
readonly id?: string | null;
|
|
209
|
-
}): Promise<CommitReceipt>;
|
|
210
|
-
update(params: AgentModelMutationOptions & {
|
|
211
|
-
readonly id: string;
|
|
212
|
-
readonly data: Record<string, unknown>;
|
|
213
|
-
}): Promise<CommitReceipt>;
|
|
214
|
-
delete(params: AgentModelMutationOptions & {
|
|
215
|
-
readonly id: string;
|
|
216
|
-
}): Promise<CommitReceipt>;
|
|
217
|
-
}
|
|
218
|
-
export interface AgentRunContext {
|
|
219
|
-
readonly task: Task;
|
|
220
|
-
readonly ablo: AbloApi;
|
|
221
|
-
model<T = Record<string, unknown>>(name: string): AgentModelClient<T>;
|
|
222
|
-
}
|
|
223
|
-
export interface Agent {
|
|
224
|
-
readonly id: string;
|
|
225
|
-
run<T>(options: AgentRunOptions, handler: (context: AgentRunContext) => Promise<T> | T): Promise<AgentRunResult<T>>;
|
|
226
|
-
}
|
|
227
118
|
export interface AbloApi {
|
|
228
119
|
ready(): Promise<void>;
|
|
229
120
|
waitForFlush(): Promise<void>;
|
|
230
121
|
dispose(): Promise<void>;
|
|
231
122
|
purge(): Promise<void>;
|
|
232
123
|
readonly capabilities: CapabilityResource;
|
|
233
|
-
readonly tasks: TaskResource;
|
|
234
124
|
readonly intents: AbloApiIntents;
|
|
235
125
|
readonly commits: CommitResource;
|
|
236
|
-
agent(id: string, options: AgentOptions): Agent;
|
|
237
126
|
model<T = Record<string, unknown>>(name: string): ModelClient<T>;
|
|
238
|
-
beginTurn(options: TaskCreateOptions): Promise<Turn>;
|
|
239
127
|
/**
|
|
240
128
|
* Resolve the active bearer credential this client authenticates with — the
|
|
241
129
|
* same token its own requests carry in `Authorization`. Returns `null` when
|