@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.
Files changed (59) hide show
  1. package/README.md +16 -15
  2. package/dist/_contracts/index.d.ts +3 -4
  3. package/dist/_contracts/index.js +1 -4
  4. package/dist/_contracts/operations.d.ts +2 -1
  5. package/dist/_contracts/operations.js +10 -0
  6. package/dist/_contracts/run-config.d.ts +1 -3
  7. package/dist/_contracts/run-config.js +2 -7
  8. package/dist/_contracts/run-trace.d.ts +0 -86
  9. package/dist/_contracts/run-trace.js +1 -184
  10. package/dist/_contracts/run-unit.d.ts +2 -25
  11. package/dist/_contracts/run-unit.js +1 -2
  12. package/dist/_contracts/runtime-manifest.d.ts +1 -1
  13. package/dist/_contracts/runtime-security-profile.d.ts +0 -2
  14. package/dist/_contracts/runtime-security-profile.js +0 -9
  15. package/dist/_contracts/runtime-types.d.ts +25 -4
  16. package/dist/_contracts/stable.d.ts +1 -1
  17. package/dist/_contracts/stable.js +1 -1
  18. package/dist/_contracts/submission.d.ts +4 -72
  19. package/dist/_contracts/submission.js +5 -472
  20. package/dist/cli.mjs +20 -442
  21. package/dist/cli.mjs.sha256 +1 -1
  22. package/dist/client.d.ts +30 -25
  23. package/dist/client.js +251 -66
  24. package/dist/client.js.map +1 -1
  25. package/dist/index.d.ts +7 -15
  26. package/dist/index.js +5 -17
  27. package/dist/index.js.map +1 -1
  28. package/dist/secret.d.ts +2 -2
  29. package/dist/secret.js +1 -1
  30. package/dist/version.d.ts +1 -1
  31. package/dist/version.js +1 -1
  32. package/docs/concepts/composition.md +8 -14
  33. package/docs/credentials.md +59 -101
  34. package/docs/defaults.md +0 -8
  35. package/docs/events.md +8 -9
  36. package/docs/limits-and-quotas.md +1 -4
  37. package/docs/limits.md +2 -6
  38. package/docs/mcp.md +4 -5
  39. package/docs/networking.md +6 -16
  40. package/docs/outputs.md +0 -4
  41. package/docs/public-surface.json +3 -3
  42. package/docs/quickstart.md +3 -7
  43. package/docs/run-config.md +6 -3
  44. package/docs/secrets.md +1 -1
  45. package/docs/skills.md +3 -3
  46. package/docs/vision-skills.md +52 -101
  47. package/examples/feature-tour.ts +4 -21
  48. package/package.json +1 -1
  49. package/dist/_contracts/proxy-protocol.d.ts +0 -305
  50. package/dist/_contracts/proxy-protocol.js +0 -297
  51. package/dist/_contracts/proxy-validation.d.ts +0 -19
  52. package/dist/_contracts/proxy-validation.js +0 -51
  53. package/dist/data-tools.d.ts +0 -82
  54. package/dist/data-tools.js +0 -251
  55. package/dist/data-tools.js.map +0 -1
  56. package/dist/proxy-endpoint.d.ts +0 -131
  57. package/dist/proxy-endpoint.js +0 -144
  58. package/dist/proxy-endpoint.js.map +0 -1
  59. 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 AssistantTextEntry, 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 SessionStateChangeAccepted, type SessionTurn, type PlatformEnvironmentInput, type PlatformSubmission, type PlatformProxyEndpoint, type PlatformProxyEndpointAuth, 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";
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 AgentExecutorOptions {
10
+ export interface AexOptions {
12
11
  /** Workspace-scoped SDK API token. */
13
- readonly apiToken: string;
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 AgentExecutor.run}:
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 AgentExecutor.run}. */
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` / `proxyEndpoints` — instances whose secrets are split into
106
- * the vaulted secrets channel server-side; the public submission carries
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 decoded assistant messages. `session.messages()`
213
- * returns this synchronously; each method fetches on call.
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
- list(): Promise<readonly AssistantTextEntry[]>;
217
- last(): Promise<AssistantTextEntry | undefined>;
218
- first(): Promise<AssistantTextEntry | undefined>;
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 decoded assistant messages (buffered output
278
- * mode: one entry per assistant message). `list()` returns them oldest-first;
279
- * `last()`/`first()` return a single entry or `undefined` when empty.
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(): SessionMessages;
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 AgentExecutor {
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(options: AgentExecutorOptions);
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
- /** Canonical SDK client name. `AgentExecutor` remains as a compatibility alias. */
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, decodeAssistantText, summarizeRunTrace, textOf, parseRunLimits, BUILTIN_TOOL_NAMES, TERMINAL_RUN_STATUSES } from "./_contracts/index.js";
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: textOf(events),
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 decoded assistant messages (buffered output
131
- * mode: one entry per assistant message). `list()` returns them oldest-first;
132
- * `last()`/`first()` return a single entry or `undefined` when empty.
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 list = async () => decodeAssistantText((await operations.listSessionEvents(http, id)));
138
- return {
139
- list,
140
- last: async () => (await list()).at(-1),
141
- first: async () => (await list())[0]
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 AgentExecutor {
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
- if (!options.apiToken) {
612
- throw new Error("AgentExecutor: apiToken is required");
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 = options.fetch ?? ((input, init) => fetch(input, init));
619
- const retryingFetch = withRetry(baseFetch, options.retry);
834
+ const baseFetch = resolved.fetch ?? ((input, init) => fetch(input, init));
835
+ const retryingFetch = withRetry(baseFetch, resolved.retry);
620
836
  this.#http = new HttpClient({
621
- ...(options.baseUrl ? { baseUrl: options.baseUrl } : {}),
622
- apiToken: options.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
- ...(options.debug
628
- ? { debug: typeof options.debug === "function" ? options.debug : (line) => console.error(line) }
843
+ ...(resolved.debug
844
+ ? { debug: typeof resolved.debug === "function" ? resolved.debug : (line) => console.error(line) }
629
845
  : {})
630
846
  });
631
- this.#fetch = options.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: summarizeRunTrace(events),
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(`AgentExecutor.run: session ${runId} ended ${turnResult.status}${errorMessage ? `: ${errorMessage}` : ""}`, { runId, status: turnResult.status });
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("AgentExecutor.downloadOutput: output path must be non-empty", {
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(`AgentExecutor.downloadOutput: output path "${selector.path}" matched multiple files`, { runId, path: selector.path, matches: matches.map((output) => output.filename ?? output.id) });
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(`AgentExecutor.downloadOutput: output path "${selector.path}" was not found`, {
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("AgentExecutor.downloadOutput: selector must include an output id or path", { runId });
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