@aexhq/sdk 0.37.3 → 0.38.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 +8 -8
- package/dist/_contracts/event-stream-client.d.ts +11 -0
- package/dist/_contracts/event-stream-client.js +45 -5
- package/dist/_contracts/http.d.ts +1 -1
- package/dist/_contracts/http.js +85 -13
- package/dist/_contracts/operations.d.ts +1 -1
- package/dist/_contracts/operations.js +43 -4
- package/dist/_contracts/provider-support.d.ts +2 -2
- package/dist/_contracts/provider-support.js +1 -1
- package/dist/_contracts/run-retention.d.ts +1 -1
- package/dist/_contracts/run-unit.d.ts +1 -1
- package/dist/_contracts/run-unit.js +12 -9
- package/dist/_contracts/runtime-types.d.ts +21 -9
- package/dist/_contracts/sdk-errors.d.ts +44 -2
- package/dist/_contracts/sdk-errors.js +104 -2
- package/dist/_contracts/sdk-secrets.js +18 -1
- package/dist/_contracts/side-effect-audit.d.ts +4 -4
- package/dist/_contracts/side-effect-audit.js +6 -6
- package/dist/_contracts/submission.d.ts +1 -1
- package/dist/asset-upload.js +8 -41
- package/dist/asset-upload.js.map +1 -1
- package/dist/cli.mjs +327 -87
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +20 -6
- package/dist/client.js +148 -18
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/retry.js +66 -6
- package/dist/retry.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/authentication.md +16 -7
- package/docs/billing.md +3 -3
- package/docs/concepts/composition.md +1 -1
- package/docs/concepts/providers-and-runtimes.md +1 -1
- package/docs/concepts/runs.md +1 -1
- package/docs/concepts/subagents.md +6 -3
- package/docs/credentials.md +7 -9
- package/docs/defaults.md +3 -3
- package/docs/errors.md +8 -4
- package/docs/events.md +5 -5
- package/docs/limits-and-quotas.md +3 -3
- package/docs/networking.md +1 -1
- package/docs/outputs.md +2 -2
- package/docs/provider-runtime-capabilities.md +3 -3
- package/docs/public-surface.json +2 -2
- package/docs/quickstart.md +4 -4
- package/docs/retries.md +1 -1
- package/docs/run-config.md +1 -1
- package/docs/run-record.md +1 -1
- package/docs/secrets.md +4 -4
- package/docs/skills.md +1 -1
- package/docs/testing.md +1 -1
- package/docs/vision-skills.md +1 -1
- package/docs/webhooks.md +4 -4
- package/examples/feature-tour.ts +3 -3
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -22,7 +22,7 @@ var COMMON_EVIDENCE = [
|
|
|
22
22
|
var ANTHROPIC_LIVE_USER_EVIDENCE = [
|
|
23
23
|
{
|
|
24
24
|
label: "Installed-SDK Anthropic live user test",
|
|
25
|
-
href: "../../../apps/user-tests/test/live/live-sdk-anthropic-managed.test.ts"
|
|
25
|
+
href: "../../../apps/user-tests/test/live/providers/live-sdk-anthropic-managed.test.ts"
|
|
26
26
|
}
|
|
27
27
|
];
|
|
28
28
|
var DEEPSEEK_LIVE_USER_EVIDENCE = [
|
|
@@ -652,6 +652,7 @@ var isTerminalType = (e) => e.type === "RUN_FINISHED" || e.type === "RUN_ERROR"
|
|
|
652
652
|
var COORDINATOR_PING = "aex:ping";
|
|
653
653
|
var DEFAULT_IDLE_TIMEOUT_MS = 45e3;
|
|
654
654
|
var DEFAULT_PING_INTERVAL_MS = 15e3;
|
|
655
|
+
var DEFAULT_EVENT_QUIET_RECHECK_MS = 9e4;
|
|
655
656
|
async function* streamCoordinatorEvents(opts) {
|
|
656
657
|
const makeWs = opts.webSocketFactory ?? ((url) => new WebSocket(url));
|
|
657
658
|
const isTerminal = opts.isTerminal ?? isTerminalType;
|
|
@@ -659,6 +660,7 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
659
660
|
const maxReconnects = opts.maxReconnects ?? Number.POSITIVE_INFINITY;
|
|
660
661
|
const idleTimeoutMs = opts.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
661
662
|
const pingIntervalMs = opts.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
|
|
663
|
+
const eventQuietRecheckMs = opts.eventQuietRecheckMs ?? DEFAULT_EVENT_QUIET_RECHECK_MS;
|
|
662
664
|
let cursor = (opts.from ?? 0) - 1;
|
|
663
665
|
let attempts = 0;
|
|
664
666
|
let done = false;
|
|
@@ -681,6 +683,7 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
681
683
|
};
|
|
682
684
|
let idleTimer = null;
|
|
683
685
|
let pingTimer = null;
|
|
686
|
+
let quietTimer = null;
|
|
684
687
|
const stopTimers = () => {
|
|
685
688
|
if (idleTimer !== null) {
|
|
686
689
|
clearTimeout(idleTimer);
|
|
@@ -690,6 +693,10 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
690
693
|
clearInterval(pingTimer);
|
|
691
694
|
pingTimer = null;
|
|
692
695
|
}
|
|
696
|
+
if (quietTimer !== null) {
|
|
697
|
+
clearTimeout(quietTimer);
|
|
698
|
+
quietTimer = null;
|
|
699
|
+
}
|
|
693
700
|
};
|
|
694
701
|
const armIdle = () => {
|
|
695
702
|
if (idleTimeoutMs <= 0)
|
|
@@ -706,6 +713,21 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
706
713
|
wake();
|
|
707
714
|
}, idleTimeoutMs);
|
|
708
715
|
};
|
|
716
|
+
const armQuiet = () => {
|
|
717
|
+
if (eventQuietRecheckMs <= 0)
|
|
718
|
+
return;
|
|
719
|
+
if (quietTimer !== null)
|
|
720
|
+
clearTimeout(quietTimer);
|
|
721
|
+
quietTimer = setTimeout(() => {
|
|
722
|
+
quietTimer = null;
|
|
723
|
+
if (closed)
|
|
724
|
+
return;
|
|
725
|
+
closed = true;
|
|
726
|
+
disconnectReason = "quiet_recheck";
|
|
727
|
+
closeQuietly(ws);
|
|
728
|
+
wake();
|
|
729
|
+
}, eventQuietRecheckMs);
|
|
730
|
+
};
|
|
709
731
|
ws.addEventListener("open", () => {
|
|
710
732
|
armIdle();
|
|
711
733
|
if (pingIntervalMs > 0 && typeof ws.send === "function") {
|
|
@@ -724,9 +746,12 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
724
746
|
return;
|
|
725
747
|
try {
|
|
726
748
|
const evt = JSON.parse(data);
|
|
727
|
-
if (typeof evt.sequence === "number"
|
|
728
|
-
|
|
729
|
-
|
|
749
|
+
if (typeof evt.sequence === "number") {
|
|
750
|
+
armQuiet();
|
|
751
|
+
if (evt.sequence > cursor) {
|
|
752
|
+
queue.push(evt);
|
|
753
|
+
wake();
|
|
754
|
+
}
|
|
730
755
|
}
|
|
731
756
|
} catch {
|
|
732
757
|
}
|
|
@@ -756,6 +781,7 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
756
781
|
};
|
|
757
782
|
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
758
783
|
armIdle();
|
|
784
|
+
armQuiet();
|
|
759
785
|
try {
|
|
760
786
|
while (true) {
|
|
761
787
|
while (queue.length > 0) {
|
|
@@ -778,6 +804,7 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
778
804
|
} finally {
|
|
779
805
|
stopTimers();
|
|
780
806
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
807
|
+
closeQuietly(ws);
|
|
781
808
|
}
|
|
782
809
|
if (done || opts.signal?.aborted)
|
|
783
810
|
return;
|
|
@@ -786,7 +813,9 @@ async function* streamCoordinatorEvents(opts) {
|
|
|
786
813
|
console.warn(`[aex] event stream gave up after ${maxReconnects} reconnect attempt(s) (last: ${disconnectReason || "unknown"}); ended before a terminal event at seq ${cursor + 1}`);
|
|
787
814
|
return;
|
|
788
815
|
}
|
|
789
|
-
|
|
816
|
+
if (disconnectReason !== "quiet_recheck") {
|
|
817
|
+
console.warn(`[aex] event stream disconnected (${disconnectReason || "unknown"}); reconnecting attempt ${attempts} from seq ${cursor + 1}`);
|
|
818
|
+
}
|
|
790
819
|
await sleep(reconnectDelayMs, opts.signal);
|
|
791
820
|
}
|
|
792
821
|
}
|
|
@@ -807,17 +836,17 @@ function sleep(ms, signal) {
|
|
|
807
836
|
}
|
|
808
837
|
|
|
809
838
|
// ../contracts/dist/run-unit.js
|
|
810
|
-
function parseRunUnitSubmission(input) {
|
|
839
|
+
function parseRunUnitSubmission(input, fallbackModel) {
|
|
811
840
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
812
|
-
return fallbackFlat();
|
|
841
|
+
return fallbackFlat(fallbackModel);
|
|
813
842
|
}
|
|
814
843
|
const value = input;
|
|
815
844
|
if (value.kind === "submission") {
|
|
816
|
-
return parseFlatProjection(value);
|
|
845
|
+
return parseFlatProjection(value, fallbackModel);
|
|
817
846
|
}
|
|
818
|
-
return fallbackFlat();
|
|
847
|
+
return fallbackFlat(fallbackModel);
|
|
819
848
|
}
|
|
820
|
-
function parseFlatProjection(value) {
|
|
849
|
+
function parseFlatProjection(value, fallbackModel) {
|
|
821
850
|
const submissionRaw = isRecord(value.submission) ? value.submission : {};
|
|
822
851
|
const outputsRaw = isRecord(submissionRaw.outputs) ? submissionRaw.outputs : {};
|
|
823
852
|
const allowedDirs = toOptionalStringArray(outputsRaw.allowedDirs);
|
|
@@ -827,7 +856,7 @@ function parseFlatProjection(value) {
|
|
|
827
856
|
const maxTotalBytes = toOptionalPositiveInteger(outputsRaw.maxTotalBytes);
|
|
828
857
|
const maxFiles = toOptionalPositiveInteger(outputsRaw.maxFiles);
|
|
829
858
|
const submission = {
|
|
830
|
-
model: coerceRunUnitModel(submissionRaw.model),
|
|
859
|
+
model: coerceRunUnitModel(submissionRaw.model ?? fallbackModel),
|
|
831
860
|
...typeof submissionRaw.system === "string" ? { system: submissionRaw.system } : {},
|
|
832
861
|
prompt: toStringArray(submissionRaw.prompt),
|
|
833
862
|
agentsMd: [],
|
|
@@ -859,11 +888,11 @@ function parseSecurityProfile(value) {
|
|
|
859
888
|
function toOptionalPositiveInteger(value) {
|
|
860
889
|
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
861
890
|
}
|
|
862
|
-
function fallbackFlat() {
|
|
891
|
+
function fallbackFlat(fallbackModel) {
|
|
863
892
|
return {
|
|
864
893
|
kind: "submission",
|
|
865
894
|
submission: {
|
|
866
|
-
model:
|
|
895
|
+
model: coerceRunUnitModel(fallbackModel),
|
|
867
896
|
prompt: [],
|
|
868
897
|
agentsMd: [],
|
|
869
898
|
files: [],
|
|
@@ -892,7 +921,10 @@ function normalizeRunUnit(raw) {
|
|
|
892
921
|
...str3(r.terminalAt) ? { terminalAt: r.terminalAt } : {},
|
|
893
922
|
...str3(r.deletedAt) ? { deletedAt: r.deletedAt } : {},
|
|
894
923
|
attemptCount: typeof r.attemptCount === "number" ? r.attemptCount : Array.isArray(r.attempts) ? r.attempts.length : 0,
|
|
895
|
-
|
|
924
|
+
// Plane responses that project a flat record (no `submission` snapshot)
|
|
925
|
+
// still carry the run's `model` at the top level — prefer it over the
|
|
926
|
+
// static fallback so `unit()` never claims a model the run did not use.
|
|
927
|
+
submission: parseRunUnitSubmission(r.submission, r.model),
|
|
896
928
|
...isRecord(r.capsSnapshot) ? { capsSnapshot: r.capsSnapshot } : {},
|
|
897
929
|
attempts: arr(r.attempts),
|
|
898
930
|
events: {
|
|
@@ -1363,6 +1395,11 @@ var HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9+/=-]{24,}/g;
|
|
|
1363
1395
|
var ENTROPY_BITS_PER_CHAR = 3;
|
|
1364
1396
|
var MIN_CHAR_CLASSES = 2;
|
|
1365
1397
|
var HIGH_ENTROPY_NO_DIGIT_MIN_LEN = 40;
|
|
1398
|
+
function isCanonicalRunIdHex(input, matchStart, match) {
|
|
1399
|
+
if (!/^[0-9a-f]{32}$/.test(match))
|
|
1400
|
+
return false;
|
|
1401
|
+
return input.slice(Math.max(0, matchStart - 4), matchStart) === "run_";
|
|
1402
|
+
}
|
|
1366
1403
|
function redactSecrets(value) {
|
|
1367
1404
|
if (typeof value === "string") {
|
|
1368
1405
|
return redactString(value);
|
|
@@ -1395,7 +1432,7 @@ function redactString(input, known = []) {
|
|
|
1395
1432
|
// prefix; the rest replace the whole match.
|
|
1396
1433
|
typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED
|
|
1397
1434
|
)), out);
|
|
1398
|
-
return out.replace(HIGH_ENTROPY_CANDIDATE, (match) => looksHighEntropySecret(match) ? REDACTED : match);
|
|
1435
|
+
return out.replace(HIGH_ENTROPY_CANDIDATE, (match, offset, whole) => !isCanonicalRunIdHex(whole, offset, match) && looksHighEntropySecret(match) ? REDACTED : match);
|
|
1399
1436
|
}
|
|
1400
1437
|
function isSecretKey(key) {
|
|
1401
1438
|
return /(?:api[_-]?key|authorization|token|secret|password|credential)/i.test(key);
|
|
@@ -1437,8 +1474,8 @@ function shannonEntropyBits(value) {
|
|
|
1437
1474
|
var AexError = class extends Error {
|
|
1438
1475
|
code;
|
|
1439
1476
|
details;
|
|
1440
|
-
constructor(code, message, details) {
|
|
1441
|
-
super(redactSecrets(message));
|
|
1477
|
+
constructor(code, message, details, options) {
|
|
1478
|
+
super(redactSecrets(message), options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
1442
1479
|
this.name = this.constructor.name;
|
|
1443
1480
|
this.code = code;
|
|
1444
1481
|
this.details = details === void 0 ? void 0 : redactSecrets(details);
|
|
@@ -1458,6 +1495,85 @@ var AexApiError = class extends AexError {
|
|
|
1458
1495
|
this.body = redactSecrets(body);
|
|
1459
1496
|
}
|
|
1460
1497
|
};
|
|
1498
|
+
var AexNetworkError = class extends AexError {
|
|
1499
|
+
method;
|
|
1500
|
+
/** Request host — never carries credentials or the query string. */
|
|
1501
|
+
host;
|
|
1502
|
+
path;
|
|
1503
|
+
/** Transport failure code (e.g. `ECONNREFUSED`), when detectable. */
|
|
1504
|
+
causeCode;
|
|
1505
|
+
/** Attempts made when a retry layer exhausted its budget; `1` otherwise. */
|
|
1506
|
+
attempts;
|
|
1507
|
+
constructor(args) {
|
|
1508
|
+
const causeCode = extractErrorCode(args.cause);
|
|
1509
|
+
super("NETWORK_ERROR", networkErrorMessage(args, causeCode), { method: args.method, host: args.host, path: args.path, ...causeCode ? { code: causeCode } : {} }, { cause: args.cause });
|
|
1510
|
+
this.method = args.method;
|
|
1511
|
+
this.host = args.host;
|
|
1512
|
+
this.path = args.path;
|
|
1513
|
+
this.causeCode = causeCode;
|
|
1514
|
+
this.attempts = args.attempts ?? 1;
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
function networkErrorMessage(args, causeCode) {
|
|
1518
|
+
const target = args.host ? `${args.host}${args.path}` : "request";
|
|
1519
|
+
const detail = shortCauseMessage(args.cause, causeCode);
|
|
1520
|
+
const suffix = args.attempts === void 0 ? "" : ` after ${args.attempts} attempt${args.attempts === 1 ? "" : "s"} over ${args.elapsedMs ?? 0}ms`;
|
|
1521
|
+
let message = `${args.method} ${target} failed`;
|
|
1522
|
+
if (causeCode)
|
|
1523
|
+
message += `: ${causeCode}`;
|
|
1524
|
+
if (detail)
|
|
1525
|
+
message += causeCode ? ` (${detail})` : `: ${detail}`;
|
|
1526
|
+
return message + suffix;
|
|
1527
|
+
}
|
|
1528
|
+
function shortCauseMessage(cause, causeCode) {
|
|
1529
|
+
const nested = cause instanceof Error && cause.cause instanceof Error ? cause.cause : cause;
|
|
1530
|
+
const message = nested instanceof Error ? nested.message || nested.name : typeof nested === "string" ? nested : void 0;
|
|
1531
|
+
if (!message || message === causeCode)
|
|
1532
|
+
return void 0;
|
|
1533
|
+
return message.replace(/https?:\/\/[^\s<>"'`]+/g, (raw) => redactUrl(raw)).slice(0, 200);
|
|
1534
|
+
}
|
|
1535
|
+
function extractErrorCode(err2) {
|
|
1536
|
+
const code = stringProperty(err2, "code");
|
|
1537
|
+
if (code)
|
|
1538
|
+
return code;
|
|
1539
|
+
const cause = objectProperty(err2, "cause");
|
|
1540
|
+
const causeCode = stringProperty(cause, "code");
|
|
1541
|
+
if (causeCode)
|
|
1542
|
+
return causeCode;
|
|
1543
|
+
const match = /\bE[A-Z0-9_]+\b/.exec(errorMessageOf(err2));
|
|
1544
|
+
return match?.[0];
|
|
1545
|
+
}
|
|
1546
|
+
function redactUrl(url) {
|
|
1547
|
+
try {
|
|
1548
|
+
const parsed = new URL(url);
|
|
1549
|
+
const auth = parsed.username || parsed.password ? "[redacted]@" : "";
|
|
1550
|
+
const query = parsed.search ? "?[redacted]" : "";
|
|
1551
|
+
return `${parsed.protocol}//${auth}${parsed.host}${parsed.pathname}${query}`;
|
|
1552
|
+
} catch {
|
|
1553
|
+
const withoutAuth = url.replace(/\/\/[^/?#\s]+@/, "//[redacted]@");
|
|
1554
|
+
const queryStart = withoutAuth.indexOf("?");
|
|
1555
|
+
return queryStart === -1 ? withoutAuth : `${withoutAuth.slice(0, queryStart)}?[redacted]`;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
function errorMessageOf(err2) {
|
|
1559
|
+
if (err2 instanceof Error)
|
|
1560
|
+
return err2.message || err2.name;
|
|
1561
|
+
if (typeof err2 === "string")
|
|
1562
|
+
return err2;
|
|
1563
|
+
return String(err2);
|
|
1564
|
+
}
|
|
1565
|
+
function objectProperty(value, key) {
|
|
1566
|
+
if (!value || typeof value !== "object")
|
|
1567
|
+
return void 0;
|
|
1568
|
+
const prop = value[key];
|
|
1569
|
+
return prop && typeof prop === "object" ? prop : void 0;
|
|
1570
|
+
}
|
|
1571
|
+
function stringProperty(value, key) {
|
|
1572
|
+
if (!value || typeof value !== "object")
|
|
1573
|
+
return void 0;
|
|
1574
|
+
const prop = value[key];
|
|
1575
|
+
return typeof prop === "string" && prop.length > 0 ? prop : void 0;
|
|
1576
|
+
}
|
|
1461
1577
|
|
|
1462
1578
|
// ../contracts/dist/webhook-verify.js
|
|
1463
1579
|
var encoder2 = new TextEncoder();
|
|
@@ -1465,17 +1581,21 @@ var encoder2 = new TextEncoder();
|
|
|
1465
1581
|
// ../contracts/dist/http.js
|
|
1466
1582
|
var HttpClient = class {
|
|
1467
1583
|
#baseUrl;
|
|
1468
|
-
#
|
|
1584
|
+
#apiKey;
|
|
1469
1585
|
#fetch;
|
|
1470
1586
|
#debug;
|
|
1471
1587
|
constructor(options) {
|
|
1472
|
-
if (!options.
|
|
1473
|
-
throw new Error("HttpClient:
|
|
1588
|
+
if (!options.apiKey) {
|
|
1589
|
+
throw new Error("HttpClient: apiKey is required");
|
|
1474
1590
|
}
|
|
1475
1591
|
const raw = options.baseUrl ?? AEX_DEFAULT_BASE_URL;
|
|
1476
1592
|
const normalized = raw.endsWith("/") ? raw : `${raw}/`;
|
|
1477
|
-
|
|
1478
|
-
|
|
1593
|
+
try {
|
|
1594
|
+
this.#baseUrl = new URL(normalized);
|
|
1595
|
+
} catch (err2) {
|
|
1596
|
+
throw new Error(`HttpClient: invalid aex baseUrl ${JSON.stringify(redactUrl(raw))} \u2014 expected an absolute URL like "${AEX_DEFAULT_BASE_URL}"`, { cause: err2 });
|
|
1597
|
+
}
|
|
1598
|
+
this.#apiKey = options.apiKey;
|
|
1479
1599
|
this.#fetch = options.fetch ?? fetch;
|
|
1480
1600
|
this.#debug = options.debug;
|
|
1481
1601
|
}
|
|
@@ -1490,7 +1610,7 @@ var HttpClient = class {
|
|
|
1490
1610
|
}
|
|
1491
1611
|
const headers = {
|
|
1492
1612
|
accept: "application/json",
|
|
1493
|
-
authorization: `Bearer ${this.#
|
|
1613
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
1494
1614
|
...normalizeHeaders(init.headers)
|
|
1495
1615
|
};
|
|
1496
1616
|
if (init.body !== void 0 && init.body !== null && !headers["content-type"]) {
|
|
@@ -1499,11 +1619,17 @@ var HttpClient = class {
|
|
|
1499
1619
|
}
|
|
1500
1620
|
}
|
|
1501
1621
|
const startedMs = Date.now();
|
|
1502
|
-
|
|
1622
|
+
let response;
|
|
1623
|
+
try {
|
|
1624
|
+
response = await this.#fetch(url, { ...init, headers });
|
|
1625
|
+
} catch (err2) {
|
|
1626
|
+
throw toNetworkError(init.method, url, err2);
|
|
1627
|
+
}
|
|
1503
1628
|
this.#trace(init.method, url, response.status, startedMs);
|
|
1504
1629
|
const body = await readJson(response);
|
|
1505
1630
|
if (!response.ok) {
|
|
1506
|
-
|
|
1631
|
+
const errorBody = withResponseRequestId(body, response.headers);
|
|
1632
|
+
throw new AexApiError(response.status, extractErrorMessage(errorBody), errorBody);
|
|
1507
1633
|
}
|
|
1508
1634
|
return body;
|
|
1509
1635
|
}
|
|
@@ -1513,19 +1639,37 @@ var HttpClient = class {
|
|
|
1513
1639
|
url.searchParams.set(key, value);
|
|
1514
1640
|
}
|
|
1515
1641
|
const headers = {
|
|
1516
|
-
authorization: `Bearer ${this.#
|
|
1642
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
1517
1643
|
...normalizeHeaders(init.headers)
|
|
1518
1644
|
};
|
|
1519
1645
|
const startedMs = Date.now();
|
|
1520
|
-
|
|
1646
|
+
let response;
|
|
1647
|
+
try {
|
|
1648
|
+
response = await this.#fetch(url, { ...init, headers });
|
|
1649
|
+
} catch (err2) {
|
|
1650
|
+
throw toNetworkError(init.method, url, err2);
|
|
1651
|
+
}
|
|
1521
1652
|
this.#trace(init.method, url, response.status, startedMs);
|
|
1522
1653
|
if (!response.ok) {
|
|
1523
1654
|
const body = await readJson(response);
|
|
1524
|
-
|
|
1655
|
+
const errorBody = withResponseRequestId(body, response.headers);
|
|
1656
|
+
throw new AexApiError(response.status, extractErrorMessage(errorBody), errorBody);
|
|
1525
1657
|
}
|
|
1526
1658
|
return { response };
|
|
1527
1659
|
}
|
|
1528
1660
|
};
|
|
1661
|
+
function toNetworkError(method, url, err2) {
|
|
1662
|
+
if (err2 instanceof AexError)
|
|
1663
|
+
return err2;
|
|
1664
|
+
if (err2?.name === "AbortError")
|
|
1665
|
+
return err2;
|
|
1666
|
+
return new AexNetworkError({
|
|
1667
|
+
method: (method ?? "GET").toUpperCase(),
|
|
1668
|
+
host: url.host,
|
|
1669
|
+
path: url.pathname,
|
|
1670
|
+
cause: err2
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1529
1673
|
function normalizeHeaders(headers) {
|
|
1530
1674
|
if (!headers)
|
|
1531
1675
|
return {};
|
|
@@ -1545,11 +1689,36 @@ async function readJson(response) {
|
|
|
1545
1689
|
return { raw: text };
|
|
1546
1690
|
}
|
|
1547
1691
|
}
|
|
1692
|
+
function withResponseRequestId(body, headers) {
|
|
1693
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
1694
|
+
return body;
|
|
1695
|
+
const record = body;
|
|
1696
|
+
if (typeof record.requestId === "string" && record.requestId.trim())
|
|
1697
|
+
return body;
|
|
1698
|
+
const requestId = responseRequestId(headers);
|
|
1699
|
+
return requestId ? { ...record, requestId } : body;
|
|
1700
|
+
}
|
|
1701
|
+
function responseRequestId(headers) {
|
|
1702
|
+
for (const name of ["x-request-id", "request-id"]) {
|
|
1703
|
+
const value = headers.get(name)?.trim();
|
|
1704
|
+
if (value)
|
|
1705
|
+
return value;
|
|
1706
|
+
}
|
|
1707
|
+
return void 0;
|
|
1708
|
+
}
|
|
1548
1709
|
function extractErrorMessage(body) {
|
|
1549
1710
|
if (body && typeof body === "object") {
|
|
1550
1711
|
const obj = body;
|
|
1551
|
-
if (typeof obj.error === "string")
|
|
1712
|
+
if (typeof obj.error === "string") {
|
|
1713
|
+
const status2 = body.status;
|
|
1714
|
+
if (obj.error === "session_busy" && typeof status2 === "string") {
|
|
1715
|
+
return `session_busy (session status: ${status2})`;
|
|
1716
|
+
}
|
|
1717
|
+
if (typeof obj.message === "string" && obj.message.length > 0 && obj.message !== obj.error) {
|
|
1718
|
+
return `${obj.error}: ${obj.message}`;
|
|
1719
|
+
}
|
|
1552
1720
|
return obj.error;
|
|
1721
|
+
}
|
|
1553
1722
|
if (obj.error && typeof obj.error === "object" && "message" in obj.error) {
|
|
1554
1723
|
const message = obj.error.message;
|
|
1555
1724
|
if (typeof message === "string")
|
|
@@ -2360,7 +2529,23 @@ async function listRuns(http, query) {
|
|
|
2360
2529
|
params.limit = String(query.limit);
|
|
2361
2530
|
if (query?.cursor !== void 0)
|
|
2362
2531
|
params.cursor = query.cursor;
|
|
2363
|
-
|
|
2532
|
+
const page = await http.request("/api/runs", {}, params);
|
|
2533
|
+
let changed = false;
|
|
2534
|
+
const runs = [];
|
|
2535
|
+
for (const run of page.runs) {
|
|
2536
|
+
if (typeof run.id !== "string" || typeof run.status !== "string" || typeof run.createdAt !== "string" || typeof run.updatedAt !== "string") {
|
|
2537
|
+
changed = true;
|
|
2538
|
+
continue;
|
|
2539
|
+
}
|
|
2540
|
+
if (typeof run.costUsd !== "number" && run.costUsd !== void 0) {
|
|
2541
|
+
const { costUsd: _dropped, ...rest } = run;
|
|
2542
|
+
runs.push(rest);
|
|
2543
|
+
changed = true;
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2546
|
+
runs.push(run);
|
|
2547
|
+
}
|
|
2548
|
+
return changed ? { ...page, runs } : page;
|
|
2364
2549
|
}
|
|
2365
2550
|
function idempotencyHeaders(options) {
|
|
2366
2551
|
return options?.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : void 0;
|
|
@@ -2488,12 +2673,17 @@ async function outputLink(http, runId, selectorOrQuery, options) {
|
|
|
2488
2673
|
method: "POST",
|
|
2489
2674
|
body: JSON.stringify({ expiresInSeconds })
|
|
2490
2675
|
});
|
|
2676
|
+
const effectiveExpiresIn = result.expiresInSeconds ?? expiresInSeconds;
|
|
2491
2677
|
return {
|
|
2492
2678
|
...result,
|
|
2493
|
-
expiresInSeconds:
|
|
2679
|
+
expiresInSeconds: effectiveExpiresIn,
|
|
2680
|
+
expiresAt: result.expiresAt ?? syntheticExpiresAt(effectiveExpiresIn),
|
|
2494
2681
|
output: result.output ?? output
|
|
2495
2682
|
};
|
|
2496
2683
|
}
|
|
2684
|
+
function syntheticExpiresAt(expiresInSeconds) {
|
|
2685
|
+
return new Date(Date.now() + expiresInSeconds * 1e3).toISOString();
|
|
2686
|
+
}
|
|
2497
2687
|
async function createOutputLink(http, runId, selectorOrQuery, options) {
|
|
2498
2688
|
return outputLink(http, runId, selectorOrQuery, options);
|
|
2499
2689
|
}
|
|
@@ -2503,9 +2693,11 @@ async function eventArchiveLink(http, runId, options) {
|
|
|
2503
2693
|
method: "POST",
|
|
2504
2694
|
body: JSON.stringify({ expiresInSeconds })
|
|
2505
2695
|
});
|
|
2696
|
+
const effectiveExpiresIn = result.expiresInSeconds ?? expiresInSeconds;
|
|
2506
2697
|
return {
|
|
2507
2698
|
...result,
|
|
2508
|
-
expiresInSeconds:
|
|
2699
|
+
expiresInSeconds: effectiveExpiresIn,
|
|
2700
|
+
expiresAt: result.expiresAt ?? syntheticExpiresAt(effectiveExpiresIn)
|
|
2509
2701
|
};
|
|
2510
2702
|
}
|
|
2511
2703
|
function resolveOutputFileSelector(outputs, selector, runId) {
|
|
@@ -3060,7 +3252,7 @@ function isSessionOk(status2) {
|
|
|
3060
3252
|
return status2 === "idle" || status2 === "suspended" || status2 === "succeeded";
|
|
3061
3253
|
}
|
|
3062
3254
|
function extractCommonHostFlags(argv) {
|
|
3063
|
-
let
|
|
3255
|
+
let apiKey = null;
|
|
3064
3256
|
let aexUrl = null;
|
|
3065
3257
|
let debug2 = false;
|
|
3066
3258
|
const rest = [];
|
|
@@ -3070,11 +3262,11 @@ function extractCommonHostFlags(argv) {
|
|
|
3070
3262
|
debug2 = true;
|
|
3071
3263
|
continue;
|
|
3072
3264
|
}
|
|
3073
|
-
if (arg === "--api-
|
|
3265
|
+
if (arg === "--api-key") {
|
|
3074
3266
|
const v = argv[++i2];
|
|
3075
3267
|
if (v === void 0)
|
|
3076
|
-
return { ok: false, reason: "--api-
|
|
3077
|
-
|
|
3268
|
+
return { ok: false, reason: "--api-key requires a value" };
|
|
3269
|
+
apiKey = v;
|
|
3078
3270
|
continue;
|
|
3079
3271
|
}
|
|
3080
3272
|
if (arg === "--aex-url") {
|
|
@@ -3087,18 +3279,18 @@ function extractCommonHostFlags(argv) {
|
|
|
3087
3279
|
if (arg === "--workspace" || arg === "--workspace-id") {
|
|
3088
3280
|
return {
|
|
3089
3281
|
ok: false,
|
|
3090
|
-
reason: `unknown flag ${arg}: workspace is derived from --api-
|
|
3282
|
+
reason: `unknown flag ${arg}: workspace is derived from --api-key on the server; drop this flag`
|
|
3091
3283
|
};
|
|
3092
3284
|
}
|
|
3093
3285
|
rest.push(arg);
|
|
3094
3286
|
}
|
|
3095
|
-
return { ok: true, flags: {
|
|
3287
|
+
return { ok: true, flags: { apiKey, aexUrl, debug: debug2, rest } };
|
|
3096
3288
|
}
|
|
3097
3289
|
async function resolveCommonHostFlags(io2, argv) {
|
|
3098
3290
|
const extracted = extractCommonHostFlags(argv);
|
|
3099
3291
|
if (!extracted.ok)
|
|
3100
3292
|
return extracted;
|
|
3101
|
-
const {
|
|
3293
|
+
const { apiKey: flagToken, aexUrl: flagUrl, debug: debug2, rest } = extracted.flags;
|
|
3102
3294
|
let token = flagToken;
|
|
3103
3295
|
let url = flagUrl;
|
|
3104
3296
|
let source = flagToken ? "flag" : "none";
|
|
@@ -3106,8 +3298,8 @@ async function resolveCommonHostFlags(io2, argv) {
|
|
|
3106
3298
|
if (!token && io2.configStore) {
|
|
3107
3299
|
const stored = await io2.configStore.read();
|
|
3108
3300
|
storedLocation = io2.configStore.location();
|
|
3109
|
-
if (stored?.
|
|
3110
|
-
token = stored.
|
|
3301
|
+
if (stored?.apiKey) {
|
|
3302
|
+
token = stored.apiKey;
|
|
3111
3303
|
source = "stored";
|
|
3112
3304
|
if (!url && stored.aexUrl)
|
|
3113
3305
|
url = stored.aexUrl;
|
|
@@ -3115,35 +3307,56 @@ async function resolveCommonHostFlags(io2, argv) {
|
|
|
3115
3307
|
}
|
|
3116
3308
|
const resolvedUrl = url ?? AEX_DEFAULT_BASE_URL;
|
|
3117
3309
|
if (debug2) {
|
|
3118
|
-
const where = source === "flag" ? "--api-
|
|
3310
|
+
const where = source === "flag" ? "--api-key flag" : source === "stored" ? `stored token (${storedLocation})` : "none";
|
|
3119
3311
|
io2.stderr(`[aex] auth: ${where}; aex-url=${resolvedUrl}
|
|
3120
3312
|
`);
|
|
3121
3313
|
}
|
|
3122
3314
|
if (!token) {
|
|
3123
|
-
return { ok: false, reason: "no API
|
|
3315
|
+
return { ok: false, reason: "no API key \u2014 pass --api-key or run `aex login`" };
|
|
3124
3316
|
}
|
|
3125
|
-
return { ok: true, flags: {
|
|
3317
|
+
return { ok: true, flags: { apiKey: token, aexUrl: resolvedUrl, debug: debug2 }, rest };
|
|
3126
3318
|
}
|
|
3127
3319
|
function describeApiError(err2) {
|
|
3128
3320
|
if (err2 instanceof AexApiError) {
|
|
3129
3321
|
const remedy = remedyForStatus(err2.status);
|
|
3322
|
+
const detail = describeErrorBody(err2.body);
|
|
3130
3323
|
return {
|
|
3131
3324
|
code: err2.code,
|
|
3132
|
-
message: err2.message,
|
|
3325
|
+
message: detail ? `${err2.message} \u2014 ${detail}` : err2.message,
|
|
3133
3326
|
status: err2.status,
|
|
3134
3327
|
...remedy ? { remedy } : {}
|
|
3135
3328
|
};
|
|
3136
3329
|
}
|
|
3137
3330
|
if (err2 instanceof AexError) {
|
|
3138
|
-
|
|
3331
|
+
const causeCode = err2 instanceof AexNetworkError ? err2.causeCode : extractErrorCode(err2.cause);
|
|
3332
|
+
const remedy = causeCode ? remedyForNetworkCode(causeCode) : void 0;
|
|
3333
|
+
const message = causeCode && !err2.message.includes(causeCode) ? `${err2.message} (${causeCode})` : err2.message;
|
|
3334
|
+
return { code: err2.code, message, ...remedy ? { remedy } : {} };
|
|
3139
3335
|
}
|
|
3140
3336
|
return { code: "error", message: err2 instanceof Error ? err2.message : String(err2) };
|
|
3141
3337
|
}
|
|
3338
|
+
var STANDARD_ERROR_BODY_KEYS = /* @__PURE__ */ new Set(["ok", "error", "message", "code"]);
|
|
3339
|
+
function describeErrorBody(body) {
|
|
3340
|
+
if (!body || typeof body !== "object")
|
|
3341
|
+
return void 0;
|
|
3342
|
+
const record = body;
|
|
3343
|
+
const extraKeys = Object.keys(record).filter((key) => !STANDARD_ERROR_BODY_KEYS.has(key));
|
|
3344
|
+
if (extraKeys.length === 0)
|
|
3345
|
+
return void 0;
|
|
3346
|
+
let text;
|
|
3347
|
+
try {
|
|
3348
|
+
text = JSON.stringify(Object.fromEntries(extraKeys.map((key) => [key, record[key]])));
|
|
3349
|
+
} catch {
|
|
3350
|
+
return void 0;
|
|
3351
|
+
}
|
|
3352
|
+
const redacted = redactSecrets(text);
|
|
3353
|
+
return redacted.length > 400 ? `${redacted.slice(0, 400)}\u2026 (truncated)` : redacted;
|
|
3354
|
+
}
|
|
3142
3355
|
function remedyForStatus(status2) {
|
|
3143
3356
|
if (status2 === 400)
|
|
3144
|
-
return "malformed request \u2014 if this is an auth failure, check --api-
|
|
3357
|
+
return "malformed request \u2014 if this is an auth failure, check --api-key or run `aex login`";
|
|
3145
3358
|
if (status2 === 401)
|
|
3146
|
-
return "check --api-
|
|
3359
|
+
return "check --api-key, or run `aex login`";
|
|
3147
3360
|
if (status2 === 403)
|
|
3148
3361
|
return "token lacks permission for this workspace/action";
|
|
3149
3362
|
if (status2 === 404)
|
|
@@ -3154,6 +3367,26 @@ function remedyForStatus(status2) {
|
|
|
3154
3367
|
return "server error \u2014 retry; re-run with --debug to capture the request trace";
|
|
3155
3368
|
return void 0;
|
|
3156
3369
|
}
|
|
3370
|
+
function remedyForNetworkCode(code) {
|
|
3371
|
+
switch (code) {
|
|
3372
|
+
case "ECONNREFUSED":
|
|
3373
|
+
case "ENOTFOUND":
|
|
3374
|
+
case "EAI_AGAIN":
|
|
3375
|
+
case "EHOSTUNREACH":
|
|
3376
|
+
case "ENETUNREACH":
|
|
3377
|
+
return "cannot reach the aex API \u2014 check --aex-url and network connectivity";
|
|
3378
|
+
case "ECONNRESET":
|
|
3379
|
+
case "ETIMEDOUT":
|
|
3380
|
+
case "UND_ERR_CONNECT_TIMEOUT":
|
|
3381
|
+
return "connection dropped \u2014 retry; check --aex-url, network connectivity, or any proxy/VPN";
|
|
3382
|
+
case "CERT_HAS_EXPIRED":
|
|
3383
|
+
case "DEPTH_ZERO_SELF_SIGNED_CERT":
|
|
3384
|
+
case "UNABLE_TO_VERIFY_LEAF_SIGNATURE":
|
|
3385
|
+
return "TLS verification failed \u2014 check --aex-url points at the right host";
|
|
3386
|
+
default:
|
|
3387
|
+
return void 0;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3157
3390
|
function suggest(input, candidates) {
|
|
3158
3391
|
const needle = input.trim();
|
|
3159
3392
|
if (!needle)
|
|
@@ -3195,7 +3428,7 @@ function levenshtein(a, b) {
|
|
|
3195
3428
|
function makeHttpClient(io2, flags) {
|
|
3196
3429
|
return new HttpClient({
|
|
3197
3430
|
baseUrl: flags.aexUrl,
|
|
3198
|
-
|
|
3431
|
+
apiKey: flags.apiKey,
|
|
3199
3432
|
fetch: io2.fetchImpl,
|
|
3200
3433
|
// `--debug`: route the transport's redacted per-request traces to stderr.
|
|
3201
3434
|
...flags.debug ? { debug: (line) => io2.stderr(`${line}
|
|
@@ -3411,7 +3644,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3411
3644
|
return USAGE_ERR;
|
|
3412
3645
|
}
|
|
3413
3646
|
rest = providerFlag.remaining;
|
|
3414
|
-
let
|
|
3647
|
+
let explicitProvider;
|
|
3415
3648
|
if (providerFlag.value !== null) {
|
|
3416
3649
|
if (!RUN_PROVIDERS.includes(providerFlag.value)) {
|
|
3417
3650
|
const hint = suggest(providerFlag.value, RUN_PROVIDERS);
|
|
@@ -3419,7 +3652,7 @@ async function runRunCmd(io2, argv) {
|
|
|
3419
3652
|
`);
|
|
3420
3653
|
return USAGE_ERR;
|
|
3421
3654
|
}
|
|
3422
|
-
|
|
3655
|
+
explicitProvider = providerFlag.value;
|
|
3423
3656
|
}
|
|
3424
3657
|
const providerKeyValues = {};
|
|
3425
3658
|
for (const p of RUN_PROVIDERS) {
|
|
@@ -3433,11 +3666,6 @@ async function runRunCmd(io2, argv) {
|
|
|
3433
3666
|
if (flag.value !== null)
|
|
3434
3667
|
providerKeyValues[p] = flag.value;
|
|
3435
3668
|
}
|
|
3436
|
-
if (!providerKeyValues[provider]) {
|
|
3437
|
-
io2.stderr(`--${provider}-api-key is required when --provider is ${provider} (the platform does not store provider keys on your behalf)
|
|
3438
|
-
`);
|
|
3439
|
-
return USAGE_ERR;
|
|
3440
|
-
}
|
|
3441
3669
|
const idempotency = takeFlagValue(rest, "--idempotency-key");
|
|
3442
3670
|
if (idempotency.error) {
|
|
3443
3671
|
io2.stderr(`${idempotency.error}
|
|
@@ -3637,6 +3865,12 @@ async function runRunCmd(io2, argv) {
|
|
|
3637
3865
|
...Object.keys(metadataFlags.entries).length > 0 ? { metadata: { ...metadataFlags.entries } } : {}
|
|
3638
3866
|
};
|
|
3639
3867
|
}
|
|
3868
|
+
const provider = explicitProvider ?? providersForModel(runConfig.model)[0] ?? DEFAULT_RUN_PROVIDER;
|
|
3869
|
+
if (!providerKeyValues[provider]) {
|
|
3870
|
+
io2.stderr(`--${provider}-api-key is required for provider ${provider}${explicitProvider === void 0 ? ` (inferred from --model ${runConfig.model})` : ""} (the platform does not store provider keys on your behalf)
|
|
3871
|
+
`);
|
|
3872
|
+
return USAGE_ERR;
|
|
3873
|
+
}
|
|
3640
3874
|
const mcpServersForSubmission = [...runConfig.mcpServers ?? []];
|
|
3641
3875
|
const mcpServerSecrets = [];
|
|
3642
3876
|
const mcpHeaderBag = new Map(mcpHeadersFromConfig);
|
|
@@ -5101,7 +5335,7 @@ function makeAwsSources(region) {
|
|
|
5101
5335
|
}
|
|
5102
5336
|
};
|
|
5103
5337
|
}
|
|
5104
|
-
var USAGE = "usage: aex debug <run-id> [--plane dev|prd] [--region eu-west-2] [--out dir] [--account <id>] [--cloudwatch] [--since <dur>] [--with-outputs]\n operator command \u2014 uses the standard AWS SDK credential chain (env/profile), NOT --api-
|
|
5338
|
+
var USAGE = "usage: aex debug <run-id> [--plane dev|prd] [--region eu-west-2] [--out dir] [--account <id>] [--cloudwatch] [--since <dur>] [--with-outputs]\n operator command \u2014 uses the standard AWS SDK credential chain (env/profile), NOT --api-key\n";
|
|
5105
5339
|
async function runDebugCmd(io2, argv) {
|
|
5106
5340
|
if (await refuseInsideManagedRun(io2, "debug"))
|
|
5107
5341
|
return USAGE_ERR;
|
|
@@ -5203,19 +5437,19 @@ async function runLoginCmd(io2, argv) {
|
|
|
5203
5437
|
`);
|
|
5204
5438
|
return USAGE_ERR;
|
|
5205
5439
|
}
|
|
5206
|
-
const {
|
|
5440
|
+
const { apiKey, aexUrl, debug: debug2, rest } = extracted.flags;
|
|
5207
5441
|
const positional = rest.filter((a) => !a.startsWith("--"));
|
|
5208
5442
|
if (positional.length > 0) {
|
|
5209
5443
|
io2.stderr(`unexpected arguments: ${positional.join(" ")}
|
|
5210
5444
|
`);
|
|
5211
5445
|
return USAGE_ERR;
|
|
5212
5446
|
}
|
|
5213
|
-
if (!
|
|
5214
|
-
io2.stderr("usage: aex login --api-
|
|
5447
|
+
if (!apiKey) {
|
|
5448
|
+
io2.stderr("usage: aex login --api-key <token> [--aex-url <url>]\n");
|
|
5215
5449
|
return USAGE_ERR;
|
|
5216
5450
|
}
|
|
5217
5451
|
const resolvedUrl = aexUrl ?? AEX_DEFAULT_BASE_URL;
|
|
5218
|
-
const http = makeHttpClient(io2, {
|
|
5452
|
+
const http = makeHttpClient(io2, { apiKey, aexUrl: resolvedUrl, debug: debug2 });
|
|
5219
5453
|
let workspaceId;
|
|
5220
5454
|
try {
|
|
5221
5455
|
const me = await operations_exports.whoami(http);
|
|
@@ -5232,7 +5466,7 @@ async function runLoginCmd(io2, argv) {
|
|
|
5232
5466
|
...described.remedy ? { remedy: described.remedy } : {}
|
|
5233
5467
|
});
|
|
5234
5468
|
}
|
|
5235
|
-
await io2.configStore.write({ schemaVersion: 1,
|
|
5469
|
+
await io2.configStore.write({ schemaVersion: 1, apiKey, ...aexUrl ? { aexUrl: resolvedUrl } : {} });
|
|
5236
5470
|
if (debug2)
|
|
5237
5471
|
io2.stderr(`[aex] login: persisted to ${io2.configStore.location()}
|
|
5238
5472
|
`);
|
|
@@ -5273,8 +5507,8 @@ async function runAuthStatusCmd(io2, argv) {
|
|
|
5273
5507
|
return USAGE_ERR;
|
|
5274
5508
|
}
|
|
5275
5509
|
const stored = await io2.configStore.read();
|
|
5276
|
-
const hasToken = Boolean(stored?.
|
|
5277
|
-
const tokenSuffix = hasToken ? stored.
|
|
5510
|
+
const hasToken = Boolean(stored?.apiKey);
|
|
5511
|
+
const tokenSuffix = hasToken ? stored.apiKey.slice(-4) : void 0;
|
|
5278
5512
|
io2.stdout(JSON.stringify({
|
|
5279
5513
|
configPath: io2.configStore.location(),
|
|
5280
5514
|
hasToken,
|
|
@@ -5436,6 +5670,12 @@ function renderEnvelope(e, options = {}) {
|
|
|
5436
5670
|
}
|
|
5437
5671
|
case "CUSTOM": {
|
|
5438
5672
|
const label = e.message ?? str2(e.data.name) ?? "custom";
|
|
5673
|
+
if (e.data.name === "aex.session.idle") {
|
|
5674
|
+
const value = e.data.value;
|
|
5675
|
+
const reason = value && typeof value.reason === "string" ? value.reason : "";
|
|
5676
|
+
if (reason && reason !== "completed")
|
|
5677
|
+
return `[aex] ${label} (${reason})`;
|
|
5678
|
+
}
|
|
5439
5679
|
return `[aex] ${label}`;
|
|
5440
5680
|
}
|
|
5441
5681
|
case "LOG": {
|
|
@@ -5863,28 +6103,28 @@ async function dispatch(io2, args) {
|
|
|
5863
6103
|
async function printGlobalHelp(io2) {
|
|
5864
6104
|
io2.stdout("aex \u2014 unified CLI for the aex platform (mirrors the SDK 1:1)\n\n");
|
|
5865
6105
|
io2.stdout("Usage:\n");
|
|
5866
|
-
io2.stdout(" aex run --config <run.json> --<provider>-api-key K --api-
|
|
5867
|
-
io2.stdout(" aex run --model M --prompt P [--system S] [--mcp name=url ...] --<provider>-api-key K --api-
|
|
5868
|
-
io2.stdout(" aex status <session-id> --api-
|
|
5869
|
-
io2.stdout(" aex deliveries <session-id> --api-
|
|
5870
|
-
io2.stdout(" aex wait <session-id> [--timeout 8m] [--interval 2s] --api-
|
|
5871
|
-
io2.stdout(" aex events <session-id> [--follow] [--timeout 8m] --api-
|
|
5872
|
-
io2.stdout(" aex tail <session-id> [--json] [--filter <type|source>] [--logs] [--settle] [--timeout 8m] --api-
|
|
5873
|
-
io2.stdout(" aex inspect <session-id> [--json] [--filter <type|source>] [--logs] [--timeout 8m] --api-
|
|
5874
|
-
io2.stdout(" aex outputs <session-id> --api-
|
|
5875
|
-
io2.stdout(" aex download <session-id> [--only outputs|events|metadata] [--out path] --api-
|
|
5876
|
-
io2.stdout(" aex cancel <session-id> --api-
|
|
5877
|
-
io2.stdout(" aex delete <session-id> --api-
|
|
5878
|
-
io2.stdout(" aex delete-asset <assetId|hash> --api-
|
|
5879
|
-
io2.stdout(" aex runs [--limit N] [--since ISO] --api-
|
|
5880
|
-
io2.stdout(" aex sessions [--limit N] --api-
|
|
5881
|
-
io2.stdout(" aex whoami --api-
|
|
5882
|
-
io2.stdout(" aex billing [--json] --api-
|
|
5883
|
-
io2.stdout(" aex billing ledger [--limit N] --api-
|
|
5884
|
-
io2.stdout(" aex billing upgrade pro|team --api-
|
|
5885
|
-
io2.stdout(" aex billing portal --api-
|
|
5886
|
-
io2.stdout(" aex webhooks secret --api-
|
|
5887
|
-
io2.stdout(" aex login --api-
|
|
6106
|
+
io2.stdout(" aex run --config <run.json> --<provider>-api-key K --api-key T [flags]\n");
|
|
6107
|
+
io2.stdout(" aex run --model M --prompt P [--system S] [--mcp name=url ...] --<provider>-api-key K --api-key T [flags]\n");
|
|
6108
|
+
io2.stdout(" aex status <session-id> --api-key T\n");
|
|
6109
|
+
io2.stdout(" aex deliveries <session-id> --api-key T\n");
|
|
6110
|
+
io2.stdout(" aex wait <session-id> [--timeout 8m] [--interval 2s] --api-key T\n");
|
|
6111
|
+
io2.stdout(" aex events <session-id> [--follow] [--timeout 8m] --api-key T\n");
|
|
6112
|
+
io2.stdout(" aex tail <session-id> [--json] [--filter <type|source>] [--logs] [--settle] [--timeout 8m] --api-key T\n");
|
|
6113
|
+
io2.stdout(" aex inspect <session-id> [--json] [--filter <type|source>] [--logs] [--timeout 8m] --api-key T\n");
|
|
6114
|
+
io2.stdout(" aex outputs <session-id> --api-key T\n");
|
|
6115
|
+
io2.stdout(" aex download <session-id> [--only outputs|events|metadata] [--out path] --api-key T\n");
|
|
6116
|
+
io2.stdout(" aex cancel <session-id> --api-key T\n");
|
|
6117
|
+
io2.stdout(" aex delete <session-id> --api-key T\n");
|
|
6118
|
+
io2.stdout(" aex delete-asset <assetId|hash> --api-key T\n");
|
|
6119
|
+
io2.stdout(" aex runs [--limit N] [--since ISO] --api-key T List the workspace's runs (newest first, JSON)\n");
|
|
6120
|
+
io2.stdout(" aex sessions [--limit N] --api-key T List the workspace's sessions (newest first, JSON)\n");
|
|
6121
|
+
io2.stdout(" aex whoami --api-key T\n");
|
|
6122
|
+
io2.stdout(" aex billing [--json] --api-key T Show prepaid balance, month spend, and spend cap\n");
|
|
6123
|
+
io2.stdout(" aex billing ledger [--limit N] --api-key T Recent credit-ledger entries (newest first, JSON)\n");
|
|
6124
|
+
io2.stdout(" aex billing upgrade pro|team --api-key T Create a hosted checkout session and print its URL\n");
|
|
6125
|
+
io2.stdout(" aex billing portal --api-key T Create a hosted billing portal session and print its URL\n");
|
|
6126
|
+
io2.stdout(" aex webhooks secret --api-key T Reveal (create on first use) the webhook signing secret\n");
|
|
6127
|
+
io2.stdout(" aex login --api-key T [--aex-url U] Persist token + url (then other verbs need no --api-key)\n");
|
|
5888
6128
|
io2.stdout(" aex logout Clear the stored token\n");
|
|
5889
6129
|
io2.stdout(" aex auth status Show the resolved config (token never printed)\n");
|
|
5890
6130
|
io2.stdout(" aex models list [--json] List models + default provider (no token needed)\n");
|
|
@@ -5894,7 +6134,7 @@ async function printGlobalHelp(io2) {
|
|
|
5894
6134
|
io2.stdout(" aex debug <run-id> [--plane dev|prd] [--region eu-west-2] [--cloudwatch] [--with-outputs] (operator; AWS creds)\n");
|
|
5895
6135
|
io2.stdout(" aex --help\n\n");
|
|
5896
6136
|
io2.stdout("Common flags on every host subcommand:\n");
|
|
5897
|
-
io2.stdout(" --api-
|
|
6137
|
+
io2.stdout(" --api-key <token> REQUIRED \u2014 aex SDK API key (workspace is derived from it)\n");
|
|
5898
6138
|
io2.stdout(" --aex-url <url> Optional; defaults to https://api.aex.dev (local/staging/hosted plane)\n");
|
|
5899
6139
|
io2.stdout(" --debug Optional; print a redacted per-request trace to stderr (uploads nothing)\n\n");
|
|
5900
6140
|
io2.stdout("aex run flags:\n");
|