@aexhq/sdk 0.40.16 → 0.41.1
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 +25 -25
- package/dist/_contracts/api-key.d.ts +6 -4
- package/dist/_contracts/api-key.js +20 -7
- package/dist/_contracts/connection-ticket.d.ts +5 -5
- package/dist/_contracts/connection-ticket.js +7 -7
- package/dist/_contracts/error-codes.d.ts +1 -1
- package/dist/_contracts/error-codes.js +4 -4
- package/dist/_contracts/error-factory.js +1 -1
- package/dist/_contracts/event-envelope.d.ts +41 -41
- package/dist/_contracts/event-envelope.js +49 -49
- package/dist/_contracts/event-stream-client.d.ts +9 -9
- package/dist/_contracts/event-stream-client.js +5 -5
- package/dist/_contracts/event-view.d.ts +6 -6
- package/dist/_contracts/event-view.js +12 -12
- package/dist/_contracts/http.js +1 -1
- package/dist/_contracts/index.d.ts +10 -10
- package/dist/_contracts/index.js +9 -9
- package/dist/_contracts/models.d.ts +17 -17
- package/dist/_contracts/models.js +14 -14
- package/dist/_contracts/operations.d.ts +79 -82
- package/dist/_contracts/operations.js +233 -243
- package/dist/_contracts/provider-support.d.ts +2 -2
- package/dist/_contracts/runner-event.d.ts +8 -8
- package/dist/_contracts/runner-event.js +9 -9
- package/dist/_contracts/runtime-manifest.d.ts +12 -12
- package/dist/_contracts/runtime-manifest.js +1 -1
- package/dist/_contracts/runtime-sizes.d.ts +12 -12
- package/dist/_contracts/runtime-sizes.js +18 -18
- package/dist/_contracts/runtime-types.d.ts +117 -117
- package/dist/_contracts/runtime-types.js +2 -2
- package/dist/_contracts/sdk-errors.d.ts +3 -3
- package/dist/_contracts/sdk-errors.js +4 -4
- package/dist/_contracts/sdk-secrets.js +10 -10
- package/dist/_contracts/session-artifacts.d.ts +151 -0
- package/dist/_contracts/session-artifacts.js +234 -0
- package/dist/_contracts/{run-config.d.ts → session-config.d.ts} +29 -29
- package/dist/_contracts/{run-config.js → session-config.js} +37 -37
- package/dist/_contracts/session-cost.d.ts +140 -0
- package/dist/_contracts/{run-cost.js → session-cost.js} +94 -94
- package/dist/_contracts/{run-custody.d.ts → session-custody.d.ts} +16 -16
- package/dist/_contracts/{run-custody.js → session-custody.js} +42 -42
- package/dist/_contracts/session-record.d.ts +112 -0
- package/dist/_contracts/{run-record.js → session-record.js} +23 -23
- package/dist/_contracts/session-retention.d.ts +209 -0
- package/dist/_contracts/{run-retention.js → session-retention.js} +116 -116
- package/dist/_contracts/{run-unit.d.ts → session-unit.d.ts} +38 -38
- package/dist/_contracts/{run-unit.js → session-unit.js} +33 -33
- package/dist/_contracts/side-effect-audit.d.ts +14 -14
- package/dist/_contracts/side-effect-audit.js +38 -38
- package/dist/_contracts/sse.d.ts +1 -1
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +1 -1
- package/dist/_contracts/stable.js +1 -1
- package/dist/_contracts/status.d.ts +18 -18
- package/dist/_contracts/status.js +19 -19
- package/dist/_contracts/submission.d.ts +101 -99
- package/dist/_contracts/submission.js +96 -96
- package/dist/_contracts/{run-trace.d.ts → turn-trace.d.ts} +1 -1
- package/dist/_contracts/webhook-verify.d.ts +1 -1
- package/dist/_contracts/webhook-verify.js +1 -1
- package/dist/agents-md.d.ts +4 -4
- package/dist/agents-md.js +5 -5
- package/dist/agents-md.js.map +1 -1
- package/dist/bundle.d.ts +1 -1
- package/dist/bundle.js +1 -1
- package/dist/bundle.js.map +1 -1
- package/dist/cli.mjs +578 -621
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +141 -155
- package/dist/client.js +236 -245
- package/dist/client.js.map +1 -1
- package/dist/fetch-archive.js +3 -3
- package/dist/file.d.ts +7 -7
- package/dist/file.js +8 -8
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.d.ts +1 -1
- package/dist/retry.d.ts +1 -1
- package/dist/secret.d.ts +6 -6
- package/dist/secret.js +6 -6
- package/dist/secret.js.map +1 -1
- package/dist/skill.d.ts +2 -2
- package/dist/skill.js +3 -3
- package/dist/skill.js.map +1 -1
- package/dist/tool.js +2 -2
- package/dist/tool.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/authentication.md +11 -11
- package/docs/billing.md +3 -3
- package/docs/cleanup.md +5 -5
- package/docs/concepts/agent-tools.md +5 -5
- package/docs/concepts/composition.md +3 -3
- package/docs/concepts/providers-and-runtimes.md +3 -3
- package/docs/concepts/{runs.md → sessions.md} +8 -8
- package/docs/concepts/subagents.md +16 -16
- package/docs/credentials.md +7 -7
- package/docs/defaults.md +14 -14
- package/docs/errors.md +10 -10
- package/docs/events.md +26 -26
- package/docs/files.md +267 -0
- package/docs/limits-and-quotas.md +35 -35
- package/docs/limits.md +6 -6
- package/docs/mcp.md +3 -3
- package/docs/networking.md +24 -24
- package/docs/provider-runtime-capabilities.md +1 -1
- package/docs/public-surface.json +6 -6
- package/docs/quickstart.md +13 -13
- package/docs/release.md +5 -5
- package/docs/retries.md +3 -3
- package/docs/secrets.md +16 -16
- package/docs/session-config.md +58 -0
- package/docs/{run-record.md → session-record.md} +16 -16
- package/docs/skills.md +9 -9
- package/docs/vision-skills.md +7 -7
- package/docs/webhooks.md +11 -11
- package/examples/feature-tour.ts +17 -17
- package/examples/spike-settle-latency.ts +11 -11
- package/package.json +1 -1
- package/dist/_contracts/run-artifacts.d.ts +0 -49
- package/dist/_contracts/run-artifacts.js +0 -102
- package/dist/_contracts/run-cost.d.ts +0 -140
- package/dist/_contracts/run-record.d.ts +0 -116
- package/dist/_contracts/run-retention.d.ts +0 -209
- package/docs/outputs.md +0 -267
- package/docs/run-config.md +0 -58
- /package/dist/_contracts/{run-trace.js → turn-trace.js} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -167,7 +167,7 @@ var MODEL_PROVIDER_IDS = {
|
|
|
167
167
|
"doubao-cn": "doubao-seed-1-6-flash-250828"
|
|
168
168
|
}
|
|
169
169
|
};
|
|
170
|
-
var
|
|
170
|
+
var SUPPORTED_MODELS = Object.keys(MODEL_PROVIDER_IDS);
|
|
171
171
|
var Models = {
|
|
172
172
|
/** Claude Haiku 4.5 — Anthropic. */
|
|
173
173
|
CLAUDE_HAIKU_4_5: "claude-haiku-4-5",
|
|
@@ -215,7 +215,7 @@ var PROVIDERS_BY_MODEL = (() => {
|
|
|
215
215
|
}
|
|
216
216
|
return map;
|
|
217
217
|
})();
|
|
218
|
-
var
|
|
218
|
+
var SUPPORTED_MODELS_BY_PROVIDER = (() => {
|
|
219
219
|
const map = {};
|
|
220
220
|
for (const [model, providers] of Object.entries(MODEL_PROVIDER_IDS)) {
|
|
221
221
|
for (const provider of Object.keys(providers)) {
|
|
@@ -240,17 +240,17 @@ function resolveModelProvider(model, provider) {
|
|
|
240
240
|
}
|
|
241
241
|
const inferred = providers[0];
|
|
242
242
|
if (inferred === void 0) {
|
|
243
|
-
const hint = suggest(model,
|
|
243
|
+
const hint = suggest(model, SUPPORTED_MODELS);
|
|
244
244
|
throw new Error(`${JSON.stringify(model)} is not a known model id` + (hint ? ` (did you mean ${JSON.stringify(hint)}?)` : "") + "; pass provider explicitly to run it");
|
|
245
245
|
}
|
|
246
246
|
return inferred;
|
|
247
247
|
}
|
|
248
|
-
function
|
|
249
|
-
return typeof input === "string" &&
|
|
248
|
+
function isModelName(input) {
|
|
249
|
+
return typeof input === "string" && SUPPORTED_MODELS.includes(input);
|
|
250
250
|
}
|
|
251
|
-
function
|
|
252
|
-
if (!
|
|
253
|
-
throw new Error(`${field} must be one of: ${
|
|
251
|
+
function parseModelName(input, field = "submission.model") {
|
|
252
|
+
if (!isModelName(input)) {
|
|
253
|
+
throw new Error(`${field} must be one of: ${SUPPORTED_MODELS.join(", ")}`);
|
|
254
254
|
}
|
|
255
255
|
return input;
|
|
256
256
|
}
|
|
@@ -283,7 +283,7 @@ var SESSION_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
|
283
283
|
"deleted",
|
|
284
284
|
"expired"
|
|
285
285
|
]);
|
|
286
|
-
var
|
|
286
|
+
var TERMINAL_SESSION_CONTROL_STATUSES = [
|
|
287
287
|
"succeeded",
|
|
288
288
|
"failed",
|
|
289
289
|
"timed_out",
|
|
@@ -292,7 +292,7 @@ var TERMINAL_RUN_STATUSES = [
|
|
|
292
292
|
"expired",
|
|
293
293
|
"cleanup_failed"
|
|
294
294
|
];
|
|
295
|
-
var
|
|
295
|
+
var terminalSessionControlStatuses = new Set(TERMINAL_SESSION_CONTROL_STATUSES);
|
|
296
296
|
var CLEANUP_STATUSES = [
|
|
297
297
|
"not_started",
|
|
298
298
|
"pending",
|
|
@@ -303,7 +303,7 @@ var CLEANUP_STATUSES = [
|
|
|
303
303
|
"skipped"
|
|
304
304
|
];
|
|
305
305
|
|
|
306
|
-
// ../contracts/dist/
|
|
306
|
+
// ../contracts/dist/session-config.js
|
|
307
307
|
var SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
308
308
|
var TOOL_NAME_PATTERN = SKILL_NAME_PATTERN;
|
|
309
309
|
var SKILL_RESERVED_NAMES = /* @__PURE__ */ new Set(["skills", "skill"]);
|
|
@@ -514,7 +514,7 @@ function parseRemoteMcpTransport(input, field) {
|
|
|
514
514
|
}
|
|
515
515
|
return input;
|
|
516
516
|
}
|
|
517
|
-
function
|
|
517
|
+
function parseSessionConfigMcpServerRef(input, path) {
|
|
518
518
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
519
519
|
throw new Error(`${path} must be an object`);
|
|
520
520
|
}
|
|
@@ -522,7 +522,7 @@ function parseRunConfigMcpServerRef(input, path) {
|
|
|
522
522
|
rejectStdioMcpShape(record);
|
|
523
523
|
for (const key of Object.keys(record)) {
|
|
524
524
|
if (key !== "name" && key !== "url" && key !== "headers" && key !== "transport") {
|
|
525
|
-
throw new Error(`${path}.${key} is not an allowed field for
|
|
525
|
+
throw new Error(`${path}.${key} is not an allowed field for SessionConfigMcpServer; permitted: name, url, transport, headers`);
|
|
526
526
|
}
|
|
527
527
|
}
|
|
528
528
|
const stripped = { name: record.name, url: record.url };
|
|
@@ -545,9 +545,9 @@ function parseRunConfigMcpServerRef(input, path) {
|
|
|
545
545
|
}
|
|
546
546
|
return { ...ref, headers };
|
|
547
547
|
}
|
|
548
|
-
function
|
|
548
|
+
function parseSessionRequestConfig(input) {
|
|
549
549
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
550
|
-
throw new Error("
|
|
550
|
+
throw new Error("session request config must be an object");
|
|
551
551
|
}
|
|
552
552
|
const record = input;
|
|
553
553
|
const allowed = /* @__PURE__ */ new Set([
|
|
@@ -562,23 +562,23 @@ function parseRunRequestConfig(input) {
|
|
|
562
562
|
]);
|
|
563
563
|
for (const key of Object.keys(record)) {
|
|
564
564
|
if (!allowed.has(key)) {
|
|
565
|
-
throw new Error(`
|
|
565
|
+
throw new Error(`session request config contains unexpected field: ${key}`);
|
|
566
566
|
}
|
|
567
567
|
}
|
|
568
|
-
const model =
|
|
568
|
+
const model = parseModelName(record.model, "session request config model");
|
|
569
569
|
const system = record.system;
|
|
570
570
|
if (system !== void 0 && typeof system !== "string") {
|
|
571
|
-
throw new Error("
|
|
571
|
+
throw new Error("session request config system, when provided, must be a string");
|
|
572
572
|
}
|
|
573
|
-
const prompt =
|
|
574
|
-
const mcpServers =
|
|
573
|
+
const prompt = parseSessionRequestConfigPrompt(record.prompt);
|
|
574
|
+
const mcpServers = parseSessionRequestConfigMcpServers(record.mcpServers);
|
|
575
575
|
return {
|
|
576
576
|
model,
|
|
577
577
|
...system !== void 0 ? { system } : {},
|
|
578
578
|
prompt,
|
|
579
579
|
...mcpServers !== void 0 ? { mcpServers } : {},
|
|
580
580
|
// environment / metadata: passed through as-is — the BFF revalidates
|
|
581
|
-
// them via `
|
|
581
|
+
// them via `parseSessionSubmissionRequest`,
|
|
582
582
|
// so duplicating the heavyweight parsers here would mean two sources
|
|
583
583
|
// of truth. The CLI surfaces structural errors at submission time.
|
|
584
584
|
...record.environment !== void 0 ? { environment: record.environment } : {},
|
|
@@ -587,10 +587,10 @@ function parseRunRequestConfig(input) {
|
|
|
587
587
|
...record.metadata !== void 0 ? { metadata: record.metadata } : {}
|
|
588
588
|
};
|
|
589
589
|
}
|
|
590
|
-
function
|
|
590
|
+
function parseSessionRequestConfigPrompt(value) {
|
|
591
591
|
if (typeof value === "string") {
|
|
592
592
|
if (value.length === 0) {
|
|
593
|
-
throw new Error("
|
|
593
|
+
throw new Error("session request config prompt must be a non-empty string");
|
|
594
594
|
}
|
|
595
595
|
return value;
|
|
596
596
|
}
|
|
@@ -599,29 +599,29 @@ function parseRunRequestConfigPrompt(value) {
|
|
|
599
599
|
for (let i2 = 0; i2 < value.length; i2++) {
|
|
600
600
|
const item = value[i2];
|
|
601
601
|
if (typeof item !== "string" || item.length === 0) {
|
|
602
|
-
throw new Error(`
|
|
602
|
+
throw new Error(`session request config prompt[${i2}] must be a non-empty string`);
|
|
603
603
|
}
|
|
604
604
|
arr.push(item);
|
|
605
605
|
}
|
|
606
606
|
if (arr.length === 0) {
|
|
607
|
-
throw new Error("
|
|
607
|
+
throw new Error("session request config prompt must be a non-empty string or array of strings");
|
|
608
608
|
}
|
|
609
609
|
return arr;
|
|
610
610
|
}
|
|
611
|
-
throw new Error("
|
|
611
|
+
throw new Error("session request config prompt must be a string or array of strings");
|
|
612
612
|
}
|
|
613
|
-
function
|
|
613
|
+
function parseSessionRequestConfigMcpServers(value) {
|
|
614
614
|
if (value === void 0) {
|
|
615
615
|
return void 0;
|
|
616
616
|
}
|
|
617
617
|
if (!Array.isArray(value)) {
|
|
618
|
-
throw new Error("
|
|
618
|
+
throw new Error("session request config mcpServers must be an array");
|
|
619
619
|
}
|
|
620
620
|
const seen = /* @__PURE__ */ new Set();
|
|
621
621
|
return value.map((item, index) => {
|
|
622
|
-
const entry =
|
|
622
|
+
const entry = parseSessionConfigMcpServerRef(item, `session request config mcpServers[${index}]`);
|
|
623
623
|
if (seen.has(entry.name)) {
|
|
624
|
-
throw new Error(`
|
|
624
|
+
throw new Error(`session request config mcpServers duplicate name: ${entry.name}`);
|
|
625
625
|
}
|
|
626
626
|
seen.add(entry.name);
|
|
627
627
|
return entry;
|
|
@@ -639,9 +639,9 @@ var RUNTIME_SIZE_PRESETS = {
|
|
|
639
639
|
};
|
|
640
640
|
var RUNTIME_SIZES = Object.keys(RUNTIME_SIZE_PRESETS);
|
|
641
641
|
var DEFAULT_RUNTIME_SIZE = "shared-0.25x-1gb";
|
|
642
|
-
var
|
|
643
|
-
var
|
|
644
|
-
var
|
|
642
|
+
var DEFAULT_SESSION_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
643
|
+
var MAX_SESSION_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
644
|
+
var MIN_SESSION_TIMEOUT_MS = 60 * 1e3;
|
|
645
645
|
var DURATION_PATTERN = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/;
|
|
646
646
|
function parseDurationToMs(input) {
|
|
647
647
|
const match = DURATION_PATTERN.exec(input.trim());
|
|
@@ -656,7 +656,7 @@ function parseDurationToMs(input) {
|
|
|
656
656
|
const factor = unit === "h" ? 36e5 : unit === "m" ? 6e4 : unit === "s" ? 1e3 : 1;
|
|
657
657
|
return Math.round(value * factor);
|
|
658
658
|
}
|
|
659
|
-
function
|
|
659
|
+
function parseSessionTimeout(input) {
|
|
660
660
|
if (input === void 0) {
|
|
661
661
|
return void 0;
|
|
662
662
|
}
|
|
@@ -664,16 +664,16 @@ function parseRunTimeout(input) {
|
|
|
664
664
|
throw new Error(`timeout must be a duration string (e.g. "1h", "30m"); got ${JSON.stringify(input)}`);
|
|
665
665
|
}
|
|
666
666
|
const ms = parseDurationToMs(input);
|
|
667
|
-
if (ms <
|
|
668
|
-
throw new Error(`timeout must be at least ${
|
|
667
|
+
if (ms < MIN_SESSION_TIMEOUT_MS) {
|
|
668
|
+
throw new Error(`timeout must be at least ${MIN_SESSION_TIMEOUT_MS}ms (1m); got ${ms}ms`);
|
|
669
669
|
}
|
|
670
|
-
if (ms >
|
|
671
|
-
throw new Error(`timeout must be at most ${
|
|
670
|
+
if (ms > MAX_SESSION_TIMEOUT_MS) {
|
|
671
|
+
throw new Error(`timeout must be at most ${MAX_SESSION_TIMEOUT_MS}ms (8h); got ${ms}ms`);
|
|
672
672
|
}
|
|
673
673
|
return ms;
|
|
674
674
|
}
|
|
675
|
-
var
|
|
676
|
-
var
|
|
675
|
+
var SESSION_PROCESS_KILL_GRACE_MS = 60 * 1e3;
|
|
676
|
+
var SESSION_TERMINAL_GRACE_MS = 90 * 1e3;
|
|
677
677
|
|
|
678
678
|
// ../contracts/dist/runtime-security-profile.js
|
|
679
679
|
var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
@@ -705,7 +705,7 @@ var RUNTIME_SECURITY_PROFILE_CONFIG = Object.freeze({
|
|
|
705
705
|
|
|
706
706
|
// ../contracts/dist/submission.js
|
|
707
707
|
var PLATFORM_PACKAGE_ECOSYSTEMS = ["apt", "npm", "pip"];
|
|
708
|
-
var
|
|
708
|
+
var PROVIDERS = [
|
|
709
709
|
"anthropic",
|
|
710
710
|
"deepseek",
|
|
711
711
|
"openai",
|
|
@@ -748,7 +748,7 @@ function optionalPositiveNumber(input, field) {
|
|
|
748
748
|
}
|
|
749
749
|
return input;
|
|
750
750
|
}
|
|
751
|
-
function
|
|
751
|
+
function parseSessionWebhook(input) {
|
|
752
752
|
if (input === void 0) {
|
|
753
753
|
return void 0;
|
|
754
754
|
}
|
|
@@ -774,26 +774,26 @@ function parseRunWebhook(input) {
|
|
|
774
774
|
}
|
|
775
775
|
return { url };
|
|
776
776
|
}
|
|
777
|
-
function
|
|
777
|
+
function parseSessionLimits(input) {
|
|
778
778
|
if (input === void 0) {
|
|
779
779
|
return void 0;
|
|
780
780
|
}
|
|
781
781
|
const value = requireRecord(input, "limits");
|
|
782
|
-
const allowed = /* @__PURE__ */ new Set(["
|
|
782
|
+
const allowed = /* @__PURE__ */ new Set(["maxConcurrentChildSessions", "maxSubagentDepth", "maxSpendUsd", "maxTurns"]);
|
|
783
783
|
for (const key of Object.keys(value)) {
|
|
784
784
|
if (!allowed.has(key)) {
|
|
785
785
|
throw new Error(`limits.${key} is not an allowed field; permitted: ${[...allowed].join(", ")}`);
|
|
786
786
|
}
|
|
787
787
|
}
|
|
788
|
-
const
|
|
788
|
+
const maxConcurrentChildSessions = optionalPositiveInt(value.maxConcurrentChildSessions, "limits.maxConcurrentChildSessions");
|
|
789
789
|
const maxSubagentDepth = optionalPositiveInt(value.maxSubagentDepth, "limits.maxSubagentDepth");
|
|
790
790
|
const maxSpendUsd = optionalPositiveNumber(value.maxSpendUsd, "limits.maxSpendUsd");
|
|
791
791
|
const maxTurns = optionalPositiveInt(value.maxTurns, "limits.maxTurns");
|
|
792
|
-
if (
|
|
792
|
+
if (maxConcurrentChildSessions === void 0 && maxSubagentDepth === void 0 && maxSpendUsd === void 0 && maxTurns === void 0) {
|
|
793
793
|
return void 0;
|
|
794
794
|
}
|
|
795
795
|
return {
|
|
796
|
-
...
|
|
796
|
+
...maxConcurrentChildSessions !== void 0 ? { maxConcurrentChildSessions } : {},
|
|
797
797
|
...maxSubagentDepth !== void 0 ? { maxSubagentDepth } : {},
|
|
798
798
|
...maxSpendUsd !== void 0 ? { maxSpendUsd } : {},
|
|
799
799
|
...maxTurns !== void 0 ? { maxTurns } : {}
|
|
@@ -823,22 +823,22 @@ var BUILTIN_TOOL_NAMES = [
|
|
|
823
823
|
"wc"
|
|
824
824
|
];
|
|
825
825
|
var DEFAULT_BUILTIN_TOOLS = BUILTIN_TOOL_NAMES;
|
|
826
|
-
var
|
|
826
|
+
var MAX_FILE_CAPTURE_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
|
|
827
827
|
var SKILLS_MAX = 64;
|
|
828
828
|
|
|
829
829
|
// ../contracts/dist/event-envelope.js
|
|
830
830
|
var AEX_EVENT_SOURCES = ["agent", "api", "runtime", "mcp", "aex", "workflow", "host"];
|
|
831
831
|
var AEX_EVENT_TYPES = [
|
|
832
|
-
"
|
|
833
|
-
"
|
|
834
|
-
"
|
|
832
|
+
"TURN_STARTED",
|
|
833
|
+
"TURN_FINISHED",
|
|
834
|
+
"TURN_ERROR",
|
|
835
835
|
"TEXT_MESSAGE_CONTENT",
|
|
836
836
|
"TOOL_CALL_START",
|
|
837
837
|
"TOOL_CALL_RESULT",
|
|
838
838
|
"CUSTOM",
|
|
839
839
|
// The carrier type for a `channel: "log"` record. Kept out of the AG-UI
|
|
840
|
-
// typed-event vocabulary on purpose: a `LOG` is never a
|
|
841
|
-
// so terminal detection (
|
|
840
|
+
// typed-event vocabulary on purpose: a `LOG` is never a session-lifecycle signal,
|
|
841
|
+
// so terminal detection (TURN_FINISHED/TURN_ERROR) is unaffected and an
|
|
842
842
|
// off-the-shelf AG-UI client filters logs out by `channel`.
|
|
843
843
|
"LOG"
|
|
844
844
|
];
|
|
@@ -857,9 +857,9 @@ function isSessionParked(e) {
|
|
|
857
857
|
function customName(e) {
|
|
858
858
|
return e.type === "CUSTOM" ? str(e.data.name) || null : null;
|
|
859
859
|
}
|
|
860
|
-
var
|
|
861
|
-
function
|
|
862
|
-
return customName(e) ===
|
|
860
|
+
var AEX_SESSION_SETTLED_NAME = "aex.session.settled";
|
|
861
|
+
function isSessionSettled(e) {
|
|
862
|
+
return customName(e) === AEX_SESSION_SETTLED_NAME || isSessionParked(e);
|
|
863
863
|
}
|
|
864
864
|
function channelOf(e) {
|
|
865
865
|
return e.channel ?? "event";
|
|
@@ -868,16 +868,16 @@ function toAGUI(e) {
|
|
|
868
868
|
const timestamp = Date.parse(e.time);
|
|
869
869
|
const d = e.data;
|
|
870
870
|
switch (e.type) {
|
|
871
|
-
case "
|
|
872
|
-
return { type: "
|
|
873
|
-
case "
|
|
874
|
-
return { type: "
|
|
875
|
-
case "
|
|
871
|
+
case "TURN_STARTED":
|
|
872
|
+
return { type: "TURN_STARTED", timestamp, threadId: e.subject, sessionId: e.subject };
|
|
873
|
+
case "TURN_FINISHED":
|
|
874
|
+
return { type: "TURN_FINISHED", timestamp, threadId: e.subject, sessionId: e.subject };
|
|
875
|
+
case "TURN_ERROR": {
|
|
876
876
|
const code = str(d.failureClass);
|
|
877
877
|
return {
|
|
878
|
-
type: "
|
|
878
|
+
type: "TURN_ERROR",
|
|
879
879
|
timestamp,
|
|
880
|
-
message: str(d.failureMessage) || e.message || "
|
|
880
|
+
message: str(d.failureMessage) || e.message || "turn error",
|
|
881
881
|
...code ? { code } : {}
|
|
882
882
|
};
|
|
883
883
|
}
|
|
@@ -917,7 +917,7 @@ function str(v) {
|
|
|
917
917
|
var encoder = new TextEncoder();
|
|
918
918
|
|
|
919
919
|
// ../contracts/dist/event-stream-client.js
|
|
920
|
-
var isTerminalType = (e) => e.type === "
|
|
920
|
+
var isTerminalType = (e) => e.type === "TURN_FINISHED" || e.type === "TURN_ERROR" || isSessionParked(e);
|
|
921
921
|
var COORDINATOR_PING = "aex:ping";
|
|
922
922
|
var COORDINATOR_REPLAY = JSON.stringify({ action: "replay" });
|
|
923
923
|
var DEFAULT_IDLE_TIMEOUT_MS = 45e3;
|
|
@@ -1153,8 +1153,8 @@ function sleep(ms, signal) {
|
|
|
1153
1153
|
});
|
|
1154
1154
|
}
|
|
1155
1155
|
|
|
1156
|
-
// ../contracts/dist/
|
|
1157
|
-
function
|
|
1156
|
+
// ../contracts/dist/session-unit.js
|
|
1157
|
+
function parseSessionUnitSubmission(input, fallbackModel) {
|
|
1158
1158
|
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
1159
1159
|
return fallbackFlat(fallbackModel);
|
|
1160
1160
|
}
|
|
@@ -1166,15 +1166,15 @@ function parseRunUnitSubmission(input, fallbackModel) {
|
|
|
1166
1166
|
}
|
|
1167
1167
|
function parseFlatProjection(value, fallbackModel) {
|
|
1168
1168
|
const submissionRaw = isRecord2(value.submission) ? value.submission : {};
|
|
1169
|
-
const
|
|
1170
|
-
const allowedDirs = toOptionalStringArray(
|
|
1171
|
-
const deniedDirs = toOptionalStringArray(
|
|
1172
|
-
const captureTimeoutMs = toOptionalPositiveInteger(
|
|
1173
|
-
const maxFileBytes = toOptionalPositiveInteger(
|
|
1174
|
-
const maxTotalBytes = toOptionalPositiveInteger(
|
|
1175
|
-
const maxFiles = toOptionalPositiveInteger(
|
|
1169
|
+
const fileCaptureRaw = isRecord2(submissionRaw.fileCapture) ? submissionRaw.fileCapture : {};
|
|
1170
|
+
const allowedDirs = toOptionalStringArray(fileCaptureRaw.allowedDirs);
|
|
1171
|
+
const deniedDirs = toOptionalStringArray(fileCaptureRaw.deniedDirs);
|
|
1172
|
+
const captureTimeoutMs = toOptionalPositiveInteger(fileCaptureRaw.captureTimeoutMs);
|
|
1173
|
+
const maxFileBytes = toOptionalPositiveInteger(fileCaptureRaw.maxFileBytes);
|
|
1174
|
+
const maxTotalBytes = toOptionalPositiveInteger(fileCaptureRaw.maxTotalBytes);
|
|
1175
|
+
const maxFiles = toOptionalPositiveInteger(fileCaptureRaw.maxFiles);
|
|
1176
1176
|
const submission = {
|
|
1177
|
-
model:
|
|
1177
|
+
model: coerceSessionUnitModel(submissionRaw.model ?? fallbackModel),
|
|
1178
1178
|
...typeof submissionRaw.system === "string" ? { system: submissionRaw.system } : {},
|
|
1179
1179
|
prompt: toStringArray(submissionRaw.prompt),
|
|
1180
1180
|
agentsMd: [],
|
|
@@ -1185,7 +1185,7 @@ function parseFlatProjection(value, fallbackModel) {
|
|
|
1185
1185
|
...parseSecurityProfile(submissionRaw.securityProfile) ? { securityProfile: parseSecurityProfile(submissionRaw.securityProfile) } : {},
|
|
1186
1186
|
...isJsonRecord(submissionRaw.metadata) ? { metadata: submissionRaw.metadata } : {},
|
|
1187
1187
|
...allowedDirs || deniedDirs || captureTimeoutMs !== void 0 || maxFileBytes !== void 0 || maxTotalBytes !== void 0 || maxFiles !== void 0 ? {
|
|
1188
|
-
|
|
1188
|
+
fileCapture: {
|
|
1189
1189
|
...allowedDirs ? { allowedDirs } : {},
|
|
1190
1190
|
...deniedDirs ? { deniedDirs } : {},
|
|
1191
1191
|
...captureTimeoutMs !== void 0 ? { captureTimeoutMs } : {},
|
|
@@ -1210,7 +1210,7 @@ function fallbackFlat(fallbackModel) {
|
|
|
1210
1210
|
return {
|
|
1211
1211
|
kind: "submission",
|
|
1212
1212
|
submission: {
|
|
1213
|
-
model:
|
|
1213
|
+
model: coerceSessionUnitModel(fallbackModel),
|
|
1214
1214
|
prompt: [],
|
|
1215
1215
|
agentsMd: [],
|
|
1216
1216
|
files: [],
|
|
@@ -1222,7 +1222,7 @@ function fallbackFlat(fallbackModel) {
|
|
|
1222
1222
|
function isRecord2(value) {
|
|
1223
1223
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1224
1224
|
}
|
|
1225
|
-
function
|
|
1225
|
+
function normalizeSessionUnit(raw) {
|
|
1226
1226
|
const r = isRecord2(raw) ? raw : {};
|
|
1227
1227
|
const eventsRaw = isRecord2(r.events) ? r.events : {};
|
|
1228
1228
|
const str3 = (v) => typeof v === "string" ? v : void 0;
|
|
@@ -1240,9 +1240,9 @@ function normalizeRunUnit(raw) {
|
|
|
1240
1240
|
...str3(r.deletedAt) ? { deletedAt: r.deletedAt } : {},
|
|
1241
1241
|
attemptCount: typeof r.attemptCount === "number" ? r.attemptCount : Array.isArray(r.attempts) ? r.attempts.length : 0,
|
|
1242
1242
|
// Plane responses that project a flat record (no `submission` snapshot)
|
|
1243
|
-
// still carry the
|
|
1244
|
-
// static fallback so `unit()` never claims a model the
|
|
1245
|
-
submission:
|
|
1243
|
+
// still carry the session's `model` at the top level — prefer it over the
|
|
1244
|
+
// static fallback so `unit()` never claims a model the session did not use.
|
|
1245
|
+
submission: parseSessionUnitSubmission(r.submission, r.model),
|
|
1246
1246
|
...isRecord2(r.capsSnapshot) ? { capsSnapshot: r.capsSnapshot } : {},
|
|
1247
1247
|
attempts: arr(r.attempts),
|
|
1248
1248
|
events: {
|
|
@@ -1252,17 +1252,17 @@ function normalizeRunUnit(raw) {
|
|
|
1252
1252
|
...str3(eventsRaw.nextCursor) ? { nextCursor: eventsRaw.nextCursor } : {}
|
|
1253
1253
|
},
|
|
1254
1254
|
rawEventPages: arr(r.rawEventPages),
|
|
1255
|
-
|
|
1256
|
-
|
|
1255
|
+
sessionFiles: arr(r.sessionFiles),
|
|
1256
|
+
fileCaptureFailures: arr(r.fileCaptureFailures),
|
|
1257
1257
|
...isRecord2(r.costTelemetry) ? { costTelemetry: r.costTelemetry } : {},
|
|
1258
1258
|
...isRecord2(r.runtimeManifest) ? { runtimeManifest: r.runtimeManifest } : {}
|
|
1259
1259
|
};
|
|
1260
1260
|
}
|
|
1261
|
-
function
|
|
1261
|
+
function coerceSessionUnitModel(value) {
|
|
1262
1262
|
if (typeof value !== "string")
|
|
1263
1263
|
return Models.CLAUDE_HAIKU_4_5;
|
|
1264
1264
|
try {
|
|
1265
|
-
return
|
|
1265
|
+
return parseModelName(value, "session unit submission.model");
|
|
1266
1266
|
} catch {
|
|
1267
1267
|
return Models.CLAUDE_HAIKU_4_5;
|
|
1268
1268
|
}
|
|
@@ -1353,7 +1353,7 @@ var RUNTIME_PATHS = Object.freeze({
|
|
|
1353
1353
|
runtimeEnv: "/mnt/session/uploads/aex/RUNTIME.env"
|
|
1354
1354
|
});
|
|
1355
1355
|
|
|
1356
|
-
// ../contracts/dist/
|
|
1356
|
+
// ../contracts/dist/session-custody.js
|
|
1357
1357
|
function scanCustodyPayloadForSensitiveValues(input) {
|
|
1358
1358
|
const findings = [];
|
|
1359
1359
|
visitCustodyValue(input, "$", findings);
|
|
@@ -1418,44 +1418,44 @@ var forbiddenStringPatterns = Object.freeze([
|
|
|
1418
1418
|
regex: /\b(?:sk-[A-Za-z0-9_-]{16,}|xox[baprs]-[A-Za-z0-9-]{8,}|AIza[A-Za-z0-9_-]{8,})/i
|
|
1419
1419
|
},
|
|
1420
1420
|
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
1421
|
-
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:
|
|
1421
|
+
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:sessions|assets)\/[^?<#\s"'`]+/i },
|
|
1422
1422
|
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
1423
1423
|
{
|
|
1424
1424
|
reason: "private_resource_handle",
|
|
1425
|
-
// `<keyword><sep><id>` opaque handles (`
|
|
1425
|
+
// `<keyword><sep><id>` opaque handles (`machine_a1B2c3D4e5`, `resource_9f8e7d...`).
|
|
1426
1426
|
// The keyword set overlaps ordinary prose, so require the id segment to
|
|
1427
1427
|
// carry a digit. That keeps genuine minted handles flagged while avoiding
|
|
1428
1428
|
// dictionary-word chains such as `agent_decision_failure`.
|
|
1429
|
-
regex: /\b(?:machine|
|
|
1429
|
+
regex: /\b(?:machine|agent|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i,
|
|
1430
1430
|
accept: isMintedResourceHandle
|
|
1431
1431
|
},
|
|
1432
1432
|
{
|
|
1433
1433
|
reason: "high_entropy_token",
|
|
1434
|
-
// Catch-all for an unrecognised opaque secret blob. The candidate
|
|
1434
|
+
// Catch-all for an unrecognised opaque secret blob. The candidate sequence
|
|
1435
1435
|
// EXCLUDES `_` (so `SCREAMING_SNAKE` env names and `slug_with_words` URL
|
|
1436
|
-
// segments split instead of fusing into a phantom 40-char
|
|
1436
|
+
// segments split instead of fusing into a phantom 40-char sequence — the live
|
|
1437
1437
|
// false positive was `ted_season_2_peacock_official_discussion_thread` in
|
|
1438
1438
|
// web-search result text and a fetched URL), and the `accept` predicate
|
|
1439
1439
|
// vetoes content-addressed hashes (md5/sha1/sha256 digests — the platform's
|
|
1440
|
-
// OWN asset filenames) and low-entropy / single-class
|
|
1440
|
+
// OWN asset filenames) and low-entropy / single-class sessions so only genuine
|
|
1441
1441
|
// opaque secrets remain. Slash-bearing secrets (signed URLs, connection
|
|
1442
1442
|
// strings, `Bearer …`) are covered by the named patterns above.
|
|
1443
1443
|
regex: /\b[A-Za-z0-9-]{40,}\b/,
|
|
1444
|
-
accept:
|
|
1444
|
+
accept: isHighEntropySecretSequence
|
|
1445
1445
|
}
|
|
1446
1446
|
]);
|
|
1447
|
-
var
|
|
1448
|
-
function
|
|
1449
|
-
if (
|
|
1447
|
+
var CONTENT_HASH_SEQUENCE = /^(?:[0-9a-f]{32}|[0-9a-f]{40}|[0-9a-f]{64})$/i;
|
|
1448
|
+
function isHighEntropySecretSequence(sequence) {
|
|
1449
|
+
if (CONTENT_HASH_SEQUENCE.test(sequence)) {
|
|
1450
1450
|
return false;
|
|
1451
1451
|
}
|
|
1452
|
-
if (!/[A-Za-z]/.test(
|
|
1452
|
+
if (!/[A-Za-z]/.test(sequence) || !/\d/.test(sequence)) {
|
|
1453
1453
|
return false;
|
|
1454
1454
|
}
|
|
1455
|
-
if (highEntropyCharClassCount(
|
|
1455
|
+
if (highEntropyCharClassCount(sequence) < 2) {
|
|
1456
1456
|
return false;
|
|
1457
1457
|
}
|
|
1458
|
-
return highEntropyShannonBits(
|
|
1458
|
+
return highEntropyShannonBits(sequence) >= 3;
|
|
1459
1459
|
}
|
|
1460
1460
|
function isMintedResourceHandle(match) {
|
|
1461
1461
|
const separatorIndex = match.search(/[_:-]/);
|
|
@@ -1491,32 +1491,32 @@ function isForbiddenCustodyFieldName(key) {
|
|
|
1491
1491
|
return /^(apiKey|apiKeys|secretValue|bearerHash|signedUrl|objectStoreKey|objectKey|vaultId|providerResponseBody|responseBody|privateResourceHandle|resourceHandle|rawBody)$/i.test(key);
|
|
1492
1492
|
}
|
|
1493
1493
|
|
|
1494
|
-
// ../contracts/dist/
|
|
1495
|
-
var
|
|
1496
|
-
var
|
|
1497
|
-
var
|
|
1498
|
-
code = "
|
|
1494
|
+
// ../contracts/dist/session-record.js
|
|
1495
|
+
var SESSION_RECORD_SCHEMA_VERSION = "aex.session-record.v1";
|
|
1496
|
+
var SESSION_RECORD_MANIFEST_SCHEMA_VERSION = "aex.session-record.manifest.v1";
|
|
1497
|
+
var SessionRecordArchiveRedactionError = class extends Error {
|
|
1498
|
+
code = "session_record_archive_not_public_safe";
|
|
1499
1499
|
findings;
|
|
1500
1500
|
constructor(findings) {
|
|
1501
|
-
super(`
|
|
1502
|
-
this.name = "
|
|
1501
|
+
super(`session record archive contains non-public data at ${formatArchiveFindingPaths(findings)}`);
|
|
1502
|
+
this.name = "SessionRecordArchiveRedactionError";
|
|
1503
1503
|
this.findings = Object.freeze([...findings]);
|
|
1504
1504
|
}
|
|
1505
1505
|
};
|
|
1506
|
-
function
|
|
1507
|
-
const
|
|
1506
|
+
function buildSessionRecordDownloadManifestV1(input) {
|
|
1507
|
+
const sessionFiles = input.sessionFiles.map((file2) => normalizeArtifactSummary(file2));
|
|
1508
1508
|
const errors = (input.errors ?? []).map((error) => Object.freeze({ ...error }));
|
|
1509
1509
|
return Object.freeze({
|
|
1510
|
-
schemaVersion:
|
|
1511
|
-
|
|
1512
|
-
|
|
1510
|
+
schemaVersion: SESSION_RECORD_MANIFEST_SCHEMA_VERSION,
|
|
1511
|
+
sessionRecordSchemaVersion: SESSION_RECORD_SCHEMA_VERSION,
|
|
1512
|
+
sessionId: input.sessionId,
|
|
1513
1513
|
namespaces: Object.freeze([
|
|
1514
|
-
namespace("metadata", "
|
|
1514
|
+
namespace("metadata", "SessionRecord metadata, submission snapshot, custody, and cost files."),
|
|
1515
1515
|
namespace("events", "Typed event-channel exports."),
|
|
1516
|
-
namespace("
|
|
1516
|
+
namespace("files", "Captured files produced by the session.")
|
|
1517
1517
|
]),
|
|
1518
1518
|
files: Object.freeze([
|
|
1519
|
-
file("metadata", "metadata/
|
|
1519
|
+
file("metadata", "metadata/session.json", "session_metadata", "present"),
|
|
1520
1520
|
file("metadata", "metadata/submission.json", "submission_snapshot", input.submission?.status ?? "unavailable"),
|
|
1521
1521
|
file("metadata", "metadata/cost.json", "cost", input.cost?.status ?? "pending"),
|
|
1522
1522
|
file("metadata", "metadata/custody.json", "custody", input.custody?.status ?? "pending"),
|
|
@@ -1524,9 +1524,9 @@ function buildRunRecordDownloadManifestV1(input) {
|
|
|
1524
1524
|
recordCount: input.typedEventCount ?? 0
|
|
1525
1525
|
}),
|
|
1526
1526
|
file("events", "events/manifest.json", "coordinator_events_manifest", input.coordinatorEventsManifest?.status ?? "unavailable"),
|
|
1527
|
-
...
|
|
1527
|
+
...sessionFiles.map((fileSummary) => artifactFile("files", "file", "files/", fileSummary))
|
|
1528
1528
|
]),
|
|
1529
|
-
|
|
1529
|
+
sessionFiles: Object.freeze(sessionFiles),
|
|
1530
1530
|
errors: Object.freeze(errors)
|
|
1531
1531
|
});
|
|
1532
1532
|
}
|
|
@@ -1567,7 +1567,7 @@ function normalizeArtifactSummary(input) {
|
|
|
1567
1567
|
...input.contentType !== void 0 ? { contentType: input.contentType } : {}
|
|
1568
1568
|
});
|
|
1569
1569
|
}
|
|
1570
|
-
function
|
|
1570
|
+
function scanSessionRecordArchiveEntriesV1(entries) {
|
|
1571
1571
|
const findings = [];
|
|
1572
1572
|
for (const entry of entries) {
|
|
1573
1573
|
if (entry.customerContent || !shouldScanArchiveEntry(entry)) {
|
|
@@ -1579,14 +1579,14 @@ function scanRunRecordArchiveEntriesV1(entries) {
|
|
|
1579
1579
|
}
|
|
1580
1580
|
return Object.freeze(findings);
|
|
1581
1581
|
}
|
|
1582
|
-
function
|
|
1583
|
-
const findings =
|
|
1582
|
+
function assertSessionRecordArchivePublicSafeV1(entries) {
|
|
1583
|
+
const findings = scanSessionRecordArchiveEntriesV1(entries);
|
|
1584
1584
|
if (findings.length > 0) {
|
|
1585
|
-
throw new
|
|
1585
|
+
throw new SessionRecordArchiveRedactionError(findings);
|
|
1586
1586
|
}
|
|
1587
1587
|
}
|
|
1588
1588
|
function shouldScanArchiveEntry(entry) {
|
|
1589
|
-
if (entry.path.startsWith("
|
|
1589
|
+
if (entry.path.startsWith("files/")) {
|
|
1590
1590
|
return false;
|
|
1591
1591
|
}
|
|
1592
1592
|
const contentType = entry.contentType?.toLowerCase() ?? "";
|
|
@@ -1613,7 +1613,7 @@ function isAllowedArchiveHighEntropyField(entryPath, finding) {
|
|
|
1613
1613
|
if (finding.reason !== "high_entropy_token" || !entryPath.endsWith("manifest.json")) {
|
|
1614
1614
|
return false;
|
|
1615
1615
|
}
|
|
1616
|
-
return /^\$(?:\.files\[\d+\]|\.
|
|
1616
|
+
return /^\$(?:\.files\[\d+\]|\.sessionFiles\[\d+\])\.id$/.test(finding.path);
|
|
1617
1617
|
}
|
|
1618
1618
|
function parseArchiveTextValues(path, text) {
|
|
1619
1619
|
if (/\.json$/i.test(path)) {
|
|
@@ -1649,14 +1649,14 @@ function formatArchiveFindingPaths(findings) {
|
|
|
1649
1649
|
return findings.map((finding) => `${finding.entryPath}${finding.path} (${finding.reason})`).join(", ");
|
|
1650
1650
|
}
|
|
1651
1651
|
|
|
1652
|
-
// ../contracts/dist/
|
|
1652
|
+
// ../contracts/dist/session-retention.js
|
|
1653
1653
|
var forbiddenStringPatterns2 = Object.freeze([
|
|
1654
1654
|
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
1655
|
-
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:
|
|
1655
|
+
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:sessions|assets)\/[^?<#\s"'`]+/i },
|
|
1656
1656
|
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
1657
1657
|
{
|
|
1658
1658
|
reason: "private_resource_handle",
|
|
1659
|
-
regex: /\b(?:machine|
|
|
1659
|
+
regex: /\b(?:machine|resource|handle|provider|asset)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
1660
1660
|
},
|
|
1661
1661
|
{ reason: "hash_like_value", regex: /\b(?:sha256|hash)[:_-][A-Fa-f0-9]{16,}\b/ }
|
|
1662
1662
|
]);
|
|
@@ -1669,11 +1669,11 @@ var forbiddenStringPatterns3 = Object.freeze([
|
|
|
1669
1669
|
regex: /\b(?:sk-(?:ant|proj|live|test|deepseek|openai)|xox[baprs]-|AIza)[A-Za-z0-9_-]{8,}/i
|
|
1670
1670
|
},
|
|
1671
1671
|
{ reason: "signed_url", regex: /[?&](?:X-Amz-Signature|X-Amz-Credential|X-Amz-Algorithm|AWSAccessKeyId)=/i },
|
|
1672
|
-
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:
|
|
1672
|
+
{ reason: "object_store_key", regex: /(^|[\s"'`])(?:sessions|assets)\/[^?<#\s"'`]+/i },
|
|
1673
1673
|
{ reason: "vault_id", regex: /\b(?:vault|vlt|secret)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i },
|
|
1674
1674
|
{
|
|
1675
1675
|
reason: "private_resource_handle",
|
|
1676
|
-
regex: /\b(?:machine|
|
|
1676
|
+
regex: /\b(?:machine|agent|resource|handle|token_hash|bearer_hash)[_:-][A-Za-z0-9][A-Za-z0-9_-]{7,}\b/i
|
|
1677
1677
|
},
|
|
1678
1678
|
{ reason: "raw_url", regex: /\bhttps?:\/\/\S+/i },
|
|
1679
1679
|
{ reason: "raw_path", regex: /(^|[\s"'`])\/[A-Za-z0-9._~!$&'()*+,;=:@%-]+(?:[/?#][^\s"'`]*)?/ },
|
|
@@ -1713,10 +1713,10 @@ var HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9+/=-]{24,}/g;
|
|
|
1713
1713
|
var ENTROPY_BITS_PER_CHAR = 3;
|
|
1714
1714
|
var MIN_CHAR_CLASSES = 2;
|
|
1715
1715
|
var HIGH_ENTROPY_NO_DIGIT_MIN_LEN = 40;
|
|
1716
|
-
function
|
|
1716
|
+
function isCanonicalSessionIdHex(input, matchStart, match) {
|
|
1717
1717
|
if (!/^[0-9a-f]{32}$/.test(match))
|
|
1718
1718
|
return false;
|
|
1719
|
-
return input.slice(Math.max(0, matchStart - 4), matchStart) === "
|
|
1719
|
+
return input.slice(Math.max(0, matchStart - 4), matchStart) === "ses_";
|
|
1720
1720
|
}
|
|
1721
1721
|
function redactSecrets(value) {
|
|
1722
1722
|
if (typeof value === "string") {
|
|
@@ -1750,7 +1750,7 @@ function redactString(input, known = []) {
|
|
|
1750
1750
|
// prefix; the rest replace the whole match.
|
|
1751
1751
|
typeof captured === "string" ? `${captured} ${REDACTED}` : REDACTED
|
|
1752
1752
|
)), out);
|
|
1753
|
-
return out.replace(HIGH_ENTROPY_CANDIDATE, (match, offset, whole) => !
|
|
1753
|
+
return out.replace(HIGH_ENTROPY_CANDIDATE, (match, offset, whole) => !isCanonicalSessionIdHex(whole, offset, match) && looksHighEntropySecret(match) ? REDACTED : match);
|
|
1754
1754
|
}
|
|
1755
1755
|
function isSecretKey(key) {
|
|
1756
1756
|
return /(?:api[_-]?key|authorization|token|secret|password|credential)/i.test(key);
|
|
@@ -1803,7 +1803,7 @@ var AEX_API_ERROR_CODES = [
|
|
|
1803
1803
|
"not_found",
|
|
1804
1804
|
"idempotency_conflict",
|
|
1805
1805
|
"session_busy",
|
|
1806
|
-
"
|
|
1806
|
+
"session_not_terminal",
|
|
1807
1807
|
"unknown_workspace",
|
|
1808
1808
|
"workspace_concurrency_exceeded",
|
|
1809
1809
|
"workspace_submit_rate_exceeded",
|
|
@@ -1824,12 +1824,12 @@ var AEX_API_ERROR_MESSAGES = {
|
|
|
1824
1824
|
not_found: "The requested resource was not found.",
|
|
1825
1825
|
idempotency_conflict: "This idempotency key was already used with a different request body.",
|
|
1826
1826
|
session_busy: "The session is busy handling another turn.",
|
|
1827
|
-
|
|
1827
|
+
session_not_terminal: "The session has not reached a terminal state yet.",
|
|
1828
1828
|
unknown_workspace: "The workspace could not be resolved from the API key.",
|
|
1829
1829
|
workspace_concurrency_exceeded: "The workspace has reached its concurrent-run limit.",
|
|
1830
1830
|
workspace_submit_rate_exceeded: "The workspace submit-rate limit was exceeded.",
|
|
1831
1831
|
workspace_spend_cap_exceeded: "The workspace monthly spend cap was reached.",
|
|
1832
|
-
insufficient_balance: "The workspace prepaid balance is insufficient to submit this
|
|
1832
|
+
insufficient_balance: "The workspace prepaid balance is insufficient to submit this session.",
|
|
1833
1833
|
rate_limited: "Too many requests \u2014 retry after a short backoff.",
|
|
1834
1834
|
upstream_error: "An upstream provider returned an error.",
|
|
1835
1835
|
internal_error: "The aex API encountered an internal error."
|
|
@@ -1850,12 +1850,12 @@ var AexError = class extends Error {
|
|
|
1850
1850
|
this.details = details === void 0 ? void 0 : redactSecrets(details);
|
|
1851
1851
|
}
|
|
1852
1852
|
};
|
|
1853
|
-
var
|
|
1853
|
+
var SessionConfigValidationError = class extends AexError {
|
|
1854
1854
|
constructor(message, details) {
|
|
1855
|
-
super("
|
|
1855
|
+
super("SESSION_CONFIG_INVALID", message, details);
|
|
1856
1856
|
}
|
|
1857
1857
|
};
|
|
1858
|
-
var
|
|
1858
|
+
var SessionStateError = class extends AexError {
|
|
1859
1859
|
/**
|
|
1860
1860
|
* HTTP status from a wrapped API rejection, when this state error is a
|
|
1861
1861
|
* bounded client-side interpretation of that rejection.
|
|
@@ -1868,7 +1868,7 @@ var RunStateError = class extends AexError {
|
|
|
1868
1868
|
constructor(message, details, options) {
|
|
1869
1869
|
const detailRecord = details && typeof details === "object" && !Array.isArray(details) ? details : void 0;
|
|
1870
1870
|
const cause = options?.cause ?? detailRecord?.cause;
|
|
1871
|
-
super("
|
|
1871
|
+
super("SESSION_STATE_ERROR", message, details, cause === void 0 ? void 0 : { cause });
|
|
1872
1872
|
const status = detailRecord?.httpStatus ?? detailRecord?.status;
|
|
1873
1873
|
const apiCode = detailRecord?.apiCode;
|
|
1874
1874
|
this.status = typeof status === "number" ? status : void 0;
|
|
@@ -2043,7 +2043,7 @@ function apiErrorKindForCode(code) {
|
|
|
2043
2043
|
case "workspace_submit_rate_exceeded":
|
|
2044
2044
|
return "rate_limit";
|
|
2045
2045
|
case "session_busy":
|
|
2046
|
-
case "
|
|
2046
|
+
case "session_not_terminal":
|
|
2047
2047
|
case "unknown_workspace":
|
|
2048
2048
|
case "workspace_spend_cap_exceeded":
|
|
2049
2049
|
case "insufficient_balance":
|
|
@@ -2397,25 +2397,28 @@ function extractErrorMessage(body) {
|
|
|
2397
2397
|
return "aex API request failed";
|
|
2398
2398
|
}
|
|
2399
2399
|
|
|
2400
|
+
// ../contracts/dist/session-artifacts.js
|
|
2401
|
+
var SESSION_INTERNAL_PREFIX = "internal";
|
|
2402
|
+
var SESSION_INTERNAL_LOGS_PREFIX = `${SESSION_INTERNAL_PREFIX}/logs`;
|
|
2403
|
+
var SESSION_INTERNAL_USAGE_PREFIX = `${SESSION_INTERNAL_PREFIX}/usage`;
|
|
2404
|
+
|
|
2400
2405
|
// ../contracts/dist/operations.js
|
|
2401
2406
|
var operations_exports = {};
|
|
2402
2407
|
__export(operations_exports, {
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2408
|
+
READ_SESSION_FILE_TEXT_DEFAULT_BYTES: () => READ_SESSION_FILE_TEXT_DEFAULT_BYTES,
|
|
2409
|
+
READ_SESSION_FILE_TEXT_MAX_BYTES: () => READ_SESSION_FILE_TEXT_MAX_BYTES,
|
|
2410
|
+
SESSION_FILE_TRANSFER_ATTEMPTS: () => SESSION_FILE_TRANSFER_ATTEMPTS,
|
|
2411
|
+
SESSION_FILE_TRANSFER_DEFAULT_TIMEOUT_MS: () => SESSION_FILE_TRANSFER_DEFAULT_TIMEOUT_MS,
|
|
2407
2412
|
approveSession: () => approveSession,
|
|
2408
|
-
cancelRun: () => cancelRun,
|
|
2409
2413
|
cancelSession: () => cancelSession,
|
|
2410
|
-
|
|
2414
|
+
classifySessionFile: () => classifySessionFile,
|
|
2411
2415
|
createBillingCheckout: () => createBillingCheckout,
|
|
2412
2416
|
createBillingPortal: () => createBillingPortal,
|
|
2413
|
-
createOutputLink: () => createOutputLink,
|
|
2414
2417
|
createSecret: () => createSecret,
|
|
2415
2418
|
createSession: () => createSession,
|
|
2419
|
+
createSessionFileLink: () => createSessionFileLink,
|
|
2416
2420
|
deleteAgentsMd: () => deleteAgentsMd,
|
|
2417
2421
|
deleteFile: () => deleteFile,
|
|
2418
|
-
deleteRun: () => deleteRun,
|
|
2419
2422
|
deleteSecret: () => deleteSecret,
|
|
2420
2423
|
deleteSession: () => deleteSession,
|
|
2421
2424
|
deleteSkill: () => deleteSkill,
|
|
@@ -2424,50 +2427,49 @@ __export(operations_exports, {
|
|
|
2424
2427
|
download: () => download,
|
|
2425
2428
|
downloadEvents: () => downloadEvents,
|
|
2426
2429
|
downloadMetadata: () => downloadMetadata,
|
|
2427
|
-
|
|
2428
|
-
|
|
2430
|
+
downloadSessionFile: () => downloadSessionFile,
|
|
2431
|
+
downloadSessionFiles: () => downloadSessionFiles,
|
|
2429
2432
|
eventArchiveLink: () => eventArchiveLink,
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
+
filterSessionFiles: () => filterSessionFiles,
|
|
2434
|
+
findSessionFile: () => findSessionFile,
|
|
2435
|
+
findSessionFiles: () => findSessionFiles,
|
|
2433
2436
|
getAgentsMd: () => getAgentsMd,
|
|
2434
2437
|
getBilling: () => getBilling,
|
|
2435
2438
|
getBillingLedger: () => getBillingLedger,
|
|
2436
2439
|
getCoordinatorTicket: () => getCoordinatorTicket,
|
|
2437
2440
|
getFile: () => getFile,
|
|
2438
|
-
getRun: () => getRun,
|
|
2439
|
-
getRunUnit: () => getRunUnit,
|
|
2440
|
-
getRunWebhookDeliveries: () => getRunWebhookDeliveries,
|
|
2441
2441
|
getSecret: () => getSecret,
|
|
2442
2442
|
getSecretValue: () => getSecretValue,
|
|
2443
2443
|
getSession: () => getSession,
|
|
2444
2444
|
getSessionCoordinatorTicket: () => getSessionCoordinatorTicket,
|
|
2445
|
+
getSessionRecord: () => getSessionRecord,
|
|
2446
|
+
getSessionUnit: () => getSessionUnit,
|
|
2447
|
+
getSessionWebhookDeliveries: () => getSessionWebhookDeliveries,
|
|
2445
2448
|
getSkill: () => getSkill,
|
|
2446
2449
|
getWebhookSigningSecret: () => getWebhookSigningSecret,
|
|
2447
2450
|
listAgentsMd: () => listAgentsMd,
|
|
2448
2451
|
listFiles: () => listFiles,
|
|
2449
|
-
listOutputs: () => listOutputs,
|
|
2450
|
-
listRunChildren: () => listRunChildren,
|
|
2451
|
-
listRunEvents: () => listRunEvents,
|
|
2452
|
-
listRuns: () => listRuns,
|
|
2453
2452
|
listSecrets: () => listSecrets,
|
|
2453
|
+
listSessionChildren: () => listSessionChildren,
|
|
2454
2454
|
listSessionEvents: () => listSessionEvents,
|
|
2455
|
+
listSessionFiles: () => listSessionFiles,
|
|
2455
2456
|
listSessionMessages: () => listSessionMessages,
|
|
2456
|
-
|
|
2457
|
+
listSessionRecordEvents: () => listSessionRecordEvents,
|
|
2458
|
+
listSessionRecords: () => listSessionRecords,
|
|
2457
2459
|
listSessions: () => listSessions,
|
|
2458
2460
|
listSkills: () => listSkills,
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
redeliverRunWebhook: () => redeliverRunWebhook,
|
|
2461
|
+
normalizeSessionFileLinkExpiresIn: () => normalizeSessionFileLinkExpiresIn,
|
|
2462
|
+
readSessionFileText: () => readSessionFileText,
|
|
2463
|
+
redeliverSessionWebhook: () => redeliverSessionWebhook,
|
|
2463
2464
|
requestApproval: () => requestApproval,
|
|
2464
2465
|
resolveIdempotencyKey: () => resolveIdempotencyKey,
|
|
2465
|
-
|
|
2466
|
+
resolveSessionFileSelector: () => resolveSessionFileSelector,
|
|
2466
2467
|
resumeSession: () => resumeSession,
|
|
2467
2468
|
rotateSecret: () => rotateSecret,
|
|
2468
2469
|
sendSessionMessage: () => sendSessionMessage,
|
|
2470
|
+
sessionFileLink: () => sessionFileLink,
|
|
2471
|
+
startSessionRecord: () => startSessionRecord,
|
|
2469
2472
|
submit: () => submit,
|
|
2470
|
-
submitRun: () => submitRun,
|
|
2471
2473
|
suspendSession: () => suspendSession,
|
|
2472
2474
|
toFilenameMatcher: () => toFilenameMatcher,
|
|
2473
2475
|
uploadWorkspaceAsset: () => uploadWorkspaceAsset,
|
|
@@ -3193,14 +3195,14 @@ function zipSync(data, opts) {
|
|
|
3193
3195
|
|
|
3194
3196
|
// ../contracts/dist/operations.js
|
|
3195
3197
|
import { randomUUID } from "node:crypto";
|
|
3196
|
-
async function
|
|
3197
|
-
const result = await http.request(`/api/
|
|
3198
|
-
return
|
|
3198
|
+
async function getSessionRecord(http, sessionId) {
|
|
3199
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}`);
|
|
3200
|
+
return hasSessionRecord(result) ? result.session : result;
|
|
3199
3201
|
}
|
|
3200
|
-
async function
|
|
3201
|
-
return
|
|
3202
|
+
async function getSessionUnit(http, sessionId) {
|
|
3203
|
+
return normalizeSessionUnit(await http.request(`/api/sessions/${encodeURIComponent(sessionId)}`));
|
|
3202
3204
|
}
|
|
3203
|
-
async function
|
|
3205
|
+
async function listSessionRecords(http, query) {
|
|
3204
3206
|
const params = {};
|
|
3205
3207
|
if (query?.status !== void 0)
|
|
3206
3208
|
params.status = query.status;
|
|
@@ -3210,30 +3212,30 @@ async function listRuns(http, query) {
|
|
|
3210
3212
|
params.limit = String(query.limit);
|
|
3211
3213
|
if (query?.cursor !== void 0)
|
|
3212
3214
|
params.cursor = query.cursor;
|
|
3213
|
-
const page = await http.request("/api/
|
|
3215
|
+
const page = await http.request("/api/sessions", {}, params);
|
|
3214
3216
|
let changed = false;
|
|
3215
|
-
const
|
|
3216
|
-
for (const
|
|
3217
|
-
if (typeof
|
|
3217
|
+
const sessions = [];
|
|
3218
|
+
for (const session of page.sessions) {
|
|
3219
|
+
if (typeof session.id !== "string" || typeof session.status !== "string" || typeof session.createdAt !== "string" || typeof session.updatedAt !== "string") {
|
|
3218
3220
|
changed = true;
|
|
3219
3221
|
continue;
|
|
3220
3222
|
}
|
|
3221
|
-
if (typeof
|
|
3222
|
-
const { costUsd: _dropped, ...rest } =
|
|
3223
|
-
|
|
3223
|
+
if (typeof session.costUsd !== "number" && session.costUsd !== void 0) {
|
|
3224
|
+
const { costUsd: _dropped, ...rest } = session;
|
|
3225
|
+
sessions.push(rest);
|
|
3224
3226
|
changed = true;
|
|
3225
3227
|
continue;
|
|
3226
3228
|
}
|
|
3227
|
-
|
|
3229
|
+
sessions.push(session);
|
|
3228
3230
|
}
|
|
3229
|
-
return changed ? { ...page,
|
|
3231
|
+
return changed ? { ...page, sessions } : page;
|
|
3230
3232
|
}
|
|
3231
3233
|
function resolveIdempotencyKey(key) {
|
|
3232
3234
|
if (key === void 0) {
|
|
3233
3235
|
return `aex-idem-${randomUUID()}`;
|
|
3234
3236
|
}
|
|
3235
3237
|
if (typeof key !== "string" || key.trim().length === 0) {
|
|
3236
|
-
throw new
|
|
3238
|
+
throw new SessionConfigValidationError("idempotencyKey must be a non-empty, non-whitespace string", {
|
|
3237
3239
|
field: "idempotencyKey",
|
|
3238
3240
|
value: key
|
|
3239
3241
|
});
|
|
@@ -3244,7 +3246,7 @@ function idempotencyHeaders(options) {
|
|
|
3244
3246
|
if (options?.idempotencyKey === void 0)
|
|
3245
3247
|
return void 0;
|
|
3246
3248
|
if (typeof options.idempotencyKey !== "string" || options.idempotencyKey.trim().length === 0) {
|
|
3247
|
-
throw new
|
|
3249
|
+
throw new SessionConfigValidationError("idempotencyKey must be a non-empty, non-whitespace string", {
|
|
3248
3250
|
field: "idempotencyKey",
|
|
3249
3251
|
value: options.idempotencyKey
|
|
3250
3252
|
});
|
|
@@ -3269,12 +3271,12 @@ async function submit(http, request, options) {
|
|
|
3269
3271
|
const sessionId = created.sessionId ?? created.id;
|
|
3270
3272
|
const accepted = await sendSessionMessage(http, sessionId, { input }, { idempotencyKey: messageKey });
|
|
3271
3273
|
const session = accepted.session;
|
|
3272
|
-
return {
|
|
3274
|
+
return { sessionId: session.sessionId ?? session.id, session };
|
|
3273
3275
|
}
|
|
3274
3276
|
function assertSubmitInput(input) {
|
|
3275
3277
|
const ok = typeof input === "string" && input.length > 0 || Array.isArray(input) && input.length > 0 && input.every((segment) => typeof segment === "string" && segment.length > 0);
|
|
3276
3278
|
if (!ok) {
|
|
3277
|
-
throw new
|
|
3279
|
+
throw new SessionConfigValidationError("submit: request.input must be a non-empty string or string array", {
|
|
3278
3280
|
field: "input",
|
|
3279
3281
|
value: input
|
|
3280
3282
|
});
|
|
@@ -3356,16 +3358,16 @@ async function listSessionEvents(http, sessionId) {
|
|
|
3356
3358
|
}
|
|
3357
3359
|
return all;
|
|
3358
3360
|
}
|
|
3359
|
-
async function
|
|
3360
|
-
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/
|
|
3361
|
-
return query === void 0 ? result.
|
|
3361
|
+
async function listSessionFiles(http, sessionId, query) {
|
|
3362
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/files`);
|
|
3363
|
+
return query === void 0 ? result.files : filterSessionFiles(result.files, query);
|
|
3362
3364
|
}
|
|
3363
3365
|
async function getSessionCoordinatorTicket(http, sessionId) {
|
|
3364
3366
|
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/events/ticket`, { method: "POST" });
|
|
3365
3367
|
}
|
|
3366
3368
|
var LIST_EVENTS_PAGE_BUDGET = 1e3;
|
|
3367
|
-
async function
|
|
3368
|
-
const path = `/api/
|
|
3369
|
+
async function listSessionRecordEvents(http, sessionId) {
|
|
3370
|
+
const path = `/api/sessions/${encodeURIComponent(sessionId)}/events`;
|
|
3369
3371
|
const all = [];
|
|
3370
3372
|
let cursor;
|
|
3371
3373
|
for (let page = 0; page < LIST_EVENTS_PAGE_BUDGET; page++) {
|
|
@@ -3378,31 +3380,27 @@ async function listRunEvents(http, runId) {
|
|
|
3378
3380
|
}
|
|
3379
3381
|
return all;
|
|
3380
3382
|
}
|
|
3381
|
-
async function getCoordinatorTicket(http,
|
|
3382
|
-
return http.request(`/api/
|
|
3383
|
-
}
|
|
3384
|
-
async function listOutputs(http, runId, query) {
|
|
3385
|
-
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/outputs`);
|
|
3386
|
-
return query === void 0 ? result.outputs : filterOutputs(result.outputs, query);
|
|
3383
|
+
async function getCoordinatorTicket(http, sessionId) {
|
|
3384
|
+
return http.request(`/api/sessions/${encodeURIComponent(sessionId)}/events/ticket`, { method: "POST" });
|
|
3387
3385
|
}
|
|
3388
|
-
async function
|
|
3389
|
-
return
|
|
3386
|
+
async function findSessionFiles(http, sessionId, query) {
|
|
3387
|
+
return listSessionFiles(http, sessionId, query);
|
|
3390
3388
|
}
|
|
3391
|
-
async function
|
|
3392
|
-
const matches = await
|
|
3389
|
+
async function findSessionFile(http, sessionId, query) {
|
|
3390
|
+
const matches = await findSessionFiles(http, sessionId, query);
|
|
3393
3391
|
if (matches.length === 0)
|
|
3394
3392
|
return null;
|
|
3395
3393
|
if (matches.length === 1)
|
|
3396
3394
|
return matches[0];
|
|
3397
|
-
throw new
|
|
3398
|
-
|
|
3399
|
-
matches: matches.map((
|
|
3395
|
+
throw new SessionStateError("files.findOne: file query matched multiple files", {
|
|
3396
|
+
sessionId,
|
|
3397
|
+
matches: matches.map((file2) => file2.filename ?? file2.id)
|
|
3400
3398
|
});
|
|
3401
3399
|
}
|
|
3402
|
-
async function
|
|
3403
|
-
const
|
|
3404
|
-
const expiresInSeconds =
|
|
3405
|
-
const result = await http.request(`/api/
|
|
3400
|
+
async function sessionFileLink(http, sessionId, selectorOrQuery, options) {
|
|
3401
|
+
const file2 = await resolveSessionFileLinkTarget(http, sessionId, selectorOrQuery);
|
|
3402
|
+
const expiresInSeconds = normalizeSessionFileLinkExpiresIn(options?.expiresIn);
|
|
3403
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(file2.id)}/link`, {
|
|
3406
3404
|
method: "POST",
|
|
3407
3405
|
body: JSON.stringify({ expiresInSeconds })
|
|
3408
3406
|
});
|
|
@@ -3411,18 +3409,18 @@ async function outputLink(http, runId, selectorOrQuery, options) {
|
|
|
3411
3409
|
...result,
|
|
3412
3410
|
expiresInSeconds: effectiveExpiresIn,
|
|
3413
3411
|
expiresAt: result.expiresAt ?? syntheticExpiresAt(effectiveExpiresIn),
|
|
3414
|
-
|
|
3412
|
+
file: result.file ?? file2
|
|
3415
3413
|
};
|
|
3416
3414
|
}
|
|
3417
3415
|
function syntheticExpiresAt(expiresInSeconds) {
|
|
3418
3416
|
return new Date(Date.now() + expiresInSeconds * 1e3).toISOString();
|
|
3419
3417
|
}
|
|
3420
|
-
async function
|
|
3421
|
-
return
|
|
3418
|
+
async function createSessionFileLink(http, sessionId, selectorOrQuery, options) {
|
|
3419
|
+
return sessionFileLink(http, sessionId, selectorOrQuery, options);
|
|
3422
3420
|
}
|
|
3423
|
-
async function eventArchiveLink(http,
|
|
3424
|
-
const expiresInSeconds =
|
|
3425
|
-
const result = await http.request(`/api/
|
|
3421
|
+
async function eventArchiveLink(http, sessionId, options) {
|
|
3422
|
+
const expiresInSeconds = normalizeSessionFileLinkExpiresIn(options?.expiresIn);
|
|
3423
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/events/link`, {
|
|
3426
3424
|
method: "POST",
|
|
3427
3425
|
body: JSON.stringify({ expiresInSeconds })
|
|
3428
3426
|
});
|
|
@@ -3433,16 +3431,16 @@ async function eventArchiveLink(http, runId, options) {
|
|
|
3433
3431
|
expiresAt: result.expiresAt ?? syntheticExpiresAt(effectiveExpiresIn)
|
|
3434
3432
|
};
|
|
3435
3433
|
}
|
|
3436
|
-
function
|
|
3434
|
+
function resolveSessionFileSelector(files, selector, sessionId) {
|
|
3437
3435
|
if (isPathSelector(selector)) {
|
|
3438
|
-
const target =
|
|
3436
|
+
const target = normalizeSessionFileLookupPath(selector.path);
|
|
3439
3437
|
if (!target) {
|
|
3440
|
-
throw new
|
|
3438
|
+
throw new SessionStateError("files.download: file path must be non-empty", { sessionId, path: selector.path });
|
|
3441
3439
|
}
|
|
3442
|
-
const matches =
|
|
3443
|
-
if (typeof
|
|
3440
|
+
const matches = files.filter((file2) => {
|
|
3441
|
+
if (typeof file2.filename !== "string")
|
|
3444
3442
|
return false;
|
|
3445
|
-
const filename =
|
|
3443
|
+
const filename = normalizeSessionFileLookupPath(file2.filename);
|
|
3446
3444
|
if (selector.match === "suffix") {
|
|
3447
3445
|
return filename === target || filename.endsWith(`/${target}`);
|
|
3448
3446
|
}
|
|
@@ -3451,62 +3449,62 @@ function resolveOutputFileSelector(outputs, selector, runId) {
|
|
|
3451
3449
|
if (matches.length === 1)
|
|
3452
3450
|
return matches[0];
|
|
3453
3451
|
if (matches.length > 1) {
|
|
3454
|
-
throw new
|
|
3452
|
+
throw new SessionStateError(`files.download: file path "${selector.path}" matched multiple files`, { sessionId, path: selector.path, matches: matches.map((file2) => file2.filename ?? file2.id) });
|
|
3455
3453
|
}
|
|
3456
|
-
throw new
|
|
3457
|
-
|
|
3454
|
+
throw new SessionStateError(`files.download: file path "${selector.path}" was not found`, {
|
|
3455
|
+
sessionId,
|
|
3458
3456
|
path: selector.path
|
|
3459
3457
|
});
|
|
3460
3458
|
}
|
|
3461
3459
|
if (typeof selector?.id !== "string" || selector.id.length === 0) {
|
|
3462
|
-
throw new
|
|
3460
|
+
throw new SessionStateError("files.download: selector must include a file id or path", { sessionId });
|
|
3463
3461
|
}
|
|
3464
3462
|
return { ...selector, id: selector.id };
|
|
3465
3463
|
}
|
|
3466
|
-
async function
|
|
3467
|
-
const
|
|
3468
|
-
const timeoutMs =
|
|
3469
|
-
const path = `/api/
|
|
3470
|
-
return {
|
|
3471
|
-
}
|
|
3472
|
-
var
|
|
3473
|
-
var
|
|
3474
|
-
var
|
|
3475
|
-
var
|
|
3476
|
-
async function
|
|
3477
|
-
const maxBytes = Math.max(1, Math.min(options?.maxBytes ??
|
|
3478
|
-
const
|
|
3479
|
-
const timeoutMs =
|
|
3480
|
-
const path = `/api/
|
|
3481
|
-
const capped = await
|
|
3464
|
+
async function downloadSessionFile(http, sessionId, selector, options) {
|
|
3465
|
+
const file2 = isPathSelector(selector) ? resolveSessionFileSelector(await listSessionFiles(http, sessionId), selector, sessionId) : resolveSessionFileSelector([], selector, sessionId);
|
|
3466
|
+
const timeoutMs = normalizeSessionFileTransferTimeoutMs(options?.timeoutMs);
|
|
3467
|
+
const path = `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(file2.id)}/download`;
|
|
3468
|
+
return { file: file2, bytes: await downloadSessionFileBytesWithRetry(http, path, timeoutMs) };
|
|
3469
|
+
}
|
|
3470
|
+
var READ_SESSION_FILE_TEXT_MAX_BYTES = 1e7;
|
|
3471
|
+
var READ_SESSION_FILE_TEXT_DEFAULT_BYTES = 5e4;
|
|
3472
|
+
var SESSION_FILE_TRANSFER_DEFAULT_TIMEOUT_MS = 3e4;
|
|
3473
|
+
var SESSION_FILE_TRANSFER_ATTEMPTS = 2;
|
|
3474
|
+
async function readSessionFileText(http, sessionId, selector, options) {
|
|
3475
|
+
const maxBytes = Math.max(1, Math.min(options?.maxBytes ?? READ_SESSION_FILE_TEXT_DEFAULT_BYTES, READ_SESSION_FILE_TEXT_MAX_BYTES));
|
|
3476
|
+
const file2 = isPathSelector(selector) ? resolveSessionFileSelector(await listSessionFiles(http, sessionId), selector, sessionId) : resolveSessionFileSelector([], selector, sessionId);
|
|
3477
|
+
const timeoutMs = normalizeSessionFileTransferTimeoutMs(options?.timeoutMs);
|
|
3478
|
+
const path = `/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(file2.id)}/download`;
|
|
3479
|
+
const capped = await readSessionFileTextWithRetry(http, path, maxBytes, timeoutMs);
|
|
3482
3480
|
const text = options?.grep === void 0 ? capped.text : grepLines(capped.text, options.grep);
|
|
3483
|
-
return {
|
|
3481
|
+
return { file: file2, text, truncated: capped.truncated, totalBytes: capped.totalBytes };
|
|
3484
3482
|
}
|
|
3485
|
-
async function
|
|
3486
|
-
return
|
|
3487
|
-
const response = await
|
|
3483
|
+
async function downloadSessionFileBytesWithRetry(http, path, timeoutMs) {
|
|
3484
|
+
return sessionFileTransferWithRetry(path, timeoutMs, async () => {
|
|
3485
|
+
const response = await downloadSessionFileResponse(http, path, timeoutMs);
|
|
3488
3486
|
return readResponseBytes(response, timeoutMs);
|
|
3489
3487
|
});
|
|
3490
3488
|
}
|
|
3491
|
-
async function
|
|
3492
|
-
return
|
|
3493
|
-
const response = await
|
|
3489
|
+
async function readSessionFileTextWithRetry(http, path, maxBytes, timeoutMs) {
|
|
3490
|
+
return sessionFileTransferWithRetry(path, timeoutMs, async () => {
|
|
3491
|
+
const response = await downloadSessionFileResponse(http, path, timeoutMs);
|
|
3494
3492
|
return readCappedText(response, maxBytes, timeoutMs);
|
|
3495
3493
|
});
|
|
3496
3494
|
}
|
|
3497
|
-
async function
|
|
3495
|
+
async function downloadSessionFileResponse(http, path, timeoutMs) {
|
|
3498
3496
|
const controller = new AbortController();
|
|
3499
|
-
const { response } = await
|
|
3497
|
+
const { response } = await withSessionFileTransferTimeout(http.download(path, { signal: controller.signal }), timeoutMs, () => controller.abort(), "download-open");
|
|
3500
3498
|
return response;
|
|
3501
3499
|
}
|
|
3502
|
-
async function
|
|
3500
|
+
async function sessionFileTransferWithRetry(path, timeoutMs, action) {
|
|
3503
3501
|
const startedMs = Date.now();
|
|
3504
3502
|
let lastTimeout;
|
|
3505
|
-
for (let attempt = 1; attempt <=
|
|
3503
|
+
for (let attempt = 1; attempt <= SESSION_FILE_TRANSFER_ATTEMPTS; attempt += 1) {
|
|
3506
3504
|
try {
|
|
3507
3505
|
return await action();
|
|
3508
3506
|
} catch (err2) {
|
|
3509
|
-
if (!(err2 instanceof
|
|
3507
|
+
if (!(err2 instanceof SessionFileTransferTimeoutError))
|
|
3510
3508
|
throw err2;
|
|
3511
3509
|
lastTimeout = err2;
|
|
3512
3510
|
}
|
|
@@ -3515,37 +3513,37 @@ async function outputTransferWithRetry(path, timeoutMs, action) {
|
|
|
3515
3513
|
method: "GET",
|
|
3516
3514
|
host: "",
|
|
3517
3515
|
path,
|
|
3518
|
-
cause: lastTimeout ?? new
|
|
3519
|
-
attempts:
|
|
3516
|
+
cause: lastTimeout ?? new SessionFileTransferTimeoutError("unknown", timeoutMs),
|
|
3517
|
+
attempts: SESSION_FILE_TRANSFER_ATTEMPTS,
|
|
3520
3518
|
elapsedMs: Date.now() - startedMs
|
|
3521
3519
|
});
|
|
3522
3520
|
}
|
|
3523
|
-
function
|
|
3521
|
+
function normalizeSessionFileTransferTimeoutMs(value) {
|
|
3524
3522
|
if (value === void 0)
|
|
3525
|
-
return
|
|
3523
|
+
return SESSION_FILE_TRANSFER_DEFAULT_TIMEOUT_MS;
|
|
3526
3524
|
if (!Number.isFinite(value) || value <= 0) {
|
|
3527
|
-
throw new
|
|
3525
|
+
throw new SessionConfigValidationError("files.download: timeoutMs must be a positive finite number", {
|
|
3528
3526
|
timeoutMs: value
|
|
3529
3527
|
});
|
|
3530
3528
|
}
|
|
3531
3529
|
return Math.max(1, Math.floor(value));
|
|
3532
3530
|
}
|
|
3533
|
-
var
|
|
3531
|
+
var SessionFileTransferTimeoutError = class extends Error {
|
|
3534
3532
|
code = "ETIMEDOUT";
|
|
3535
3533
|
phase;
|
|
3536
3534
|
constructor(phase, timeoutMs) {
|
|
3537
|
-
super(`
|
|
3538
|
-
this.name = "
|
|
3535
|
+
super(`file transfer phase=${phase} timed out after ${timeoutMs}ms`);
|
|
3536
|
+
this.name = "SessionFileTransferTimeoutError";
|
|
3539
3537
|
this.phase = phase;
|
|
3540
3538
|
}
|
|
3541
3539
|
};
|
|
3542
|
-
async function
|
|
3540
|
+
async function withSessionFileTransferTimeout(promise, timeoutMs, abort, phase) {
|
|
3543
3541
|
let timedOut = false;
|
|
3544
3542
|
let timeout;
|
|
3545
3543
|
const timeoutPromise = new Promise((_, reject) => {
|
|
3546
3544
|
timeout = setTimeout(() => {
|
|
3547
3545
|
timedOut = true;
|
|
3548
|
-
reject(new
|
|
3546
|
+
reject(new SessionFileTransferTimeoutError(phase, timeoutMs));
|
|
3549
3547
|
queueMicrotask(() => {
|
|
3550
3548
|
try {
|
|
3551
3549
|
abort();
|
|
@@ -3558,7 +3556,7 @@ async function withOutputTransferTimeout(promise, timeoutMs, abort, phase) {
|
|
|
3558
3556
|
return await Promise.race([promise, timeoutPromise]);
|
|
3559
3557
|
} catch (err2) {
|
|
3560
3558
|
if (timedOut && isAbortLikeError(err2))
|
|
3561
|
-
throw new
|
|
3559
|
+
throw new SessionFileTransferTimeoutError(phase, timeoutMs);
|
|
3562
3560
|
throw err2;
|
|
3563
3561
|
} finally {
|
|
3564
3562
|
if (timeout !== void 0)
|
|
@@ -3572,7 +3570,7 @@ function isAbortLikeError(err2) {
|
|
|
3572
3570
|
async function readResponseBytes(response, timeoutMs) {
|
|
3573
3571
|
const body = response.body;
|
|
3574
3572
|
if (!body) {
|
|
3575
|
-
const buffer = await
|
|
3573
|
+
const buffer = await withSessionFileTransferTimeout(response.arrayBuffer(), timeoutMs, () => {
|
|
3576
3574
|
}, "body-read");
|
|
3577
3575
|
return new Uint8Array(buffer);
|
|
3578
3576
|
}
|
|
@@ -3580,7 +3578,7 @@ async function readResponseBytes(response, timeoutMs) {
|
|
|
3580
3578
|
const chunks = [];
|
|
3581
3579
|
try {
|
|
3582
3580
|
while (true) {
|
|
3583
|
-
const { done, value } = await
|
|
3581
|
+
const { done, value } = await withSessionFileTransferTimeout(reader.read(), timeoutMs, () => {
|
|
3584
3582
|
void reader.cancel().catch(() => {
|
|
3585
3583
|
});
|
|
3586
3584
|
}, "body-read");
|
|
@@ -3601,7 +3599,7 @@ async function readCappedText(response, maxBytes, timeoutMs) {
|
|
|
3601
3599
|
const decoder = new TextDecoder("utf-8");
|
|
3602
3600
|
const body = response.body;
|
|
3603
3601
|
if (!body) {
|
|
3604
|
-
const buf = new Uint8Array(await
|
|
3602
|
+
const buf = new Uint8Array(await withSessionFileTransferTimeout(response.arrayBuffer(), timeoutMs, () => {
|
|
3605
3603
|
}, "body-read"));
|
|
3606
3604
|
const total = declared ?? buf.byteLength;
|
|
3607
3605
|
return {
|
|
@@ -3616,7 +3614,7 @@ async function readCappedText(response, maxBytes, timeoutMs) {
|
|
|
3616
3614
|
let sawMore = false;
|
|
3617
3615
|
try {
|
|
3618
3616
|
while (read < maxBytes) {
|
|
3619
|
-
const { done, value } = await
|
|
3617
|
+
const { done, value } = await withSessionFileTransferTimeout(reader.read(), timeoutMs, () => {
|
|
3620
3618
|
void reader.cancel().catch(() => {
|
|
3621
3619
|
});
|
|
3622
3620
|
}, "body-read");
|
|
@@ -3628,7 +3626,7 @@ async function readCappedText(response, maxBytes, timeoutMs) {
|
|
|
3628
3626
|
}
|
|
3629
3627
|
}
|
|
3630
3628
|
if (read >= maxBytes) {
|
|
3631
|
-
const next = await
|
|
3629
|
+
const next = await withSessionFileTransferTimeout(reader.read(), timeoutMs, () => {
|
|
3632
3630
|
void reader.cancel().catch(() => {
|
|
3633
3631
|
});
|
|
3634
3632
|
}, "body-read");
|
|
@@ -3660,22 +3658,16 @@ function grepLines(text, pattern) {
|
|
|
3660
3658
|
const test = typeof pattern === "string" ? (line) => line.toLowerCase().includes(pattern.toLowerCase()) : (line) => pattern.test(line);
|
|
3661
3659
|
return text.split("\n").filter((line) => test(line)).join("\n");
|
|
3662
3660
|
}
|
|
3663
|
-
async function
|
|
3664
|
-
const result = await http.request(`/api/
|
|
3661
|
+
async function listSessionChildren(http, sessionId) {
|
|
3662
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/children`);
|
|
3665
3663
|
return Array.isArray(result) ? result : result.children;
|
|
3666
3664
|
}
|
|
3667
|
-
async function
|
|
3668
|
-
await http.request(`/api/
|
|
3669
|
-
}
|
|
3670
|
-
async function deleteRun(http, runId) {
|
|
3671
|
-
await http.request(`/api/runs/${encodeURIComponent(runId)}`, { method: "DELETE" });
|
|
3672
|
-
}
|
|
3673
|
-
async function getRunWebhookDeliveries(http, runId) {
|
|
3674
|
-
const result = await http.request(`/api/runs/${encodeURIComponent(runId)}/webhook-deliveries`);
|
|
3665
|
+
async function getSessionWebhookDeliveries(http, sessionId) {
|
|
3666
|
+
const result = await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/webhook-deliveries`);
|
|
3675
3667
|
return Array.isArray(result) ? result : result.deliveries;
|
|
3676
3668
|
}
|
|
3677
|
-
async function
|
|
3678
|
-
await http.request(`/api/
|
|
3669
|
+
async function redeliverSessionWebhook(http, sessionId, deliveryId) {
|
|
3670
|
+
await http.request(`/api/sessions/${encodeURIComponent(sessionId)}/webhook-deliveries/${encodeURIComponent(deliveryId)}/redeliver`, { method: "POST" });
|
|
3679
3671
|
}
|
|
3680
3672
|
async function deleteWorkspaceAsset(http, hash) {
|
|
3681
3673
|
const assetId = hash.startsWith("asset_") ? hash : `asset_${hash.startsWith("sha256:") ? hash.slice("sha256:".length) : hash}`;
|
|
@@ -3708,17 +3700,17 @@ async function getBillingLedger(http, query) {
|
|
|
3708
3700
|
async function getWebhookSigningSecret(http) {
|
|
3709
3701
|
return http.request("/api/webhook/signing-secret", { method: "POST" });
|
|
3710
3702
|
}
|
|
3711
|
-
async function collectArtifactBytes(http,
|
|
3703
|
+
async function collectArtifactBytes(http, sessionId, items, zipPrefix, namespace2, timeoutMs = SESSION_FILE_TRANSFER_DEFAULT_TIMEOUT_MS) {
|
|
3712
3704
|
const entries = [];
|
|
3713
3705
|
const captured = [];
|
|
3714
3706
|
const errors = [];
|
|
3715
3707
|
for (const item of items) {
|
|
3716
3708
|
const rel = item.filename ?? item.id;
|
|
3717
3709
|
try {
|
|
3718
|
-
const path = `/api/
|
|
3710
|
+
const path = `/api/sessions/${encodeURIComponent(sessionId)}/${namespace2}/${encodeURIComponent(item.id)}/download`;
|
|
3719
3711
|
entries.push({
|
|
3720
3712
|
path: `${zipPrefix}${rel}`,
|
|
3721
|
-
bytes: await
|
|
3713
|
+
bytes: await downloadSessionFileBytesWithRetry(http, path, timeoutMs),
|
|
3722
3714
|
...item.contentType !== void 0 ? { contentType: item.contentType } : {},
|
|
3723
3715
|
customerContent: true
|
|
3724
3716
|
});
|
|
@@ -3740,11 +3732,11 @@ function eventsJsonl(events) {
|
|
|
3740
3732
|
function isPathSelector(selector) {
|
|
3741
3733
|
return Boolean(selector && typeof selector === "object" && "path" in selector);
|
|
3742
3734
|
}
|
|
3743
|
-
function
|
|
3735
|
+
function normalizeSessionFileLookupPath(path) {
|
|
3744
3736
|
return path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3745
3737
|
}
|
|
3746
|
-
function
|
|
3747
|
-
return
|
|
3738
|
+
function filterSessionFiles(files, query) {
|
|
3739
|
+
return files.filter((file2) => sessionFileMatchesQuery(file2, query));
|
|
3748
3740
|
}
|
|
3749
3741
|
function toFilenameMatcher(filename) {
|
|
3750
3742
|
if (typeof filename === "string") {
|
|
@@ -3756,8 +3748,8 @@ function toFilenameMatcher(filename) {
|
|
|
3756
3748
|
return filename.test(name);
|
|
3757
3749
|
};
|
|
3758
3750
|
}
|
|
3759
|
-
function
|
|
3760
|
-
const contentType = normalizeContentType(
|
|
3751
|
+
function classifySessionFile(file2) {
|
|
3752
|
+
const contentType = normalizeContentType(file2.contentType);
|
|
3761
3753
|
if (contentType) {
|
|
3762
3754
|
if (contentType === "application/json" || contentType.endsWith("+json") || contentType.includes("json")) {
|
|
3763
3755
|
return "json";
|
|
@@ -3779,7 +3771,7 @@ function classifyOutput(output) {
|
|
|
3779
3771
|
return "binary";
|
|
3780
3772
|
return "unknown";
|
|
3781
3773
|
}
|
|
3782
|
-
const extension = extensionOf(
|
|
3774
|
+
const extension = extensionOf(file2.filename);
|
|
3783
3775
|
if (!extension)
|
|
3784
3776
|
return "unknown";
|
|
3785
3777
|
if (["json", "jsonl", "ndjson"].includes(extension))
|
|
@@ -3802,10 +3794,10 @@ function classifyOutput(output) {
|
|
|
3802
3794
|
return "binary";
|
|
3803
3795
|
return "unknown";
|
|
3804
3796
|
}
|
|
3805
|
-
function
|
|
3797
|
+
function normalizeSessionFileLinkExpiresIn(input = "1h") {
|
|
3806
3798
|
if (typeof input === "number") {
|
|
3807
3799
|
if (!Number.isFinite(input) || input <= 0) {
|
|
3808
|
-
throw new
|
|
3800
|
+
throw new SessionStateError("sessionFileLink: expiresIn must be a positive number of seconds", {
|
|
3809
3801
|
expiresIn: input
|
|
3810
3802
|
});
|
|
3811
3803
|
}
|
|
@@ -3817,34 +3809,34 @@ function normalizeOutputLinkExpiresIn(input = "1h") {
|
|
|
3817
3809
|
return 60 * 60;
|
|
3818
3810
|
if (input === "1d")
|
|
3819
3811
|
return 24 * 60 * 60;
|
|
3820
|
-
throw new
|
|
3812
|
+
throw new SessionStateError('sessionFileLink: expiresIn must be seconds, "15m", "1h", or "1d"', {
|
|
3821
3813
|
expiresIn: input
|
|
3822
3814
|
});
|
|
3823
3815
|
}
|
|
3824
|
-
async function
|
|
3816
|
+
async function resolveSessionFileLinkTarget(http, sessionId, selectorOrQuery) {
|
|
3825
3817
|
if (typeof selectorOrQuery === "string") {
|
|
3826
3818
|
if (selectorOrQuery.length === 0) {
|
|
3827
|
-
throw new
|
|
3819
|
+
throw new SessionStateError("sessionFileLink: selector must include a file id or query", { sessionId });
|
|
3828
3820
|
}
|
|
3829
3821
|
return { id: selectorOrQuery };
|
|
3830
3822
|
}
|
|
3831
|
-
if (
|
|
3823
|
+
if (hasSessionFileId(selectorOrQuery)) {
|
|
3832
3824
|
if (selectorOrQuery.id.length === 0) {
|
|
3833
|
-
throw new
|
|
3825
|
+
throw new SessionStateError("sessionFileLink: selector must include a file id or query", { sessionId });
|
|
3834
3826
|
}
|
|
3835
3827
|
return selectorOrQuery;
|
|
3836
3828
|
}
|
|
3837
3829
|
if (isPathSelector(selectorOrQuery) && selectorOrQuery.match === "suffix") {
|
|
3838
|
-
return
|
|
3830
|
+
return resolveSessionFileSelector(await listSessionFiles(http, sessionId), selectorOrQuery, sessionId);
|
|
3839
3831
|
}
|
|
3840
|
-
const match = await
|
|
3832
|
+
const match = await findSessionFile(http, sessionId, selectorOrQuery);
|
|
3841
3833
|
if (match)
|
|
3842
3834
|
return match;
|
|
3843
|
-
throw new
|
|
3835
|
+
throw new SessionStateError("sessionFileLink: file query matched no files", { sessionId });
|
|
3844
3836
|
}
|
|
3845
|
-
function
|
|
3846
|
-
const normalizedPath = typeof
|
|
3847
|
-
if (query.path !== void 0 && normalizedPath !==
|
|
3837
|
+
function sessionFileMatchesQuery(file2, query) {
|
|
3838
|
+
const normalizedPath = typeof file2.filename === "string" ? normalizeSessionFileQueryPath(file2.filename) : "";
|
|
3839
|
+
if (query.path !== void 0 && normalizedPath !== normalizeSessionFileQueryPath(query.path)) {
|
|
3848
3840
|
return false;
|
|
3849
3841
|
}
|
|
3850
3842
|
if (query.filename !== void 0) {
|
|
@@ -3864,21 +3856,21 @@ function outputMatchesQuery(output, query) {
|
|
|
3864
3856
|
if (query.extension !== void 0 && extensionOf(normalizedPath) !== normalizeExtension(query.extension)) {
|
|
3865
3857
|
return false;
|
|
3866
3858
|
}
|
|
3867
|
-
if (query.contentType !== void 0 && !contentTypeMatches(
|
|
3859
|
+
if (query.contentType !== void 0 && !contentTypeMatches(file2.contentType, query.contentType)) {
|
|
3868
3860
|
return false;
|
|
3869
3861
|
}
|
|
3870
|
-
if (query.type !== void 0 &&
|
|
3862
|
+
if (query.type !== void 0 && classifySessionFile(file2) !== query.type) {
|
|
3871
3863
|
return false;
|
|
3872
3864
|
}
|
|
3873
3865
|
return true;
|
|
3874
3866
|
}
|
|
3875
|
-
function
|
|
3867
|
+
function hasSessionFileId(value) {
|
|
3876
3868
|
return Boolean(value && typeof value === "object" && "id" in value && typeof value.id === "string");
|
|
3877
3869
|
}
|
|
3878
|
-
function
|
|
3870
|
+
function normalizeSessionFileQueryPath(path) {
|
|
3879
3871
|
let normalized = path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3880
|
-
while (normalized === "
|
|
3881
|
-
normalized = normalized === "
|
|
3872
|
+
while (normalized === "files" || normalized.startsWith("files/")) {
|
|
3873
|
+
normalized = normalized === "files" ? "" : normalized.slice("files/".length);
|
|
3882
3874
|
}
|
|
3883
3875
|
return normalized.replace(/\/+$/, "");
|
|
3884
3876
|
}
|
|
@@ -3886,7 +3878,7 @@ function basenameOf(path) {
|
|
|
3886
3878
|
return path.split("/").filter(Boolean).pop() ?? "";
|
|
3887
3879
|
}
|
|
3888
3880
|
function directoryMatches(path, dir, recursive) {
|
|
3889
|
-
const normalizedDir =
|
|
3881
|
+
const normalizedDir = normalizeSessionFileQueryPath(dir);
|
|
3890
3882
|
if (normalizedDir.length === 0)
|
|
3891
3883
|
return true;
|
|
3892
3884
|
const prefix = `${normalizedDir}/`;
|
|
@@ -3901,7 +3893,7 @@ function normalizeExtension(extension) {
|
|
|
3901
3893
|
function extensionOf(path) {
|
|
3902
3894
|
if (!path)
|
|
3903
3895
|
return "";
|
|
3904
|
-
const basename = basenameOf(
|
|
3896
|
+
const basename = basenameOf(normalizeSessionFileQueryPath(path));
|
|
3905
3897
|
const index = basename.lastIndexOf(".");
|
|
3906
3898
|
return index > 0 && index < basename.length - 1 ? basename.slice(index + 1).toLowerCase() : "";
|
|
3907
3899
|
}
|
|
@@ -3918,67 +3910,67 @@ function contentTypeMatches(actual, expected) {
|
|
|
3918
3910
|
}
|
|
3919
3911
|
return normalizedActual === normalizedExpected;
|
|
3920
3912
|
}
|
|
3921
|
-
async function download(http,
|
|
3922
|
-
const [
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3913
|
+
async function download(http, sessionId) {
|
|
3914
|
+
const [sessionRecord, events, files] = await Promise.all([
|
|
3915
|
+
getSessionRecord(http, sessionId),
|
|
3916
|
+
listSessionRecordEvents(http, sessionId),
|
|
3917
|
+
listSessionFiles(http, sessionId)
|
|
3926
3918
|
]);
|
|
3927
|
-
const
|
|
3928
|
-
const submissionSnapshot = extractSubmissionSnapshot(
|
|
3929
|
-
const costTelemetry = extractCostTelemetry(
|
|
3930
|
-
const manifest =
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
errors:
|
|
3919
|
+
const collectedFiles = await collectArtifactBytes(http, sessionId, files, "files/", "files");
|
|
3920
|
+
const submissionSnapshot = extractSubmissionSnapshot(sessionRecord);
|
|
3921
|
+
const costTelemetry = extractCostTelemetry(sessionRecord);
|
|
3922
|
+
const manifest = buildSessionRecordDownloadManifestV1({
|
|
3923
|
+
sessionId,
|
|
3924
|
+
sessionFiles: collectedFiles.captured,
|
|
3925
|
+
errors: collectedFiles.errors,
|
|
3934
3926
|
typedEventCount: events.length,
|
|
3935
3927
|
...submissionSnapshot ? { submission: { status: "present" } } : {},
|
|
3936
3928
|
...costTelemetry ? { cost: { status: "present" } } : {}
|
|
3937
3929
|
});
|
|
3938
3930
|
return zipEntries([
|
|
3939
|
-
jsonEntry("metadata/
|
|
3931
|
+
jsonEntry("metadata/session.json", sessionRecord),
|
|
3940
3932
|
...submissionSnapshot ? [jsonEntry("metadata/submission.json", submissionSnapshot)] : [],
|
|
3941
3933
|
...costTelemetry ? [jsonEntry("metadata/cost.json", costTelemetry)] : [],
|
|
3942
3934
|
jsonlEntry("events/events.jsonl", events),
|
|
3943
|
-
...
|
|
3935
|
+
...collectedFiles.entries,
|
|
3944
3936
|
jsonEntry("manifest.json", manifest)
|
|
3945
3937
|
]);
|
|
3946
3938
|
}
|
|
3947
|
-
async function
|
|
3948
|
-
const
|
|
3949
|
-
const timeoutMs =
|
|
3950
|
-
const { entries, captured, errors } = await collectArtifactBytes(http,
|
|
3939
|
+
async function downloadSessionFiles(http, sessionId, options) {
|
|
3940
|
+
const files = await listSessionFiles(http, sessionId);
|
|
3941
|
+
const timeoutMs = normalizeSessionFileTransferTimeoutMs(options?.timeoutMs);
|
|
3942
|
+
const { entries, captured, errors } = await collectArtifactBytes(http, sessionId, files, "", "files", timeoutMs);
|
|
3951
3943
|
return zipEntries([
|
|
3952
3944
|
...entries,
|
|
3953
|
-
jsonEntry("manifest.json", {
|
|
3945
|
+
jsonEntry("manifest.json", { sessionId, namespace: "files", files: captured, errors })
|
|
3954
3946
|
]);
|
|
3955
3947
|
}
|
|
3956
|
-
async function downloadEvents(http,
|
|
3957
|
-
const events = await
|
|
3948
|
+
async function downloadEvents(http, sessionId) {
|
|
3949
|
+
const events = await listSessionRecordEvents(http, sessionId);
|
|
3958
3950
|
return zipEntries([
|
|
3959
3951
|
jsonlEntry("events.jsonl", events),
|
|
3960
3952
|
jsonEntry("manifest.json", {
|
|
3961
|
-
|
|
3953
|
+
sessionId,
|
|
3962
3954
|
namespace: "events",
|
|
3963
3955
|
files: [{ path: "events.jsonl", role: "typed_events", status: "present", recordCount: events.length }],
|
|
3964
3956
|
errors: []
|
|
3965
3957
|
})
|
|
3966
3958
|
]);
|
|
3967
3959
|
}
|
|
3968
|
-
async function downloadMetadata(http,
|
|
3969
|
-
const
|
|
3960
|
+
async function downloadMetadata(http, sessionId) {
|
|
3961
|
+
const sessionRecord = await getSessionRecord(http, sessionId);
|
|
3970
3962
|
return zipEntries([
|
|
3971
|
-
jsonEntry("
|
|
3963
|
+
jsonEntry("session.json", sessionRecord),
|
|
3972
3964
|
jsonEntry("manifest.json", {
|
|
3973
|
-
|
|
3965
|
+
sessionId,
|
|
3974
3966
|
namespace: "metadata",
|
|
3975
|
-
files: [{ path: "
|
|
3967
|
+
files: [{ path: "session.json", role: "session_metadata", status: "present" }],
|
|
3976
3968
|
errors: []
|
|
3977
3969
|
})
|
|
3978
3970
|
]);
|
|
3979
3971
|
}
|
|
3980
3972
|
function zipEntries(entries) {
|
|
3981
|
-
|
|
3973
|
+
assertSessionRecordArchivePublicSafeV1(entries);
|
|
3982
3974
|
const files = {};
|
|
3983
3975
|
for (const entry of entries) {
|
|
3984
3976
|
files[entry.path] = entry.bytes;
|
|
@@ -3999,8 +3991,8 @@ function jsonlEntry(path, events) {
|
|
|
3999
3991
|
contentType: "application/jsonl; charset=utf-8"
|
|
4000
3992
|
};
|
|
4001
3993
|
}
|
|
4002
|
-
function extractSubmissionSnapshot(
|
|
4003
|
-
const raw =
|
|
3994
|
+
function extractSubmissionSnapshot(sessionRecord) {
|
|
3995
|
+
const raw = sessionRecord.submission;
|
|
4004
3996
|
if (!isRecord3(raw) || raw.kind !== "submission" || !isRecord3(raw.submission)) {
|
|
4005
3997
|
return void 0;
|
|
4006
3998
|
}
|
|
@@ -4008,15 +4000,15 @@ function extractSubmissionSnapshot(run) {
|
|
|
4008
4000
|
submission: raw.submission
|
|
4009
4001
|
};
|
|
4010
4002
|
}
|
|
4011
|
-
function extractCostTelemetry(
|
|
4012
|
-
const raw =
|
|
4003
|
+
function extractCostTelemetry(sessionRecord) {
|
|
4004
|
+
const raw = sessionRecord.costTelemetry;
|
|
4013
4005
|
return isRecord3(raw) ? raw : void 0;
|
|
4014
4006
|
}
|
|
4015
4007
|
function isRecord3(value) {
|
|
4016
4008
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4017
4009
|
}
|
|
4018
|
-
async function
|
|
4019
|
-
return http.request("/api/
|
|
4010
|
+
async function startSessionRecord(http, request) {
|
|
4011
|
+
return http.request("/api/sessions", {
|
|
4020
4012
|
method: "POST",
|
|
4021
4013
|
body: JSON.stringify(request)
|
|
4022
4014
|
});
|
|
@@ -4140,8 +4132,8 @@ function unwrapSkill(result) {
|
|
|
4140
4132
|
}
|
|
4141
4133
|
return result;
|
|
4142
4134
|
}
|
|
4143
|
-
function
|
|
4144
|
-
return Boolean(value && typeof value === "object" && "
|
|
4135
|
+
function hasSessionRecord(value) {
|
|
4136
|
+
return Boolean(value && typeof value === "object" && "session" in value);
|
|
4145
4137
|
}
|
|
4146
4138
|
function unwrapSession(result) {
|
|
4147
4139
|
if (result && typeof result === "object" && "session" in result) {
|
|
@@ -4179,7 +4171,7 @@ var SUCCESS = { code: 0 };
|
|
|
4179
4171
|
var USAGE_ERR = { code: 2 };
|
|
4180
4172
|
var RUNTIME_ERR = { code: 1 };
|
|
4181
4173
|
var TIMEOUT_ERR = { code: 3 };
|
|
4182
|
-
var TERMINAL_STATUSES = new Set(
|
|
4174
|
+
var TERMINAL_STATUSES = new Set(TERMINAL_SESSION_CONTROL_STATUSES);
|
|
4183
4175
|
function isSessionParked2(status) {
|
|
4184
4176
|
return status === "idle" || status === "suspended" || status === "error" || TERMINAL_STATUSES.has(status);
|
|
4185
4177
|
}
|
|
@@ -4314,7 +4306,7 @@ function remedyForStatus(status) {
|
|
|
4314
4306
|
if (status === 429)
|
|
4315
4307
|
return "rate limited \u2014 retry with backoff";
|
|
4316
4308
|
if (status >= 500)
|
|
4317
|
-
return "server error \u2014 retry; re-
|
|
4309
|
+
return "server error \u2014 retry; re-session with --debug to capture the request trace";
|
|
4318
4310
|
return void 0;
|
|
4319
4311
|
}
|
|
4320
4312
|
function remedyForNetworkCode(code) {
|
|
@@ -4348,10 +4340,10 @@ function makeHttpClient(io2, flags) {
|
|
|
4348
4340
|
`) } : {}
|
|
4349
4341
|
});
|
|
4350
4342
|
}
|
|
4351
|
-
async function
|
|
4343
|
+
async function refuseInsideManagedSession(io2, verb) {
|
|
4352
4344
|
try {
|
|
4353
4345
|
await io2.readFile(AEX_INDEX_PATH);
|
|
4354
|
-
io2.stderr(`\`aex ${verb}\` is a host command and cannot
|
|
4346
|
+
io2.stderr(`\`aex ${verb}\` is a host command and cannot execute inside a managed session container.
|
|
4355
4347
|
Make HTTP calls from your code and pass credentials through secrets.
|
|
4356
4348
|
`);
|
|
4357
4349
|
return true;
|
|
@@ -4360,7 +4352,7 @@ Make HTTP calls from your code and pass credentials through secrets.
|
|
|
4360
4352
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
4361
4353
|
return false;
|
|
4362
4354
|
}
|
|
4363
|
-
io2.stderr(`\`aex ${verb}\` could not determine whether it is running inside a managed
|
|
4355
|
+
io2.stderr(`\`aex ${verb}\` could not determine whether it is running inside a managed session container (error reading ${AEX_INDEX_PATH}: ${err2.message ?? "unknown"}). Refusing to proceed.
|
|
4364
4356
|
`);
|
|
4365
4357
|
return true;
|
|
4366
4358
|
}
|
|
@@ -4491,27 +4483,27 @@ function takeOptionFlag(rest, flag) {
|
|
|
4491
4483
|
return { value, remaining };
|
|
4492
4484
|
}
|
|
4493
4485
|
|
|
4494
|
-
// dist/
|
|
4495
|
-
async function
|
|
4486
|
+
// dist/files-sync.js
|
|
4487
|
+
async function executeFilesSyncCmd(io2, dirs) {
|
|
4496
4488
|
if (dirs.length === 0) {
|
|
4497
|
-
io2.stderr("usage: aex
|
|
4489
|
+
io2.stderr("usage: aex files sync <dir> [<dir> ...]\n");
|
|
4498
4490
|
return USAGE_ERR;
|
|
4499
4491
|
}
|
|
4500
4492
|
try {
|
|
4501
4493
|
await io2.readFile(AEX_INDEX_PATH);
|
|
4502
4494
|
} catch {
|
|
4503
|
-
io2.stderr("`aex
|
|
4495
|
+
io2.stderr("`aex files sync` is an in-container internal command and cannot run on the host.\n");
|
|
4504
4496
|
return USAGE_ERR;
|
|
4505
4497
|
}
|
|
4506
4498
|
if (!io2.walkDirectory) {
|
|
4507
|
-
io2.stderr("aex
|
|
4499
|
+
io2.stderr("aex files sync: walkDirectory IO is not available\n");
|
|
4508
4500
|
return RUNTIME_ERR;
|
|
4509
4501
|
}
|
|
4510
4502
|
let scanned = 0;
|
|
4511
4503
|
let missing = 0;
|
|
4512
4504
|
for (const dir of dirs) {
|
|
4513
4505
|
if (!dir.startsWith("/")) {
|
|
4514
|
-
io2.stderr(JSON.stringify({ dir, error: "non_absolute_path", message: "skipping non-absolute
|
|
4506
|
+
io2.stderr(JSON.stringify({ dir, error: "non_absolute_path", message: "skipping non-absolute file dir" }) + "\n");
|
|
4515
4507
|
missing++;
|
|
4516
4508
|
continue;
|
|
4517
4509
|
}
|
|
@@ -4539,7 +4531,7 @@ async function runOutputsSyncCmd(io2, dirs) {
|
|
|
4539
4531
|
|
|
4540
4532
|
// dist/host/registry.js
|
|
4541
4533
|
var COMMON_HOST_FLAGS = ["--api-key", "--aex-url", "--json", "--debug"];
|
|
4542
|
-
var
|
|
4534
|
+
var START_FLAGS = [
|
|
4543
4535
|
"--provider",
|
|
4544
4536
|
"--model",
|
|
4545
4537
|
"--system",
|
|
@@ -4553,20 +4545,20 @@ var RUN_FLAGS = [
|
|
|
4553
4545
|
"--mcp-auth",
|
|
4554
4546
|
"--metadata",
|
|
4555
4547
|
"--runtime-size",
|
|
4556
|
-
"--
|
|
4548
|
+
"--session-timeout",
|
|
4557
4549
|
"--idempotency-key",
|
|
4558
4550
|
"--webhook",
|
|
4559
4551
|
"--follow",
|
|
4560
4552
|
"--timeout"
|
|
4561
4553
|
];
|
|
4562
|
-
var
|
|
4554
|
+
var FILES_SUBVERBS = ["read", "download", "link", "find", "search"];
|
|
4563
4555
|
var CLI_VERBS = [
|
|
4564
4556
|
{
|
|
4565
|
-
name: "
|
|
4557
|
+
name: "start",
|
|
4566
4558
|
summary: "One-shot: open a session, send the prompt as the first turn (delegates to the SDK).",
|
|
4567
4559
|
usage: [
|
|
4568
|
-
"aex
|
|
4569
|
-
"aex
|
|
4560
|
+
"aex start --model M --prompt P [--system S] [--provider name] --<provider>-api-key K",
|
|
4561
|
+
"aex start --config <session.json> --<provider>-api-key K",
|
|
4570
4562
|
" --skill @file Attach a workspace skill bundle (repeatable)",
|
|
4571
4563
|
" --tool @file.js Attach a custom tool module (repeatable)",
|
|
4572
4564
|
" --agents-md @file Attach an AGENTS.md brief (repeatable)",
|
|
@@ -4574,20 +4566,20 @@ var CLI_VERBS = [
|
|
|
4574
4566
|
" --mcp name=url MCP server (repeatable); --mcp-auth name=Hdr:Val for headers",
|
|
4575
4567
|
" --metadata key=value Submission metadata (repeatable)",
|
|
4576
4568
|
" --runtime-size <s> Managed runtime preset",
|
|
4577
|
-
" --
|
|
4578
|
-
" --webhook <url> Per-
|
|
4569
|
+
" --session-timeout <dur> Server-side session deadline (validated client-side by the SDK)",
|
|
4570
|
+
" --webhook <url> Per-session terminal callback (https)",
|
|
4579
4571
|
" --follow Stream the turn's events until the session parks"
|
|
4580
4572
|
],
|
|
4581
|
-
flags:
|
|
4573
|
+
flags: START_FLAGS
|
|
4582
4574
|
},
|
|
4583
4575
|
{
|
|
4584
4576
|
name: "status",
|
|
4585
|
-
summary: "Print a session/
|
|
4577
|
+
summary: "Print a session/session record (GET /api/sessions/:id).",
|
|
4586
4578
|
usage: ["aex status <session-id>"]
|
|
4587
4579
|
},
|
|
4588
4580
|
{
|
|
4589
4581
|
name: "deliveries",
|
|
4590
|
-
summary: "List a
|
|
4582
|
+
summary: "List a session's webhook delivery attempts.",
|
|
4591
4583
|
usage: ["aex deliveries <session-id>"]
|
|
4592
4584
|
},
|
|
4593
4585
|
{
|
|
@@ -4615,28 +4607,28 @@ var CLI_VERBS = [
|
|
|
4615
4607
|
flags: ["--filter", "--logs", "--timeout"]
|
|
4616
4608
|
},
|
|
4617
4609
|
{
|
|
4618
|
-
name: "
|
|
4619
|
-
summary: "List a session's captured
|
|
4610
|
+
name: "files",
|
|
4611
|
+
summary: "List a session's captured files, or read/download/link/find/search one file.",
|
|
4620
4612
|
usage: [
|
|
4621
|
-
"aex
|
|
4622
|
-
"aex
|
|
4623
|
-
"aex
|
|
4624
|
-
"aex
|
|
4625
|
-
"aex
|
|
4626
|
-
"aex
|
|
4613
|
+
"aex files <session-id> List captured files (NDJSON)",
|
|
4614
|
+
"aex files read <session-id> <path> Read one file as capped text",
|
|
4615
|
+
"aex files download <session-id> <path> [--out] Download one file's raw bytes",
|
|
4616
|
+
"aex files link <session-id> <path> Mint a temporary download URL",
|
|
4617
|
+
"aex files find <session-id> [--name S] [--ext E] [--type T]",
|
|
4618
|
+
"aex files search [--query S] [--name S] [--ext E] [--session-id ID] Cross-session"
|
|
4627
4619
|
],
|
|
4628
|
-
flags: ["--out", "--name", "--ext", "--type", "--content-type", "--query", "--
|
|
4629
|
-
subverbs:
|
|
4620
|
+
flags: ["--out", "--name", "--ext", "--type", "--content-type", "--query", "--session-id", "--limit", "--max-bytes"],
|
|
4621
|
+
subverbs: FILES_SUBVERBS
|
|
4630
4622
|
},
|
|
4631
4623
|
{
|
|
4632
4624
|
name: "download",
|
|
4633
4625
|
summary: "Download a session's content as a zip (whole or one namespace).",
|
|
4634
|
-
usage: ["aex download <session-id> [--only
|
|
4626
|
+
usage: ["aex download <session-id> [--only files|events|metadata] [--out path]"],
|
|
4635
4627
|
flags: ["--only", "--out"]
|
|
4636
4628
|
},
|
|
4637
4629
|
{
|
|
4638
4630
|
name: "cancel",
|
|
4639
|
-
summary: "Cancel a
|
|
4631
|
+
summary: "Cancel a sessionning session.",
|
|
4640
4632
|
usage: ["aex cancel <session-id>"]
|
|
4641
4633
|
},
|
|
4642
4634
|
{
|
|
@@ -4650,9 +4642,9 @@ var CLI_VERBS = [
|
|
|
4650
4642
|
usage: ["aex delete-asset <assetId|hash>"]
|
|
4651
4643
|
},
|
|
4652
4644
|
{
|
|
4653
|
-
name: "
|
|
4654
|
-
summary: "List the workspace's
|
|
4655
|
-
usage: ["aex
|
|
4645
|
+
name: "sessions",
|
|
4646
|
+
summary: "List the workspace's sessions (newest first).",
|
|
4647
|
+
usage: ["aex sessions [--limit N] [--since ISO]"],
|
|
4656
4648
|
flags: ["--limit", "--since"]
|
|
4657
4649
|
},
|
|
4658
4650
|
{
|
|
@@ -4717,7 +4709,7 @@ var CLI_VERBS = [
|
|
|
4717
4709
|
{
|
|
4718
4710
|
name: "runtime-sizes",
|
|
4719
4711
|
summary: "List managed runtime presets (no token needed).",
|
|
4720
|
-
usage: ["aex
|
|
4712
|
+
usage: ["aex starttime-sizes list [--json]"]
|
|
4721
4713
|
}
|
|
4722
4714
|
];
|
|
4723
4715
|
var VERB_BY_NAME = new Map(CLI_VERBS.map((v) => [v.name, v]));
|
|
@@ -4736,7 +4728,7 @@ function renderVerbHelp(spec) {
|
|
|
4736
4728
|
return lines.join("\n") + "\n";
|
|
4737
4729
|
}
|
|
4738
4730
|
|
|
4739
|
-
// dist/host/
|
|
4731
|
+
// dist/host/start-cmd.js
|
|
4740
4732
|
import { resolve as resolvePath } from "node:path";
|
|
4741
4733
|
|
|
4742
4734
|
// ../contracts/dist/retry-core.js
|
|
@@ -4972,7 +4964,7 @@ function bufferToHex(buffer) {
|
|
|
4972
4964
|
return out;
|
|
4973
4965
|
}
|
|
4974
4966
|
|
|
4975
|
-
// dist/host/
|
|
4967
|
+
// dist/host/start-submit.js
|
|
4976
4968
|
var TEXT = new TextEncoder();
|
|
4977
4969
|
var ZIP_EPOCH = new Date(Date.UTC(1980, 0, 1));
|
|
4978
4970
|
var UPLOAD_CONCURRENCY = 5;
|
|
@@ -5059,9 +5051,9 @@ async function buildSessionCreateRequest(http, fetchImpl, options) {
|
|
|
5059
5051
|
const provider = resolveModelProvider(options.model, options.provider);
|
|
5060
5052
|
validateApiKeys(options.apiKeys, provider);
|
|
5061
5053
|
try {
|
|
5062
|
-
|
|
5054
|
+
parseSessionTimeout(options.overrides?.timeout);
|
|
5063
5055
|
if (options.webhook !== void 0)
|
|
5064
|
-
|
|
5056
|
+
parseSessionWebhook(options.webhook);
|
|
5065
5057
|
} catch (err2) {
|
|
5066
5058
|
throw new Error(err2 instanceof Error ? err2.message : String(err2));
|
|
5067
5059
|
}
|
|
@@ -5070,7 +5062,7 @@ async function buildSessionCreateRequest(http, fetchImpl, options) {
|
|
|
5070
5062
|
limitsInput.maxSpendUsd = options.overrides.maxSpendUsd;
|
|
5071
5063
|
if (options.overrides?.maxTurns !== void 0)
|
|
5072
5064
|
limitsInput.maxTurns = options.overrides.maxTurns;
|
|
5073
|
-
const limits =
|
|
5065
|
+
const limits = parseSessionLimits(Object.keys(limitsInput).length > 0 ? limitsInput : void 0);
|
|
5074
5066
|
const [preparedTools, preparedSkills, preparedAgentsMd, preparedFiles] = await Promise.all([
|
|
5075
5067
|
prepareTools(http, fetchImpl, options.tools ?? []),
|
|
5076
5068
|
prepareSkills(http, fetchImpl, options.skills ?? []),
|
|
@@ -5432,7 +5424,7 @@ async function* openEnvelopeStream(io2, http, sessionId, options = {}) {
|
|
|
5432
5424
|
from: options.from ?? 0,
|
|
5433
5425
|
fetchTicket: async () => (await operations_exports.getSessionCoordinatorTicket(http, sessionId)).ticket,
|
|
5434
5426
|
...io2.webSocketFactory ? { webSocketFactory: io2.webSocketFactory } : {},
|
|
5435
|
-
...options.settleConsistent ? { isTerminal:
|
|
5427
|
+
...options.settleConsistent ? { isTerminal: isSessionSettled } : {},
|
|
5436
5428
|
...options.signal ? { signal: options.signal } : {}
|
|
5437
5429
|
});
|
|
5438
5430
|
}
|
|
@@ -5455,8 +5447,8 @@ function renderEnvelope(e, options = {}) {
|
|
|
5455
5447
|
if (channelOf(e) === "log" && !options.logs)
|
|
5456
5448
|
return null;
|
|
5457
5449
|
switch (e.type) {
|
|
5458
|
-
case "
|
|
5459
|
-
return "\u25B6
|
|
5450
|
+
case "TURN_STARTED":
|
|
5451
|
+
return "\u25B6 turn started";
|
|
5460
5452
|
case "TEXT_MESSAGE_CONTENT": {
|
|
5461
5453
|
const delta = toAGUI(e).type === "TEXT_MESSAGE_CONTENT" ? toAGUI(e).delta : "";
|
|
5462
5454
|
return delta ? delta : null;
|
|
@@ -5487,12 +5479,12 @@ function renderEnvelope(e, options = {}) {
|
|
|
5487
5479
|
const level = e.level ?? "info";
|
|
5488
5480
|
return `[${level}] ${e.message ?? str2(e.data.message)}`;
|
|
5489
5481
|
}
|
|
5490
|
-
case "
|
|
5491
|
-
return "\u2713
|
|
5492
|
-
case "
|
|
5482
|
+
case "TURN_FINISHED":
|
|
5483
|
+
return "\u2713 session finished";
|
|
5484
|
+
case "TURN_ERROR": {
|
|
5493
5485
|
const agui = toAGUI(e);
|
|
5494
|
-
const message = agui.type === "
|
|
5495
|
-
return `\u2717
|
|
5486
|
+
const message = agui.type === "TURN_ERROR" ? agui.message : e.message ?? "turn error";
|
|
5487
|
+
return `\u2717 turn error: ${message}`;
|
|
5496
5488
|
}
|
|
5497
5489
|
default:
|
|
5498
5490
|
return null;
|
|
@@ -5520,12 +5512,12 @@ function parseFilters(tokens) {
|
|
|
5520
5512
|
return { predicate };
|
|
5521
5513
|
}
|
|
5522
5514
|
|
|
5523
|
-
// dist/host/
|
|
5515
|
+
// dist/host/start-cmd.js
|
|
5524
5516
|
var DEFAULT_SESSION_IDLE_TTL = "3m";
|
|
5525
5517
|
var FOLLOW_SETTLE_POLL_DEADLINE_MS = 6e4;
|
|
5526
5518
|
var FOLLOW_SETTLE_POLL_INTERVAL_MS = 750;
|
|
5527
|
-
async function
|
|
5528
|
-
if (await
|
|
5519
|
+
async function executeStartCmd(io2, argv) {
|
|
5520
|
+
if (await refuseInsideManagedSession(io2, "start"))
|
|
5529
5521
|
return USAGE_ERR;
|
|
5530
5522
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
5531
5523
|
if (!common.ok) {
|
|
@@ -5543,16 +5535,16 @@ async function runRunCmd(io2, argv) {
|
|
|
5543
5535
|
rest = providerFlag.remaining;
|
|
5544
5536
|
let explicitProvider;
|
|
5545
5537
|
if (providerFlag.value !== null) {
|
|
5546
|
-
if (!
|
|
5547
|
-
const hint = suggest(providerFlag.value,
|
|
5548
|
-
io2.stderr(`--provider must be one of: ${
|
|
5538
|
+
if (!PROVIDERS.includes(providerFlag.value)) {
|
|
5539
|
+
const hint = suggest(providerFlag.value, PROVIDERS);
|
|
5540
|
+
io2.stderr(`--provider must be one of: ${PROVIDERS.join(", ")} (got: ${providerFlag.value})${hint ? `; did you mean "${hint}"?` : ""}
|
|
5549
5541
|
`);
|
|
5550
5542
|
return USAGE_ERR;
|
|
5551
5543
|
}
|
|
5552
5544
|
explicitProvider = providerFlag.value;
|
|
5553
5545
|
}
|
|
5554
5546
|
const providerKeyValues = {};
|
|
5555
|
-
for (const p of
|
|
5547
|
+
for (const p of PROVIDERS) {
|
|
5556
5548
|
const flag = takeFlagValue(rest, `--${p}-api-key`);
|
|
5557
5549
|
if (flag.error) {
|
|
5558
5550
|
io2.stderr(`${flag.error}
|
|
@@ -5590,18 +5582,18 @@ async function runRunCmd(io2, argv) {
|
|
|
5590
5582
|
`);
|
|
5591
5583
|
return USAGE_ERR;
|
|
5592
5584
|
}
|
|
5593
|
-
const
|
|
5594
|
-
if (
|
|
5595
|
-
io2.stderr(`${
|
|
5585
|
+
const sessionTimeoutFlag = takeFlagValue(rest, "--session-timeout");
|
|
5586
|
+
if (sessionTimeoutFlag.error) {
|
|
5587
|
+
io2.stderr(`${sessionTimeoutFlag.error}
|
|
5596
5588
|
`);
|
|
5597
5589
|
return USAGE_ERR;
|
|
5598
5590
|
}
|
|
5599
|
-
rest =
|
|
5600
|
-
if (
|
|
5591
|
+
rest = sessionTimeoutFlag.remaining;
|
|
5592
|
+
if (sessionTimeoutFlag.value) {
|
|
5601
5593
|
try {
|
|
5602
|
-
|
|
5594
|
+
parseSessionTimeout(sessionTimeoutFlag.value);
|
|
5603
5595
|
} catch (err2) {
|
|
5604
|
-
io2.stderr(`--
|
|
5596
|
+
io2.stderr(`--session-timeout: ${err2.message}
|
|
5605
5597
|
`);
|
|
5606
5598
|
return USAGE_ERR;
|
|
5607
5599
|
}
|
|
@@ -5723,7 +5715,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5723
5715
|
return USAGE_ERR;
|
|
5724
5716
|
}
|
|
5725
5717
|
if (positional.length > 0) {
|
|
5726
|
-
io2.stderr(`aex
|
|
5718
|
+
io2.stderr(`aex start takes no positional arguments (got: ${positional.join(" ")})
|
|
5727
5719
|
`);
|
|
5728
5720
|
return USAGE_ERR;
|
|
5729
5721
|
}
|
|
@@ -5741,7 +5733,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5741
5733
|
io2.stderr("--config cannot be combined with --model/--system/--prompt/--mcp/--metadata\n");
|
|
5742
5734
|
return USAGE_ERR;
|
|
5743
5735
|
}
|
|
5744
|
-
let
|
|
5736
|
+
let sessionConfig;
|
|
5745
5737
|
try {
|
|
5746
5738
|
const absPath = resolvePath(io2.cwd(), config.value);
|
|
5747
5739
|
const text = await io2.readFile(absPath);
|
|
@@ -5749,20 +5741,20 @@ async function runRunCmd(io2, argv) {
|
|
|
5749
5741
|
const { mcpHeaders, normalised } = stripMcpHeadersForParsing(raw);
|
|
5750
5742
|
for (const [name, headers] of mcpHeaders)
|
|
5751
5743
|
mcpHeaderBag.set(name, headers);
|
|
5752
|
-
|
|
5744
|
+
sessionConfig = parseSessionRequestConfig(normalised);
|
|
5753
5745
|
} catch (err2) {
|
|
5754
5746
|
io2.stderr(`failed to load --config: ${err2.message}
|
|
5755
5747
|
`);
|
|
5756
5748
|
return USAGE_ERR;
|
|
5757
5749
|
}
|
|
5758
|
-
model =
|
|
5759
|
-
system =
|
|
5760
|
-
promptArray = Array.isArray(
|
|
5761
|
-
configMcpServers =
|
|
5762
|
-
configEnvironment =
|
|
5763
|
-
configRuntimeSize =
|
|
5764
|
-
configTimeout =
|
|
5765
|
-
metadata =
|
|
5750
|
+
model = sessionConfig.model;
|
|
5751
|
+
system = sessionConfig.system;
|
|
5752
|
+
promptArray = Array.isArray(sessionConfig.prompt) ? [...sessionConfig.prompt] : [sessionConfig.prompt];
|
|
5753
|
+
configMcpServers = sessionConfig.mcpServers ?? [];
|
|
5754
|
+
configEnvironment = sessionConfig.environment;
|
|
5755
|
+
configRuntimeSize = sessionConfig.runtimeSize;
|
|
5756
|
+
configTimeout = sessionConfig.timeout;
|
|
5757
|
+
metadata = sessionConfig.metadata ? { ...sessionConfig.metadata } : void 0;
|
|
5766
5758
|
} else {
|
|
5767
5759
|
if (!modelFlag.value) {
|
|
5768
5760
|
io2.stderr("--model is required when --config is not provided\n");
|
|
@@ -5860,7 +5852,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5860
5852
|
}
|
|
5861
5853
|
const environment = toCliSessionEnvironment(configEnvironment);
|
|
5862
5854
|
const runtimeSize = runtimeSizeFlag.value ?? configRuntimeSize;
|
|
5863
|
-
const timeout =
|
|
5855
|
+
const timeout = sessionTimeoutFlag.value ?? configTimeout;
|
|
5864
5856
|
const options = {
|
|
5865
5857
|
message: promptArray,
|
|
5866
5858
|
provider,
|
|
@@ -5886,7 +5878,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5886
5878
|
if (follow.present && !io2.webSocketFactory) {
|
|
5887
5879
|
io2.stderr(JSON.stringify({
|
|
5888
5880
|
error: "websocket_unavailable",
|
|
5889
|
-
message: "`aex
|
|
5881
|
+
message: "`aex start --follow` needs a global WebSocket (Bun or Node >= 22). Upgrade Node or session with bun."
|
|
5890
5882
|
}) + "\n");
|
|
5891
5883
|
return USAGE_ERR;
|
|
5892
5884
|
}
|
|
@@ -5895,7 +5887,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5895
5887
|
session = await submitCliRun(http, io2.fetchImpl, options);
|
|
5896
5888
|
} catch (err2) {
|
|
5897
5889
|
const d = describeApiError(err2);
|
|
5898
|
-
return emitJsonError(io2, "
|
|
5890
|
+
return emitJsonError(io2, "session_failed", d.message, {
|
|
5899
5891
|
...d.status !== void 0 ? { status: d.status } : {},
|
|
5900
5892
|
...d.remedy ? { remedy: d.remedy } : {}
|
|
5901
5893
|
});
|
|
@@ -5929,7 +5921,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5929
5921
|
if (timer)
|
|
5930
5922
|
clearTimeout(timer);
|
|
5931
5923
|
if (timedOut) {
|
|
5932
|
-
emitJsonError(io2, "
|
|
5924
|
+
emitJsonError(io2, "session_follow_timeout", `timed out after ${followTimeoutMs}ms following session`, {
|
|
5933
5925
|
sessionId: session.id,
|
|
5934
5926
|
lastSeq,
|
|
5935
5927
|
...followTimeoutContext(session),
|
|
@@ -5948,7 +5940,7 @@ async function runRunCmd(io2, argv) {
|
|
|
5948
5940
|
if (timer)
|
|
5949
5941
|
clearTimeout(timer);
|
|
5950
5942
|
if (timedOut) {
|
|
5951
|
-
emitJsonError(io2, "
|
|
5943
|
+
emitJsonError(io2, "session_follow_timeout", `timed out after ${followTimeoutMs}ms following session`, {
|
|
5952
5944
|
sessionId: session.id,
|
|
5953
5945
|
lastSeq,
|
|
5954
5946
|
...followTimeoutContext(session),
|
|
@@ -6110,8 +6102,8 @@ async function readMaybeFile(io2, value) {
|
|
|
6110
6102
|
}
|
|
6111
6103
|
|
|
6112
6104
|
// dist/host/status.js
|
|
6113
|
-
async function
|
|
6114
|
-
if (await
|
|
6105
|
+
async function executeStatusCmd(io2, argv) {
|
|
6106
|
+
if (await refuseInsideManagedSession(io2, "status"))
|
|
6115
6107
|
return USAGE_ERR;
|
|
6116
6108
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6117
6109
|
if (!common.ok) {
|
|
@@ -6146,8 +6138,8 @@ async function runStatusCmd(io2, argv) {
|
|
|
6146
6138
|
}
|
|
6147
6139
|
|
|
6148
6140
|
// dist/host/deliveries.js
|
|
6149
|
-
async function
|
|
6150
|
-
if (await
|
|
6141
|
+
async function executeDeliveriesCmd(io2, argv) {
|
|
6142
|
+
if (await refuseInsideManagedSession(io2, "deliveries"))
|
|
6151
6143
|
return USAGE_ERR;
|
|
6152
6144
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6153
6145
|
if (!common.ok) {
|
|
@@ -6168,7 +6160,7 @@ async function runDeliveriesCmd(io2, argv) {
|
|
|
6168
6160
|
const sessionId = positional[0];
|
|
6169
6161
|
const http = makeHttpClient(io2, common.flags);
|
|
6170
6162
|
try {
|
|
6171
|
-
const deliveries = await operations_exports.
|
|
6163
|
+
const deliveries = await operations_exports.getSessionWebhookDeliveries(http, sessionId);
|
|
6172
6164
|
io2.stdout(JSON.stringify(deliveries) + "\n");
|
|
6173
6165
|
return SUCCESS;
|
|
6174
6166
|
} catch (err2) {
|
|
@@ -6183,8 +6175,8 @@ async function runDeliveriesCmd(io2, argv) {
|
|
|
6183
6175
|
|
|
6184
6176
|
// dist/host/wait.js
|
|
6185
6177
|
var DEFAULT_INTERVAL_MS = 2e3;
|
|
6186
|
-
async function
|
|
6187
|
-
if (await
|
|
6178
|
+
async function executeWaitCmd(io2, argv) {
|
|
6179
|
+
if (await refuseInsideManagedSession(io2, "wait"))
|
|
6188
6180
|
return USAGE_ERR;
|
|
6189
6181
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6190
6182
|
if (!common.ok) {
|
|
@@ -6257,8 +6249,8 @@ function sleep3(ms) {
|
|
|
6257
6249
|
}
|
|
6258
6250
|
|
|
6259
6251
|
// dist/host/events.js
|
|
6260
|
-
async function
|
|
6261
|
-
if (await
|
|
6252
|
+
async function executeEventsCmd(io2, argv) {
|
|
6253
|
+
if (await refuseInsideManagedSession(io2, "events"))
|
|
6262
6254
|
return USAGE_ERR;
|
|
6263
6255
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6264
6256
|
if (!common.ok) {
|
|
@@ -6348,10 +6340,10 @@ function sleep4(ms) {
|
|
|
6348
6340
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6349
6341
|
}
|
|
6350
6342
|
|
|
6351
|
-
// dist/host/
|
|
6343
|
+
// dist/host/files.js
|
|
6352
6344
|
import { resolve as resolvePath2 } from "node:path";
|
|
6353
|
-
async function
|
|
6354
|
-
if (await
|
|
6345
|
+
async function executeSessionFilesCmd(io2, argv) {
|
|
6346
|
+
if (await refuseInsideManagedSession(io2, "files"))
|
|
6355
6347
|
return USAGE_ERR;
|
|
6356
6348
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6357
6349
|
if (!common.ok) {
|
|
@@ -6364,21 +6356,21 @@ async function runOutputsCmd(io2, argv) {
|
|
|
6364
6356
|
const http = makeHttpClient(io2, common.flags);
|
|
6365
6357
|
switch (sub) {
|
|
6366
6358
|
case "read":
|
|
6367
|
-
return
|
|
6359
|
+
return filesRead(io2, http, args.slice(1));
|
|
6368
6360
|
case "download":
|
|
6369
|
-
return
|
|
6361
|
+
return filesDownload(io2, http, args.slice(1), common.flags);
|
|
6370
6362
|
case "link":
|
|
6371
|
-
return
|
|
6363
|
+
return filesLink(io2, http, args.slice(1));
|
|
6372
6364
|
case "find":
|
|
6373
|
-
return
|
|
6365
|
+
return filesFind(io2, http, args.slice(1));
|
|
6374
6366
|
case "search":
|
|
6375
|
-
return
|
|
6367
|
+
return filesSearch(io2, http, args.slice(1));
|
|
6376
6368
|
default:
|
|
6377
|
-
return
|
|
6369
|
+
return filesList(io2, http, args);
|
|
6378
6370
|
}
|
|
6379
6371
|
}
|
|
6380
|
-
async function
|
|
6381
|
-
const usage = "usage: aex
|
|
6372
|
+
async function filesList(io2, http, args) {
|
|
6373
|
+
const usage = "usage: aex files <session-id> [common flags]";
|
|
6382
6374
|
const unknown = rejectUnknownFlags(io2, args, usage);
|
|
6383
6375
|
if (unknown)
|
|
6384
6376
|
return unknown;
|
|
@@ -6390,16 +6382,16 @@ async function outputsList(io2, http, args) {
|
|
|
6390
6382
|
}
|
|
6391
6383
|
const sessionId = positional[0];
|
|
6392
6384
|
try {
|
|
6393
|
-
const
|
|
6394
|
-
for (const
|
|
6395
|
-
io2.stdout(JSON.stringify(
|
|
6385
|
+
const files = await operations_exports.listSessionFiles(http, sessionId);
|
|
6386
|
+
for (const file2 of files)
|
|
6387
|
+
io2.stdout(JSON.stringify(file2) + "\n");
|
|
6396
6388
|
return SUCCESS;
|
|
6397
6389
|
} catch (err2) {
|
|
6398
|
-
return
|
|
6390
|
+
return filesError(io2, "files_failed", err2, { sessionId });
|
|
6399
6391
|
}
|
|
6400
6392
|
}
|
|
6401
|
-
async function
|
|
6402
|
-
const usage = "usage: aex
|
|
6393
|
+
async function filesRead(io2, http, args) {
|
|
6394
|
+
const usage = "usage: aex files read <session-id> <path> [common flags]";
|
|
6403
6395
|
const unknown = rejectUnknownFlags(io2, args, usage);
|
|
6404
6396
|
if (unknown)
|
|
6405
6397
|
return unknown;
|
|
@@ -6411,14 +6403,14 @@ async function outputsRead(io2, http, args) {
|
|
|
6411
6403
|
}
|
|
6412
6404
|
const [sessionId, selector] = positional;
|
|
6413
6405
|
try {
|
|
6414
|
-
const text = await operations_exports.
|
|
6406
|
+
const text = await operations_exports.readSessionFileText(http, sessionId, { path: selector });
|
|
6415
6407
|
io2.stdout(JSON.stringify(text) + "\n");
|
|
6416
6408
|
return SUCCESS;
|
|
6417
6409
|
} catch (err2) {
|
|
6418
|
-
return
|
|
6410
|
+
return filesError(io2, "files_read_failed", err2, { sessionId, path: selector });
|
|
6419
6411
|
}
|
|
6420
6412
|
}
|
|
6421
|
-
async function
|
|
6413
|
+
async function filesDownload(io2, http, args, flags) {
|
|
6422
6414
|
const outFlag = takeFlagValue(args, "--out");
|
|
6423
6415
|
if (outFlag.error) {
|
|
6424
6416
|
io2.stderr(`${outFlag.error}
|
|
@@ -6426,7 +6418,7 @@ async function outputsDownload(io2, http, args, flags) {
|
|
|
6426
6418
|
return USAGE_ERR;
|
|
6427
6419
|
}
|
|
6428
6420
|
void flags;
|
|
6429
|
-
const usage = "usage: aex
|
|
6421
|
+
const usage = "usage: aex files download <session-id> <path> [--out file] [common flags]";
|
|
6430
6422
|
const unknown = rejectUnknownFlags(io2, outFlag.remaining, usage);
|
|
6431
6423
|
if (unknown)
|
|
6432
6424
|
return unknown;
|
|
@@ -6439,9 +6431,9 @@ async function outputsDownload(io2, http, args, flags) {
|
|
|
6439
6431
|
const [sessionId, selector] = positional;
|
|
6440
6432
|
let bytes;
|
|
6441
6433
|
try {
|
|
6442
|
-
bytes = (await operations_exports.
|
|
6434
|
+
bytes = (await operations_exports.downloadSessionFile(http, sessionId, { path: selector })).bytes;
|
|
6443
6435
|
} catch (err2) {
|
|
6444
|
-
return
|
|
6436
|
+
return filesError(io2, "files_download_failed", err2, { sessionId, path: selector });
|
|
6445
6437
|
}
|
|
6446
6438
|
const destination = resolvePath2(io2.cwd(), outFlag.value ?? baseName2(selector));
|
|
6447
6439
|
try {
|
|
@@ -6452,8 +6444,8 @@ async function outputsDownload(io2, http, args, flags) {
|
|
|
6452
6444
|
io2.stdout(JSON.stringify({ sessionId, path: selector, out: destination, bytes: bytes.byteLength }) + "\n");
|
|
6453
6445
|
return SUCCESS;
|
|
6454
6446
|
}
|
|
6455
|
-
async function
|
|
6456
|
-
const usage = "usage: aex
|
|
6447
|
+
async function filesLink(io2, http, args) {
|
|
6448
|
+
const usage = "usage: aex files link <session-id> <path> [common flags]";
|
|
6457
6449
|
const unknown = rejectUnknownFlags(io2, args, usage);
|
|
6458
6450
|
if (unknown)
|
|
6459
6451
|
return unknown;
|
|
@@ -6465,14 +6457,14 @@ async function outputsLink(io2, http, args) {
|
|
|
6465
6457
|
}
|
|
6466
6458
|
const [sessionId, selector] = positional;
|
|
6467
6459
|
try {
|
|
6468
|
-
const link = await operations_exports.
|
|
6460
|
+
const link = await operations_exports.sessionFileLink(http, sessionId, { path: selector });
|
|
6469
6461
|
io2.stdout(JSON.stringify(link) + "\n");
|
|
6470
6462
|
return SUCCESS;
|
|
6471
6463
|
} catch (err2) {
|
|
6472
|
-
return
|
|
6464
|
+
return filesError(io2, "files_link_failed", err2, { sessionId, path: selector });
|
|
6473
6465
|
}
|
|
6474
6466
|
}
|
|
6475
|
-
async function
|
|
6467
|
+
async function filesFind(io2, http, args) {
|
|
6476
6468
|
const name = takeFlagValue(args, "--name");
|
|
6477
6469
|
const ext = takeFlagValue(name.remaining, "--ext");
|
|
6478
6470
|
const type = takeFlagValue(ext.remaining, "--type");
|
|
@@ -6483,7 +6475,7 @@ async function outputsFind(io2, http, args) {
|
|
|
6483
6475
|
`);
|
|
6484
6476
|
return USAGE_ERR;
|
|
6485
6477
|
}
|
|
6486
|
-
const usage = "usage: aex
|
|
6478
|
+
const usage = "usage: aex files find <session-id> [--name S] [--ext E] [--type T] [--content-type CT] [common flags]";
|
|
6487
6479
|
const unknown = rejectUnknownFlags(io2, contentType.remaining, usage);
|
|
6488
6480
|
if (unknown)
|
|
6489
6481
|
return unknown;
|
|
@@ -6501,33 +6493,33 @@ async function outputsFind(io2, http, args) {
|
|
|
6501
6493
|
...contentType.value !== null ? { contentType: contentType.value } : {}
|
|
6502
6494
|
};
|
|
6503
6495
|
try {
|
|
6504
|
-
const hits = await
|
|
6496
|
+
const hits = await searchSessionFiles(http, sessionId, query);
|
|
6505
6497
|
for (const hit of hits)
|
|
6506
6498
|
io2.stdout(JSON.stringify(hit) + "\n");
|
|
6507
6499
|
return SUCCESS;
|
|
6508
6500
|
} catch (err22) {
|
|
6509
|
-
return
|
|
6501
|
+
return filesError(io2, "files_find_failed", err22, { sessionId });
|
|
6510
6502
|
}
|
|
6511
6503
|
}
|
|
6512
|
-
async function
|
|
6504
|
+
async function filesSearch(io2, http, args) {
|
|
6513
6505
|
const query = takeFlagValue(args, "--query");
|
|
6514
6506
|
const name = takeFlagValue(query.remaining, "--name");
|
|
6515
6507
|
const ext = takeFlagValue(name.remaining, "--ext");
|
|
6516
6508
|
const contentType = takeFlagValue(ext.remaining, "--content-type");
|
|
6517
6509
|
const limit = takeFlagValue(contentType.remaining, "--limit");
|
|
6518
|
-
const
|
|
6519
|
-
const err2 = query.error ?? name.error ?? ext.error ?? contentType.error ?? limit.error ??
|
|
6510
|
+
const sessionIds = collectRepeated(limit.remaining, "--session-id");
|
|
6511
|
+
const err2 = query.error ?? name.error ?? ext.error ?? contentType.error ?? limit.error ?? sessionIds.error;
|
|
6520
6512
|
if (err2) {
|
|
6521
6513
|
io2.stderr(`${err2}
|
|
6522
6514
|
`);
|
|
6523
6515
|
return USAGE_ERR;
|
|
6524
6516
|
}
|
|
6525
|
-
const usage = "usage: aex
|
|
6526
|
-
const unknown = rejectUnknownFlags(io2,
|
|
6517
|
+
const usage = "usage: aex files search [--query S] [--name S] [--ext E] [--content-type CT] [--session-id ID] [--limit N] [common flags]";
|
|
6518
|
+
const unknown = rejectUnknownFlags(io2, sessionIds.remaining, usage);
|
|
6527
6519
|
if (unknown)
|
|
6528
6520
|
return unknown;
|
|
6529
|
-
if (
|
|
6530
|
-
io2.stderr(`unexpected arguments: ${
|
|
6521
|
+
if (sessionIds.remaining.length > 0) {
|
|
6522
|
+
io2.stderr(`unexpected arguments: ${sessionIds.remaining.join(" ")}
|
|
6531
6523
|
`);
|
|
6532
6524
|
io2.stderr(`${usage}
|
|
6533
6525
|
`);
|
|
@@ -6548,18 +6540,18 @@ async function outputsSearch(io2, http, args) {
|
|
|
6548
6540
|
...filename !== null ? { filename } : {},
|
|
6549
6541
|
...ext.value !== null ? { extension: ext.value } : {},
|
|
6550
6542
|
...contentType.value !== null ? { contentType: contentType.value } : {},
|
|
6551
|
-
...
|
|
6543
|
+
...sessionIds.values.length > 0 ? { sessionIds: [...sessionIds.values] } : {},
|
|
6552
6544
|
...limitValue !== void 0 ? { limit: limitValue } : {}
|
|
6553
6545
|
};
|
|
6554
6546
|
try {
|
|
6555
|
-
const page = await
|
|
6547
|
+
const page = await searchWorkspaceFiles(http, search);
|
|
6556
6548
|
io2.stdout(JSON.stringify(page) + "\n");
|
|
6557
6549
|
return SUCCESS;
|
|
6558
6550
|
} catch (err22) {
|
|
6559
|
-
return
|
|
6551
|
+
return filesError(io2, "files_search_failed", err22, {});
|
|
6560
6552
|
}
|
|
6561
6553
|
}
|
|
6562
|
-
function
|
|
6554
|
+
function filesError(io2, code, err2, extra) {
|
|
6563
6555
|
const d = describeApiError(err2);
|
|
6564
6556
|
return emitJsonError(io2, code, d.message, {
|
|
6565
6557
|
...extra,
|
|
@@ -6567,23 +6559,23 @@ function outputsError(io2, code, err2, extra) {
|
|
|
6567
6559
|
...d.remedy ? { remedy: d.remedy } : {}
|
|
6568
6560
|
});
|
|
6569
6561
|
}
|
|
6570
|
-
async function
|
|
6571
|
-
|
|
6572
|
-
const
|
|
6562
|
+
async function searchWorkspaceFiles(http, query) {
|
|
6563
|
+
assertMetadataOnlySessionFileSearch(query, "aex files search");
|
|
6564
|
+
const sessionIds = query.sessionIds && query.sessionIds.length > 0 ? [...query.sessionIds] : void 0;
|
|
6573
6565
|
const limit = query.limit ?? 100;
|
|
6574
6566
|
const hits = [];
|
|
6575
|
-
const candidates =
|
|
6576
|
-
for (const
|
|
6577
|
-
const
|
|
6578
|
-
for (const
|
|
6579
|
-
hits.push(
|
|
6567
|
+
const candidates = sessionIds ?? await listRecentSessionIds(http, limit);
|
|
6568
|
+
for (const sessionId of candidates) {
|
|
6569
|
+
const files = await searchSessionFiles(http, sessionId, query);
|
|
6570
|
+
for (const file2 of files) {
|
|
6571
|
+
hits.push(fileHit(sessionId, file2));
|
|
6580
6572
|
if (hits.length >= limit)
|
|
6581
6573
|
return { hits };
|
|
6582
6574
|
}
|
|
6583
6575
|
}
|
|
6584
6576
|
return { hits };
|
|
6585
6577
|
}
|
|
6586
|
-
async function
|
|
6578
|
+
async function listRecentSessionIds(http, limit) {
|
|
6587
6579
|
const out = [];
|
|
6588
6580
|
let cursor;
|
|
6589
6581
|
while (out.length < limit) {
|
|
@@ -6595,30 +6587,30 @@ async function listRecentRunIds(http, limit) {
|
|
|
6595
6587
|
}
|
|
6596
6588
|
return out;
|
|
6597
6589
|
}
|
|
6598
|
-
async function
|
|
6590
|
+
async function searchSessionFiles(http, sessionId, query) {
|
|
6599
6591
|
const listQuery = {
|
|
6600
6592
|
...query.extension !== void 0 ? { extension: query.extension } : {},
|
|
6601
6593
|
...query.contentType !== void 0 ? { contentType: query.contentType } : {}
|
|
6602
6594
|
};
|
|
6603
|
-
const
|
|
6595
|
+
const files = await operations_exports.listSessionFiles(http, sessionId, Object.keys(listQuery).length > 0 ? listQuery : void 0);
|
|
6604
6596
|
if (query.filename === void 0)
|
|
6605
|
-
return
|
|
6597
|
+
return files;
|
|
6606
6598
|
const match = operations_exports.toFilenameMatcher(query.filename);
|
|
6607
|
-
return
|
|
6599
|
+
return files.filter((file2) => typeof file2.filename === "string" && match(file2.filename));
|
|
6608
6600
|
}
|
|
6609
|
-
function
|
|
6601
|
+
function fileHit(sessionId, file2) {
|
|
6610
6602
|
return {
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
...
|
|
6614
|
-
...
|
|
6615
|
-
...
|
|
6603
|
+
sessionId,
|
|
6604
|
+
fileId: file2.id,
|
|
6605
|
+
...file2.filename !== void 0 ? { filename: file2.filename } : {},
|
|
6606
|
+
...file2.sizeBytes !== void 0 ? { sizeBytes: file2.sizeBytes } : {},
|
|
6607
|
+
...file2.contentType !== void 0 ? { contentType: file2.contentType } : {}
|
|
6616
6608
|
};
|
|
6617
6609
|
}
|
|
6618
|
-
function
|
|
6610
|
+
function assertMetadataOnlySessionFileSearch(query, surface) {
|
|
6619
6611
|
for (const key of ["content", "text", "query", "grep", "body"]) {
|
|
6620
6612
|
if (Object.prototype.hasOwnProperty.call(query, key)) {
|
|
6621
|
-
throw new Error(`${surface}: ${key} is not supported;
|
|
6613
|
+
throw new Error(`${surface}: ${key} is not supported; file search is metadata-only`);
|
|
6622
6614
|
}
|
|
6623
6615
|
}
|
|
6624
6616
|
}
|
|
@@ -6631,12 +6623,12 @@ function baseName2(p) {
|
|
|
6631
6623
|
// dist/host/download.js
|
|
6632
6624
|
import { resolve as resolvePath3 } from "node:path";
|
|
6633
6625
|
var NAMESPACE_DOWNLOADERS = {
|
|
6634
|
-
|
|
6626
|
+
files: operations_exports.downloadSessionFiles,
|
|
6635
6627
|
events: operations_exports.downloadEvents,
|
|
6636
6628
|
metadata: operations_exports.downloadMetadata
|
|
6637
6629
|
};
|
|
6638
|
-
async function
|
|
6639
|
-
if (await
|
|
6630
|
+
async function executeDownloadCmd(io2, argv) {
|
|
6631
|
+
if (await refuseInsideManagedSession(io2, "download"))
|
|
6640
6632
|
return USAGE_ERR;
|
|
6641
6633
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6642
6634
|
if (!common.ok) {
|
|
@@ -6662,7 +6654,7 @@ async function runDownloadCmd(io2, argv) {
|
|
|
6662
6654
|
return USAGE_ERR;
|
|
6663
6655
|
}
|
|
6664
6656
|
const namespace2 = onlyFlag.value;
|
|
6665
|
-
const usage = "usage: aex download <session-id> [--only
|
|
6657
|
+
const usage = "usage: aex download <session-id> [--only files|events|metadata] [--out path] [common flags]";
|
|
6666
6658
|
const unknown = rejectUnknownFlags(io2, onlyFlag.remaining, usage);
|
|
6667
6659
|
if (unknown)
|
|
6668
6660
|
return unknown;
|
|
@@ -6704,8 +6696,8 @@ function resolveDestination(io2, out, sessionId, namespace2) {
|
|
|
6704
6696
|
}
|
|
6705
6697
|
|
|
6706
6698
|
// dist/host/cancel.js
|
|
6707
|
-
async function
|
|
6708
|
-
if (await
|
|
6699
|
+
async function executeCancelCmd(io2, argv) {
|
|
6700
|
+
if (await refuseInsideManagedSession(io2, "cancel"))
|
|
6709
6701
|
return USAGE_ERR;
|
|
6710
6702
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6711
6703
|
if (!common.ok) {
|
|
@@ -6740,8 +6732,8 @@ async function runCancelCmd(io2, argv) {
|
|
|
6740
6732
|
}
|
|
6741
6733
|
|
|
6742
6734
|
// dist/host/delete.js
|
|
6743
|
-
async function
|
|
6744
|
-
if (await
|
|
6735
|
+
async function executeDeleteCmd(io2, argv) {
|
|
6736
|
+
if (await refuseInsideManagedSession(io2, "delete"))
|
|
6745
6737
|
return USAGE_ERR;
|
|
6746
6738
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6747
6739
|
if (!common.ok) {
|
|
@@ -6776,8 +6768,8 @@ async function runDeleteCmd(io2, argv) {
|
|
|
6776
6768
|
}
|
|
6777
6769
|
|
|
6778
6770
|
// dist/host/delete-asset.js
|
|
6779
|
-
async function
|
|
6780
|
-
if (await
|
|
6771
|
+
async function executeDeleteAssetCmd(io2, argv) {
|
|
6772
|
+
if (await refuseInsideManagedSession(io2, "delete-asset"))
|
|
6781
6773
|
return USAGE_ERR;
|
|
6782
6774
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6783
6775
|
if (!common.ok) {
|
|
@@ -6812,8 +6804,8 @@ async function runDeleteAssetCmd(io2, argv) {
|
|
|
6812
6804
|
}
|
|
6813
6805
|
|
|
6814
6806
|
// dist/host/whoami.js
|
|
6815
|
-
async function
|
|
6816
|
-
if (await
|
|
6807
|
+
async function executeWhoamiCmd(io2, argv) {
|
|
6808
|
+
if (await refuseInsideManagedSession(io2, "whoami"))
|
|
6817
6809
|
return USAGE_ERR;
|
|
6818
6810
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6819
6811
|
if (!common.ok) {
|
|
@@ -6858,8 +6850,8 @@ function parseLimit(io2, raw) {
|
|
|
6858
6850
|
}
|
|
6859
6851
|
return { ok: true, limit };
|
|
6860
6852
|
}
|
|
6861
|
-
async function
|
|
6862
|
-
if (await
|
|
6853
|
+
async function executeBillingCmd(io2, argv) {
|
|
6854
|
+
if (await refuseInsideManagedSession(io2, "billing"))
|
|
6863
6855
|
return USAGE_ERR;
|
|
6864
6856
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6865
6857
|
if (!common.ok) {
|
|
@@ -6987,8 +6979,8 @@ async function runBillingLedger(io2, argv, flags) {
|
|
|
6987
6979
|
}
|
|
6988
6980
|
|
|
6989
6981
|
// dist/host/webhooks-cmd.js
|
|
6990
|
-
async function
|
|
6991
|
-
if (await
|
|
6982
|
+
async function sessionWebhooksCmd(io2, argv) {
|
|
6983
|
+
if (await refuseInsideManagedSession(io2, "webhooks"))
|
|
6992
6984
|
return USAGE_ERR;
|
|
6993
6985
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
6994
6986
|
if (!common.ok) {
|
|
@@ -7003,7 +6995,7 @@ async function runWebhooksCmd(io2, argv) {
|
|
|
7003
6995
|
}
|
|
7004
6996
|
const { present: rotate, remaining } = takeBooleanFlag(rest, "--rotate");
|
|
7005
6997
|
if (rotate) {
|
|
7006
|
-
io2.stderr("--rotate is not supported: the hosted API reveals (or creates on first use) the workspace webhook signing secret but does not rotate it.
|
|
6998
|
+
io2.stderr("--rotate is not supported: the hosted API reveals (or creates on first use) the workspace webhook signing secret but does not rotate it. SessionRecord `aex webhooks secret` to reveal the current value.\n");
|
|
7007
6999
|
return USAGE_ERR;
|
|
7008
7000
|
}
|
|
7009
7001
|
if (remaining.length > 0) {
|
|
@@ -7039,8 +7031,8 @@ function parseLimit2(io2, raw) {
|
|
|
7039
7031
|
}
|
|
7040
7032
|
return { ok: true, limit };
|
|
7041
7033
|
}
|
|
7042
|
-
async function
|
|
7043
|
-
if (await
|
|
7034
|
+
async function executeSessionsCmd(io2, argv) {
|
|
7035
|
+
if (await refuseInsideManagedSession(io2, "sessions"))
|
|
7044
7036
|
return USAGE_ERR;
|
|
7045
7037
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
7046
7038
|
if (!common.ok) {
|
|
@@ -7053,7 +7045,7 @@ async function runRunsCmd(io2, argv) {
|
|
|
7053
7045
|
if (remaining.length > 0) {
|
|
7054
7046
|
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
7055
7047
|
`);
|
|
7056
|
-
io2.stderr("usage: aex
|
|
7048
|
+
io2.stderr("usage: aex sessions [--limit N] [--since ISO-8601] [common flags]\n");
|
|
7057
7049
|
return USAGE_ERR;
|
|
7058
7050
|
}
|
|
7059
7051
|
const parsed = parseLimit2(io2, rawLimit);
|
|
@@ -7067,47 +7059,15 @@ async function runRunsCmd(io2, argv) {
|
|
|
7067
7059
|
}
|
|
7068
7060
|
const http = makeHttpClient(io2, common.flags);
|
|
7069
7061
|
try {
|
|
7070
|
-
const page = await operations_exports.
|
|
7062
|
+
const page = await operations_exports.listSessionRecords(http, {
|
|
7071
7063
|
...parsed.limit !== void 0 ? { limit: parsed.limit } : {},
|
|
7072
7064
|
...since !== void 0 ? { since } : {}
|
|
7073
7065
|
});
|
|
7074
|
-
const
|
|
7075
|
-
const created = Date.parse(
|
|
7066
|
+
const sessions = sinceMs === void 0 ? page.sessions : page.sessions.filter((session) => {
|
|
7067
|
+
const created = Date.parse(session.createdAt);
|
|
7076
7068
|
return !Number.isNaN(created) && created >= sinceMs;
|
|
7077
7069
|
});
|
|
7078
|
-
io2.stdout(JSON.stringify({ ...page,
|
|
7079
|
-
return SUCCESS;
|
|
7080
|
-
} catch (err2) {
|
|
7081
|
-
const d = describeApiError(err2);
|
|
7082
|
-
return emitJsonError(io2, "runs_failed", d.message, {
|
|
7083
|
-
...d.status !== void 0 ? { status: d.status } : {},
|
|
7084
|
-
...d.remedy ? { remedy: d.remedy } : {}
|
|
7085
|
-
});
|
|
7086
|
-
}
|
|
7087
|
-
}
|
|
7088
|
-
async function runSessionsCmd(io2, argv) {
|
|
7089
|
-
if (await refuseInsideManagedRun(io2, "sessions"))
|
|
7090
|
-
return USAGE_ERR;
|
|
7091
|
-
const common = await resolveCommonHostFlags(io2, argv);
|
|
7092
|
-
if (!common.ok) {
|
|
7093
|
-
io2.stderr(`${common.reason}
|
|
7094
|
-
`);
|
|
7095
|
-
return USAGE_ERR;
|
|
7096
|
-
}
|
|
7097
|
-
const { value: rawLimit, remaining } = takeOptionFlag(common.rest, "--limit");
|
|
7098
|
-
if (remaining.length > 0) {
|
|
7099
|
-
io2.stderr(`unexpected arguments: ${remaining.join(" ")}
|
|
7100
|
-
`);
|
|
7101
|
-
io2.stderr("usage: aex sessions [--limit N] [common flags]\n");
|
|
7102
|
-
return USAGE_ERR;
|
|
7103
|
-
}
|
|
7104
|
-
const parsed = parseLimit2(io2, rawLimit);
|
|
7105
|
-
if (!parsed.ok)
|
|
7106
|
-
return USAGE_ERR;
|
|
7107
|
-
const http = makeHttpClient(io2, common.flags);
|
|
7108
|
-
try {
|
|
7109
|
-
const page = await operations_exports.listSessions(http, parsed.limit !== void 0 ? { limit: parsed.limit } : void 0);
|
|
7110
|
-
io2.stdout(JSON.stringify(page) + "\n");
|
|
7070
|
+
io2.stdout(JSON.stringify({ ...page, sessions }) + "\n");
|
|
7111
7071
|
return SUCCESS;
|
|
7112
7072
|
} catch (err2) {
|
|
7113
7073
|
const d = describeApiError(err2);
|
|
@@ -7119,8 +7079,8 @@ async function runSessionsCmd(io2, argv) {
|
|
|
7119
7079
|
}
|
|
7120
7080
|
|
|
7121
7081
|
// dist/host/auth-cmd.js
|
|
7122
|
-
async function
|
|
7123
|
-
if (await
|
|
7082
|
+
async function executeLoginCmd(io2, argv) {
|
|
7083
|
+
if (await refuseInsideManagedSession(io2, "login"))
|
|
7124
7084
|
return USAGE_ERR;
|
|
7125
7085
|
if (!io2.configStore) {
|
|
7126
7086
|
return emitJsonError(io2, "config_store_unavailable", "config store unavailable in this environment");
|
|
@@ -7177,8 +7137,8 @@ async function runLoginCmd(io2, argv) {
|
|
|
7177
7137
|
}) + "\n");
|
|
7178
7138
|
return SUCCESS;
|
|
7179
7139
|
}
|
|
7180
|
-
async function
|
|
7181
|
-
if (await
|
|
7140
|
+
async function executeLogoutCmd(io2, argv) {
|
|
7141
|
+
if (await refuseInsideManagedSession(io2, "logout"))
|
|
7182
7142
|
return USAGE_ERR;
|
|
7183
7143
|
if (!io2.configStore) {
|
|
7184
7144
|
return emitJsonError(io2, "config_store_unavailable", "config store unavailable in this environment");
|
|
@@ -7204,8 +7164,8 @@ async function runLogoutCmd(io2, argv) {
|
|
|
7204
7164
|
io2.stdout(JSON.stringify({ ok: true, cleared: true, configPath: io2.configStore.location() }) + "\n");
|
|
7205
7165
|
return SUCCESS;
|
|
7206
7166
|
}
|
|
7207
|
-
async function
|
|
7208
|
-
if (await
|
|
7167
|
+
async function executeAuthStatusCmd(io2, argv) {
|
|
7168
|
+
if (await refuseInsideManagedSession(io2, "auth"))
|
|
7209
7169
|
return USAGE_ERR;
|
|
7210
7170
|
if (!io2.configStore) {
|
|
7211
7171
|
return emitJsonError(io2, "config_store_unavailable", "config store unavailable in this environment");
|
|
@@ -7253,11 +7213,11 @@ function wantsJson(argv) {
|
|
|
7253
7213
|
const { present, remaining } = takeBooleanFlag(argv, "--json");
|
|
7254
7214
|
return { json: present, rest: remaining };
|
|
7255
7215
|
}
|
|
7256
|
-
function
|
|
7216
|
+
function modelNamesCmd(io2, argv) {
|
|
7257
7217
|
const { json, rest } = wantsJson(stripListSubcommand(argv));
|
|
7258
7218
|
if (hasUnknown(io2, rest, "models"))
|
|
7259
7219
|
return USAGE_ERR;
|
|
7260
|
-
const entries =
|
|
7220
|
+
const entries = SUPPORTED_MODELS.map((model) => ({
|
|
7261
7221
|
model,
|
|
7262
7222
|
defaultProvider: providerForModel(model) ?? null,
|
|
7263
7223
|
providers: providersForModel(model)
|
|
@@ -7269,14 +7229,14 @@ function runModelsCmd(io2, argv) {
|
|
|
7269
7229
|
}
|
|
7270
7230
|
return SUCCESS;
|
|
7271
7231
|
}
|
|
7272
|
-
function
|
|
7232
|
+
function providerNamesCmd(io2, argv) {
|
|
7273
7233
|
const { json, rest } = wantsJson(stripListSubcommand(argv));
|
|
7274
7234
|
if (hasUnknown(io2, rest, "providers"))
|
|
7275
7235
|
return USAGE_ERR;
|
|
7276
|
-
const entries =
|
|
7236
|
+
const entries = PROVIDERS.map((provider) => ({
|
|
7277
7237
|
provider,
|
|
7278
7238
|
displayName: PROVIDER_PUBLIC_SUPPORT[provider].displayName,
|
|
7279
|
-
models:
|
|
7239
|
+
models: SUPPORTED_MODELS_BY_PROVIDER[provider] ?? []
|
|
7280
7240
|
}));
|
|
7281
7241
|
if (json) {
|
|
7282
7242
|
io2.stdout(JSON.stringify(entries) + "\n");
|
|
@@ -7285,7 +7245,7 @@ function runProvidersCmd(io2, argv) {
|
|
|
7285
7245
|
}
|
|
7286
7246
|
return SUCCESS;
|
|
7287
7247
|
}
|
|
7288
|
-
function
|
|
7248
|
+
function executeToolsCmd(io2, argv) {
|
|
7289
7249
|
const { json, rest } = wantsJson(stripListSubcommand(argv));
|
|
7290
7250
|
if (hasUnknown(io2, rest, "tools"))
|
|
7291
7251
|
return USAGE_ERR;
|
|
@@ -7300,7 +7260,7 @@ function runToolsCmd(io2, argv) {
|
|
|
7300
7260
|
}
|
|
7301
7261
|
return SUCCESS;
|
|
7302
7262
|
}
|
|
7303
|
-
function
|
|
7263
|
+
function executeRuntimeSizesCmd(io2, argv) {
|
|
7304
7264
|
const { json, rest } = wantsJson(stripListSubcommand(argv));
|
|
7305
7265
|
if (hasUnknown(io2, rest, "runtime-sizes"))
|
|
7306
7266
|
return USAGE_ERR;
|
|
@@ -7336,8 +7296,8 @@ function hasUnknown(io2, rest, verb) {
|
|
|
7336
7296
|
}
|
|
7337
7297
|
|
|
7338
7298
|
// dist/host/tail.js
|
|
7339
|
-
async function
|
|
7340
|
-
if (await
|
|
7299
|
+
async function executeTailCmd(io2, argv) {
|
|
7300
|
+
if (await refuseInsideManagedSession(io2, "tail"))
|
|
7341
7301
|
return USAGE_ERR;
|
|
7342
7302
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
7343
7303
|
if (!common.ok) {
|
|
@@ -7390,7 +7350,7 @@ async function runTailCmd(io2, argv) {
|
|
|
7390
7350
|
if (!io2.webSocketFactory) {
|
|
7391
7351
|
io2.stderr(JSON.stringify({
|
|
7392
7352
|
error: "websocket_unavailable",
|
|
7393
|
-
message: "`aex tail` needs a global WebSocket (Bun or Node >= 22). Upgrade Node or
|
|
7353
|
+
message: "`aex tail` needs a global WebSocket (Bun or Node >= 22). Upgrade Node or session with bun.",
|
|
7394
7354
|
sessionId
|
|
7395
7355
|
}) + "\n");
|
|
7396
7356
|
return USAGE_ERR;
|
|
@@ -7443,7 +7403,7 @@ async function runTailCmd(io2, argv) {
|
|
|
7443
7403
|
eventCount++;
|
|
7444
7404
|
}
|
|
7445
7405
|
}
|
|
7446
|
-
if (e.type === "
|
|
7406
|
+
if (e.type === "TURN_ERROR")
|
|
7447
7407
|
runErrorLine = renderEnvelope(e, { logs: true });
|
|
7448
7408
|
}
|
|
7449
7409
|
} catch (err2) {
|
|
@@ -7495,8 +7455,8 @@ async function runTailCmd(io2, argv) {
|
|
|
7495
7455
|
}
|
|
7496
7456
|
|
|
7497
7457
|
// dist/host/inspect.js
|
|
7498
|
-
async function
|
|
7499
|
-
if (await
|
|
7458
|
+
async function executeInspectCmd(io2, argv) {
|
|
7459
|
+
if (await refuseInsideManagedSession(io2, "inspect"))
|
|
7500
7460
|
return USAGE_ERR;
|
|
7501
7461
|
const common = await resolveCommonHostFlags(io2, argv);
|
|
7502
7462
|
if (!common.ok) {
|
|
@@ -7537,7 +7497,7 @@ async function runInspectCmd(io2, argv) {
|
|
|
7537
7497
|
if (!io2.webSocketFactory) {
|
|
7538
7498
|
io2.stderr(JSON.stringify({
|
|
7539
7499
|
error: "websocket_unavailable",
|
|
7540
|
-
message: "`aex inspect` needs a global WebSocket (Bun or Node >= 22). Upgrade Node or
|
|
7500
|
+
message: "`aex inspect` needs a global WebSocket (Bun or Node >= 22). Upgrade Node or session with bun.",
|
|
7541
7501
|
sessionId
|
|
7542
7502
|
}) + "\n");
|
|
7543
7503
|
return USAGE_ERR;
|
|
@@ -7584,7 +7544,7 @@ async function runInspectCmd(io2, argv) {
|
|
|
7584
7544
|
...debug2 ? { debug: debug2 } : {}
|
|
7585
7545
|
});
|
|
7586
7546
|
for await (const e of stream) {
|
|
7587
|
-
if (e.type === "
|
|
7547
|
+
if (e.type === "TURN_ERROR")
|
|
7588
7548
|
runErrorEvent = e;
|
|
7589
7549
|
if (filters.predicate && !filters.predicate(e))
|
|
7590
7550
|
continue;
|
|
@@ -7623,7 +7583,7 @@ async function runInspectCmd(io2, argv) {
|
|
|
7623
7583
|
} else {
|
|
7624
7584
|
if (runErrorEvent) {
|
|
7625
7585
|
const d = runErrorEvent.data;
|
|
7626
|
-
const failureMessage = typeof d.failureMessage === "string" ? d.failureMessage : runErrorEvent.message ?? "
|
|
7586
|
+
const failureMessage = typeof d.failureMessage === "string" ? d.failureMessage : runErrorEvent.message ?? "turn error";
|
|
7627
7587
|
const failureClass = typeof d.failureClass === "string" ? ` [${d.failureClass}]` : "";
|
|
7628
7588
|
io2.stdout(`
|
|
7629
7589
|
\u2717 ${failureMessage}${failureClass}
|
|
@@ -7651,8 +7611,8 @@ async function runInspectCmd(io2, argv) {
|
|
|
7651
7611
|
return RUNTIME_ERR;
|
|
7652
7612
|
}
|
|
7653
7613
|
|
|
7654
|
-
// dist/
|
|
7655
|
-
async function
|
|
7614
|
+
// dist/main.js
|
|
7615
|
+
async function executeCli(io2) {
|
|
7656
7616
|
const args = io2.argv.slice(2);
|
|
7657
7617
|
try {
|
|
7658
7618
|
const exit = await dispatch(io2, args);
|
|
@@ -7670,87 +7630,84 @@ async function dispatch(io2, args) {
|
|
|
7670
7630
|
const sub = args[0];
|
|
7671
7631
|
const rest = args.slice(1);
|
|
7672
7632
|
const spec = sub === void 0 ? void 0 : findVerbSpec(sub);
|
|
7673
|
-
if (spec && wantsVerbHelp(rest) && !(sub === "
|
|
7633
|
+
if (spec && wantsVerbHelp(rest) && !(sub === "files" && rest[0] === "sync")) {
|
|
7674
7634
|
io2.stdout(renderVerbHelp(spec));
|
|
7675
7635
|
return SUCCESS;
|
|
7676
7636
|
}
|
|
7677
7637
|
switch (sub) {
|
|
7678
|
-
case "
|
|
7679
|
-
return
|
|
7638
|
+
case "start":
|
|
7639
|
+
return executeStartCmd(io2, rest);
|
|
7680
7640
|
case "status":
|
|
7681
|
-
return
|
|
7641
|
+
return executeStatusCmd(io2, rest);
|
|
7682
7642
|
case "deliveries":
|
|
7683
|
-
return
|
|
7643
|
+
return executeDeliveriesCmd(io2, rest);
|
|
7684
7644
|
case "wait":
|
|
7685
|
-
return
|
|
7645
|
+
return executeWaitCmd(io2, rest);
|
|
7686
7646
|
case "events":
|
|
7687
|
-
return
|
|
7647
|
+
return executeEventsCmd(io2, rest);
|
|
7688
7648
|
case "tail":
|
|
7689
|
-
return
|
|
7649
|
+
return executeTailCmd(io2, rest);
|
|
7690
7650
|
case "inspect":
|
|
7691
|
-
return
|
|
7692
|
-
case "
|
|
7651
|
+
return executeInspectCmd(io2, rest);
|
|
7652
|
+
case "files":
|
|
7693
7653
|
if (rest[0] === "sync") {
|
|
7694
|
-
return
|
|
7654
|
+
return executeFilesSyncCmd(io2, rest.slice(1));
|
|
7695
7655
|
}
|
|
7696
|
-
return
|
|
7656
|
+
return executeSessionFilesCmd(io2, rest);
|
|
7697
7657
|
case "download":
|
|
7698
|
-
return
|
|
7658
|
+
return executeDownloadCmd(io2, rest);
|
|
7699
7659
|
case "cancel":
|
|
7700
|
-
return
|
|
7660
|
+
return executeCancelCmd(io2, rest);
|
|
7701
7661
|
case "delete":
|
|
7702
|
-
return
|
|
7662
|
+
return executeDeleteCmd(io2, rest);
|
|
7703
7663
|
case "delete-asset":
|
|
7704
|
-
return
|
|
7705
|
-
case "runs":
|
|
7706
|
-
return runRunsCmd(io2, rest);
|
|
7664
|
+
return executeDeleteAssetCmd(io2, rest);
|
|
7707
7665
|
case "sessions":
|
|
7708
|
-
return
|
|
7666
|
+
return executeSessionsCmd(io2, rest);
|
|
7709
7667
|
case "whoami":
|
|
7710
|
-
return
|
|
7668
|
+
return executeWhoamiCmd(io2, rest);
|
|
7711
7669
|
case "billing":
|
|
7712
|
-
return
|
|
7670
|
+
return executeBillingCmd(io2, rest);
|
|
7713
7671
|
case "webhooks":
|
|
7714
|
-
return
|
|
7672
|
+
return sessionWebhooksCmd(io2, rest);
|
|
7715
7673
|
case "login":
|
|
7716
|
-
return
|
|
7674
|
+
return executeLoginCmd(io2, rest);
|
|
7717
7675
|
case "logout":
|
|
7718
|
-
return
|
|
7676
|
+
return executeLogoutCmd(io2, rest);
|
|
7719
7677
|
case "auth":
|
|
7720
|
-
return
|
|
7678
|
+
return executeAuthStatusCmd(io2, rest[0] === "status" ? rest.slice(1) : rest);
|
|
7721
7679
|
case "models":
|
|
7722
|
-
return
|
|
7680
|
+
return modelNamesCmd(io2, rest);
|
|
7723
7681
|
case "providers":
|
|
7724
|
-
return
|
|
7682
|
+
return providerNamesCmd(io2, rest);
|
|
7725
7683
|
case "tools":
|
|
7726
|
-
return
|
|
7684
|
+
return executeToolsCmd(io2, rest);
|
|
7727
7685
|
case "runtime-sizes":
|
|
7728
|
-
return
|
|
7686
|
+
return executeRuntimeSizesCmd(io2, rest);
|
|
7729
7687
|
default:
|
|
7730
7688
|
io2.stderr(`unknown subcommand: ${sub}
|
|
7731
7689
|
`);
|
|
7732
|
-
io2.stderr("
|
|
7690
|
+
io2.stderr("use `aex --help` for usage\n");
|
|
7733
7691
|
return USAGE_ERR;
|
|
7734
7692
|
}
|
|
7735
7693
|
}
|
|
7736
7694
|
async function printGlobalHelp(io2) {
|
|
7737
7695
|
io2.stdout("aex \u2014 unified CLI for the aex platform (a thin pass-through over the SDK)\n\n");
|
|
7738
7696
|
io2.stdout("Usage:\n");
|
|
7739
|
-
io2.stdout(" aex
|
|
7740
|
-
io2.stdout(" aex
|
|
7697
|
+
io2.stdout(" aex start --config <session.json> --<provider>-api-key K --api-key T [flags]\n");
|
|
7698
|
+
io2.stdout(" aex start --model M --prompt P [--system S] [--mcp name=url ...] --<provider>-api-key K --api-key T [flags]\n");
|
|
7741
7699
|
io2.stdout(" aex status <session-id> --api-key T\n");
|
|
7742
7700
|
io2.stdout(" aex deliveries <session-id> --api-key T\n");
|
|
7743
7701
|
io2.stdout(" aex wait <session-id> [--timeout 8m] [--interval 2s] --api-key T\n");
|
|
7744
7702
|
io2.stdout(" aex events <session-id> [--follow] [--timeout 8m] --api-key T\n");
|
|
7745
7703
|
io2.stdout(" aex tail <session-id> [--json] [--filter <type|source>] [--logs] [--settle] [--timeout 8m] --api-key T\n");
|
|
7746
7704
|
io2.stdout(" aex inspect <session-id> [--json] [--filter <type|source>] [--logs] [--timeout 8m] --api-key T\n");
|
|
7747
|
-
io2.stdout(" aex
|
|
7748
|
-
io2.stdout(" aex download <session-id> [--only
|
|
7705
|
+
io2.stdout(" aex files <session-id> --api-key T\n");
|
|
7706
|
+
io2.stdout(" aex download <session-id> [--only files|events|metadata] [--out path] --api-key T\n");
|
|
7749
7707
|
io2.stdout(" aex cancel <session-id> --api-key T\n");
|
|
7750
7708
|
io2.stdout(" aex delete <session-id> --api-key T\n");
|
|
7751
7709
|
io2.stdout(" aex delete-asset <assetId|hash> --api-key T\n");
|
|
7752
|
-
io2.stdout(" aex
|
|
7753
|
-
io2.stdout(" aex sessions [--limit N] --api-key T List the workspace's sessions (newest first, JSON)\n");
|
|
7710
|
+
io2.stdout(" aex sessions [--limit N] [--since ISO] --api-key T List the workspace's sessions (newest first, JSON)\n");
|
|
7754
7711
|
io2.stdout(" aex whoami --api-key T\n");
|
|
7755
7712
|
io2.stdout(" aex billing [--json] --api-key T Show prepaid balance, month spend, and spend cap\n");
|
|
7756
7713
|
io2.stdout(" aex billing ledger [--limit N] --api-key T Recent credit-ledger entries (newest first, JSON)\n");
|
|
@@ -7763,20 +7720,20 @@ async function printGlobalHelp(io2) {
|
|
|
7763
7720
|
io2.stdout(" aex models list [--json] List models + default provider (no token needed)\n");
|
|
7764
7721
|
io2.stdout(" aex providers list [--json] List providers + their models (no token needed)\n");
|
|
7765
7722
|
io2.stdout(" aex tools list [--json] List builtin tools (all default; no token needed)\n");
|
|
7766
|
-
io2.stdout(" aex
|
|
7723
|
+
io2.stdout(" aex starttime-sizes list [--json] List managed runtime presets (no token needed)\n");
|
|
7767
7724
|
io2.stdout(" aex --help\n\n");
|
|
7768
7725
|
io2.stdout("Common flags on every host subcommand:\n");
|
|
7769
7726
|
io2.stdout(" --api-key <token> REQUIRED \u2014 aex SDK API key (workspace is derived from it)\n");
|
|
7770
7727
|
io2.stdout(" --aex-url <url> Optional; defaults to https://api.aex.dev (local/staging/hosted plane)\n");
|
|
7771
7728
|
io2.stdout(" --debug Optional; print a redacted per-request trace to stderr (uploads nothing)\n\n");
|
|
7772
|
-
io2.stdout("aex
|
|
7773
|
-
io2.stdout(` --provider <name> Optional; one of: ${
|
|
7729
|
+
io2.stdout("aex start flags:\n");
|
|
7730
|
+
io2.stdout(` --provider <name> Optional; one of: ${PROVIDERS.join(", ")} (default anthropic)
|
|
7774
7731
|
`);
|
|
7775
|
-
for (const provider of
|
|
7732
|
+
for (const provider of PROVIDERS) {
|
|
7776
7733
|
io2.stdout(` --${provider}-api-key <key>${" ".repeat(Math.max(1, 13 - provider.length))}REQUIRED when --provider ${provider}; never stored
|
|
7777
7734
|
`);
|
|
7778
7735
|
}
|
|
7779
|
-
io2.stdout(" --config <path>
|
|
7736
|
+
io2.stdout(" --config <path> Session request JSON (mutually exclusive with the flat --model/--prompt flags)\n");
|
|
7780
7737
|
io2.stdout(" --model <model-id> Provider model id (required in flat mode)\n");
|
|
7781
7738
|
io2.stdout(" --system @file | <text> System message; @-prefix reads from file\n");
|
|
7782
7739
|
io2.stdout(" --prompt @file | <text> User message; @-prefix reads from file (repeatable)\n");
|
|
@@ -7784,10 +7741,10 @@ async function printGlobalHelp(io2) {
|
|
|
7784
7741
|
io2.stdout(" --mcp-auth name=Hdr:Val Auth header on the matching --mcp; routed into vaulted secrets (repeatable)\n");
|
|
7785
7742
|
io2.stdout(" --metadata key=value Submission metadata entry (repeatable)\n");
|
|
7786
7743
|
io2.stdout(" --runtime-size <size> managed runtime preset\n");
|
|
7787
|
-
io2.stdout(" --
|
|
7744
|
+
io2.stdout(" --session-timeout <dur> Server-side session deadline (e.g. 1h, max 8h); distinct from --timeout\n");
|
|
7788
7745
|
io2.stdout(" --idempotency-key <key> Optional; defaults to a fresh UUID\n");
|
|
7789
|
-
io2.stdout(" --webhook <url> Optional per-
|
|
7790
|
-
io2.stdout(" --follow Poll events to stdout until the
|
|
7746
|
+
io2.stdout(" --webhook <url> Optional per-session callback URL (https); receives the terminal session.finished event\n");
|
|
7747
|
+
io2.stdout(" --follow Poll events to stdout until the session reaches a terminal state\n");
|
|
7791
7748
|
io2.stdout(" --timeout <dur> With --follow: give up after this long (e.g. 8m, 30s, 500ms); exit code 3\n");
|
|
7792
7749
|
return SUCCESS;
|
|
7793
7750
|
}
|
|
@@ -7884,4 +7841,4 @@ var io = {
|
|
|
7884
7841
|
process.on(signal, handler);
|
|
7885
7842
|
}
|
|
7886
7843
|
};
|
|
7887
|
-
await
|
|
7844
|
+
await executeCli(io);
|