@aexhq/sdk 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -6
- package/dist/_contracts/event-guards.d.ts +67 -0
- package/dist/_contracts/event-guards.js +36 -0
- package/dist/_contracts/index.d.ts +2 -0
- package/dist/_contracts/index.js +6 -0
- package/dist/_contracts/run-trace.d.ts +7 -0
- package/dist/_contracts/run-trace.js +9 -0
- package/dist/_contracts/runtime-types.d.ts +31 -0
- package/dist/_contracts/submission.d.ts +16 -2
- package/dist/_contracts/submission.js +23 -5
- package/dist/agents-md.d.ts +4 -1
- package/dist/agents-md.js +10 -9
- package/dist/agents-md.js.map +1 -1
- package/dist/cli.mjs +17785 -3914
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +91 -12
- package/dist/client.js +236 -77
- package/dist/client.js.map +1 -1
- package/dist/data-tools.d.ts +23 -0
- package/dist/data-tools.js +102 -13
- package/dist/data-tools.js.map +1 -1
- package/dist/file.d.ts +4 -1
- package/dist/file.js +10 -9
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/skill.d.ts +8 -6
- package/dist/skill.js +14 -14
- package/dist/skill.js.map +1 -1
- package/dist/tool.d.ts +4 -1
- package/dist/tool.js +10 -8
- package/dist/tool.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/concepts/agent-tools.md +7 -3
- package/docs/events.md +32 -9
- package/docs/networking.md +141 -0
- package/docs/quickstart.md +19 -10
- package/examples/chat-corpus.ts +85 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,17 +21,28 @@ bun add @aexhq/sdk
|
|
|
21
21
|
## First Run
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
|
-
import { AgentExecutor, Models
|
|
24
|
+
import { AgentExecutor, Models } from "@aexhq/sdk";
|
|
25
25
|
|
|
26
|
-
const aex = new AgentExecutor({
|
|
27
|
-
|
|
26
|
+
const aex = new AgentExecutor({ apiToken: process.env.AEX_API_TOKEN! });
|
|
27
|
+
|
|
28
|
+
// run() submits, waits for the run to settle, and returns the result —
|
|
29
|
+
// no manual poll loop. `provider` is derived from the model.
|
|
30
|
+
const { text, ok } = await aex.run({
|
|
31
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
32
|
+
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
33
|
+
prompt: "Summarize this repo."
|
|
28
34
|
});
|
|
29
35
|
|
|
36
|
+
console.log(ok, text);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Need the run id, live events, or downloads? Use `submit` + `stream` + `wait`:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
30
42
|
const runId = await aex.submit({
|
|
31
|
-
provider: Providers.ANTHROPIC,
|
|
32
43
|
model: Models.CLAUDE_HAIKU_4_5,
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
45
|
+
prompt: "Write the report and save outputs."
|
|
35
46
|
});
|
|
36
47
|
|
|
37
48
|
for await (const event of aex.stream(runId)) {
|
|
@@ -44,6 +55,17 @@ console.log(run.status);
|
|
|
44
55
|
await aex.download(runId, { to: "./run.zip" });
|
|
45
56
|
```
|
|
46
57
|
|
|
58
|
+
For multiple providers (e.g. subagents on a different model family), pass a
|
|
59
|
+
`credentials` map instead of `apiKey`:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
await aex.run({
|
|
63
|
+
model: Models.CLAUDE_HAIKU_4_5,
|
|
64
|
+
credentials: { anthropic: process.env.ANTHROPIC_API_KEY!, openai: process.env.OPENAI_API_KEY! },
|
|
65
|
+
prompt: "Delegate research to a subagent."
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
47
69
|
The same request can run from the CLI:
|
|
48
70
|
|
|
49
71
|
```bash
|
|
@@ -55,6 +77,57 @@ aex run \
|
|
|
55
77
|
--follow
|
|
56
78
|
```
|
|
57
79
|
|
|
80
|
+
## CLI: login, discovery, typed errors
|
|
81
|
+
|
|
82
|
+
Stop re-passing `--api-token` on every command — log in once and the token (plus
|
|
83
|
+
your default `--aex-url`) is persisted to a `0600` config file
|
|
84
|
+
(`$XDG_CONFIG_HOME/aex/config.json` or `~/.config/aex/config.json`; `%APPDATA%\aex\config.json`
|
|
85
|
+
on Windows). An explicit `--api-token` flag always overrides the stored one.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
aex login --api-token "$AEX_API_TOKEN" [--aex-url https://api.aex.dev]
|
|
89
|
+
aex whoami # no --api-token needed after login
|
|
90
|
+
aex auth status # show the resolved config (the token value is never printed)
|
|
91
|
+
aex logout # clear the stored token
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Discover the closed sets the platform accepts — no token, no network (human table
|
|
95
|
+
by default, machine JSON under `--json`):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
aex models list # canonical models + their default provider
|
|
99
|
+
aex providers list # providers + the models each serves
|
|
100
|
+
aex tools list # builtin tools (default vs opt-in, e.g. notebook_edit)
|
|
101
|
+
aex runtime-sizes list # managed runtime presets (cpus / memory / default)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Errors are typed and actionable. Every `submit()` config-validation failure throws
|
|
105
|
+
a `RunConfigValidationError` (`err.code === "RUN_CONFIG_INVALID"`) you can `catch`
|
|
106
|
+
by code; CLI failures print a JSON envelope carrying the HTTP `status`, a one-line
|
|
107
|
+
`remedy`, and the `runId` where known, and a wrong `--model`/`--provider`/
|
|
108
|
+
`--runtime-size`/`--region` gets a "did you mean?" suggestion.
|
|
109
|
+
|
|
110
|
+
## Chat over a corpus of runs
|
|
111
|
+
|
|
112
|
+
Turn a selected set of runs into a read-only chat. `createCorpusTools(client, { runIds })`
|
|
113
|
+
returns vendor-neutral, corpus-scoped read tools (`list_runs` / `get_run` /
|
|
114
|
+
`list_outputs` / `read_output` / `search_outputs`) — every tool refuses a run
|
|
115
|
+
outside the corpus. Drive them with any LLM; `examples/chat-corpus.ts` shows the
|
|
116
|
+
direct-Claude loop (`@anthropic-ai/sdk`), and the CLI ships it as a one-shot
|
|
117
|
+
command (BYOK; the importable SDK stays LLM-vendor-free):
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
aex chat --run run_<A> --run run_<B> \
|
|
121
|
+
--anthropic-api-key "$ANTHROPIC_API_KEY" \
|
|
122
|
+
--model claude-opus-4-8 \
|
|
123
|
+
--prompt "Across these runs, which produced a report.md and what's its headline finding?" \
|
|
124
|
+
--api-token "$AEX_API_TOKEN"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`AgentExecutor.searchOutputs({ runIds, filename, extension, contentType, limit })`
|
|
128
|
+
finds output files across runs and returns references (no bytes) you then
|
|
129
|
+
`readOutputText`.
|
|
130
|
+
|
|
58
131
|
## Feature Areas
|
|
59
132
|
|
|
60
133
|
- **Agent runtime:** managed autonomous runs with filesystem read/edit, grep/glob/head/tail, open web fetch/search defaults, optional notebook tools, and post-hook repair.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
|
|
3
|
+
*
|
|
4
|
+
* The envelope guards in `event-envelope.ts` operate on the coordinator
|
|
5
|
+
* {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
|
|
6
|
+
* These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
|
|
7
|
+
* snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
|
|
8
|
+
* `event.data` to the fields that event type carries, so a consumer reads
|
|
9
|
+
* `event.data.text` (etc.) without a manual cast.
|
|
10
|
+
*
|
|
11
|
+
* They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
|
|
12
|
+
* envelope guards: the narrowed `data` shape is a typing convenience, not a deep
|
|
13
|
+
* runtime validation. Parse/verify the payload fields before trusting them when
|
|
14
|
+
* the producer is untrusted.
|
|
15
|
+
*
|
|
16
|
+
* The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
|
|
17
|
+
* snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
|
|
18
|
+
* either shape while narrowing to the {@link RunEvent}-typed payloads.
|
|
19
|
+
*/
|
|
20
|
+
import type { RunEvent } from "./runtime-types.js";
|
|
21
|
+
/** A `TEXT_MESSAGE_CONTENT` run event with its assistant-text payload narrowed. */
|
|
22
|
+
export interface TextMessageRunEvent extends RunEvent {
|
|
23
|
+
readonly type: "TEXT_MESSAGE_CONTENT";
|
|
24
|
+
readonly data: {
|
|
25
|
+
readonly text: string;
|
|
26
|
+
readonly messageId?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** A `TOOL_CALL_START` run event with the tool-call id/name/args narrowed. */
|
|
30
|
+
export interface ToolCallStartRunEvent extends RunEvent {
|
|
31
|
+
readonly type: "TOOL_CALL_START";
|
|
32
|
+
readonly data: {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly arguments?: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** A `TOOL_CALL_RESULT` run event with the correlating id + result narrowed. */
|
|
39
|
+
export interface ToolCallResultRunEvent extends RunEvent {
|
|
40
|
+
readonly type: "TOOL_CALL_RESULT";
|
|
41
|
+
readonly data: {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly content?: unknown;
|
|
44
|
+
readonly isError?: boolean;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** A terminal `RUN_FINISHED` run event. */
|
|
48
|
+
export interface RunFinishedRunEvent extends RunEvent {
|
|
49
|
+
readonly type: "RUN_FINISHED";
|
|
50
|
+
readonly data: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
/** True for an assistant text event; narrows `event.data.text` to `string`. */
|
|
53
|
+
export declare function isTextMessage(event: {
|
|
54
|
+
readonly type: string;
|
|
55
|
+
}): event is TextMessageRunEvent;
|
|
56
|
+
/** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
|
|
57
|
+
export declare function isToolCallStart(event: {
|
|
58
|
+
readonly type: string;
|
|
59
|
+
}): event is ToolCallStartRunEvent;
|
|
60
|
+
/** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
|
|
61
|
+
export declare function isToolCallResult(event: {
|
|
62
|
+
readonly type: string;
|
|
63
|
+
}): event is ToolCallResultRunEvent;
|
|
64
|
+
/** True for the terminal success event; narrows `event.data` to a record. */
|
|
65
|
+
export declare function isRunFinished(event: {
|
|
66
|
+
readonly type: string;
|
|
67
|
+
}): event is RunFinishedRunEvent;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-narrowing guards over the loose {@link RunEvent} `listEvents` shape.
|
|
3
|
+
*
|
|
4
|
+
* The envelope guards in `event-envelope.ts` operate on the coordinator
|
|
5
|
+
* {@link import("./event-envelope.js").AexEvent} and return a plain `boolean`.
|
|
6
|
+
* These mirror the same AG-UI discriminants but operate on the {@link RunEvent}
|
|
7
|
+
* snapshot shape returned by `listEvents` / `RunResult.events` and NARROW
|
|
8
|
+
* `event.data` to the fields that event type carries, so a consumer reads
|
|
9
|
+
* `event.data.text` (etc.) without a manual cast.
|
|
10
|
+
*
|
|
11
|
+
* They are DISCRIMINANT-only at runtime (they test `event.type`), matching the
|
|
12
|
+
* envelope guards: the narrowed `data` shape is a typing convenience, not a deep
|
|
13
|
+
* runtime validation. Parse/verify the payload fields before trusting them when
|
|
14
|
+
* the producer is untrusted.
|
|
15
|
+
*
|
|
16
|
+
* The parameter is the minimal `{ type }` discriminant both the {@link RunEvent}
|
|
17
|
+
* snapshot and the coordinator `AexEvent` envelope satisfy, so the guards accept
|
|
18
|
+
* either shape while narrowing to the {@link RunEvent}-typed payloads.
|
|
19
|
+
*/
|
|
20
|
+
/** True for an assistant text event; narrows `event.data.text` to `string`. */
|
|
21
|
+
export function isTextMessage(event) {
|
|
22
|
+
return event.type === "TEXT_MESSAGE_CONTENT";
|
|
23
|
+
}
|
|
24
|
+
/** True for a tool-call start event; narrows `event.data` to `{ id, name }`. */
|
|
25
|
+
export function isToolCallStart(event) {
|
|
26
|
+
return event.type === "TOOL_CALL_START";
|
|
27
|
+
}
|
|
28
|
+
/** True for a tool-call result event; narrows `event.data` to `{ id, content }`. */
|
|
29
|
+
export function isToolCallResult(event) {
|
|
30
|
+
return event.type === "TOOL_CALL_RESULT";
|
|
31
|
+
}
|
|
32
|
+
/** True for the terminal success event; narrows `event.data` to a record. */
|
|
33
|
+
export function isRunFinished(event) {
|
|
34
|
+
return event.type === "RUN_FINISHED";
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=event-guards.js.map
|
|
@@ -29,3 +29,5 @@ export * from "./run-artifacts.js";
|
|
|
29
29
|
export * as operations from "./operations.js";
|
|
30
30
|
export * from "./proxy-validation.js";
|
|
31
31
|
export * from "./sse.js";
|
|
32
|
+
export { isRunFinished, isTextMessage, isToolCallResult, isToolCallStart } from "./event-guards.js";
|
|
33
|
+
export type { RunFinishedRunEvent, TextMessageRunEvent, ToolCallResultRunEvent, ToolCallStartRunEvent } from "./event-guards.js";
|
package/dist/_contracts/index.js
CHANGED
|
@@ -29,4 +29,10 @@ export * from "./run-artifacts.js";
|
|
|
29
29
|
export * as operations from "./operations.js";
|
|
30
30
|
export * from "./proxy-validation.js";
|
|
31
31
|
export * from "./sse.js";
|
|
32
|
+
// Explicit re-export (shadows the same-named `AexEvent` guards from
|
|
33
|
+
// `event-envelope.js`): the public `is*` guards narrow the loose `RunEvent`
|
|
34
|
+
// snapshot shape `listEvents` returns. An `AexEvent` is assignable to `RunEvent`,
|
|
35
|
+
// so envelope consumers keep working; the envelope-typed guards stay reachable
|
|
36
|
+
// via the direct `event-envelope.js` module.
|
|
37
|
+
export { isRunFinished, isTextMessage, isToolCallResult, isToolCallStart } from "./event-guards.js";
|
|
32
38
|
//# sourceMappingURL=index.js.map
|
|
@@ -96,6 +96,13 @@ export declare function decodeToolCalls(events: readonly TraceEvent[]): readonly
|
|
|
96
96
|
* `totalTokens` is the sum of input + output tokens. Pure.
|
|
97
97
|
*/
|
|
98
98
|
export declare function summarizeRunUsage(events: readonly TraceEvent[]): UsageSummary;
|
|
99
|
+
/**
|
|
100
|
+
* The run's final assistant text: every `TEXT_MESSAGE_CONTENT` block in stream
|
|
101
|
+
* order, concatenated. The one-line "what did the agent say" accessor over
|
|
102
|
+
* {@link decodeAssistantText} (buffered mode yields whole messages, stream mode
|
|
103
|
+
* yields token deltas — both concatenate correctly). Pure.
|
|
104
|
+
*/
|
|
105
|
+
export declare function textOf(events: readonly TraceEvent[]): string;
|
|
99
106
|
/** Decode the assistant text blocks (`TEXT_MESSAGE_CONTENT`) in stream order. Pure. */
|
|
100
107
|
export declare function decodeAssistantText(events: readonly TraceEvent[]): readonly AssistantTextEntry[];
|
|
101
108
|
/**
|
|
@@ -123,6 +123,15 @@ export function summarizeRunUsage(events) {
|
|
|
123
123
|
totalTokens: totals.inputTokens + totals.outputTokens
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* The run's final assistant text: every `TEXT_MESSAGE_CONTENT` block in stream
|
|
128
|
+
* order, concatenated. The one-line "what did the agent say" accessor over
|
|
129
|
+
* {@link decodeAssistantText} (buffered mode yields whole messages, stream mode
|
|
130
|
+
* yields token deltas — both concatenate correctly). Pure.
|
|
131
|
+
*/
|
|
132
|
+
export function textOf(events) {
|
|
133
|
+
return decodeAssistantText(events).map((entry) => entry.text).join("");
|
|
134
|
+
}
|
|
126
135
|
/** Decode the assistant text blocks (`TEXT_MESSAGE_CONTENT`) in stream order. Pure. */
|
|
127
136
|
export function decodeAssistantText(events) {
|
|
128
137
|
const out = [];
|
|
@@ -79,6 +79,37 @@ export interface RunListPage {
|
|
|
79
79
|
readonly runs: readonly RunSummary[];
|
|
80
80
|
readonly nextCursor?: string;
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Cross-run output search query (`AgentExecutor.searchOutputs`). Restrict to a
|
|
84
|
+
* corpus with `runIds`; filter by filename substring / extension / content type.
|
|
85
|
+
* The MVP composes this client-side (per-run `listOutputs` + filter) — a future
|
|
86
|
+
* server-side `GET /api/outputs/search` can back the same contract with a real
|
|
87
|
+
* cross-run index, body-only swap.
|
|
88
|
+
*/
|
|
89
|
+
export interface OutputSearchQuery {
|
|
90
|
+
/** Restrict the search to these runs (the chat corpus allow-list). */
|
|
91
|
+
readonly runIds?: readonly string[];
|
|
92
|
+
/** Case-insensitive substring match on the output filename. */
|
|
93
|
+
readonly filename?: string;
|
|
94
|
+
/** File extension, with or without a leading dot. Case-insensitive. */
|
|
95
|
+
readonly extension?: string;
|
|
96
|
+
/** Exact content type or a prefix wildcard such as `image/*`. */
|
|
97
|
+
readonly contentType?: string;
|
|
98
|
+
/** Cap the number of hits returned (default 100). */
|
|
99
|
+
readonly limit?: number;
|
|
100
|
+
}
|
|
101
|
+
/** One output-search hit — a reference only (no bytes); read with `readOutputText`. */
|
|
102
|
+
export interface OutputSearchHit {
|
|
103
|
+
readonly runId: string;
|
|
104
|
+
readonly outputId: string;
|
|
105
|
+
readonly filename?: string;
|
|
106
|
+
readonly sizeBytes?: number;
|
|
107
|
+
readonly contentType?: string;
|
|
108
|
+
}
|
|
109
|
+
/** A page of output-search hits. */
|
|
110
|
+
export interface OutputSearchPage {
|
|
111
|
+
readonly hits: readonly OutputSearchHit[];
|
|
112
|
+
}
|
|
82
113
|
/**
|
|
83
114
|
* A run event as recorded by the dashboard. Includes the `type` field
|
|
84
115
|
* that the `is*Event` type guards narrow on plus any provider payload.
|
|
@@ -143,7 +143,7 @@ export declare const Providers: {
|
|
|
143
143
|
* each region to co-located managed Postgres, object storage, run-state
|
|
144
144
|
* placement, and sandbox backing.
|
|
145
145
|
*
|
|
146
|
-
* eu-west → London (Western Europe
|
|
146
|
+
* eu-west → London (Western Europe)
|
|
147
147
|
* us-west → N. California (Western North America)
|
|
148
148
|
* ap-northeast → Seoul (Northeast Asia)
|
|
149
149
|
*
|
|
@@ -154,7 +154,7 @@ export declare const REGIONS: readonly ["eu-west", "us-west", "ap-northeast"];
|
|
|
154
154
|
export type Region = (typeof REGIONS)[number];
|
|
155
155
|
/** Symbol-style accessors for the closed region set — e.g. `Regions.EU_WEST`. */
|
|
156
156
|
export declare const Regions: {
|
|
157
|
-
/** Western Europe — London.
|
|
157
|
+
/** Western Europe — London. */
|
|
158
158
|
readonly EU_WEST: "eu-west";
|
|
159
159
|
/** Western North America — N. California. */
|
|
160
160
|
readonly US_WEST: "us-west";
|
|
@@ -324,6 +324,11 @@ export declare function requireString(input: unknown, field: string): string;
|
|
|
324
324
|
export declare function optionalString(input: unknown, field: string): string | undefined;
|
|
325
325
|
export declare function optionalEnum<const T extends readonly string[]>(input: unknown, field: string, allowed: T): T[number] | undefined;
|
|
326
326
|
export declare function optionalPositiveInt(input: unknown, field: string): number | undefined;
|
|
327
|
+
/**
|
|
328
|
+
* A finite positive NUMBER (fractional allowed — e.g. a USD amount like `2.5`), or
|
|
329
|
+
* undefined when absent. Rejects non-numbers, NaN/Infinity, and `<= 0`.
|
|
330
|
+
*/
|
|
331
|
+
export declare function optionalPositiveNumber(input: unknown, field: string): number | undefined;
|
|
327
332
|
/**
|
|
328
333
|
* Wire-level submission posted to /api/runs in the flat surface. The
|
|
329
334
|
* `prompt` is always an array internally so the worker, the audit log,
|
|
@@ -517,6 +522,15 @@ export interface RunWebhookSpec {
|
|
|
517
522
|
export interface RunLimits {
|
|
518
523
|
readonly maxConcurrentChildRuns?: number;
|
|
519
524
|
readonly maxSubagentDepth?: number;
|
|
525
|
+
/**
|
|
526
|
+
* Per-run spend cap in USD (defense-in-depth). The platform converts it to a
|
|
527
|
+
* wall-clock budget (priced compute is wall-time; BYOK provider tokens cost the
|
|
528
|
+
* platform nothing) and kills the run once it would out-spend the cap. A
|
|
529
|
+
* positive number; omitted ⇒ unbounded per-run (only the run's wall-clock
|
|
530
|
+
* `timeout` + the per-workspace spend cap apply). Only shape/positivity are
|
|
531
|
+
* validated here.
|
|
532
|
+
*/
|
|
533
|
+
readonly maxSpendUsd?: number;
|
|
520
534
|
}
|
|
521
535
|
/**
|
|
522
536
|
* Wire shape posted by the SDK and CLI. `workspaceId` is **omitted by
|
|
@@ -120,7 +120,7 @@ export const Providers = {
|
|
|
120
120
|
* each region to co-located managed Postgres, object storage, run-state
|
|
121
121
|
* placement, and sandbox backing.
|
|
122
122
|
*
|
|
123
|
-
* eu-west → London (Western Europe
|
|
123
|
+
* eu-west → London (Western Europe)
|
|
124
124
|
* us-west → N. California (Western North America)
|
|
125
125
|
* ap-northeast → Seoul (Northeast Asia)
|
|
126
126
|
*
|
|
@@ -130,7 +130,7 @@ export const Providers = {
|
|
|
130
130
|
export const REGIONS = ["eu-west", "us-west", "ap-northeast"];
|
|
131
131
|
/** Symbol-style accessors for the closed region set — e.g. `Regions.EU_WEST`. */
|
|
132
132
|
export const Regions = {
|
|
133
|
-
/** Western Europe — London.
|
|
133
|
+
/** Western Europe — London. */
|
|
134
134
|
EU_WEST: "eu-west",
|
|
135
135
|
/** Western North America — N. California. */
|
|
136
136
|
US_WEST: "us-west",
|
|
@@ -997,6 +997,19 @@ export function optionalPositiveInt(input, field) {
|
|
|
997
997
|
}
|
|
998
998
|
return input;
|
|
999
999
|
}
|
|
1000
|
+
/**
|
|
1001
|
+
* A finite positive NUMBER (fractional allowed — e.g. a USD amount like `2.5`), or
|
|
1002
|
+
* undefined when absent. Rejects non-numbers, NaN/Infinity, and `<= 0`.
|
|
1003
|
+
*/
|
|
1004
|
+
export function optionalPositiveNumber(input, field) {
|
|
1005
|
+
if (input === undefined) {
|
|
1006
|
+
return undefined;
|
|
1007
|
+
}
|
|
1008
|
+
if (typeof input !== "number" || !Number.isFinite(input) || input <= 0) {
|
|
1009
|
+
throw new Error(`${field} must be a positive finite number`);
|
|
1010
|
+
}
|
|
1011
|
+
return input;
|
|
1012
|
+
}
|
|
1000
1013
|
function parseOptionalBoundedInt(input, field, min, max) {
|
|
1001
1014
|
if (input === undefined) {
|
|
1002
1015
|
return undefined;
|
|
@@ -1198,7 +1211,7 @@ export function parseRunLimits(input) {
|
|
|
1198
1211
|
return undefined;
|
|
1199
1212
|
}
|
|
1200
1213
|
const value = requireRecord(input, "limits");
|
|
1201
|
-
const allowed = new Set(["maxConcurrentChildRuns", "maxSubagentDepth"]);
|
|
1214
|
+
const allowed = new Set(["maxConcurrentChildRuns", "maxSubagentDepth", "maxSpendUsd"]);
|
|
1202
1215
|
for (const key of Object.keys(value)) {
|
|
1203
1216
|
if (!allowed.has(key)) {
|
|
1204
1217
|
throw new Error(`limits.${key} is not an allowed field; permitted: ${[...allowed].join(", ")}`);
|
|
@@ -1206,15 +1219,20 @@ export function parseRunLimits(input) {
|
|
|
1206
1219
|
}
|
|
1207
1220
|
const maxConcurrentChildRuns = optionalPositiveInt(value.maxConcurrentChildRuns, "limits.maxConcurrentChildRuns");
|
|
1208
1221
|
const maxSubagentDepth = optionalPositiveInt(value.maxSubagentDepth, "limits.maxSubagentDepth");
|
|
1222
|
+
// maxSpendUsd is a USD amount (may be fractional, e.g. $2.50) so it is a positive
|
|
1223
|
+
// NUMBER, not a positive int. Clamping to the workspace/platform ceiling is the
|
|
1224
|
+
// resolver's job; here we only enforce shape + positivity.
|
|
1225
|
+
const maxSpendUsd = optionalPositiveNumber(value.maxSpendUsd, "limits.maxSpendUsd");
|
|
1209
1226
|
// Collapse an all-absent override (e.g. `limits: {}`) to `undefined` so it never
|
|
1210
1227
|
// lands an empty object on the request — matches sibling parsers (parseRunWebhook,
|
|
1211
1228
|
// parseEnvironment). The resolver supplies platform defaults for absent fields.
|
|
1212
|
-
if (maxConcurrentChildRuns === undefined && maxSubagentDepth === undefined) {
|
|
1229
|
+
if (maxConcurrentChildRuns === undefined && maxSubagentDepth === undefined && maxSpendUsd === undefined) {
|
|
1213
1230
|
return undefined;
|
|
1214
1231
|
}
|
|
1215
1232
|
return {
|
|
1216
1233
|
...(maxConcurrentChildRuns !== undefined ? { maxConcurrentChildRuns } : {}),
|
|
1217
|
-
...(maxSubagentDepth !== undefined ? { maxSubagentDepth } : {})
|
|
1234
|
+
...(maxSubagentDepth !== undefined ? { maxSubagentDepth } : {}),
|
|
1235
|
+
...(maxSpendUsd !== undefined ? { maxSpendUsd } : {})
|
|
1218
1236
|
};
|
|
1219
1237
|
}
|
|
1220
1238
|
export function parseRegion(input) {
|
package/dist/agents-md.d.ts
CHANGED
|
@@ -15,7 +15,10 @@ export declare class AgentsMd {
|
|
|
15
15
|
constructor(ref: AgentsMdRef | DraftAgentsMdRef, zipBytes?: Uint8Array);
|
|
16
16
|
get ref(): AgentsMdRef | DraftAgentsMdRef;
|
|
17
17
|
get isDraft(): boolean;
|
|
18
|
-
|
|
18
|
+
/** Internal: the asset id resolved on a prior submit, or undefined. */
|
|
19
|
+
get _cachedAssetId(): string | undefined;
|
|
20
|
+
/** Internal: remember the asset id resolved for this draft's bytes. */
|
|
21
|
+
_rememberAsset(assetId: string): void;
|
|
19
22
|
/**
|
|
20
23
|
* Build a draft AgentsMd from a markdown string. The SDK zips the
|
|
21
24
|
* content under the canonical filename `AGENTS.md` so the hash is a
|
package/dist/agents-md.js
CHANGED
|
@@ -15,7 +15,8 @@ import { strToU8, zipSync } from "fflate";
|
|
|
15
15
|
export class AgentsMd {
|
|
16
16
|
#ref;
|
|
17
17
|
#zipBytes;
|
|
18
|
-
|
|
18
|
+
/** Asset id cached after the first submit, so reuse skips a re-upload. */
|
|
19
|
+
#assetId;
|
|
19
20
|
constructor(ref, zipBytes) {
|
|
20
21
|
this.#ref = ref;
|
|
21
22
|
this.#zipBytes = zipBytes;
|
|
@@ -24,10 +25,15 @@ export class AgentsMd {
|
|
|
24
25
|
return this.#ref;
|
|
25
26
|
}
|
|
26
27
|
get isDraft() {
|
|
27
|
-
return this.#ref.kind === "draft"
|
|
28
|
+
return this.#ref.kind === "draft";
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
/** Internal: the asset id resolved on a prior submit, or undefined. */
|
|
31
|
+
get _cachedAssetId() {
|
|
32
|
+
return this.#assetId;
|
|
33
|
+
}
|
|
34
|
+
/** Internal: remember the asset id resolved for this draft's bytes. */
|
|
35
|
+
_rememberAsset(assetId) {
|
|
36
|
+
this.#assetId = assetId;
|
|
31
37
|
}
|
|
32
38
|
/**
|
|
33
39
|
* Build a draft AgentsMd from a markdown string. The SDK zips the
|
|
@@ -56,14 +62,9 @@ export class AgentsMd {
|
|
|
56
62
|
* `client.submit` can upload it as an asset.
|
|
57
63
|
*/
|
|
58
64
|
_takeDraftBundle() {
|
|
59
|
-
if (this.#consumed) {
|
|
60
|
-
throw new Error("AgentsMd: cannot reuse a consumed AgentsMd in submit. Build a fresh one " +
|
|
61
|
-
"via AgentsMd.fromContent(...) / AgentsMd.fromPath(...) per submit call.");
|
|
62
|
-
}
|
|
63
65
|
if (this.#ref.kind !== "draft" || !this.#zipBytes) {
|
|
64
66
|
return undefined;
|
|
65
67
|
}
|
|
66
|
-
this.#consumed = true;
|
|
67
68
|
return {
|
|
68
69
|
name: this.#ref.name,
|
|
69
70
|
contentHash: this.#ref.contentHash,
|
package/dist/agents-md.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,QAAQ;IACV,IAAI,CAAiC;IACrC,SAAS,CAAyB;IAC3C,
|
|
1
|
+
{"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"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"}
|