@aexhq/sdk 0.38.1 → 0.40.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/README.md +23 -17
- package/dist/_contracts/api-key.d.ts +49 -0
- package/dist/_contracts/api-key.js +87 -0
- package/dist/_contracts/bundle-manifest.d.ts +86 -0
- package/dist/_contracts/bundle-manifest.js +157 -0
- package/dist/_contracts/error-codes.d.ts +26 -0
- package/dist/_contracts/error-codes.js +79 -0
- package/dist/_contracts/error-factory.d.ts +32 -0
- package/dist/_contracts/error-factory.js +142 -0
- package/dist/_contracts/event-envelope.d.ts +33 -10
- package/dist/_contracts/event-envelope.js +46 -10
- package/dist/_contracts/event-view.d.ts +123 -0
- package/dist/_contracts/event-view.js +120 -0
- package/dist/_contracts/http.js +12 -3
- package/dist/_contracts/index.d.ts +8 -4
- package/dist/_contracts/index.js +11 -7
- package/dist/_contracts/models.d.ts +15 -0
- package/dist/_contracts/models.js +33 -0
- package/dist/_contracts/operations.d.ts +70 -2
- package/dist/_contracts/operations.js +143 -7
- package/dist/_contracts/run-config.d.ts +35 -10
- package/dist/_contracts/run-config.js +17 -5
- package/dist/_contracts/run-record.d.ts +3 -2
- package/dist/_contracts/runtime-types.d.ts +148 -36
- package/dist/_contracts/runtime-types.js +33 -1
- package/dist/_contracts/sdk-errors.d.ts +61 -2
- package/dist/_contracts/sdk-errors.js +83 -3
- package/dist/_contracts/sdk-secrets.js +31 -6
- package/dist/_contracts/stable.d.ts +14 -0
- package/dist/_contracts/stable.js +14 -0
- package/dist/_contracts/status.d.ts +28 -1
- package/dist/_contracts/status.js +48 -3
- package/dist/_contracts/submission.d.ts +157 -14
- package/dist/_contracts/submission.js +319 -55
- package/dist/_contracts/suggest.d.ts +15 -0
- package/dist/_contracts/suggest.js +54 -0
- package/dist/asset-upload.d.ts +27 -1
- package/dist/asset-upload.js +219 -4
- package/dist/asset-upload.js.map +1 -1
- package/dist/bundle.d.ts +23 -14
- package/dist/bundle.js +39 -20
- package/dist/bundle.js.map +1 -1
- package/dist/canonical-zip.d.ts +68 -0
- package/dist/canonical-zip.js +307 -0
- package/dist/canonical-zip.js.map +1 -0
- package/dist/cli.mjs +1927 -326
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +273 -70
- package/dist/client.js +885 -335
- package/dist/client.js.map +1 -1
- package/dist/fetch-archive.js +14 -14
- package/dist/fetch-archive.js.map +1 -1
- package/dist/file.d.ts +33 -6
- package/dist/file.js +120 -54
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.js +31 -14
- package/dist/index.js.map +1 -1
- package/dist/node-fs.d.ts +26 -9
- package/dist/node-fs.js +13 -38
- package/dist/node-fs.js.map +1 -1
- package/dist/node-walk.d.ts +69 -0
- package/dist/node-walk.js +146 -0
- package/dist/node-walk.js.map +1 -0
- package/dist/retry.d.ts +9 -13
- package/dist/retry.js +18 -17
- package/dist/retry.js.map +1 -1
- package/dist/skill.d.ts +151 -0
- package/dist/skill.js +298 -0
- package/dist/skill.js.map +1 -0
- package/dist/tool.d.ts +14 -2
- package/dist/tool.js +33 -7
- package/dist/tool.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +29 -5
- package/docs/billing.md +6 -0
- package/docs/concepts/agent-tools.md +11 -0
- package/docs/concepts/composition.md +3 -3
- package/docs/defaults.md +1 -0
- package/docs/errors.md +64 -4
- package/docs/events.md +84 -49
- package/docs/limits-and-quotas.md +24 -0
- package/docs/mcp.md +3 -2
- package/docs/networking.md +7 -1
- package/docs/outputs.md +36 -7
- package/docs/provider-runtime-capabilities.md +1 -1
- package/docs/quickstart.md +17 -7
- package/docs/run-config.md +3 -3
- package/docs/secrets.md +14 -0
- package/docs/skills.md +74 -44
- package/docs/vision-skills.md +3 -3
- package/examples/feature-tour.ts +4 -6
- package/examples/spike-settle-latency.ts +125 -0
- package/package.json +4 -3
- package/dist/_contracts/event-guards.d.ts +0 -67
- package/dist/_contracts/event-guards.js +0 -36
- package/dist/skill-tool.d.ts +0 -102
- package/dist/skill-tool.js +0 -190
- package/dist/skill-tool.js.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { suggest } from "./suggest.js";
|
|
1
2
|
/**
|
|
2
3
|
* Source of truth for the closed model set: each canonical model id maps to the
|
|
3
4
|
* upstream providers that can serve it and the **provider-native** model string
|
|
@@ -149,6 +150,38 @@ export function resolveProviderModelId(model, provider) {
|
|
|
149
150
|
}
|
|
150
151
|
return native;
|
|
151
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* The single model→provider resolver shared by the SDK and the CLI, wrapping
|
|
155
|
+
* {@link providersForModel} with the forward-compat unknown-model allowance:
|
|
156
|
+
*
|
|
157
|
+
* - `provider` given: it is honored. If `model` is a KNOWN id, the provider
|
|
158
|
+
* must serve it (else throw). If `model` is UNKNOWN, it is allowed through
|
|
159
|
+
* so a slightly-old client can still run a newly-launched model (the server
|
|
160
|
+
* arbitrates).
|
|
161
|
+
* - `provider` omitted: a known model resolves to its DEFAULT provider (first
|
|
162
|
+
* declared). An UNKNOWN model with no provider throws a `did you mean?`
|
|
163
|
+
* hint — you must name a provider to run a model this client doesn't know.
|
|
164
|
+
*
|
|
165
|
+
* Returns the resolved {@link RunProvider}.
|
|
166
|
+
*/
|
|
167
|
+
export function resolveModelProvider(model, provider) {
|
|
168
|
+
const providers = providersForModel(model);
|
|
169
|
+
if (provider !== undefined) {
|
|
170
|
+
if (providers.length > 0 && !providers.includes(provider)) {
|
|
171
|
+
throw new Error(`model ${JSON.stringify(model)} is not available for provider ${provider}; ` +
|
|
172
|
+
`available: ${providers.join(", ")}`);
|
|
173
|
+
}
|
|
174
|
+
return provider;
|
|
175
|
+
}
|
|
176
|
+
const inferred = providers[0];
|
|
177
|
+
if (inferred === undefined) {
|
|
178
|
+
const hint = suggest(model, RUN_MODELS);
|
|
179
|
+
throw new Error(`${JSON.stringify(model)} is not a known model id` +
|
|
180
|
+
(hint ? ` (did you mean ${JSON.stringify(hint)}?)` : "") +
|
|
181
|
+
"; pass provider explicitly to run it");
|
|
182
|
+
}
|
|
183
|
+
return inferred;
|
|
184
|
+
}
|
|
152
185
|
export function isRunModel(input) {
|
|
153
186
|
return typeof input === "string" && RUN_MODELS.includes(input);
|
|
154
187
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { HttpClient } from "./http.js";
|
|
2
|
+
import type { AexEvent } from "./event-envelope.js";
|
|
2
3
|
import type { RunUnit } from "./run-unit.js";
|
|
3
|
-
import type { AgentsMdRecord, BillingCheckoutRequest, BillingHostedSession, BillingLedgerPage, BillingLedgerQuery, BillingPortalRequest, BillingSummary, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run,
|
|
4
|
+
import type { AgentsMdRecord, BillingCheckoutRequest, BillingHostedSession, BillingLedgerPage, BillingLedgerQuery, BillingPortalRequest, BillingSummary, ChildRunRef, FileRecord, Output, OutputLink, OutputLinkOptions, OutputFileDownload, OutputFileSelector, OutputFileType, OutputQuery, OutputText, ReadOutputTextOptions, Run, RunListPage, RunListQuery, Session, SessionCreateRequest, SessionEvent, SessionListPage, SessionListQuery, SessionMessageAccepted, SessionMessageRequest, SessionMessagesPage, SessionMessagesQuery, SessionStateChangeAccepted, RunWebhookDelivery, SecretRecord, SecretReveal, SkillRecord, WebhookSigningSecret, WhoAmI } from "./runtime-types.js";
|
|
4
5
|
import type { PlatformRunSubmissionInput } from "./submission.js";
|
|
5
6
|
/**
|
|
6
7
|
* The single source of truth for SDK<->BFF transport. The SDK class
|
|
@@ -39,7 +40,29 @@ export declare function listRuns(http: HttpClient, query?: RunListQuery): Promis
|
|
|
39
40
|
export interface IdempotencyOptions {
|
|
40
41
|
readonly idempotencyKey?: string;
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a caller-supplied idempotency key to the value that ships on the
|
|
45
|
+
* request. FAIL-FAST: an empty or whitespace-only key THROWS
|
|
46
|
+
* {@link RunConfigValidationError} — a footgun that silently disabled dedup
|
|
47
|
+
* (`?? generate()` kept `''`, then a downstream truthy header-drop shipped no
|
|
48
|
+
* `Idempotency-Key`). An absent key generates a fresh one; a real key is
|
|
49
|
+
* returned verbatim. The single choke point every send/create/run entry uses.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveIdempotencyKey(key?: string): string;
|
|
42
52
|
export declare function createSession(http: HttpClient, request: SessionCreateRequest, options?: IdempotencyOptions): Promise<Session>;
|
|
53
|
+
/** The result of a non-blocking {@link submit}: the run id + the created session. */
|
|
54
|
+
export interface SubmitResult {
|
|
55
|
+
readonly runId: string;
|
|
56
|
+
readonly session: Session;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fire-and-forget submit — create the session and post its first turn WITHOUT
|
|
60
|
+
* awaiting the turn to settle (the honest counterpart to await-settle `run()`).
|
|
61
|
+
* Returns the `runId` immediately; observe the run via a `webhook`, the event
|
|
62
|
+
* stream, or by re-opening the session. Mirrors {@link createSession}'s
|
|
63
|
+
* idempotency handling.
|
|
64
|
+
*/
|
|
65
|
+
export declare function submit(http: HttpClient, request: SessionCreateRequest, options?: IdempotencyOptions): Promise<SubmitResult>;
|
|
43
66
|
export declare function getSession(http: HttpClient, sessionId: string): Promise<Session>;
|
|
44
67
|
export declare function listSessions(http: HttpClient, query?: SessionListQuery): Promise<SessionListPage>;
|
|
45
68
|
export declare function sendSessionMessage(http: HttpClient, sessionId: string, request: SessionMessageRequest, options?: IdempotencyOptions): Promise<SessionMessageAccepted>;
|
|
@@ -47,6 +70,16 @@ export declare function listSessionMessages(http: HttpClient, sessionId: string,
|
|
|
47
70
|
export declare function suspendSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
48
71
|
export declare function cancelSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
49
72
|
export declare function resumeSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
73
|
+
/**
|
|
74
|
+
* Request the HITL write-gate: park the session `awaiting_approval` before its
|
|
75
|
+
* next gated action (mirrors {@link suspendSession}). Imperative counterpart to
|
|
76
|
+
* the declarative submission-time `approvalGate`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function requestApproval(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
79
|
+
/** Approve an `awaiting_approval` session so the held turn resumes (→ running). */
|
|
80
|
+
export declare function approveSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
81
|
+
/** Deny an `awaiting_approval` session so the held turn is cancelled (→ cancelled). */
|
|
82
|
+
export declare function denySession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted>;
|
|
50
83
|
export declare function deleteSession(http: HttpClient, sessionId: string, options?: IdempotencyOptions): Promise<SessionStateChangeAccepted | void>;
|
|
51
84
|
export declare function listSessionEvents(http: HttpClient, sessionId: string): Promise<readonly SessionEvent[]>;
|
|
52
85
|
export declare function listSessionOutputs(http: HttpClient, sessionId: string, query?: OutputQuery): Promise<readonly Output[]>;
|
|
@@ -57,7 +90,7 @@ export declare function getSessionCoordinatorTicket(http: HttpClient, sessionId:
|
|
|
57
90
|
* pages and returns the FULL accumulated list, preserving the prior single-call
|
|
58
91
|
* contract for callers (download/*, CLI, streamEvents polling).
|
|
59
92
|
*/
|
|
60
|
-
export declare function listRunEvents(http: HttpClient, runId: string): Promise<readonly
|
|
93
|
+
export declare function listRunEvents(http: HttpClient, runId: string): Promise<readonly AexEvent[]>;
|
|
61
94
|
/** A coordinator WS connection grant minted by the hosted API's ticket broker. */
|
|
62
95
|
export interface CoordinatorTicket {
|
|
63
96
|
readonly wsUrl: string;
|
|
@@ -94,6 +127,13 @@ export declare const READ_OUTPUT_TEXT_DEFAULT_BYTES = 50000;
|
|
|
94
127
|
* selector lists the run's outputs to resolve the id; an id selector skips that.
|
|
95
128
|
*/
|
|
96
129
|
export declare function readOutputText(http: HttpClient, runId: string, selector: OutputFileSelector, options?: ReadOutputTextOptions): Promise<OutputText>;
|
|
130
|
+
/**
|
|
131
|
+
* List a run's subagent CHILD runs (`GET /runs/:id/children`). Each row is a
|
|
132
|
+
* {@link ChildRunRef} whose `id` resolves through the run facade (getRun /
|
|
133
|
+
* events / outputs) — so every child the platform hands you is resolvable. An
|
|
134
|
+
* empty array means the run spawned no children.
|
|
135
|
+
*/
|
|
136
|
+
export declare function listRunChildren(http: HttpClient, runId: string): Promise<readonly ChildRunRef[]>;
|
|
97
137
|
export declare function cancelRun(http: HttpClient, runId: string): Promise<void>;
|
|
98
138
|
export declare function deleteRun(http: HttpClient, runId: string): Promise<void>;
|
|
99
139
|
/**
|
|
@@ -146,6 +186,14 @@ export declare function getBillingLedger(http: HttpClient, query?: BillingLedger
|
|
|
146
186
|
*/
|
|
147
187
|
export declare function getWebhookSigningSecret(http: HttpClient): Promise<WebhookSigningSecret>;
|
|
148
188
|
export declare function filterOutputs(outputs: readonly Output[], query: OutputQuery): readonly Output[];
|
|
189
|
+
/**
|
|
190
|
+
* The single filename-matcher for cross-run / per-session output SEARCH. A
|
|
191
|
+
* string is a case-insensitive SUBSTRING match; a RegExp is tested as given (and
|
|
192
|
+
* reset to `lastIndex = 0` so a reused `/g` regex is safe). Sharing this SSoT is
|
|
193
|
+
* what closes the T16 crash class: `searchOutputs` no longer assumes `filename`
|
|
194
|
+
* is a string and passes a RegExp into `escapeRegExp(...).replace(...)`.
|
|
195
|
+
*/
|
|
196
|
+
export declare function toFilenameMatcher(filename: string | RegExp): (name: string) => boolean;
|
|
149
197
|
export declare function classifyOutput(output: Pick<Output, "filename" | "contentType">): OutputFileType;
|
|
150
198
|
export declare function normalizeOutputLinkExpiresIn(input?: OutputLinkOptions["expiresIn"]): number;
|
|
151
199
|
/**
|
|
@@ -197,6 +245,26 @@ export declare function rotateSecret(http: HttpClient, args: {
|
|
|
197
245
|
readonly value: string;
|
|
198
246
|
}): Promise<SecretRecord>;
|
|
199
247
|
export declare function deleteSecret(http: HttpClient, name: string): Promise<void>;
|
|
248
|
+
/** Result of an `upsertSkill`: the stored record + whether the bytes changed. */
|
|
249
|
+
export interface SkillUpsertResult {
|
|
250
|
+
readonly skill: SkillRecord;
|
|
251
|
+
readonly updated: boolean;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Upsert a workspace skill by name — `PUT /skills/{name}`. The bundle bytes must
|
|
255
|
+
* already exist in the asset store (staged via presign/finalize before this
|
|
256
|
+
* call); the body carries only the metadata. Identical `contentHash` is a no-op
|
|
257
|
+
* (`updated:false`).
|
|
258
|
+
*/
|
|
259
|
+
export declare function upsertSkill(http: HttpClient, args: {
|
|
260
|
+
readonly name: string;
|
|
261
|
+
readonly contentHash: string;
|
|
262
|
+
readonly description: string;
|
|
263
|
+
readonly sizeBytes: number;
|
|
264
|
+
}): Promise<SkillUpsertResult>;
|
|
265
|
+
export declare function listSkills(http: HttpClient): Promise<readonly SkillRecord[]>;
|
|
266
|
+
export declare function getSkill(http: HttpClient, name: string): Promise<SkillRecord>;
|
|
267
|
+
export declare function deleteSkill(http: HttpClient, name: string): Promise<void>;
|
|
200
268
|
export interface AssetUploadResult {
|
|
201
269
|
readonly assetId: string;
|
|
202
270
|
readonly contentHash: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { strToU8, zipSync } from "fflate";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { normalizeRunUnit } from "./run-unit.js";
|
|
3
|
-
import { RunStateError } from "./sdk-errors.js";
|
|
4
|
+
import { RunConfigValidationError, RunStateError } from "./sdk-errors.js";
|
|
4
5
|
import { assertRunRecordArchivePublicSafeV1, buildRunRecordDownloadManifestV1 } from "./run-record.js";
|
|
5
6
|
/**
|
|
6
7
|
* The single source of truth for SDK<->BFF transport. The SDK class
|
|
@@ -83,8 +84,41 @@ export async function listRuns(http, query) {
|
|
|
83
84
|
}
|
|
84
85
|
return changed ? { ...page, runs } : page;
|
|
85
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Resolve a caller-supplied idempotency key to the value that ships on the
|
|
89
|
+
* request. FAIL-FAST: an empty or whitespace-only key THROWS
|
|
90
|
+
* {@link RunConfigValidationError} — a footgun that silently disabled dedup
|
|
91
|
+
* (`?? generate()` kept `''`, then a downstream truthy header-drop shipped no
|
|
92
|
+
* `Idempotency-Key`). An absent key generates a fresh one; a real key is
|
|
93
|
+
* returned verbatim. The single choke point every send/create/run entry uses.
|
|
94
|
+
*/
|
|
95
|
+
export function resolveIdempotencyKey(key) {
|
|
96
|
+
if (key === undefined) {
|
|
97
|
+
return `aex-idem-${randomUUID()}`;
|
|
98
|
+
}
|
|
99
|
+
if (typeof key !== "string" || key.trim().length === 0) {
|
|
100
|
+
throw new RunConfigValidationError("idempotencyKey must be a non-empty, non-whitespace string", {
|
|
101
|
+
field: "idempotencyKey",
|
|
102
|
+
value: key
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return key;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Fail-closed idempotency header builder. An EMPTY string throws (defense in
|
|
109
|
+
* depth alongside {@link resolveIdempotencyKey}) rather than silently dropping
|
|
110
|
+
* the header and proceeding non-idempotent; an absent key yields no header.
|
|
111
|
+
*/
|
|
86
112
|
function idempotencyHeaders(options) {
|
|
87
|
-
|
|
113
|
+
if (options?.idempotencyKey === undefined)
|
|
114
|
+
return undefined;
|
|
115
|
+
if (typeof options.idempotencyKey !== "string" || options.idempotencyKey.trim().length === 0) {
|
|
116
|
+
throw new RunConfigValidationError("idempotencyKey must be a non-empty, non-whitespace string", {
|
|
117
|
+
field: "idempotencyKey",
|
|
118
|
+
value: options.idempotencyKey
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return { "Idempotency-Key": options.idempotencyKey };
|
|
88
122
|
}
|
|
89
123
|
export async function createSession(http, request, options) {
|
|
90
124
|
const headers = idempotencyHeaders(options);
|
|
@@ -95,6 +129,17 @@ export async function createSession(http, request, options) {
|
|
|
95
129
|
});
|
|
96
130
|
return unwrapSession(result);
|
|
97
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Fire-and-forget submit — create the session and post its first turn WITHOUT
|
|
134
|
+
* awaiting the turn to settle (the honest counterpart to await-settle `run()`).
|
|
135
|
+
* Returns the `runId` immediately; observe the run via a `webhook`, the event
|
|
136
|
+
* stream, or by re-opening the session. Mirrors {@link createSession}'s
|
|
137
|
+
* idempotency handling.
|
|
138
|
+
*/
|
|
139
|
+
export async function submit(http, request, options) {
|
|
140
|
+
const session = await createSession(http, request, options);
|
|
141
|
+
return { runId: session.sessionId ?? session.id, session };
|
|
142
|
+
}
|
|
98
143
|
export async function getSession(http, sessionId) {
|
|
99
144
|
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
100
145
|
return unwrapSession(result);
|
|
@@ -141,6 +186,25 @@ export async function resumeSession(http, sessionId, options) {
|
|
|
141
186
|
const headers = idempotencyHeaders(options);
|
|
142
187
|
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/resume`, { method: "POST", ...(headers ? { headers } : {}) });
|
|
143
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Request the HITL write-gate: park the session `awaiting_approval` before its
|
|
191
|
+
* next gated action (mirrors {@link suspendSession}). Imperative counterpart to
|
|
192
|
+
* the declarative submission-time `approvalGate`.
|
|
193
|
+
*/
|
|
194
|
+
export async function requestApproval(http, sessionId, options) {
|
|
195
|
+
const headers = idempotencyHeaders(options);
|
|
196
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/request-approval`, { method: "POST", ...(headers ? { headers } : {}) });
|
|
197
|
+
}
|
|
198
|
+
/** Approve an `awaiting_approval` session so the held turn resumes (→ running). */
|
|
199
|
+
export async function approveSession(http, sessionId, options) {
|
|
200
|
+
const headers = idempotencyHeaders(options);
|
|
201
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/approve`, { method: "POST", ...(headers ? { headers } : {}) });
|
|
202
|
+
}
|
|
203
|
+
/** Deny an `awaiting_approval` session so the held turn is cancelled (→ cancelled). */
|
|
204
|
+
export async function denySession(http, sessionId, options) {
|
|
205
|
+
const headers = idempotencyHeaders(options);
|
|
206
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/deny`, { method: "POST", ...(headers ? { headers } : {}) });
|
|
207
|
+
}
|
|
144
208
|
export async function deleteSession(http, sessionId, options) {
|
|
145
209
|
const headers = idempotencyHeaders(options);
|
|
146
210
|
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}`, { method: "DELETE", ...(headers ? { headers } : {}) });
|
|
@@ -212,7 +276,7 @@ export async function findOutput(http, runId, query) {
|
|
|
212
276
|
return null;
|
|
213
277
|
if (matches.length === 1)
|
|
214
278
|
return matches[0];
|
|
215
|
-
throw new RunStateError("
|
|
279
|
+
throw new RunStateError("outputs.findOne: output query matched multiple files", {
|
|
216
280
|
runId,
|
|
217
281
|
matches: matches.map((output) => output.filename ?? output.id)
|
|
218
282
|
});
|
|
@@ -260,7 +324,7 @@ export function resolveOutputFileSelector(outputs, selector, runId) {
|
|
|
260
324
|
if (isPathSelector(selector)) {
|
|
261
325
|
const target = normalizeOutputLookupPath(selector.path);
|
|
262
326
|
if (!target) {
|
|
263
|
-
throw new RunStateError("
|
|
327
|
+
throw new RunStateError("outputs.download: output path must be non-empty", { runId, path: selector.path });
|
|
264
328
|
}
|
|
265
329
|
const matches = outputs.filter((output) => {
|
|
266
330
|
if (typeof output.filename !== "string")
|
|
@@ -274,15 +338,15 @@ export function resolveOutputFileSelector(outputs, selector, runId) {
|
|
|
274
338
|
if (matches.length === 1)
|
|
275
339
|
return matches[0];
|
|
276
340
|
if (matches.length > 1) {
|
|
277
|
-
throw new RunStateError(`
|
|
341
|
+
throw new RunStateError(`outputs.download: output path "${selector.path}" matched multiple files`, { runId, path: selector.path, matches: matches.map((output) => output.filename ?? output.id) });
|
|
278
342
|
}
|
|
279
|
-
throw new RunStateError(`
|
|
343
|
+
throw new RunStateError(`outputs.download: output path "${selector.path}" was not found`, {
|
|
280
344
|
runId,
|
|
281
345
|
path: selector.path
|
|
282
346
|
});
|
|
283
347
|
}
|
|
284
348
|
if (typeof selector?.id !== "string" || selector.id.length === 0) {
|
|
285
|
-
throw new RunStateError("
|
|
349
|
+
throw new RunStateError("outputs.download: selector must include an output id or path", { runId });
|
|
286
350
|
}
|
|
287
351
|
return { ...selector, id: selector.id };
|
|
288
352
|
}
|
|
@@ -387,6 +451,18 @@ function grepLines(text, pattern) {
|
|
|
387
451
|
.filter((line) => test(line))
|
|
388
452
|
.join("\n");
|
|
389
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* List a run's subagent CHILD runs (`GET /runs/:id/children`). Each row is a
|
|
456
|
+
* {@link ChildRunRef} whose `id` resolves through the run facade (getRun /
|
|
457
|
+
* events / outputs) — so every child the platform hands you is resolvable. An
|
|
458
|
+
* empty array means the run spawned no children.
|
|
459
|
+
*/
|
|
460
|
+
export async function listRunChildren(http, runId) {
|
|
461
|
+
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/children`);
|
|
462
|
+
return Array.isArray(result)
|
|
463
|
+
? result
|
|
464
|
+
: result.children;
|
|
465
|
+
}
|
|
390
466
|
export async function cancelRun(http, runId) {
|
|
391
467
|
await http.request(`/api/runs/${encodeURIComponent(runId)}/cancel`, { method: "POST" });
|
|
392
468
|
}
|
|
@@ -522,6 +598,23 @@ function normalizeOutputLookupPath(path) {
|
|
|
522
598
|
export function filterOutputs(outputs, query) {
|
|
523
599
|
return outputs.filter((output) => outputMatchesQuery(output, query));
|
|
524
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* The single filename-matcher for cross-run / per-session output SEARCH. A
|
|
603
|
+
* string is a case-insensitive SUBSTRING match; a RegExp is tested as given (and
|
|
604
|
+
* reset to `lastIndex = 0` so a reused `/g` regex is safe). Sharing this SSoT is
|
|
605
|
+
* what closes the T16 crash class: `searchOutputs` no longer assumes `filename`
|
|
606
|
+
* is a string and passes a RegExp into `escapeRegExp(...).replace(...)`.
|
|
607
|
+
*/
|
|
608
|
+
export function toFilenameMatcher(filename) {
|
|
609
|
+
if (typeof filename === "string") {
|
|
610
|
+
const needle = filename.toLowerCase();
|
|
611
|
+
return (name) => name.toLowerCase().includes(needle);
|
|
612
|
+
}
|
|
613
|
+
return (name) => {
|
|
614
|
+
filename.lastIndex = 0;
|
|
615
|
+
return filename.test(name);
|
|
616
|
+
};
|
|
617
|
+
}
|
|
525
618
|
export function classifyOutput(output) {
|
|
526
619
|
const contentType = normalizeContentType(output.contentType);
|
|
527
620
|
if (contentType) {
|
|
@@ -902,6 +995,49 @@ function unwrapSecret(result) {
|
|
|
902
995
|
}
|
|
903
996
|
return result;
|
|
904
997
|
}
|
|
998
|
+
/**
|
|
999
|
+
* Upsert a workspace skill by name — `PUT /skills/{name}`. The bundle bytes must
|
|
1000
|
+
* already exist in the asset store (staged via presign/finalize before this
|
|
1001
|
+
* call); the body carries only the metadata. Identical `contentHash` is a no-op
|
|
1002
|
+
* (`updated:false`).
|
|
1003
|
+
*/
|
|
1004
|
+
export async function upsertSkill(http, args) {
|
|
1005
|
+
const result = await http.request(`/api/skills/${encodeURIComponent(args.name)}`, {
|
|
1006
|
+
method: "PUT",
|
|
1007
|
+
body: JSON.stringify({
|
|
1008
|
+
contentHash: args.contentHash,
|
|
1009
|
+
description: args.description,
|
|
1010
|
+
sizeBytes: args.sizeBytes
|
|
1011
|
+
})
|
|
1012
|
+
});
|
|
1013
|
+
if (result && typeof result === "object" && "skill" in result) {
|
|
1014
|
+
const wrapped = result;
|
|
1015
|
+
return { skill: wrapped.skill, updated: wrapped.updated === true };
|
|
1016
|
+
}
|
|
1017
|
+
return { skill: result, updated: true };
|
|
1018
|
+
}
|
|
1019
|
+
export async function listSkills(http) {
|
|
1020
|
+
const result = await http.request("/api/skills");
|
|
1021
|
+
if (Array.isArray(result)) {
|
|
1022
|
+
return result;
|
|
1023
|
+
}
|
|
1024
|
+
return result.skills;
|
|
1025
|
+
}
|
|
1026
|
+
export async function getSkill(http, name) {
|
|
1027
|
+
const result = await http.request(`/api/skills/${encodeURIComponent(name)}`);
|
|
1028
|
+
return unwrapSkill(result);
|
|
1029
|
+
}
|
|
1030
|
+
export async function deleteSkill(http, name) {
|
|
1031
|
+
await http.request(`/api/skills/${encodeURIComponent(name)}`, {
|
|
1032
|
+
method: "DELETE"
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
function unwrapSkill(result) {
|
|
1036
|
+
if (result && typeof result === "object" && "skill" in result) {
|
|
1037
|
+
return result.skill;
|
|
1038
|
+
}
|
|
1039
|
+
return result;
|
|
1040
|
+
}
|
|
905
1041
|
function hasRun(value) {
|
|
906
1042
|
return Boolean(value && typeof value === "object" && "run" in value);
|
|
907
1043
|
}
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public composition concepts:
|
|
5
5
|
*
|
|
6
|
-
* - `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* - `SkillRef` is the PUBLIC wire-level reference to a workspace skill: just
|
|
7
|
+
* `{ kind:"skill", name }`. The binding is BY NAME and mutable — the run
|
|
8
|
+
* resolves the name to the workspace skill's current bytes at submit time.
|
|
9
|
+
* It travels in `submission.skills` (NOT `submission.tools`).
|
|
10
|
+
*
|
|
11
|
+
* - `ResolvedSkillRef` is the BFF-produced, boot-record-only resolution of a
|
|
12
|
+
* `SkillRef`: `{ kind:"skill", assetId, name, description }`. It never
|
|
13
|
+
* appears on the public ingress wire — the resolver fills it before
|
|
14
|
+
* persisting the boot record so the in-container re-parse can read the
|
|
15
|
+
* skill's asset + description without a DB round-trip.
|
|
11
16
|
*
|
|
12
17
|
* - `McpServerRef` is the non-secret part of an MCP server declaration:
|
|
13
18
|
* `name` and `url`. Bearer / cookie / per-request headers travel in
|
|
@@ -52,6 +57,13 @@ export declare const SKILL_NAME_PATTERN: RegExp;
|
|
|
52
57
|
* because SessionDO reserves that separator for MCP namespace routing.
|
|
53
58
|
*/
|
|
54
59
|
export declare const TOOL_NAME_PATTERN: RegExp;
|
|
60
|
+
/**
|
|
61
|
+
* Names reserved by the skills subsystem and therefore usable as neither a
|
|
62
|
+
* skill name nor a custom tool name. `skills` is the injected meta-tool (see
|
|
63
|
+
* {@link SKILLS_TOOL_NAME} in `submission.ts`); `skill` is its singular. Both
|
|
64
|
+
* the SDK factories and the BFF `parseSkills` / `parseTools` reject these.
|
|
65
|
+
*/
|
|
66
|
+
export declare const SKILL_RESERVED_NAMES: ReadonlySet<string>;
|
|
55
67
|
/**
|
|
56
68
|
* Hard caps applied at upload time. The SDK enforces these before
|
|
57
69
|
* computing the zip hash so a clearly-too-big bundle never wastes
|
|
@@ -82,12 +94,25 @@ export declare const SKILL_BUNDLE_LIMITS: {
|
|
|
82
94
|
readonly defaultDirMode: 493;
|
|
83
95
|
};
|
|
84
96
|
/**
|
|
85
|
-
*
|
|
86
|
-
* the
|
|
87
|
-
*
|
|
88
|
-
*
|
|
97
|
+
* The PUBLIC wire reference to a workspace skill — by NAME, no bytes, no hash.
|
|
98
|
+
* This is what the SDK sends in `submission.skills` and what the idempotency
|
|
99
|
+
* hash covers. The run resolves the name to the workspace skill's CURRENT bytes
|
|
100
|
+
* at submit time (a re-upload under the same name changes what later runs see).
|
|
101
|
+
*/
|
|
102
|
+
export interface SkillRef {
|
|
103
|
+
readonly kind: "skill";
|
|
104
|
+
readonly name: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* BFF-produced, BOOT-RECORD-ONLY resolution of a {@link SkillRef}. The submit-time
|
|
108
|
+
* resolver looks the name up in the workspace skill registry and fills in the
|
|
109
|
+
* current `assetId` + `description`; this is written to the boot record's trusted
|
|
110
|
+
* `submission.resolvedSkills` so the in-container re-parse and the manifest /
|
|
111
|
+
* materialize layers can stage the bundle without a DB round-trip. It NEVER
|
|
112
|
+
* appears on the public ingress wire (rejected by `parseSubmission` unless the
|
|
113
|
+
* caller is a trusted re-parse).
|
|
89
114
|
*/
|
|
90
|
-
export interface
|
|
115
|
+
export interface ResolvedSkillRef {
|
|
91
116
|
readonly kind: "skill";
|
|
92
117
|
readonly assetId: string;
|
|
93
118
|
readonly name: string;
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Public composition concepts:
|
|
5
5
|
*
|
|
6
|
-
* - `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* - `SkillRef` is the PUBLIC wire-level reference to a workspace skill: just
|
|
7
|
+
* `{ kind:"skill", name }`. The binding is BY NAME and mutable — the run
|
|
8
|
+
* resolves the name to the workspace skill's current bytes at submit time.
|
|
9
|
+
* It travels in `submission.skills` (NOT `submission.tools`).
|
|
10
|
+
*
|
|
11
|
+
* - `ResolvedSkillRef` is the BFF-produced, boot-record-only resolution of a
|
|
12
|
+
* `SkillRef`: `{ kind:"skill", assetId, name, description }`. It never
|
|
13
|
+
* appears on the public ingress wire — the resolver fills it before
|
|
14
|
+
* persisting the boot record so the in-container re-parse can read the
|
|
15
|
+
* skill's asset + description without a DB round-trip.
|
|
11
16
|
*
|
|
12
17
|
* - `McpServerRef` is the non-secret part of an MCP server declaration:
|
|
13
18
|
* `name` and `url`. Bearer / cookie / per-request headers travel in
|
|
@@ -53,6 +58,13 @@ export const SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
|
53
58
|
* because SessionDO reserves that separator for MCP namespace routing.
|
|
54
59
|
*/
|
|
55
60
|
export const TOOL_NAME_PATTERN = SKILL_NAME_PATTERN;
|
|
61
|
+
/**
|
|
62
|
+
* Names reserved by the skills subsystem and therefore usable as neither a
|
|
63
|
+
* skill name nor a custom tool name. `skills` is the injected meta-tool (see
|
|
64
|
+
* {@link SKILLS_TOOL_NAME} in `submission.ts`); `skill` is its singular. Both
|
|
65
|
+
* the SDK factories and the BFF `parseSkills` / `parseTools` reject these.
|
|
66
|
+
*/
|
|
67
|
+
export const SKILL_RESERVED_NAMES = new Set(["skills", "skill"]);
|
|
56
68
|
// ---------------------------------------------------------------------------
|
|
57
69
|
// Skill bundle limits (uploaded bundles)
|
|
58
70
|
// ---------------------------------------------------------------------------
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RunCostTelemetry } from "./run-cost.js";
|
|
2
2
|
import { type CustodyManifestV1, type CustodyRedactionFinding } from "./run-custody.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { AexEvent } from "./event-envelope.js";
|
|
4
|
+
import type { Run, Output } from "./runtime-types.js";
|
|
4
5
|
import type { PlatformSubmission } from "./submission.js";
|
|
5
6
|
export declare const RUN_RECORD_SCHEMA_VERSION: "aex.run-record.v1";
|
|
6
7
|
export declare const RUN_RECORD_MANIFEST_SCHEMA_VERSION: "aex.run-record.manifest.v1";
|
|
@@ -22,7 +23,7 @@ export interface RunRecordMetadataV1 {
|
|
|
22
23
|
}
|
|
23
24
|
export interface RunRecordEventsV1 {
|
|
24
25
|
/** Typed `channel: "event"` records in the SDK `events/events.jsonl` export. */
|
|
25
|
-
readonly typed: readonly
|
|
26
|
+
readonly typed: readonly AexEvent[];
|
|
26
27
|
}
|
|
27
28
|
export interface RunRecordV1 {
|
|
28
29
|
readonly schemaVersion: typeof RUN_RECORD_SCHEMA_VERSION;
|