@alisio/sdk 0.1.0-alpha.17 → 0.1.0-alpha.19

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 CHANGED
@@ -103,7 +103,154 @@ export type UiBlock = {
103
103
  kind: "progress";
104
104
  title?: string;
105
105
  steps: ProgressStep[];
106
+ }
107
+ /** A published, downloadable artifact (`ToolContext.artifacts`). Text surfaces show one line. */
108
+ | {
109
+ kind: "artifact";
110
+ artifact: ArtifactRef;
106
111
  };
112
+ /** Kind of a published artifact; decides the icon, the label and the renderer. */
113
+ export type ArtifactKind = "dashboard" | "document" | "spreadsheet" | "image" | "data" | "code" | "archive" | "file";
114
+ /** Public reference to a published artifact. Never carries absolute paths. */
115
+ export interface ArtifactRef {
116
+ /** `art_<ULID>`. */
117
+ id: string;
118
+ /** Root session that owns the artifact. */
119
+ sessionId: string;
120
+ title: string;
121
+ /** Download name, e.g. `report.md`, or `site.zip` for a multi-file artifact. */
122
+ fileName: string;
123
+ kind: ArtifactKind;
124
+ mimeType: string;
125
+ bytes: number;
126
+ /** More than 1 for multi-file dashboards. */
127
+ fileCount: number;
128
+ /** Decided by the host from the artifact kind and size. */
129
+ previewable: boolean;
130
+ createdAt: number;
131
+ /** Published from a failed execution (`publishOnError`). */
132
+ partial?: boolean;
133
+ status: "ready" | "deleted" | "expired";
134
+ }
135
+ /** Input of `ArtifactPublisher.publish`: files already written by the caller. */
136
+ export interface ArtifactPublishInput {
137
+ /** Absolute path of a file or a directory owned by the caller. */
138
+ source: string;
139
+ title?: string;
140
+ /** Entry file for a directory; defaults to `index.html` when present. */
141
+ entry?: string;
142
+ }
143
+ /** Publishes caller-owned files as downloadable artifacts of the current session. */
144
+ export interface ArtifactPublisher {
145
+ /** Validates, copies and registers; throws with a user-readable message on rejection. */
146
+ publish(input: ArtifactPublishInput): Promise<ArtifactRef>;
147
+ /** Creates a single-file artifact from text the tool already holds. */
148
+ publishText(input: {
149
+ fileName: string;
150
+ title?: string;
151
+ text: string;
152
+ }): Promise<ArtifactRef>;
153
+ }
154
+ /** Finer-grained permissions inside an effect (closed union; extended additively). */
155
+ export type AnalysisCapability = "analysis.run" | "analysis.install";
156
+ /**
157
+ * What an `analysis.install` approval shows (phase 4): the optional Python packages that would be
158
+ * installed, an estimate of the download and that it needs the network. Always asks, only `once`.
159
+ */
160
+ export interface InstallPreview {
161
+ extras: "analysis" | "science";
162
+ /** Top-level packages, e.g. `pandas`, `numpy`. */
163
+ packages: string[];
164
+ /** Pinned distributions in the lockfile (the packages plus their dependencies). */
165
+ packageCount: number;
166
+ /** Rough download size (wheels only); an estimate, not a measurement. */
167
+ estimatedBytes: number;
168
+ network: true;
169
+ }
170
+ /** What a tool asks the host to approve before installing packages (capability `analysis.install`). */
171
+ export type InstallApprover = (request: InstallPreview) => Promise<"once" | "deny">;
172
+ /** A persisted capability decision as exposed by the web API. */
173
+ export interface CapabilityGrantWire {
174
+ id: string;
175
+ capability: AnalysisCapability;
176
+ sessionId: string;
177
+ scope: "once" | "session";
178
+ decision: "allow" | "deny";
179
+ source: "tui" | "web" | "flag" | "headless-grant";
180
+ createdAt: number;
181
+ revokedAt?: number;
182
+ }
183
+ /** Tabular formats the data tools ingest into one SQLite file per dataset. */
184
+ export type DatasetFormat = "csv" | "tsv" | "json" | "jsonl" | "xlsx";
185
+ /** A dataset (a CSV/TSV/JSON/JSONL/XLSX file ingested into SQLite). Never carries paths. */
186
+ export interface DatasetRef {
187
+ /** `ds_<ULID>`. */
188
+ id: string;
189
+ /** Original file name. */
190
+ name: string;
191
+ format: DatasetFormat;
192
+ bytes: number;
193
+ sha256: string;
194
+ sheets: Array<{
195
+ name: string;
196
+ table: string;
197
+ rows: number;
198
+ columns: number;
199
+ }>;
200
+ }
201
+ /** Column of a dataset table with the statistics computed at ingestion. */
202
+ export interface DatasetColumnWire {
203
+ name: string;
204
+ /** Original header text. */
205
+ label: string;
206
+ /** A hint (`integer`, `real`, `date`, `boolean`, `text`); values are stored without conversion. */
207
+ type: string;
208
+ nulls: number;
209
+ distinct: number;
210
+ distinctExact: boolean;
211
+ min?: string;
212
+ max?: string;
213
+ mean?: number;
214
+ textFallbacks: number;
215
+ top: Array<{
216
+ value: string;
217
+ count: number;
218
+ }>;
219
+ }
220
+ /** `GET /api/datasets/:did`: the dataset with the schema and statistics of every sheet. */
221
+ export interface DatasetDetailWire extends DatasetRef {
222
+ ingestVersion: number;
223
+ encoding?: string;
224
+ delimiter?: string;
225
+ sheetDetails: Array<{
226
+ name: string;
227
+ table: string;
228
+ rows: number;
229
+ columns: DatasetColumnWire[];
230
+ }>;
231
+ /** Sorting and filtering are disabled above this many rows (`analysis.data.maxInteractiveRows`). */
232
+ maxInteractiveRows: number;
233
+ }
234
+ /** `GET /api/datasets/:did/rows`: one page of a sheet (keyset-paginated). */
235
+ export interface DatasetRowsPage {
236
+ columns: Array<{
237
+ name: string;
238
+ label: string;
239
+ type: string;
240
+ }>;
241
+ /** Cell values as stored: numbers stay numbers, everything else is text, empty cells are null. */
242
+ rows: Array<Array<string | number | null>>;
243
+ /** 1-based position of the first row in the (unfiltered, unsorted) sheet, per row. */
244
+ rowids: number[];
245
+ /** Opaque cursor for the next page; absent on the last page. */
246
+ next?: string;
247
+ /** Rows in the sheet. */
248
+ total: number;
249
+ /** Rows matching the filter (first page only). */
250
+ matched?: number;
251
+ /** Sorting and filtering were ignored because the sheet exceeds `maxInteractiveRows`. */
252
+ interactive: boolean;
253
+ }
107
254
  /** One case of a `{ kind: "test-results" }` UI block. */
108
255
  export interface TestCaseResult {
109
256
  name: string;
@@ -123,7 +270,7 @@ export interface ProgressStep {
123
270
  * validators). Surfaces must still render an unknown kind as text: blocks persisted by a newer
124
271
  * Alisio can be replayed by an older one.
125
272
  */
126
- export declare const UI_BLOCK_KINDS: readonly ["table", "key-value", "tree", "code", "markdown", "diff", "terminal", "mermaid", "math", "json", "test-results", "progress"];
273
+ export declare const UI_BLOCK_KINDS: readonly ["table", "key-value", "tree", "code", "markdown", "diff", "terminal", "mermaid", "math", "json", "test-results", "progress", "artifact"];
127
274
  export interface ToolResult {
128
275
  content: Array<{
129
276
  type: "text";
@@ -167,6 +314,8 @@ export type Message =
167
314
  summary?: boolean;
168
315
  display?: string;
169
316
  attachments?: Attachment[];
317
+ /** Datasets attached to this prompt (UI chips); the model sees their text summary in `text`. */
318
+ datasets?: DatasetRef[];
170
319
  } | {
171
320
  role: "assistant";
172
321
  text: string;
@@ -324,6 +473,17 @@ export interface ToolContext {
324
473
  * do not inject this fall back to the workspace-only `safePath` policy.
325
474
  */
326
475
  resolvePath?: (path: string) => Promise<string>;
476
+ /** Run and tool call that issued this execution, when run by the agent loop. */
477
+ runId?: string;
478
+ callId?: string;
479
+ /** Present when the host has an artifact store for this session (built-in tools only in v1). */
480
+ artifacts?: ArtifactPublisher;
481
+ /**
482
+ * Asks the user to approve installing the optional Python packages (capability
483
+ * `analysis.install`; built-in tools only). Resolves `deny` where nobody can be asked
484
+ * (headless, `--read-only`), because no flag grants an installation.
485
+ */
486
+ approveInstall?: InstallApprover;
327
487
  }
328
488
  export interface ToolDefinition {
329
489
  name: string;
@@ -334,6 +494,11 @@ export interface ToolDefinition {
334
494
  /** May run concurrently with other read/concurrent calls of the same turn (e.g. delegation). */
335
495
  concurrent?: boolean;
336
496
  paths?: (input: Record<string, unknown>) => string[];
497
+ /**
498
+ * Finer-grained permission inside `effect`: a broad grant of `effect` covers it, a grant of the
499
+ * capability never widens `effect`. Honored for built-in tools only (ignored for plugins in v1).
500
+ */
501
+ capability?: AnalysisCapability;
337
502
  execute(input: Record<string, unknown>, context: ToolContext): Promise<ToolResult>;
338
503
  }
339
504
  /**
@@ -359,6 +524,28 @@ export interface RunEvent {
359
524
  /** Embedder-supplied correlation id (for example an HTTP `X-Request-Id`), when given. */
360
525
  correlationId?: string;
361
526
  }
527
+ /** What a `run_failed` event with `code: "timeout"` says about the limit that stopped the run. */
528
+ export interface RunTimeoutInfo {
529
+ /** `run`: the whole-run limit (`limits.timeoutMs`); `first_token`: a silent request (`limits.firstTokenTimeoutMs`). */
530
+ kind: "run" | "first_token";
531
+ /** The limit that was reached, in milliseconds. */
532
+ ms: number;
533
+ /** Model the run was using, when known. */
534
+ model?: string;
535
+ /** Short provider label (the host of an OpenAI-compatible endpoint), when known. */
536
+ provider?: string;
537
+ /** What the run was doing: waiting for the first token of a request, streaming, or running a tool. */
538
+ stage: "waiting_model" | "streaming" | "tool" | "other";
539
+ /** The tool that was running when `stage` is `tool`. */
540
+ tool?: string;
541
+ /** Nothing had been produced yet: the very first model request of the run got no answer. */
542
+ firstRequest?: boolean;
543
+ /**
544
+ * `first_token` only: how many times the same request was sent (the first try plus the silent
545
+ * retries of `limits.firstTokenRetries`); `1` when retrying is disabled.
546
+ */
547
+ attempts?: number;
548
+ }
362
549
  /**
363
550
  * Payload of each event type the core emits today, keyed by `RunEvent.type`. Additive: new
364
551
  * types and new optional fields may appear; existing fields keep their meaning.
@@ -411,12 +598,29 @@ export interface RunEventDataMap {
411
598
  name: string;
412
599
  effect: "write" | "process" | "external";
413
600
  label?: string;
601
+ /** The approval is for this capability (not the whole effect). */
602
+ capability?: AnalysisCapability;
603
+ /** `analysis.install` approvals: the packages, the size estimate and the network need. */
604
+ install?: InstallPreview;
414
605
  };
415
606
  approval_resolved: {
416
607
  id: string;
417
608
  name: string;
418
609
  effect: "write" | "process" | "external";
419
610
  decision: "once" | "session" | "deny";
611
+ capability?: AnalysisCapability;
612
+ /** A `session` capability decision was stored and survives restarts. */
613
+ persisted?: boolean;
614
+ };
615
+ /**
616
+ * A tool published an artifact. `path` is the absolute local path of the file (or the entry of a
617
+ * multi-file artifact) for local consumers (TUI, JSONL); web clients ignore it.
618
+ */
619
+ artifact_published: {
620
+ artifact: ArtifactRef;
621
+ path: string;
622
+ callId?: string;
623
+ executionId?: string;
420
624
  };
421
625
  run_completed: {
422
626
  tokens: number;
@@ -427,12 +631,31 @@ export interface RunEventDataMap {
427
631
  turn: number;
428
632
  maxOutputTokens: number;
429
633
  };
634
+ /**
635
+ * A model request stayed completely silent for `limits.firstTokenTimeoutMs` and the same
636
+ * request is sent again (no new turn, nothing appended to the session). `attempt` is the
637
+ * retry about to start (1-based), `of` the retries allowed (`limits.firstTokenRetries`) and
638
+ * `afterMs` how long the aborted request had been silent.
639
+ */
640
+ request_retry: {
641
+ attempt: number;
642
+ of: number;
643
+ reason: "first_token_timeout";
644
+ afterMs: number;
645
+ };
430
646
  run_turns_exceeded: {
431
647
  turns: number;
432
648
  maxTurns: number;
433
649
  };
650
+ /**
651
+ * The run failed. `error` is always a human-readable message. `code: "timeout"` (with `timeout`)
652
+ * marks a run stopped by a time limit instead of a provider or tool error; both fields are
653
+ * additive and absent for every other failure.
654
+ */
434
655
  run_failed: {
435
656
  error: string;
657
+ code?: "timeout";
658
+ timeout?: RunTimeoutInfo;
436
659
  };
437
660
  run_cancelled: {
438
661
  error: string;
@@ -1010,6 +1233,8 @@ export interface SessionDetailWire {
1010
1233
  export interface InflightState {
1011
1234
  runId: string;
1012
1235
  status: "queued" | "running";
1236
+ /** Epoch milliseconds when the run started executing; lets a reloaded client show elapsed time. */
1237
+ startedAt?: number;
1013
1238
  /** Assistant text streamed since the last `turn_completed`. */
1014
1239
  text: string;
1015
1240
  /** Reasoning streamed since the last `turn_completed` (never persisted). */
@@ -1041,6 +1266,14 @@ export interface PendingApproval {
1041
1266
  /** Pretty-printed tool input, truncated to 4 KB. */
1042
1267
  input: string;
1043
1268
  expiresAt?: number;
1269
+ /** The approval is for this capability (for example running Python), not the whole effect. */
1270
+ capability?: AnalysisCapability;
1271
+ /** A short preview for capability approvals (the first 40 lines of the script). */
1272
+ preview?: string;
1273
+ /** Capability approvals: `managed` (not sandboxed) or `oci` (container). */
1274
+ runtime?: "managed" | "oci";
1275
+ /** `analysis.install` approvals: only `once` and `deny` are offered. */
1276
+ install?: InstallPreview;
1044
1277
  }
1045
1278
  /** A plugin UI request (`ui.select` / `ui.askQuestions`) waiting for a web client. */
1046
1279
  export interface PendingInteraction {
@@ -1153,6 +1386,24 @@ export type ServerFrame = {
1153
1386
  t: "resync";
1154
1387
  sessionId?: string;
1155
1388
  reason: "overflow" | "gap" | "server_restart";
1389
+ }
1390
+ /** A persisted capability grant of this root session was added or revoked. */
1391
+ | {
1392
+ t: "capabilities_changed";
1393
+ sessionId: string;
1394
+ }
1395
+ /** A dataset uploaded from the web finished ingesting (root session). */
1396
+ | {
1397
+ t: "dataset_ready";
1398
+ sessionId: string;
1399
+ dataset: DatasetRef;
1400
+ }
1401
+ /** A dataset upload could not be ingested. */
1402
+ | {
1403
+ t: "dataset_failed";
1404
+ sessionId: string;
1405
+ name: string;
1406
+ error: string;
1156
1407
  };
1157
1408
  export type ApiErrorCode = "unauthorized" | "forbidden_origin" | "forbidden_host" | "validation_failed" | "not_found" | "unknown_command" | "session_busy" | "session_locked" | "workspace_limit"
1158
1409
  /** A known workspace whose folder was deleted, moved or is no longer accessible (404). */
@@ -1168,7 +1419,19 @@ export type ApiErrorCode = "unauthorized" | "forbidden_origin" | "forbidden_host
1168
1419
  /** The server user may not read that directory (403). */
1169
1420
  | "permission_denied"
1170
1421
  /** The request was cancelled before it finished, e.g. a `/btw` side question (409). */
1171
- | "cancelled" | "internal";
1422
+ | "cancelled"
1423
+ /** The artifact does not exist or belongs to another session (404). */
1424
+ | "artifact_not_found"
1425
+ /** The artifact exceeds a size limit for this operation (413). */
1426
+ | "artifact_too_large"
1427
+ /** No usable Python runtime (503). */
1428
+ | "runtime_unavailable"
1429
+ /** The file is not a supported dataset, or needs a runtime that is missing (415/503 body code). */
1430
+ | "dataset_unsupported"
1431
+ /** A data query was rejected by the read-only guard (400). */
1432
+ | "query_rejected"
1433
+ /** A data query exceeded `analysis.data.queryTimeoutMs` (408). */
1434
+ | "query_timeout" | "internal";
1172
1435
  /** `GET /api/health` (the only unauthenticated API route). */
1173
1436
  export interface HealthInfo {
1174
1437
  name: "alisio";
@@ -1405,6 +1668,55 @@ export interface McpServerWire {
1405
1668
  };
1406
1669
  diagnostic?: string;
1407
1670
  }
1671
+ /**
1672
+ * `GET /api/analysis`: the state of the data-analysis runtime for Settings (read only). Never
1673
+ * carries a script or a repository path; interpreter paths are the user's own.
1674
+ */
1675
+ export interface AnalysisStatus {
1676
+ /** `analysis.enabled` and not `--read-only`: python_run is registered. */
1677
+ enabled: boolean;
1678
+ readOnly: boolean;
1679
+ mode: "managed" | "oci";
1680
+ /** The discovered (or `--python`) interpreter and the extras environment. */
1681
+ python: {
1682
+ found: true;
1683
+ path: string;
1684
+ version: string;
1685
+ source: string;
1686
+ extras: string[];
1687
+ runtimeVersion?: string;
1688
+ } | {
1689
+ found: false;
1690
+ reason: string;
1691
+ /** Installation guidance for this system (commands are shown, never run). */
1692
+ hints: {
1693
+ system: string;
1694
+ heading?: string;
1695
+ primary: string;
1696
+ alternatives: string[];
1697
+ notes: string[];
1698
+ };
1699
+ };
1700
+ /** Container settings; `available` is probed only when the mode is `oci` or an image is set. */
1701
+ oci: {
1702
+ engine: "docker" | "podman";
1703
+ image?: string;
1704
+ memoryMb: number;
1705
+ cpus: number;
1706
+ available?: boolean;
1707
+ version?: string;
1708
+ reason?: string;
1709
+ };
1710
+ limits: {
1711
+ timeoutMs: number;
1712
+ };
1713
+ retention: {
1714
+ jobsDays: number;
1715
+ intermediateDays: number;
1716
+ artifactsDays: number;
1717
+ lastSweep?: number;
1718
+ };
1719
+ }
1408
1720
  /** `GET /api/mcp`: the workspace's MCP runtime permission and servers. */
1409
1721
  export interface McpOverview {
1410
1722
  permission: "granted" | "not-granted" | "read-only";
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export const UI_BLOCK_KINDS = [
16
16
  "json",
17
17
  "test-results",
18
18
  "progress",
19
+ "artifact",
19
20
  ];
20
21
  export const EPHEMERAL_RUN_EVENT_TYPES = [
21
22
  "text_delta",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alisio/sdk",
3
- "version": "0.1.0-alpha.17",
3
+ "version": "0.1.0-alpha.19",
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",