@aexhq/sdk 0.35.0 → 0.36.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 +16 -15
- package/dist/_contracts/index.d.ts +3 -4
- package/dist/_contracts/index.js +1 -4
- package/dist/_contracts/operations.d.ts +2 -1
- package/dist/_contracts/operations.js +10 -0
- package/dist/_contracts/run-config.d.ts +1 -3
- package/dist/_contracts/run-config.js +2 -7
- package/dist/_contracts/run-trace.d.ts +0 -86
- package/dist/_contracts/run-trace.js +1 -184
- package/dist/_contracts/run-unit.d.ts +2 -25
- package/dist/_contracts/run-unit.js +1 -2
- package/dist/_contracts/runtime-manifest.d.ts +1 -1
- package/dist/_contracts/runtime-security-profile.d.ts +0 -2
- package/dist/_contracts/runtime-security-profile.js +0 -9
- package/dist/_contracts/runtime-types.d.ts +25 -4
- package/dist/_contracts/stable.d.ts +1 -1
- package/dist/_contracts/stable.js +1 -1
- package/dist/_contracts/submission.d.ts +4 -72
- package/dist/_contracts/submission.js +5 -472
- package/dist/cli.mjs +20 -442
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +30 -25
- package/dist/client.js +251 -66
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +7 -15
- package/dist/index.js +5 -17
- package/dist/index.js.map +1 -1
- package/dist/secret.d.ts +2 -2
- package/dist/secret.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/concepts/composition.md +8 -14
- package/docs/credentials.md +59 -101
- package/docs/defaults.md +0 -8
- package/docs/events.md +8 -9
- package/docs/limits-and-quotas.md +1 -4
- package/docs/limits.md +2 -6
- package/docs/mcp.md +4 -5
- package/docs/networking.md +6 -16
- package/docs/outputs.md +0 -4
- package/docs/public-surface.json +3 -3
- package/docs/quickstart.md +3 -7
- package/docs/run-config.md +6 -3
- package/docs/secrets.md +1 -1
- package/docs/skills.md +3 -3
- package/docs/vision-skills.md +52 -101
- package/examples/feature-tour.ts +4 -21
- package/package.json +1 -1
- package/dist/_contracts/proxy-protocol.d.ts +0 -305
- package/dist/_contracts/proxy-protocol.js +0 -297
- package/dist/_contracts/proxy-validation.d.ts +0 -19
- package/dist/_contracts/proxy-validation.js +0 -51
- package/dist/data-tools.d.ts +0 -82
- package/dist/data-tools.js +0 -251
- package/dist/data-tools.js.map +0 -1
- package/dist/proxy-endpoint.d.ts +0 -131
- package/dist/proxy-endpoint.js +0 -144
- package/dist/proxy-endpoint.js.map +0 -1
- package/examples/chat-corpus.ts +0 -84
package/dist/client.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { HttpClient, SecretString, type AexEvent, type AgentsMdRecord, type
|
|
1
|
+
import { HttpClient, SecretString, type AexEvent, type AgentsMdRecord, type DebugSink, type FetchLike, type FileRecord, type Output, type OutputFileType, type OutputLink, type OutputLinkOptions, type OutputQuery, type OutputText, type OutputMode, type ReadOutputTextOptions, type OutputSearchQuery, type OutputSearchPage, type Session, type SessionCreateRequest, type SessionEvent, type SessionListPage, type SessionListQuery, type SessionMessage, type SessionStateChangeAccepted, type SessionTurn, type PlatformEnvironmentInput, type PlatformSubmission, type Run, type RunModel, type RunEvent, type RunTrace, type UsageSummary, type RunWebhookDelivery, type RunProvider, type SecretRecord, type RunUnit, type BuiltinToolName, type RuntimeSize, type WebSocketFactory, type WhoAmI } from "./_contracts/index.js";
|
|
2
2
|
import { AgentsMd } from "./agents-md.js";
|
|
3
3
|
import { type UploadedAsset } from "./asset-upload.js";
|
|
4
4
|
import { File } from "./file.js";
|
|
5
5
|
import { McpServer } from "./mcp-server.js";
|
|
6
|
-
import { ProxyEndpoint } from "./proxy-endpoint.js";
|
|
7
6
|
import { type RetryOptions } from "./retry.js";
|
|
8
7
|
import { Secret } from "./secret.js";
|
|
9
8
|
import { SkillTool } from "./skill-tool.js";
|
|
10
9
|
import { Tool } from "./tool.js";
|
|
11
|
-
export interface
|
|
10
|
+
export interface AexOptions {
|
|
12
11
|
/** Workspace-scoped SDK API token. */
|
|
13
|
-
readonly
|
|
12
|
+
readonly apiKey?: string;
|
|
13
|
+
/** @deprecated Use `apiKey`; kept as a source-compatible alias during launch. */
|
|
14
|
+
readonly apiToken?: string;
|
|
14
15
|
/**
|
|
15
16
|
* API plane root, e.g. `https://aex.example.com`. Optional —
|
|
16
17
|
* defaults to the canonical hosted URL (`https://api.aex.dev`).
|
|
@@ -37,7 +38,7 @@ export interface AgentExecutorOptions {
|
|
|
37
38
|
readonly retry?: RetryOptions | false;
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
|
-
* The settle-consistent result of {@link
|
|
41
|
+
* The settle-consistent result of {@link Aex.run}:
|
|
41
42
|
* the one-shot session record plus its events, decoded trace, assistant text,
|
|
42
43
|
* and captured outputs — everything a "do it and give me the result" caller
|
|
43
44
|
* needs without hand-rolling a session/message/stream loop.
|
|
@@ -57,6 +58,8 @@ export interface RunResult {
|
|
|
57
58
|
readonly ok: boolean;
|
|
58
59
|
/** The assistant's final text. */
|
|
59
60
|
readonly text: string;
|
|
61
|
+
/** Assistant messages projected from the settled event stream. */
|
|
62
|
+
readonly messages: readonly Message[];
|
|
60
63
|
/** The session turn event stream. */
|
|
61
64
|
readonly events: readonly RunEvent[];
|
|
62
65
|
/** Decoded view of the events: tool calls + usage + assistant text. */
|
|
@@ -70,7 +73,7 @@ export interface RunResult {
|
|
|
70
73
|
/** The run's error message when `!ok`. */
|
|
71
74
|
readonly error?: string;
|
|
72
75
|
}
|
|
73
|
-
/** Options for {@link
|
|
76
|
+
/** Options for {@link Aex.run}. */
|
|
74
77
|
export interface RunCollectOptions {
|
|
75
78
|
/** Overall wait budget (ms) for the one-shot session turn to park. */
|
|
76
79
|
readonly timeoutMs?: number;
|
|
@@ -102,9 +105,8 @@ export interface SessionOverrides {
|
|
|
102
105
|
* - `agentsMd` / `files` — local composition instances
|
|
103
106
|
* (`AgentsMd.fromContent` / `File.fromBytes`, …), materialized to the
|
|
104
107
|
* hosted asset store before the session lands.
|
|
105
|
-
* - `mcpServers`
|
|
106
|
-
*
|
|
107
|
-
* only the declarations.
|
|
108
|
+
* - `mcpServers` — instances whose secrets are split into the vaulted secrets
|
|
109
|
+
* channel server-side; the public submission carries only the declarations.
|
|
108
110
|
* - `apiKeys` — the BYOK provider key(s), keyed by provider. A key for the
|
|
109
111
|
* selected provider is REQUIRED. The platform never holds a long-lived
|
|
110
112
|
* provider key on your behalf.
|
|
@@ -158,7 +160,6 @@ export interface SessionCreateOptions {
|
|
|
158
160
|
readonly outputMode?: OutputMode;
|
|
159
161
|
readonly metadata?: PlatformSubmission["metadata"];
|
|
160
162
|
readonly idempotencyKey?: string;
|
|
161
|
-
readonly proxyEndpoints?: readonly ProxyEndpoint[];
|
|
162
163
|
/** BYOK provider key(s), keyed by provider. */
|
|
163
164
|
readonly apiKeys?: Partial<Record<RunProvider, string>>;
|
|
164
165
|
readonly environment?: SessionEnvironmentOptions;
|
|
@@ -199,6 +200,7 @@ export interface SessionTurnResult {
|
|
|
199
200
|
readonly text: string;
|
|
200
201
|
readonly events: readonly SessionEvent[];
|
|
201
202
|
readonly outputs: readonly Output[];
|
|
203
|
+
readonly messages: readonly Message[];
|
|
202
204
|
}
|
|
203
205
|
export interface SessionRunResult extends SessionTurnResult {
|
|
204
206
|
}
|
|
@@ -208,14 +210,18 @@ export declare class SessionTurnStream implements AsyncIterable<SessionEvent> {
|
|
|
208
210
|
[Symbol.asyncIterator](): AsyncIterator<SessionEvent>;
|
|
209
211
|
done(): Promise<SessionTurnResult>;
|
|
210
212
|
}
|
|
213
|
+
type CallableSessionMessages = SessionMessages & (() => SessionMessages);
|
|
214
|
+
export type Message = SessionMessage;
|
|
211
215
|
/**
|
|
212
|
-
* Accessor over the session's
|
|
213
|
-
*
|
|
216
|
+
* Accessor over the session's assistant messages. `session.messages` returns
|
|
217
|
+
* this synchronously; each method fetches on call.
|
|
214
218
|
*/
|
|
215
219
|
export interface SessionMessages {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
all(): Promise<readonly Message[]>;
|
|
221
|
+
/** Compatibility alias for {@link SessionMessages.all}. */
|
|
222
|
+
list(): Promise<readonly Message[]>;
|
|
223
|
+
last(): Promise<Message | undefined>;
|
|
224
|
+
first(): Promise<Message | undefined>;
|
|
219
225
|
}
|
|
220
226
|
/**
|
|
221
227
|
* Accessor over the session's event stream (`session.events()`): the buffered
|
|
@@ -274,11 +280,12 @@ export declare class SessionHandle {
|
|
|
274
280
|
resume(options?: Pick<SessionSendOptions, "idempotencyKey">): Promise<SessionStateChangeAccepted>;
|
|
275
281
|
delete(options?: Pick<SessionSendOptions, "idempotencyKey">): Promise<void>;
|
|
276
282
|
/**
|
|
277
|
-
* Accessor for the session's
|
|
278
|
-
*
|
|
279
|
-
*
|
|
283
|
+
* Accessor for the session's assistant messages. `all()` returns them
|
|
284
|
+
* oldest-first; `last()`/`first()` return a single entry or `undefined` when
|
|
285
|
+
* empty. The accessor is callable as a compatibility shim for older
|
|
286
|
+
* `session.messages().list()` callers.
|
|
280
287
|
*/
|
|
281
|
-
messages():
|
|
288
|
+
get messages(): CallableSessionMessages;
|
|
282
289
|
/**
|
|
283
290
|
* Accessor for the session's event stream: the buffered `SessionEvent`
|
|
284
291
|
* snapshots (`list`/`last`/`first`), the polling `RunEvent` iterator
|
|
@@ -473,13 +480,14 @@ export declare class SecretsClient {
|
|
|
473
480
|
* `client.whoami()` if you want to introspect which workspace the
|
|
474
481
|
* token resolves to.
|
|
475
482
|
*/
|
|
476
|
-
export declare class
|
|
483
|
+
export declare class Aex {
|
|
477
484
|
#private;
|
|
478
485
|
readonly agentsMd: AgentsMdClient;
|
|
479
486
|
readonly files: FilesClient;
|
|
480
487
|
readonly secrets: SecretsClient;
|
|
481
488
|
readonly sessions: SessionClient;
|
|
482
|
-
constructor(
|
|
489
|
+
constructor(apiKey: string, options?: Omit<AexOptions, "apiKey" | "apiToken">);
|
|
490
|
+
constructor(options: AexOptions);
|
|
483
491
|
/**
|
|
484
492
|
* Internal: satisfies the `SecretUploader` surface so a
|
|
485
493
|
* `Secret.value(...).upload(client, { name })` promotes an ephemeral secret
|
|
@@ -522,7 +530,4 @@ export declare class AgentExecutor {
|
|
|
522
530
|
deleteWorkspaceAsset(hash: string): Promise<void>;
|
|
523
531
|
whoami(): Promise<WhoAmI>;
|
|
524
532
|
}
|
|
525
|
-
|
|
526
|
-
export declare class Aex extends AgentExecutor {
|
|
527
|
-
}
|
|
528
|
-
export type { OutputFileType, OutputLink, OutputLinkOptions, OutputQuery, PlatformProxyEndpoint, PlatformProxyEndpointAuth };
|
|
533
|
+
export type { OutputFileType, OutputLink, OutputLinkOptions, OutputQuery };
|
package/dist/client.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { AexError, DEFAULT_RUN_PROVIDER, HttpClient, RunConfigValidationError, RunStateError, SecretString, customName, isRunSettled, operations, providersForModel, streamCoordinatorEvents,
|
|
1
|
+
import { AexApiError, AexError, DEFAULT_RUN_PROVIDER, HttpClient, RunConfigValidationError, RunStateError, SecretString, customName, isRunSettled, operations, providersForModel, streamCoordinatorEvents, parseRunLimits, BUILTIN_TOOL_NAMES, TERMINAL_RUN_STATUSES } from "./_contracts/index.js";
|
|
2
2
|
import { AgentsMd } from "./agents-md.js";
|
|
3
3
|
import { uploadAsset } from "./asset-upload.js";
|
|
4
4
|
import { File } from "./file.js";
|
|
5
5
|
import { McpServer } from "./mcp-server.js";
|
|
6
|
-
import { splitProxyEndpoints } from "./proxy-endpoint.js";
|
|
7
6
|
import { AexRateLimitError, isThrottleFault, parseProviderFault, withRetry } from "./retry.js";
|
|
8
7
|
import { splitSecretEnv } from "./secret.js";
|
|
9
8
|
import { SkillTool } from "./skill-tool.js";
|
|
@@ -95,14 +94,16 @@ export class SessionHandle {
|
|
|
95
94
|
const readSession = await operations.getSession(this.#http, this.id).catch(() => this.#session);
|
|
96
95
|
this.#session = withTerminalSessionStatus(readSession, terminalStatus);
|
|
97
96
|
const outputs = await operations.listSessionOutputs(this.#http, this.id).catch(() => []);
|
|
97
|
+
const messages = projectAssistantMessages(events);
|
|
98
98
|
return {
|
|
99
99
|
sessionId: this.id,
|
|
100
100
|
session: this.#session,
|
|
101
101
|
turn,
|
|
102
102
|
status: this.#session.status,
|
|
103
|
-
text:
|
|
103
|
+
text: assistantTextFromEvents(events),
|
|
104
104
|
events,
|
|
105
|
-
outputs
|
|
105
|
+
outputs,
|
|
106
|
+
messages
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
async suspend(options = {}) {
|
|
@@ -127,19 +128,39 @@ export class SessionHandle {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
/**
|
|
130
|
-
* Accessor for the session's
|
|
131
|
-
*
|
|
132
|
-
*
|
|
131
|
+
* Accessor for the session's assistant messages. `all()` returns them
|
|
132
|
+
* oldest-first; `last()`/`first()` return a single entry or `undefined` when
|
|
133
|
+
* empty. The accessor is callable as a compatibility shim for older
|
|
134
|
+
* `session.messages().list()` callers.
|
|
133
135
|
*/
|
|
134
|
-
messages() {
|
|
136
|
+
get messages() {
|
|
135
137
|
const http = this.#http;
|
|
136
138
|
const id = this.id;
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const fromEvents = async () => projectAssistantMessages(await operations.listSessionEvents(http, id));
|
|
140
|
+
const all = async () => {
|
|
141
|
+
try {
|
|
142
|
+
const page = await operations.listSessionMessages(http, id);
|
|
143
|
+
if (!Array.isArray(page.messages)) {
|
|
144
|
+
return fromEvents();
|
|
145
|
+
}
|
|
146
|
+
return page.messages.map(messageFromWire);
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
if (!isMissingMessagesEndpoint(err)) {
|
|
150
|
+
throw err;
|
|
151
|
+
}
|
|
152
|
+
return fromEvents();
|
|
153
|
+
}
|
|
142
154
|
};
|
|
155
|
+
let accessor;
|
|
156
|
+
accessor = (() => accessor);
|
|
157
|
+
Object.assign(accessor, {
|
|
158
|
+
all,
|
|
159
|
+
list: all,
|
|
160
|
+
last: async () => (await all()).at(-1),
|
|
161
|
+
first: async () => (await all())[0]
|
|
162
|
+
});
|
|
163
|
+
return accessor;
|
|
143
164
|
}
|
|
144
165
|
/**
|
|
145
166
|
* Accessor for the session's event stream: the buffered `SessionEvent`
|
|
@@ -447,6 +468,199 @@ function sessionOutputs(http, id, fetchLike) {
|
|
|
447
468
|
download: (selector, options) => downloadSessionOutput(http, id, selector, options)
|
|
448
469
|
};
|
|
449
470
|
}
|
|
471
|
+
function messageFromWire(message) {
|
|
472
|
+
return {
|
|
473
|
+
id: message.id,
|
|
474
|
+
sender: message.sender,
|
|
475
|
+
text: message.text,
|
|
476
|
+
...(message.timestamp !== undefined ? { timestamp: message.timestamp } : {}),
|
|
477
|
+
...(message.turnSeq !== undefined ? { turnSeq: message.turnSeq } : {}),
|
|
478
|
+
...(message.sequence !== undefined ? { sequence: message.sequence } : {})
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function isMissingMessagesEndpoint(err) {
|
|
482
|
+
return err instanceof AexApiError && (err.status === 404 || err.status === 405 || err.status === 501);
|
|
483
|
+
}
|
|
484
|
+
function projectAssistantMessages(events) {
|
|
485
|
+
const out = [];
|
|
486
|
+
const byMessageId = new Map();
|
|
487
|
+
for (let i = 0; i < events.length; i++) {
|
|
488
|
+
const event = events[i];
|
|
489
|
+
if (event.type !== "TEXT_MESSAGE_CONTENT")
|
|
490
|
+
continue;
|
|
491
|
+
const data = asRecord(event.data);
|
|
492
|
+
const text = typeof data.text === "string" ? data.text : undefined;
|
|
493
|
+
if (text === undefined)
|
|
494
|
+
continue;
|
|
495
|
+
const messageId = typeof data.messageId === "string" && data.messageId ? data.messageId : undefined;
|
|
496
|
+
const sequence = event.sequence ?? event.seq;
|
|
497
|
+
const timestamp = event.time ?? event.recordedAt ?? timestampFromEpochMs(event.receivedAt);
|
|
498
|
+
const turnSeq = typeof data.turnSeq === "number" ? data.turnSeq : undefined;
|
|
499
|
+
if (messageId !== undefined) {
|
|
500
|
+
const existing = byMessageId.get(messageId);
|
|
501
|
+
if (existing !== undefined) {
|
|
502
|
+
const current = out[existing];
|
|
503
|
+
out[existing] = {
|
|
504
|
+
...current,
|
|
505
|
+
text: `${current.text}${text}`,
|
|
506
|
+
...(timestamp !== undefined ? { timestamp } : {}),
|
|
507
|
+
...(sequence !== undefined ? { sequence } : {}),
|
|
508
|
+
...(turnSeq !== undefined ? { turnSeq } : {})
|
|
509
|
+
};
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
byMessageId.set(messageId, out.length);
|
|
513
|
+
}
|
|
514
|
+
out.push({
|
|
515
|
+
id: messageId ?? (typeof event.id === "string" && event.id ? event.id : `message-${i}`),
|
|
516
|
+
sender: "assistant",
|
|
517
|
+
text,
|
|
518
|
+
...(timestamp !== undefined ? { timestamp } : {}),
|
|
519
|
+
...(sequence !== undefined ? { sequence } : {}),
|
|
520
|
+
...(turnSeq !== undefined ? { turnSeq } : {})
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
return out;
|
|
524
|
+
}
|
|
525
|
+
function assistantTextFromEvents(events) {
|
|
526
|
+
return assistantTextEntriesFromEvents(events).map((entry) => entry.text).join("");
|
|
527
|
+
}
|
|
528
|
+
function runTraceFromEvents(events) {
|
|
529
|
+
return {
|
|
530
|
+
toolCalls: toolCallsFromEvents(events),
|
|
531
|
+
usage: usageFromEvents(events),
|
|
532
|
+
text: assistantTextEntriesFromEvents(events)
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function assistantTextEntriesFromEvents(events) {
|
|
536
|
+
const out = [];
|
|
537
|
+
for (const raw of events) {
|
|
538
|
+
const event = raw;
|
|
539
|
+
if (event.type !== "TEXT_MESSAGE_CONTENT")
|
|
540
|
+
continue;
|
|
541
|
+
const data = asRecord(event.data);
|
|
542
|
+
const text = typeof data.text === "string" ? data.text : undefined;
|
|
543
|
+
if (text === undefined)
|
|
544
|
+
continue;
|
|
545
|
+
const entry = { text };
|
|
546
|
+
const messageId = typeof data.messageId === "string" ? data.messageId : undefined;
|
|
547
|
+
if (messageId !== undefined)
|
|
548
|
+
entry.messageId = messageId;
|
|
549
|
+
if (typeof event.seq === "number")
|
|
550
|
+
entry.seq = event.seq;
|
|
551
|
+
const recordedAt = typeof event.recordedAt === "string" ? event.recordedAt : undefined;
|
|
552
|
+
if (recordedAt !== undefined)
|
|
553
|
+
entry.recordedAt = recordedAt;
|
|
554
|
+
out.push(entry);
|
|
555
|
+
}
|
|
556
|
+
return out;
|
|
557
|
+
}
|
|
558
|
+
function toolCallsFromEvents(events) {
|
|
559
|
+
const order = [];
|
|
560
|
+
const byId = new Map();
|
|
561
|
+
for (const event of events) {
|
|
562
|
+
const data = asRecord(event.data);
|
|
563
|
+
if (event.type === "TOOL_CALL_START") {
|
|
564
|
+
const id = typeof data.id === "string" ? data.id : undefined;
|
|
565
|
+
if (id === undefined)
|
|
566
|
+
continue;
|
|
567
|
+
const trace = {
|
|
568
|
+
id,
|
|
569
|
+
name: typeof data.name === "string" ? data.name : "",
|
|
570
|
+
args: asRecord(data.arguments)
|
|
571
|
+
};
|
|
572
|
+
const messageId = typeof data.messageId === "string" ? data.messageId : undefined;
|
|
573
|
+
if (messageId !== undefined)
|
|
574
|
+
trace.messageId = messageId;
|
|
575
|
+
if (typeof event.seq === "number")
|
|
576
|
+
trace.startSeq = event.seq;
|
|
577
|
+
if (typeof event.recordedAt === "string")
|
|
578
|
+
trace.startedAt = event.recordedAt;
|
|
579
|
+
if (!byId.has(id))
|
|
580
|
+
order.push(id);
|
|
581
|
+
byId.set(id, trace);
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
if (event.type === "TOOL_CALL_RESULT") {
|
|
585
|
+
const id = typeof data.id === "string" ? data.id : undefined;
|
|
586
|
+
if (id === undefined)
|
|
587
|
+
continue;
|
|
588
|
+
const result = {
|
|
589
|
+
isError: data.isError === true,
|
|
590
|
+
content: data.content ?? null
|
|
591
|
+
};
|
|
592
|
+
if (typeof event.seq === "number")
|
|
593
|
+
result.seq = event.seq;
|
|
594
|
+
if (typeof event.recordedAt === "string")
|
|
595
|
+
result.recordedAt = event.recordedAt;
|
|
596
|
+
let trace = byId.get(id);
|
|
597
|
+
if (trace === undefined) {
|
|
598
|
+
trace = { id, name: "", args: {} };
|
|
599
|
+
order.push(id);
|
|
600
|
+
byId.set(id, trace);
|
|
601
|
+
}
|
|
602
|
+
trace.result = result;
|
|
603
|
+
const duration = durationMs(trace.startedAt, result.recordedAt);
|
|
604
|
+
if (duration !== undefined)
|
|
605
|
+
trace.durationMs = duration;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return order.map((id) => byId.get(id));
|
|
609
|
+
}
|
|
610
|
+
function usageFromEvents(events) {
|
|
611
|
+
const totals = { inputTokens: 0, outputTokens: 0, cacheReadInputTokens: 0, cacheCreationInputTokens: 0 };
|
|
612
|
+
let seen = false;
|
|
613
|
+
for (const event of events) {
|
|
614
|
+
if (event.type !== "CUSTOM")
|
|
615
|
+
continue;
|
|
616
|
+
const data = asRecord(event.data);
|
|
617
|
+
if (data.name !== "aex.usage")
|
|
618
|
+
continue;
|
|
619
|
+
const value = asRecord(data.value);
|
|
620
|
+
const fields = [
|
|
621
|
+
["input_tokens", "inputTokens"],
|
|
622
|
+
["output_tokens", "outputTokens"],
|
|
623
|
+
["cache_read_input_tokens", "cacheReadInputTokens"],
|
|
624
|
+
["cache_creation_input_tokens", "cacheCreationInputTokens"]
|
|
625
|
+
];
|
|
626
|
+
for (const [wireName, apiName] of fields) {
|
|
627
|
+
const n = value[wireName];
|
|
628
|
+
if (typeof n === "number" && Number.isFinite(n)) {
|
|
629
|
+
totals[apiName] += n;
|
|
630
|
+
seen = true;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (!seen)
|
|
635
|
+
return {};
|
|
636
|
+
return {
|
|
637
|
+
inputTokens: totals.inputTokens,
|
|
638
|
+
outputTokens: totals.outputTokens,
|
|
639
|
+
cacheReadInputTokens: totals.cacheReadInputTokens,
|
|
640
|
+
cacheCreationInputTokens: totals.cacheCreationInputTokens,
|
|
641
|
+
totalTokens: totals.inputTokens + totals.outputTokens
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function asRecord(value) {
|
|
645
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
646
|
+
? value
|
|
647
|
+
: {};
|
|
648
|
+
}
|
|
649
|
+
function timestampFromEpochMs(value) {
|
|
650
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
651
|
+
? new Date(value).toISOString()
|
|
652
|
+
: undefined;
|
|
653
|
+
}
|
|
654
|
+
function durationMs(start, end) {
|
|
655
|
+
if (start === undefined || end === undefined)
|
|
656
|
+
return undefined;
|
|
657
|
+
const a = Date.parse(start);
|
|
658
|
+
const b = Date.parse(end);
|
|
659
|
+
if (!Number.isFinite(a) || !Number.isFinite(b))
|
|
660
|
+
return undefined;
|
|
661
|
+
const delta = b - a;
|
|
662
|
+
return delta >= 0 ? delta : undefined;
|
|
663
|
+
}
|
|
450
664
|
function isSessionTurnTerminalEvent(event, turnSeq) {
|
|
451
665
|
const name = customName(event);
|
|
452
666
|
if (name !== "aex.session.idle" &&
|
|
@@ -599,7 +813,7 @@ function unwrapSecretValue(value) {
|
|
|
599
813
|
* `client.whoami()` if you want to introspect which workspace the
|
|
600
814
|
* token resolves to.
|
|
601
815
|
*/
|
|
602
|
-
export class
|
|
816
|
+
export class Aex {
|
|
603
817
|
#http;
|
|
604
818
|
/** The same fetch the HttpClient uses, threaded into `_uploadAsset`. */
|
|
605
819
|
#fetch;
|
|
@@ -607,28 +821,30 @@ export class AgentExecutor {
|
|
|
607
821
|
files;
|
|
608
822
|
secrets;
|
|
609
823
|
sessions;
|
|
610
|
-
constructor(options) {
|
|
611
|
-
|
|
612
|
-
|
|
824
|
+
constructor(options, overrides = {}) {
|
|
825
|
+
const resolved = typeof options === "string" ? { ...overrides, apiKey: options } : options;
|
|
826
|
+
const apiKey = resolved.apiKey ?? resolved.apiToken;
|
|
827
|
+
if (!apiKey) {
|
|
828
|
+
throw new Error("Aex: apiKey is required");
|
|
613
829
|
}
|
|
614
830
|
// Wrap the transport fetch (the caller's override, or global `fetch`) with
|
|
615
831
|
// the bounded-retry layer so every BFF request gets default resilience.
|
|
616
832
|
// The raw `#fetch` below stays unwrapped for the direct-to-storage asset PUT
|
|
617
833
|
// and presigned output GETs, which target object storage, not the API plane.
|
|
618
|
-
const baseFetch =
|
|
619
|
-
const retryingFetch = withRetry(baseFetch,
|
|
834
|
+
const baseFetch = resolved.fetch ?? ((input, init) => fetch(input, init));
|
|
835
|
+
const retryingFetch = withRetry(baseFetch, resolved.retry);
|
|
620
836
|
this.#http = new HttpClient({
|
|
621
|
-
...(
|
|
622
|
-
apiToken:
|
|
837
|
+
...(resolved.baseUrl ? { baseUrl: resolved.baseUrl } : {}),
|
|
838
|
+
apiToken: apiKey,
|
|
623
839
|
fetch: retryingFetch,
|
|
624
840
|
// Opt-in local diagnostics: emit a redacted per-request trace to
|
|
625
841
|
// stderr. Uploads nothing. A caller wanting a custom sink can pass
|
|
626
842
|
// a function instead of `true`.
|
|
627
|
-
...(
|
|
628
|
-
? { debug: typeof
|
|
843
|
+
...(resolved.debug
|
|
844
|
+
? { debug: typeof resolved.debug === "function" ? resolved.debug : (line) => console.error(line) }
|
|
629
845
|
: {})
|
|
630
846
|
});
|
|
631
|
-
this.#fetch =
|
|
847
|
+
this.#fetch = resolved.fetch;
|
|
632
848
|
this.agentsMd = new AgentsMdClient(this.#http);
|
|
633
849
|
this.files = new FilesClient(this.#http);
|
|
634
850
|
this.secrets = new SecretsClient(this.#http);
|
|
@@ -709,8 +925,9 @@ export class AgentExecutor {
|
|
|
709
925
|
status: turnResult.status,
|
|
710
926
|
ok,
|
|
711
927
|
text: turnResult.text,
|
|
928
|
+
messages: turnResult.messages,
|
|
712
929
|
events,
|
|
713
|
-
trace:
|
|
930
|
+
trace: runTraceFromEvents(events),
|
|
714
931
|
outputs,
|
|
715
932
|
...(turnResult.session.usage ? { usage: turnResult.session.usage } : {}),
|
|
716
933
|
...(typeof costUsd === "number" ? { costUsd } : {}),
|
|
@@ -730,7 +947,7 @@ export class AgentExecutor {
|
|
|
730
947
|
...(throttle.retryAfterMs !== undefined ? { retryAfterMs: throttle.retryAfterMs } : {})
|
|
731
948
|
});
|
|
732
949
|
}
|
|
733
|
-
throw new RunStateError(`
|
|
950
|
+
throw new RunStateError(`Aex.run: session ${runId} ended ${turnResult.status}${errorMessage ? `: ${errorMessage}` : ""}`, { runId, status: turnResult.status });
|
|
734
951
|
}
|
|
735
952
|
return result;
|
|
736
953
|
}
|
|
@@ -760,8 +977,6 @@ export class AgentExecutor {
|
|
|
760
977
|
if (typeof options.model !== "string" || !options.model) {
|
|
761
978
|
throw new RunConfigValidationError("Aex.openSession: model is required");
|
|
762
979
|
}
|
|
763
|
-
const { endpoints: proxyEndpointDeclarations, auth: proxyEndpointAuthFromInstances } = splitProxyEndpoints(options.proxyEndpoints ?? []);
|
|
764
|
-
const mergedProxyAuth = mergeProxyEndpointAuth(proxyEndpointAuthFromInstances, []);
|
|
765
980
|
const { declarations: secretEnvDeclarations, values: envSecretValues } = splitSecretEnv(options.environment?.secrets);
|
|
766
981
|
let limits;
|
|
767
982
|
try {
|
|
@@ -804,7 +1019,6 @@ export class AgentExecutor {
|
|
|
804
1019
|
const secrets = {
|
|
805
1020
|
...(options.apiKeys ? { apiKeys: options.apiKeys } : {}),
|
|
806
1021
|
...(mergedMcpSecrets.length > 0 ? { mcpServers: mergedMcpSecrets } : {}),
|
|
807
|
-
...(mergedProxyAuth.length > 0 ? { proxyEndpointAuth: mergedProxyAuth } : {}),
|
|
808
1022
|
...(Object.keys(envSecretValues).length > 0 ? { envSecrets: envSecretValues } : {})
|
|
809
1023
|
};
|
|
810
1024
|
const retention = sessionRetentionForWire(options);
|
|
@@ -818,10 +1032,7 @@ export class AgentExecutor {
|
|
|
818
1032
|
// Operational/delivery concern — sibling of secrets, NOT part of the
|
|
819
1033
|
// hashed submission. Delivered at the settle-consistent barrier.
|
|
820
1034
|
...(options.webhook ? { webhook: options.webhook } : {}),
|
|
821
|
-
secrets
|
|
822
|
-
...(proxyEndpointDeclarations.length > 0
|
|
823
|
-
? { proxyEndpoints: proxyEndpointDeclarations }
|
|
824
|
-
: {})
|
|
1035
|
+
secrets
|
|
825
1036
|
};
|
|
826
1037
|
}
|
|
827
1038
|
/**
|
|
@@ -836,9 +1047,6 @@ export class AgentExecutor {
|
|
|
836
1047
|
return operations.whoami(this.#http);
|
|
837
1048
|
}
|
|
838
1049
|
}
|
|
839
|
-
/** Canonical SDK client name. `AgentExecutor` remains as a compatibility alias. */
|
|
840
|
-
export class Aex extends AgentExecutor {
|
|
841
|
-
}
|
|
842
1050
|
// `Run.status` is a loose `string` on the wire shape, so we membership-test
|
|
843
1051
|
// against the canonical terminal set rather than re-deriving one (which is how
|
|
844
1052
|
// `timed_out` got dropped from the old hardcoded list).
|
|
@@ -895,7 +1103,7 @@ function resolveOutputFileSelector(outputs, selector, runId) {
|
|
|
895
1103
|
if (isOutputPathSelector(selector)) {
|
|
896
1104
|
const target = normalizeOutputLookupPath(selector.path);
|
|
897
1105
|
if (!target) {
|
|
898
|
-
throw new RunStateError("
|
|
1106
|
+
throw new RunStateError("Aex.downloadOutput: output path must be non-empty", {
|
|
899
1107
|
runId,
|
|
900
1108
|
path: selector.path
|
|
901
1109
|
});
|
|
@@ -912,15 +1120,15 @@ function resolveOutputFileSelector(outputs, selector, runId) {
|
|
|
912
1120
|
if (matches.length === 1)
|
|
913
1121
|
return matches[0];
|
|
914
1122
|
if (matches.length > 1) {
|
|
915
|
-
throw new RunStateError(`
|
|
1123
|
+
throw new RunStateError(`Aex.downloadOutput: output path "${selector.path}" matched multiple files`, { runId, path: selector.path, matches: matches.map((output) => output.filename ?? output.id) });
|
|
916
1124
|
}
|
|
917
|
-
throw new RunStateError(`
|
|
1125
|
+
throw new RunStateError(`Aex.downloadOutput: output path "${selector.path}" was not found`, {
|
|
918
1126
|
runId,
|
|
919
1127
|
path: selector.path
|
|
920
1128
|
});
|
|
921
1129
|
}
|
|
922
1130
|
if (typeof selector.id !== "string" || selector.id.length === 0) {
|
|
923
|
-
throw new RunStateError("
|
|
1131
|
+
throw new RunStateError("Aex.downloadOutput: selector must include an output id or path", { runId });
|
|
924
1132
|
}
|
|
925
1133
|
return { ...selector, id: selector.id };
|
|
926
1134
|
}
|
|
@@ -1010,6 +1218,7 @@ function normaliseSessionInput(input, surface, field) {
|
|
|
1010
1218
|
}
|
|
1011
1219
|
function assertNoLegacySessionFields(options, surface) {
|
|
1012
1220
|
const record = options;
|
|
1221
|
+
const removedProxyField = "proxy" + "Endpoints";
|
|
1013
1222
|
const messages = {
|
|
1014
1223
|
input: "send user messages with session.send(...) or use run({ message }).",
|
|
1015
1224
|
prompt: "use message for one-shot run input or session.send(...) for follow-up messages.",
|
|
@@ -1025,7 +1234,8 @@ function assertNoLegacySessionFields(options, surface) {
|
|
|
1025
1234
|
limits: "use overrides.",
|
|
1026
1235
|
timeout: "use overrides.timeout.",
|
|
1027
1236
|
signal: "use session.cancel() / session.suspend() for remote control.",
|
|
1028
|
-
postHook: "send a follow-up validation message when the session returns idle."
|
|
1237
|
+
postHook: "send a follow-up validation message when the session returns idle.",
|
|
1238
|
+
[removedProxyField]: "proxy endpoints are not part of the public SDK session API."
|
|
1029
1239
|
};
|
|
1030
1240
|
for (const [field, message] of Object.entries(messages)) {
|
|
1031
1241
|
if (Object.prototype.hasOwnProperty.call(record, field)) {
|
|
@@ -1247,29 +1457,4 @@ function mergeMcpServers(inputs, explicitSecrets) {
|
|
|
1247
1457
|
mergedMcpSecrets: Array.from(secretByName.values())
|
|
1248
1458
|
};
|
|
1249
1459
|
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Merge `ProxyEndpoint`-derived auth entries with any
|
|
1252
|
-
* `secrets.proxyEndpointAuth` the caller passed explicitly. Per-instance
|
|
1253
|
-
* auth values win on the same `name`; a type mismatch (e.g. instance
|
|
1254
|
-
* declares `bearer` but secrets carry `header` for the same name) is a
|
|
1255
|
-
* call-site error and we throw at the SDK boundary instead of letting
|
|
1256
|
-
* the BFF reject the submission an HTTP request later.
|
|
1257
|
-
*/
|
|
1258
|
-
function mergeProxyEndpointAuth(fromInstances, fromExplicitSecrets) {
|
|
1259
|
-
if (fromInstances.length === 0 && fromExplicitSecrets.length === 0)
|
|
1260
|
-
return [];
|
|
1261
|
-
const byName = new Map();
|
|
1262
|
-
for (const entry of fromExplicitSecrets) {
|
|
1263
|
-
byName.set(entry.name, entry);
|
|
1264
|
-
}
|
|
1265
|
-
for (const entry of fromInstances) {
|
|
1266
|
-
const existing = byName.get(entry.name);
|
|
1267
|
-
if (existing && existing.value.type !== entry.value.type) {
|
|
1268
|
-
throw new RunConfigValidationError(`aex: proxyEndpoint "${entry.name}" auth type conflicts ` +
|
|
1269
|
-
`with secrets.proxyEndpointAuth (instance=${entry.value.type}, secrets=${existing.value.type})`);
|
|
1270
|
-
}
|
|
1271
|
-
byName.set(entry.name, entry);
|
|
1272
|
-
}
|
|
1273
|
-
return Array.from(byName.values());
|
|
1274
|
-
}
|
|
1275
1460
|
//# sourceMappingURL=client.js.map
|