@alisio/sdk 0.2.1 → 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/index.d.ts +209 -1
- package/dist/index.js +69 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -489,6 +489,11 @@ export interface ToolContext {
|
|
|
489
489
|
* (headless, `--read-only`), because no flag grants an installation.
|
|
490
490
|
*/
|
|
491
491
|
approveInstall?: InstallApprover;
|
|
492
|
+
/**
|
|
493
|
+
* Decision Intelligence, consumer side, bound by the host to the current run. Absent when the
|
|
494
|
+
* host does not offer it: feature-detect with `context.decisions?.tryDecide(...)`.
|
|
495
|
+
*/
|
|
496
|
+
decisions?: ToolDecisions;
|
|
492
497
|
}
|
|
493
498
|
export interface ToolDefinition {
|
|
494
499
|
name: string;
|
|
@@ -761,6 +766,32 @@ export interface RunEventDataMap {
|
|
|
761
766
|
error: string;
|
|
762
767
|
continued: true;
|
|
763
768
|
};
|
|
769
|
+
/** A Decision Intelligence call that produced usable answers. Metadata only, never the state. */
|
|
770
|
+
decision_completed: {
|
|
771
|
+
decisionId: string;
|
|
772
|
+
pack?: {
|
|
773
|
+
id: string;
|
|
774
|
+
version: number;
|
|
775
|
+
};
|
|
776
|
+
provider: string;
|
|
777
|
+
latencyMs: number;
|
|
778
|
+
/** Accepted answers. */
|
|
779
|
+
decisionCount: number;
|
|
780
|
+
rejectedCount: number;
|
|
781
|
+
/** Lowest confidence among the accepted answers. */
|
|
782
|
+
confidenceMin: number;
|
|
783
|
+
};
|
|
784
|
+
/** A Decision Intelligence call that fell back to the consumer's deterministic default. */
|
|
785
|
+
decision_fallback: {
|
|
786
|
+
decisionId: string;
|
|
787
|
+
pack?: {
|
|
788
|
+
id: string;
|
|
789
|
+
version: number;
|
|
790
|
+
};
|
|
791
|
+
provider: string;
|
|
792
|
+
latencyMs: number;
|
|
793
|
+
reason: DecisionFallbackReason;
|
|
794
|
+
};
|
|
764
795
|
}
|
|
765
796
|
/** Every `RunEvent.type` the core emits today. `RunEvent.type` itself stays `string`. */
|
|
766
797
|
export type RunEventType = keyof RunEventDataMap;
|
|
@@ -908,8 +939,9 @@ export interface MascotProvider {
|
|
|
908
939
|
* - `"mcp"` — MCP-server management or bundling helpers.
|
|
909
940
|
* - `"storage"` — durable storage backends beyond the default SQLite state.
|
|
910
941
|
* - `"ui"` — TUI presentation providers (startup screens, mascots, panels).
|
|
942
|
+
* - `"decisions"` — Decision Intelligence providers (`api.decisions.registerProvider`).
|
|
911
943
|
*/
|
|
912
|
-
export type PluginCategory = "model-provider" | "methodology-harness" | "memory" | "subagents" | "search" | "tools" | "security" | "analytics" | "mcp" | "storage" | "ui";
|
|
944
|
+
export type PluginCategory = "model-provider" | "methodology-harness" | "memory" | "subagents" | "search" | "tools" | "security" | "analytics" | "mcp" | "storage" | "ui" | "decisions";
|
|
913
945
|
export interface PluginMetadata {
|
|
914
946
|
id: string;
|
|
915
947
|
version: string;
|
|
@@ -1324,6 +1356,163 @@ export declare class ViewParamsError extends Error {
|
|
|
1324
1356
|
readonly code = "view_invalid_params";
|
|
1325
1357
|
constructor(message?: string);
|
|
1326
1358
|
}
|
|
1359
|
+
export interface DecisionsApi {
|
|
1360
|
+
/** Registers a provider (does NOT activate it; activation is `decisions.provider` in config). */
|
|
1361
|
+
registerProvider(provider: DecisionProvider): () => void;
|
|
1362
|
+
/** True when decisions are enabled and the configured provider is registered. */
|
|
1363
|
+
available(): boolean;
|
|
1364
|
+
activeProvider(): {
|
|
1365
|
+
id: string;
|
|
1366
|
+
name: string;
|
|
1367
|
+
} | null;
|
|
1368
|
+
/**
|
|
1369
|
+
* Never throws for infrastructure problems: resolves null (disabled, no provider, timeout,
|
|
1370
|
+
* provider error, circuit open, or every answer rejected). Throws `DecisionRequestError` (a
|
|
1371
|
+
* `TypeError`) for a malformed request and rethrows an abort requested by the caller.
|
|
1372
|
+
*/
|
|
1373
|
+
tryDecide(request: DecisionRequest, options?: DecisionOptions): Promise<DecisionResponse | null>;
|
|
1374
|
+
}
|
|
1375
|
+
/** What a tool receives in `ToolContext.decisions`: the consumer side, bound to the run. */
|
|
1376
|
+
export type ToolDecisions = Omit<DecisionsApi, "registerProvider">;
|
|
1377
|
+
export interface DecisionProvider {
|
|
1378
|
+
/** `^[a-z0-9][a-z0-9.-]{0,63}$`, unique among registered providers. */
|
|
1379
|
+
id: string;
|
|
1380
|
+
name: string;
|
|
1381
|
+
capabilities: {
|
|
1382
|
+
select: boolean;
|
|
1383
|
+
boolean: boolean;
|
|
1384
|
+
ordinal: boolean;
|
|
1385
|
+
};
|
|
1386
|
+
/** Called ONLY by `/decisions` (own 1 s timeout), never on the decide path. */
|
|
1387
|
+
health?(signal?: AbortSignal): Promise<{
|
|
1388
|
+
status: "ready" | "starting" | "unavailable";
|
|
1389
|
+
detail?: string;
|
|
1390
|
+
}>;
|
|
1391
|
+
/** Called when this provider becomes the active one. Bounded, never fatal, never awaited at startup. Cold start belongs here. */
|
|
1392
|
+
activate?(): void | Promise<void>;
|
|
1393
|
+
/** Called when it stops being the active one (config change, unregister, shutdown). */
|
|
1394
|
+
deactivate?(): void | Promise<void>;
|
|
1395
|
+
/** Fail fast with `DecisionProviderError("not_ready" | "unavailable")` instead of waiting. */
|
|
1396
|
+
decide(request: DecisionRequest, context: {
|
|
1397
|
+
signal: AbortSignal;
|
|
1398
|
+
timeoutMs: number;
|
|
1399
|
+
}): Promise<DecisionProviderResult>;
|
|
1400
|
+
}
|
|
1401
|
+
export interface DecisionRequest {
|
|
1402
|
+
version: 1;
|
|
1403
|
+
/** BCP 47 hint (for example "es-CO"); providers may ignore it. */
|
|
1404
|
+
language?: string;
|
|
1405
|
+
/** Non-sensitive call-site label (becomes `decisionId` in events), for example "smart-dashboard-v1". Never data-derived. */
|
|
1406
|
+
id: string;
|
|
1407
|
+
pack?: {
|
|
1408
|
+
id: string;
|
|
1409
|
+
version: number;
|
|
1410
|
+
};
|
|
1411
|
+
/** JSON sent to the provider. Keep it minimal; a provider may be remote. At most 16 KB serialized (the whole request at most 32 KB). */
|
|
1412
|
+
state: JsonValue;
|
|
1413
|
+
/** 1..16 decisions keyed by `^[A-Za-z][A-Za-z0-9_]{0,63}$`. */
|
|
1414
|
+
decisions: Record<string, DecisionDefinition>;
|
|
1415
|
+
}
|
|
1416
|
+
export type DecisionDefinition = {
|
|
1417
|
+
type: "select";
|
|
1418
|
+
instruction: string;
|
|
1419
|
+
options: Record<string, string>;
|
|
1420
|
+
} | {
|
|
1421
|
+
type: "boolean";
|
|
1422
|
+
instruction: string;
|
|
1423
|
+
trueMeaning?: string;
|
|
1424
|
+
falseMeaning?: string;
|
|
1425
|
+
} | {
|
|
1426
|
+
type: "ordinal";
|
|
1427
|
+
instruction: string;
|
|
1428
|
+
levels: string[];
|
|
1429
|
+
};
|
|
1430
|
+
/**
|
|
1431
|
+
* `confidence` is the provider's best estimate, in [0,1], that the answer is correct. The core does
|
|
1432
|
+
* not assume it is calibrated: `minConfidence` is a heuristic filter. Each adapter chooses which
|
|
1433
|
+
* native field feeds it.
|
|
1434
|
+
*/
|
|
1435
|
+
export type DecisionAnswer = {
|
|
1436
|
+
type: "select";
|
|
1437
|
+
value: string;
|
|
1438
|
+
confidence: number;
|
|
1439
|
+
probabilities?: Record<string, number>;
|
|
1440
|
+
} | {
|
|
1441
|
+
type: "boolean";
|
|
1442
|
+
value: boolean;
|
|
1443
|
+
confidence: number;
|
|
1444
|
+
probability: number;
|
|
1445
|
+
} | {
|
|
1446
|
+
type: "ordinal";
|
|
1447
|
+
level: string;
|
|
1448
|
+
index: number;
|
|
1449
|
+
confidence: number;
|
|
1450
|
+
distribution?: number[];
|
|
1451
|
+
};
|
|
1452
|
+
export interface DecisionProviderResult {
|
|
1453
|
+
decisions: Record<string, DecisionAnswer>;
|
|
1454
|
+
usage?: {
|
|
1455
|
+
inputUnits?: number;
|
|
1456
|
+
outputUnits?: number;
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
export interface DecisionOptions {
|
|
1460
|
+
/** Default: config `decisions.timeoutMs`. */
|
|
1461
|
+
timeoutMs?: number;
|
|
1462
|
+
/** Default: config `decisions.minConfidence`. */
|
|
1463
|
+
minConfidence?: number;
|
|
1464
|
+
signal?: AbortSignal;
|
|
1465
|
+
}
|
|
1466
|
+
export type DecisionRejection = "low_confidence" | "invalid" | "unsupported" | "missing";
|
|
1467
|
+
export interface DecisionResponse {
|
|
1468
|
+
provider: string;
|
|
1469
|
+
latencyMs: number;
|
|
1470
|
+
/** Only validated answers that reached `minConfidence`. */
|
|
1471
|
+
decisions: Record<string, DecisionAnswer>;
|
|
1472
|
+
rejected: Record<string, DecisionRejection>;
|
|
1473
|
+
usage?: {
|
|
1474
|
+
inputUnits?: number;
|
|
1475
|
+
outputUnits?: number;
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
export type DecisionFallbackReason = "timeout" | "not_ready" | "unavailable" | "invalid_response" | "provider_error" | "circuit_open" | "unsupported" | "all_rejected";
|
|
1479
|
+
export type DecisionProviderErrorCode = "not_ready" | "unavailable" | "timeout" | "invalid_response" | "internal";
|
|
1480
|
+
/**
|
|
1481
|
+
* Providers throw this. `not_ready` and `unavailable` are fast fallbacks that do NOT count toward
|
|
1482
|
+
* the circuit breaker. Hosts match on `code`/`name` (not `instanceof`), because a plugin may
|
|
1483
|
+
* bundle its own copy of this package.
|
|
1484
|
+
*/
|
|
1485
|
+
export declare class DecisionProviderError extends Error {
|
|
1486
|
+
readonly code: DecisionProviderErrorCode;
|
|
1487
|
+
constructor(code: DecisionProviderErrorCode, message?: string);
|
|
1488
|
+
}
|
|
1489
|
+
/** A malformed `DecisionRequest`: a programming error of the consumer, never swallowed by the host. */
|
|
1490
|
+
export declare class DecisionRequestError extends TypeError {
|
|
1491
|
+
readonly code = "decision_invalid_request";
|
|
1492
|
+
constructor(message: string);
|
|
1493
|
+
}
|
|
1494
|
+
export interface DecisionStats {
|
|
1495
|
+
requests: number;
|
|
1496
|
+
completed: number;
|
|
1497
|
+
fallbacks: number;
|
|
1498
|
+
/** Over the completed calls. */
|
|
1499
|
+
avgLatencyMs?: number;
|
|
1500
|
+
p95LatencyMs?: number;
|
|
1501
|
+
lastFallback?: {
|
|
1502
|
+
reason: DecisionFallbackReason;
|
|
1503
|
+
decisionId: string;
|
|
1504
|
+
at: string;
|
|
1505
|
+
};
|
|
1506
|
+
/** Calls per pack id. */
|
|
1507
|
+
packs: Record<string, number>;
|
|
1508
|
+
/** Provider of the most recent decision event. */
|
|
1509
|
+
provider?: string;
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Pure: summarizes `decision_completed` / `decision_fallback` events (other events are ignored).
|
|
1513
|
+
* The TUI, the web UI and `/stats` all call this so the three surfaces agree.
|
|
1514
|
+
*/
|
|
1515
|
+
export declare function summarizeDecisionEvents(events: readonly RunEvent[]): DecisionStats;
|
|
1327
1516
|
export interface PluginAPI {
|
|
1328
1517
|
tools: {
|
|
1329
1518
|
register(tool: ToolDefinition): () => void;
|
|
@@ -1386,6 +1575,25 @@ export interface PluginAPI {
|
|
|
1386
1575
|
views?: {
|
|
1387
1576
|
register(view: ViewDefinition): () => void;
|
|
1388
1577
|
};
|
|
1578
|
+
/**
|
|
1579
|
+
* Decision Intelligence: register a `DecisionProvider` or consume decisions. Absent on a core
|
|
1580
|
+
* that predates it: feature-detect with `api.decisions?.registerProvider(...)`.
|
|
1581
|
+
*/
|
|
1582
|
+
decisions?: DecisionsApi;
|
|
1583
|
+
/**
|
|
1584
|
+
* Per-plugin directories resolved by the host and created with mode 0700. Absent on a core that
|
|
1585
|
+
* predates it.
|
|
1586
|
+
*/
|
|
1587
|
+
paths?: {
|
|
1588
|
+
state: string;
|
|
1589
|
+
config: string;
|
|
1590
|
+
cache: string;
|
|
1591
|
+
};
|
|
1592
|
+
/**
|
|
1593
|
+
* Options from `pluginOverrides[id].options` (`{}` when none), frozen at `setup`. Absent on a
|
|
1594
|
+
* core that predates it.
|
|
1595
|
+
*/
|
|
1596
|
+
options?: Readonly<Record<string, JsonValue>>;
|
|
1389
1597
|
/** Provide an implementation for a named extension point (e.g. mascot, startup-screen). */
|
|
1390
1598
|
extensions: {
|
|
1391
1599
|
register<K extends keyof ExtensionPoints>(point: K, provider: ExtensionPoints[K], options?: ExtensionOptions): () => void;
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,75 @@ export class ViewParamsError extends Error {
|
|
|
35
35
|
this.name = "ViewParamsError";
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Providers throw this. `not_ready` and `unavailable` are fast fallbacks that do NOT count toward
|
|
40
|
+
* the circuit breaker. Hosts match on `code`/`name` (not `instanceof`), because a plugin may
|
|
41
|
+
* bundle its own copy of this package.
|
|
42
|
+
*/
|
|
43
|
+
export class DecisionProviderError extends Error {
|
|
44
|
+
code;
|
|
45
|
+
constructor(code, message) {
|
|
46
|
+
super(message ?? code);
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.name = "DecisionProviderError";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** A malformed `DecisionRequest`: a programming error of the consumer, never swallowed by the host. */
|
|
52
|
+
export class DecisionRequestError extends TypeError {
|
|
53
|
+
code = "decision_invalid_request";
|
|
54
|
+
constructor(message) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = "DecisionRequestError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
60
|
+
/**
|
|
61
|
+
* Pure: summarizes `decision_completed` / `decision_fallback` events (other events are ignored).
|
|
62
|
+
* The TUI, the web UI and `/stats` all call this so the three surfaces agree.
|
|
63
|
+
*/
|
|
64
|
+
export function summarizeDecisionEvents(events) {
|
|
65
|
+
const latencies = [];
|
|
66
|
+
const packs = {};
|
|
67
|
+
let completed = 0;
|
|
68
|
+
let fallbacks = 0;
|
|
69
|
+
let provider;
|
|
70
|
+
let lastFallback;
|
|
71
|
+
for (const event of events) {
|
|
72
|
+
if (event.type !== "decision_completed" && event.type !== "decision_fallback")
|
|
73
|
+
continue;
|
|
74
|
+
if (!isRecord(event.data))
|
|
75
|
+
continue;
|
|
76
|
+
const data = event.data;
|
|
77
|
+
if (event.type === "decision_completed") {
|
|
78
|
+
completed++;
|
|
79
|
+
if (typeof data.latencyMs === "number" && Number.isFinite(data.latencyMs))
|
|
80
|
+
latencies.push(data.latencyMs);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
fallbacks++;
|
|
84
|
+
lastFallback = {
|
|
85
|
+
reason: data.reason,
|
|
86
|
+
decisionId: String(data.decisionId),
|
|
87
|
+
at: event.timestamp,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (typeof data.provider === "string")
|
|
91
|
+
provider = data.provider;
|
|
92
|
+
if (isRecord(data.pack) && typeof data.pack.id === "string")
|
|
93
|
+
packs[data.pack.id] = (packs[data.pack.id] ?? 0) + 1;
|
|
94
|
+
}
|
|
95
|
+
const stats = { requests: completed + fallbacks, completed, fallbacks, packs };
|
|
96
|
+
if (latencies.length) {
|
|
97
|
+
const sorted = [...latencies].sort((a, b) => a - b);
|
|
98
|
+
stats.avgLatencyMs = Math.round(sorted.reduce((sum, v) => sum + v, 0) / sorted.length);
|
|
99
|
+
stats.p95LatencyMs = sorted[Math.ceil(0.95 * sorted.length) - 1];
|
|
100
|
+
}
|
|
101
|
+
if (lastFallback)
|
|
102
|
+
stats.lastFallback = lastFallback;
|
|
103
|
+
if (provider)
|
|
104
|
+
stats.provider = provider;
|
|
105
|
+
return stats;
|
|
106
|
+
}
|
|
38
107
|
export function definePlugin(plugin) {
|
|
39
108
|
return plugin;
|
|
40
109
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alisio/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Typed plugin SDK for Alisio: the stable contract for tools, commands, context, compaction and session hooks, model completions and storage. Types only plus tiny helpers; zero runtime dependencies.",
|
|
5
5
|
"author": "Gustavo Gutiérrez",
|
|
6
6
|
"license": "MIT",
|