@workerkit/core 0.3.1 → 0.3.2
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/CHANGELOG.md +80 -0
- package/README.md +1 -1
- package/dist/descriptors/index.d.ts +1 -1
- package/dist/descriptors/index.js +1 -1
- package/dist/descriptors/index.js.map +1 -1
- package/dist/descriptors/manage.d.ts.map +1 -1
- package/dist/descriptors/manage.js +101 -16
- package/dist/descriptors/manage.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,86 @@ and the package adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.2] - 2026-09-12
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
Five manager descriptors: the fleet-operations lane. Reading the state of a
|
|
14
|
+
fleet took a crawl over `workers_list`, `worker_get` and `runs_feed`; the
|
|
15
|
+
account's headroom, a run's raw process log, fan-out and deletion were not
|
|
16
|
+
reachable from the toolset at all. The registry now ships 79 manager and 9
|
|
17
|
+
anonymous descriptors.
|
|
18
|
+
|
|
19
|
+
- **`fleet_health`** is the digest to brief from. A fleet operated from a chat
|
|
20
|
+
window rots quietly: workers installed but never deployed while their
|
|
21
|
+
schedules sit enabled, deployments paused with due times drifting into the
|
|
22
|
+
past, runs that ended by asking a question nobody saw, last runs refused at
|
|
23
|
+
the gate. One call returns the counts plus typed sections (`blocked`,
|
|
24
|
+
`notDeployed`, `overdueSchedules`, `awaitingInput`, `lastRunAttention`), each
|
|
25
|
+
row naming the worker and the fix. Paused and expired workers are counted,
|
|
26
|
+
never listed. The question preview inside `awaitingInput` is run content and
|
|
27
|
+
needs `readRuns`; the rest rides `readWorkers`.
|
|
28
|
+
- **`account_usage`** is the headroom read: plan tier, worker slots,
|
|
29
|
+
hosted-deployment slots, the wallet's spendable balance with the top-up URL to
|
|
30
|
+
hand a human, the plan's request windows and settled run spend — so a 402 on
|
|
31
|
+
`kit_install`, `worker_deploy` or a scheduled run is something an agent plans
|
|
32
|
+
around rather than discovers. Rides `readWorkers`.
|
|
33
|
+
- **`run_transcript`** reads a run's stored LLM process log, the raw record
|
|
34
|
+
behind the digest, which was readable only in the dashboard. It is opt-in per
|
|
35
|
+
deployment (`transcriptRetention`) and kept for 7 days, so the description
|
|
36
|
+
teaches the agent to read the receipt's `transcriptAvailable` first and to
|
|
37
|
+
expect 404 `no_transcript` as the normal answer on a worker that never opted
|
|
38
|
+
in. Rides `readRuns`.
|
|
39
|
+
- **`run_bulk`** fans one prompt out across up to 20 workers in one call, each
|
|
40
|
+
named by `workerId` (preferred) or its deprecated `tokenId`, on a window of
|
|
41
|
+
its own (2 calls a minute, 20 an hour per account). Like `worker_clone_bulk`
|
|
42
|
+
it is not atomic and reports per item — and unlike it, a miss never aborts
|
|
43
|
+
the batch: an unknown id, a missing deployment or a cap already hit lands on
|
|
44
|
+
that item and the loop goes on. A Skipped receipt counts as a success (a run
|
|
45
|
+
was minted; its `skipReason` says why it did not start). Rides `runWorkers`.
|
|
46
|
+
- **`worker_delete`** removes a worker. Deleting existed only in the WorkerKit
|
|
47
|
+
dashboard, so an agent could create workers — `kit_install`, `worker_clone` —
|
|
48
|
+
and never remove one, which also left `kit_install`'s 402 worker-cap wall
|
|
49
|
+
with no fix an agent could apply. It is permanent and not reversible by any
|
|
50
|
+
call: the key stops working, the schedules stop, and the instruction, memory,
|
|
51
|
+
deployment and delivery destinations go. Two things the description teaches
|
|
52
|
+
because an agent gets them wrong by default: deleting an orchestrator deletes
|
|
53
|
+
its sub-workers too (`subWorkersDeleted` says how many), and
|
|
54
|
+
`worker_set_enabled` with `enabled:false` is the reversible thing to reach
|
|
55
|
+
for when someone says "stop" or "turn off". Run receipts survive; the freed
|
|
56
|
+
slot is the fix for 402 `limit_exceeded`. Requires the new `deleteWorkers`
|
|
57
|
+
scope.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **`workers_list`** takes filters — `status`, `deployed`, `readiness`, `q` —
|
|
62
|
+
and answers `totalWorkers` (the unfiltered count, so an empty page is
|
|
63
|
+
readable). Every row now carries `readiness`, and `lastRun` carries
|
|
64
|
+
`skipReason` and `errorCode`.
|
|
65
|
+
- **`runs_feed`** and **`worker_runs`**: `awaitingInput` joined the status
|
|
66
|
+
filter and the outcome vocabulary. The server always accepted it; the closed
|
|
67
|
+
enum here did not, which made the questions a fleet was waiting on
|
|
68
|
+
unreachable from the feed.
|
|
69
|
+
- **`budget_get`** and **`budget_set`**: `maxConcurrentRuns` is set by the
|
|
70
|
+
account's plan — Free 5, Pro 20, Team 50, Enterprise uncapped — rather than
|
|
71
|
+
fixed at 1, and stays absent from `budget_set` because raising it is an
|
|
72
|
+
upgrade. It bounds runs started on demand; **`schedule_create`** and
|
|
73
|
+
**`schedule_update`** now say that a schedule never overlaps itself whatever
|
|
74
|
+
the plan allows, and **`worker_run`** points to `run_bulk` for fan-out.
|
|
75
|
+
- **`worker_set_enabled`** now names itself as the reversible half of the pair,
|
|
76
|
+
so the permanent one is never picked by accident, and spells out that
|
|
77
|
+
stopping an orchestrator cascades to its sub-workers while re-enabling brings
|
|
78
|
+
back only the parent.
|
|
79
|
+
- **`kit_install`** names `worker_delete` as the second way out of the 402
|
|
80
|
+
worker-cap wall, to be proposed only with the person's agreement.
|
|
81
|
+
|
|
82
|
+
### Note
|
|
83
|
+
|
|
84
|
+
`worker_delete` needs the new `deleteWorkers` scope. Like every scope younger
|
|
85
|
+
than the manager-key surface, a key minted before it existed does not carry
|
|
86
|
+
it — including one minted with "all" — so a 403 there is fixed by an account
|
|
87
|
+
admin re-scoping the key, never by retrying.
|
|
88
|
+
|
|
9
89
|
## [0.3.1] - 2026-09-11
|
|
10
90
|
|
|
11
91
|
### Added
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
8
|
The shareable [WorkerKit](https://workerkit.ai) surface: an HTTP API client, the
|
|
9
|
-
declarative tool-descriptor registry (
|
|
9
|
+
declarative tool-descriptor registry (79 authenticated fleet-management tools +
|
|
10
10
|
9 anonymous kits-directory tools), and the single wire-execution path that turns
|
|
11
11
|
a descriptor plus parameters into exactly one upstream request.
|
|
12
12
|
|
|
@@ -3,7 +3,7 @@ export type { HttpMethod, ToolAnnotations, ToolDescriptor } from "./types.js";
|
|
|
3
3
|
export { manageDescriptors } from "./manage.js";
|
|
4
4
|
export { directoryDescriptors, kitDetailData, kitDetailFooter, kitListData, listFooter, publisherPageData, publisherPageFooter, } from "./directory.js";
|
|
5
5
|
import type { ToolDescriptor } from "./types.js";
|
|
6
|
-
/** Every descriptor this package ships —
|
|
6
|
+
/** Every descriptor this package ships — 79 manager + 9 anonymous. */
|
|
7
7
|
export declare const allDescriptors: readonly ToolDescriptor[];
|
|
8
8
|
/** Look a descriptor up by its tool name. */
|
|
9
9
|
export declare function byName(name: string): ToolDescriptor | undefined;
|
|
@@ -3,7 +3,7 @@ export { manageDescriptors } from "./manage.js";
|
|
|
3
3
|
export { directoryDescriptors, kitDetailData, kitDetailFooter, kitListData, listFooter, publisherPageData, publisherPageFooter, } from "./directory.js";
|
|
4
4
|
import { manageDescriptors } from "./manage.js";
|
|
5
5
|
import { directoryDescriptors } from "./directory.js";
|
|
6
|
-
/** Every descriptor this package ships —
|
|
6
|
+
/** Every descriptor this package ships — 79 manager + 9 anonymous. */
|
|
7
7
|
export const allDescriptors = [
|
|
8
8
|
...manageDescriptors,
|
|
9
9
|
...directoryDescriptors,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,EACP,MAAM,GACP,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAA8B;IACvD,GAAG,iBAAiB;IACpB,GAAG,oBAAoB;CACxB,CAAC;AAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["export {\n CREATE,\n DELETE,\n READ_ONLY,\n TRIGGER,\n UPDATE,\n} from \"./types.js\";\nexport type { HttpMethod, ToolAnnotations, ToolDescriptor } from \"./types.js\";\n\nexport { manageDescriptors } from \"./manage.js\";\nexport {\n directoryDescriptors,\n kitDetailData,\n kitDetailFooter,\n kitListData,\n listFooter,\n publisherPageData,\n publisherPageFooter,\n} from \"./directory.js\";\n\nimport type { ToolDescriptor } from \"./types.js\";\nimport { manageDescriptors } from \"./manage.js\";\nimport { directoryDescriptors } from \"./directory.js\";\n\n/** Every descriptor this package ships —
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/descriptors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,EACP,MAAM,GACP,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAA8B;IACvD,GAAG,iBAAiB;IACpB,GAAG,oBAAoB;CACxB,CAAC;AAEF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["export {\n CREATE,\n DELETE,\n READ_ONLY,\n TRIGGER,\n UPDATE,\n} from \"./types.js\";\nexport type { HttpMethod, ToolAnnotations, ToolDescriptor } from \"./types.js\";\n\nexport { manageDescriptors } from \"./manage.js\";\nexport {\n directoryDescriptors,\n kitDetailData,\n kitDetailFooter,\n kitListData,\n listFooter,\n publisherPageData,\n publisherPageFooter,\n} from \"./directory.js\";\n\nimport type { ToolDescriptor } from \"./types.js\";\nimport { manageDescriptors } from \"./manage.js\";\nimport { directoryDescriptors } from \"./directory.js\";\n\n/** Every descriptor this package ships — 79 manager + 9 anonymous. */\nexport const allDescriptors: readonly ToolDescriptor[] = [\n ...manageDescriptors,\n ...directoryDescriptors,\n];\n\nconst byNameIndex = new Map(allDescriptors.map((d) => [d.name, d]));\n\n/** Look a descriptor up by its tool name. */\nexport function byName(name: string): ToolDescriptor | undefined {\n return byNameIndex.get(name);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/descriptors/manage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/descriptors/manage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAi7D7F,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAgFtD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The
|
|
1
|
+
// The 79 authenticated fleet-management tools, as pure descriptors. The
|
|
2
2
|
// descriptions ARE the product surface: they are served verbatim to MCP
|
|
3
3
|
// clients (and any future CLI help), so every contract nuance an agent must
|
|
4
4
|
// not get wrong is taught here.
|
|
@@ -37,17 +37,42 @@ const getKeyInfo = {
|
|
|
37
37
|
const listWorkers = {
|
|
38
38
|
name: "workers_list",
|
|
39
39
|
title: "List Workers",
|
|
40
|
-
description: "List
|
|
40
|
+
description: "List the AI workers on this account with live status: title, avatar, status (active|paused|expired), isEnabled, expiresAt, readiness (status ready|blocked with the actionable issues — the same block worker_get carries), deployment (null = this worker is NOT on the hosted runtime and will never run, whatever readiness says; worker_deploy fixes that), lastRun (the newest SETTLED run: runId, outcome succeeded|attention|failed|awaitingInput|skipped|canceled, skipReason, errorCode — in-flight runs never appear here), schedule rollup (total/enabled/nextRunUtc), and live state (isRunning, inFlightRuns, currentRunId — poll run_get with currentRunId to watch it). FILTERS, all optional and ANDed: status, deployed, readiness, q (title substring); an unknown status/readiness value is a 400 invalid_filter, never an empty page. totalWorkers is the count BEFORE filtering: 0 means nothing is installed on this account yet (shortlist a kit with kits_search on the Directory server, kit_install it with deploy:true), non-zero with an empty workers[] means the filter matched nothing. For 'what is wrong with this fleet' call fleet_health instead of scanning this list. Compute elapsed/next-run times against the response's serverTimeUtc, never your own clock. IMPORTANT: lastRun.resultText is the report the worker itself wrote and requires the manager key to hold the readRuns scope IN ADDITION to readWorkers — with readWorkers only it is null, which does NOT mean the run produced no report; check your key's scopes before concluding anything from a null. Scope model for every tool here: a 403 OPERATION_NOT_ALLOWED names the missing scope — the key must be re-minted with broader scopes by an account admin at https://workerkit.ai (do not retry the call).",
|
|
41
41
|
auth: "manager",
|
|
42
42
|
method: "get",
|
|
43
|
-
schema: {
|
|
43
|
+
schema: {
|
|
44
|
+
status: z.enum(["active", "paused", "expired"]).optional().describe("Only workers in this lifecycle state. paused = stopped with worker_set_enabled; expired = the key's expiry passed. Omit for all."),
|
|
45
|
+
deployed: z.boolean().optional().describe("true = only workers on the hosted runtime (the ones that can run); false = only workers without a deployment. Omit for both."),
|
|
46
|
+
readiness: z.enum(["ready", "blocked"]).optional().describe("ready = configuration lets it run hosted; blocked = something actionable is missing (an app connection, an instruction, an identity). Omit for both."),
|
|
47
|
+
q: z.string().max(100).optional().describe("Case-insensitive substring of the worker's title."),
|
|
48
|
+
},
|
|
44
49
|
path: API,
|
|
45
50
|
annotations: READ_ONLY,
|
|
46
51
|
};
|
|
52
|
+
const fleetHealth = {
|
|
53
|
+
name: "fleet_health",
|
|
54
|
+
title: "Fleet Health",
|
|
55
|
+
description: "The fleet's rot in ONE call — the digest to brief from instead of crawling workers_list + worker_get + runs_feed: counts (workers, active, paused, expired, runsInFlight, and one per section: blocked, notDeployed, overdueSchedules, awaitingInput, lastRunAttention) plus five typed sections, each row naming the worker (workerId, tokenId, title) and what to do. blocked[] = active workers whose readiness is blocked, with issues[] (app_not_connected → app_connect on the worker's operator or the human at the dashboard; no_instruction → instruction_set; no_identity → the dashboard). notDeployed[] = active workers with NO hosted deployment: they fire no schedule and refuse worker_run with not_deployed, however ready they look — enabledSchedules > 0 there is a schedule that will never run until worker_deploy; readiness says whether deploying is enough. overdueSchedules[] = deployed workers whose earliest enabled schedule was due more than 15 minutes ago and was never claimed (nextRunUtc, overdueMinutes, deploymentStatus — Paused explains it by itself: deployment_update with resume). awaitingInput[] = runs that ended by ASKING their owner and are still waiting (questionId, runId, askedAtUtc, expiresAtUtc, chainDepth, and question — a 300-char preview that needs readRuns and is NULL without it: that null is a scope gap, not an empty question; run_question has the full text and options, run_answer takes the runId). lastRunAttention[] = active workers whose newest settled run was failed (errorCode), attention (succeeded with friction — denials, tool errors, reported issues) or skipped (skipReason says why; InsufficientCredits means the wallet, TokenDisabled/DailyRunCap/FleetSpendCap name themselves). Paused and expired workers are COUNTED, never listed: stopping a worker is a decision, not rot. Empty sections are the healthy answer. Measure every age against serverTimeUtc. Requires the readWorkers scope.",
|
|
56
|
+
auth: "manager",
|
|
57
|
+
method: "get",
|
|
58
|
+
schema: {},
|
|
59
|
+
path: `${API}/fleet/health`,
|
|
60
|
+
annotations: READ_ONLY,
|
|
61
|
+
};
|
|
62
|
+
const accountUsage = {
|
|
63
|
+
name: "account_usage",
|
|
64
|
+
title: "Account Usage",
|
|
65
|
+
description: "The account's headroom — read it BEFORE an install, a deploy or a run rather than discovering a 402 afterwards. Returns operator (the one kit_install targets by default; limits are per operator), plan (tier free|pro|team|enterprise, complimentaryUntilUtc when the tier is a time-boxed invite grant), workers {used, max, remaining} (remaining 0 → kit_install, worker_clone and re-enabling a stopped worker answer 402 limit_exceeded; worker_delete frees a slot, the plan is the other way out), hostedWorkers {used, max, remaining} (the worker_deploy cap; suspended deployments do not count), wallet {spendableBalanceUsd, promoRemainingUsd, promoExpiresAtUtc, topUpUrl} (hosted runs meter from spendableBalanceUsd — at zero worker_deploy answers 402 wallet_required and scheduled runs are refused with skipReason InsufficientCredits; AN AGENT CANNOT TOP IT UP, hand the human topUpUrl), requests {daily, hourly, monthly} each {limit, used, remaining, resetsAt} (the plan's data-plane windows — the calls workers make to apps; limit 0 means that window is DISABLED on this plan, not exhausted), and spend {todayUsd, thisMonthUsd, reservedInFlightUsd} (settled run spend plus what running runs hold; null while hosted runs are not enabled for the environment). The account's OWN ceilings live on fleet_budget_get, not here. 404 not_found means the account has no active operator. Requires the readWorkers scope.",
|
|
66
|
+
auth: "manager",
|
|
67
|
+
method: "get",
|
|
68
|
+
schema: {},
|
|
69
|
+
path: `${API}/account/usage`,
|
|
70
|
+
annotations: READ_ONLY,
|
|
71
|
+
};
|
|
47
72
|
const getWorker = {
|
|
48
73
|
name: "worker_get",
|
|
49
74
|
title: "Get Worker",
|
|
50
|
-
description: "One worker in full: everything workers_list shows
|
|
75
|
+
description: "One worker in full: everything workers_list shows (including readiness: status ready|blocked with actionable issues — worker_inactive, no_identity, app_not_connected incl. candidateProviders, no_instruction) plus timeZoneId, maxRunsPerDay, kit provenance (templateId/slug/name), hasInstruction, isProtected, jobSentence, apps[] (every app the worker has enabled with connection connected|needs_connection|unknown and the providers serving it — the per-worker view of apps_list; an app at needs_connection is fixed with app_connect on the worker's operator or on the dashboard), deployment (status + modelSlug, or NULL WHEN THE WORKER IS NOT DEPLOYED — an undeployed worker never runs, whatever readiness says, because readiness judges configuration and deployment is what puts it on the runtime; fix with worker_deploy), and 30-day activity (runs by outcome, success rate, cost; null while hosted runs are not enabled for the environment).",
|
|
51
76
|
auth: "manager",
|
|
52
77
|
method: "get",
|
|
53
78
|
schema: {
|
|
@@ -61,7 +86,7 @@ const getWorker = {
|
|
|
61
86
|
const runWorker = {
|
|
62
87
|
name: "worker_run",
|
|
63
88
|
title: "Run Worker Now",
|
|
64
|
-
description: "Trigger the worker to run now (recorded as an API-triggered run, attributed to the manager key's minter). The response is the minted run's RECEIPT — read status before assuming it ran: policy rejections (kill switch, usage window, daily run/spend cap, concurrency, wallet credits, readiness, or a rejected BYOK provider key) come back as HTTP 200 with status Skipped and a skipReason telling the story; that is a normal receipt, NOT an error. Most skips clear on their own (a cap resets, concurrency frees up, credits top up) — but skipReason 'ByokKeyInvalid' / errorCode 'byok_key_invalid' means the ACCOUNT's own model-provider API key was rejected by the provider, arrives with errorDetail null (no prose), and is owner-fixable ONLY: never retry it, report it to the human so they can re-add or remove the key. Structural refusals are 409 (not_deployed, deployment_paused, deployment_suspended, model_unavailable) and 404 for an unknown worker; run-endpoint errors use the {error, message} envelope where error IS the snake_case code. prompt = what to do THIS run; omit it and the worker runs on its standing instructions. Rate limit: 30 run-triggers per minute per ACCOUNT (all of this account's keys and clients share it; other accounts do not affect you). On a 429 back off for the Retry-After — never tighten a loop in response." +
|
|
89
|
+
description: "Trigger the worker to run now (recorded as an API-triggered run, attributed to the manager key's minter). The response is the minted run's RECEIPT — read status before assuming it ran: policy rejections (kill switch, usage window, daily run/spend cap, concurrency, wallet credits, readiness, or a rejected BYOK provider key) come back as HTTP 200 with status Skipped and a skipReason telling the story; that is a normal receipt, NOT an error. Most skips clear on their own (a cap resets, concurrency frees up, credits top up) — but skipReason 'ByokKeyInvalid' / errorCode 'byok_key_invalid' means the ACCOUNT's own model-provider API key was rejected by the provider, arrives with errorDetail null (no prose), and is owner-fixable ONLY: never retry it, report it to the human so they can re-add or remove the key. Structural refusals are 409 (not_deployed, deployment_paused, deployment_suspended, model_unavailable) and 404 for an unknown worker; run-endpoint errors use the {error, message} envelope where error IS the snake_case code. prompt = what to do THIS run; omit it and the worker runs on its standing instructions. Rate limit: 30 run-triggers per minute per ACCOUNT (all of this account's keys and clients share it; other accounts do not affect you). On a 429 back off for the Retry-After — never tighten a loop in response. To fan one prompt across many workers, run_bulk takes up to 20 in one call on a window of its own. Runs in flight per worker are bounded by the account's plan (Free 5, Pro 20, Team 50); at that limit this answers a Skipped receipt with skipReason ConcurrencyLimit." +
|
|
65
90
|
RUNTIME_NOTE,
|
|
66
91
|
auth: "manager",
|
|
67
92
|
method: "post",
|
|
@@ -74,6 +99,29 @@ const runWorker = {
|
|
|
74
99
|
bodyBuilder: (params) => ({ prompt: params.prompt, modelSlug: params.modelSlug }),
|
|
75
100
|
annotations: TRIGGER,
|
|
76
101
|
};
|
|
102
|
+
const runWorkersBulk = {
|
|
103
|
+
name: "run_bulk",
|
|
104
|
+
title: "Run Workers in Bulk",
|
|
105
|
+
description: "Run several workers now in ONE call — a prompt fanned out across a fleet without spending the single trigger's 30/min budget one worker at a time. Up to 20 workers per call, each named by workerId (preferred) or its deprecated tokenId (the GUID wins when both are sent), each with its own optional prompt and modelSlug. IT IS NOT ATOMIC AND IT DOES NOT STOP: every worker passes the mint gauntlet on its own, so an unknown id, a missing deployment or a cap already hit is reported on THAT item (success false, errorCode, error) and the loop goes on to the next — a stale id in a fan-out never discards the nineteen runs that were fine. A SKIPPED RECEIPT IS A SUCCESS HERE: a run was minted and its status/skipReason say why it did not start, so read items[] and never the status code or minted alone. Each successful item carries runId, status, skipReason and errorCode; run_events and run_get take the runId from there. Recorded as API-triggered runs, attributed to the manager key's minter. Own window: 2 calls per minute and 20 per hour per ACCOUNT, on top of the surface windows. Requires the runWorkers scope." +
|
|
106
|
+
RUNTIME_NOTE,
|
|
107
|
+
auth: "manager",
|
|
108
|
+
method: "post",
|
|
109
|
+
schema: {
|
|
110
|
+
workers: z
|
|
111
|
+
.array(z.object({
|
|
112
|
+
workerId: z.string().uuid().optional().describe("The worker's stable public id, as every response that names a worker returns it (preferred). Send this or tokenId."),
|
|
113
|
+
tokenId: z.number().int().min(1).optional().describe("The worker's deprecated numeric token ID. workerId wins when both are sent."),
|
|
114
|
+
prompt: z.string().max(8000).optional().describe("What THIS worker should do on this run (≤8000 chars). Omit to run its standing instructions unchanged."),
|
|
115
|
+
modelSlug: z.string().max(64).optional().describe("One-off model override for this worker's run (≤64 chars). Omit to use its configured model."),
|
|
116
|
+
}))
|
|
117
|
+
.min(1)
|
|
118
|
+
.max(20)
|
|
119
|
+
.describe("One entry per worker to run, 1–20 of them; each needs a workerId or a tokenId."),
|
|
120
|
+
},
|
|
121
|
+
path: `${API}/runs/bulk`,
|
|
122
|
+
bodyBuilder: (params) => ({ workers: params.workers }),
|
|
123
|
+
annotations: TRIGGER,
|
|
124
|
+
};
|
|
77
125
|
// ─── Fleet-wide run reads ───────────────────────────────────────────────────
|
|
78
126
|
// The two calls that watch a WHOLE fleet without fanning out per worker. Both are
|
|
79
127
|
// account-scoped by the key itself, so neither takes a worker id, and both are
|
|
@@ -81,7 +129,7 @@ const runWorker = {
|
|
|
81
129
|
const runsFeed = {
|
|
82
130
|
name: "runs_feed",
|
|
83
131
|
title: "Account Run Feed",
|
|
84
|
-
description: "Every worker's runs in ONE account-wide feed, newest first — THE fleet-watching call. When you are minding many workers, call this instead of looping workers_list or worker_runs per worker. Each row is a scan line: runId, workerId, tokenTitle, status, outcome (running|succeeded|attention|failed|skipped|canceled — 'attention' is a SUCCEEDED run that hit friction, i.e. firewall denials, tool errors or reported issues, so report it apart from a clean success), skipReason, errorCode, triggerKind, scheduleTitle, timings, the friction counts (toolCalls, firewallDenials, toolErrors, issueCount, hasBlockerIssue), and one line of what the run did in summary + summarySource ('distilled' = a condensed record of what the run ACTUALLY did; 'report' = the worker's OWN closing account; 'error'/'skipped'/'activity' = the machine's own words — these are not equally reliable, so say which one you are quoting). Carries NO cost and NO token counts by design: read those from run_get on the one run that matters. Cursor-paged, never page-numbered — scroll by passing the previous response's nextCursor back as cursor (hasMore says whether another page exists), and re-fetch with NO cursor to refresh the head; there is deliberately no total count. A cursor we did not issue is a 400 invalid_cursor — drop it and reload the head. An unknown status is a 400 invalid_status, never a silently ignored filter. Requires the readRuns scope." +
|
|
132
|
+
description: "Every worker's runs in ONE account-wide feed, newest first — THE fleet-watching call. When you are minding many workers, call this instead of looping workers_list or worker_runs per worker. Each row is a scan line: runId, workerId, tokenTitle, status, outcome (running|succeeded|attention|failed|awaitingInput|skipped|canceled — 'attention' is a SUCCEEDED run that hit friction, i.e. firewall denials, tool errors or reported issues, so report it apart from a clean success; 'awaitingInput' is a run that ended by asking its owner a question — waiting on a person, not broken: run_question reads it, run_answer answers it, and fleet_health lists every open one), skipReason, errorCode, triggerKind, scheduleTitle, timings, the friction counts (toolCalls, firewallDenials, toolErrors, issueCount, hasBlockerIssue), and one line of what the run did in summary + summarySource ('distilled' = a condensed record of what the run ACTUALLY did; 'report' = the worker's OWN closing account; 'error'/'skipped'/'activity' = the machine's own words — these are not equally reliable, so say which one you are quoting). Carries NO cost and NO token counts by design: read those from run_get on the one run that matters. Cursor-paged, never page-numbered — scroll by passing the previous response's nextCursor back as cursor (hasMore says whether another page exists), and re-fetch with NO cursor to refresh the head; there is deliberately no total count. A cursor we did not issue is a 400 invalid_cursor — drop it and reload the head. An unknown status is a 400 invalid_status, never a silently ignored filter. Requires the readRuns scope." +
|
|
85
133
|
RUNTIME_NOTE,
|
|
86
134
|
auth: "manager",
|
|
87
135
|
method: "get",
|
|
@@ -92,9 +140,9 @@ const runsFeed = {
|
|
|
92
140
|
// two composite values.
|
|
93
141
|
status: z.enum([
|
|
94
142
|
"pending", "dispatched", "running", "succeeded", "failed",
|
|
95
|
-
"timedOut", "budgetExceeded", "skipped", "canceled",
|
|
143
|
+
"timedOut", "budgetExceeded", "awaitingInput", "skipped", "canceled",
|
|
96
144
|
"settled", "all",
|
|
97
|
-
]).optional().describe("Filter to one run status. 'settled' is the composite for every terminal outcome (everything not in flight) — use it for a logbook, and fleet_pulse for what is running. 'all' is an explicit no-op. Omit for all runs."),
|
|
145
|
+
]).optional().describe("Filter to one run status. 'awaitingInput' = runs waiting on their owner's answer (terminal for money, open for the person). 'settled' is the composite for every terminal outcome (everything not in flight, awaitingInput included) — use it for a logbook, and fleet_pulse for what is running. 'all' is an explicit no-op. Omit for all runs."),
|
|
98
146
|
cursor: z.string().optional().describe("Opaque cursor from the previous response's nextCursor — fetches the next (older) page. Omit to read the head of the feed."),
|
|
99
147
|
limit: z.number().int().min(1).max(100).default(20).describe("Rows per page (1–100)."),
|
|
100
148
|
},
|
|
@@ -127,8 +175,8 @@ const listRuns = {
|
|
|
127
175
|
// read as the real subset. These are the WorkerRunStatus names verbatim.
|
|
128
176
|
status: z.enum([
|
|
129
177
|
"pending", "dispatched", "running", "succeeded", "failed",
|
|
130
|
-
"timedOut", "budgetExceeded", "skipped", "canceled",
|
|
131
|
-
]).optional().describe("Filter by run status. Omit for all runs."),
|
|
178
|
+
"timedOut", "budgetExceeded", "awaitingInput", "skipped", "canceled",
|
|
179
|
+
]).optional().describe("Filter by run status ('awaitingInput' = waiting on the owner's answer). Omit for all runs."),
|
|
132
180
|
page: z.number().int().min(1).default(1).describe("1-based page number."),
|
|
133
181
|
pageSize: z.number().int().min(1).max(100).default(20).describe("Results per page (max 100)."),
|
|
134
182
|
fromUtc: z.string().optional().describe(`Only runs started at/after this time. ${UTC_HINT}`),
|
|
@@ -175,6 +223,20 @@ const getRunEvents = {
|
|
|
175
223
|
},
|
|
176
224
|
annotations: READ_ONLY,
|
|
177
225
|
};
|
|
226
|
+
const getRunTranscript = {
|
|
227
|
+
name: "run_transcript",
|
|
228
|
+
title: "Get Run Transcript",
|
|
229
|
+
description: "The run's stored LLM process log — the raw record behind the digest: every model turn and tool call, as the worker made them. EXPECT 404 no_transcript MORE OFTEN THAN 200: transcripts are OFF by default and kept for 7 days, so this answers only when the worker's deployment had transcriptRetention on before the run happened and the window has not elapsed; a worker installed from a protected kit never stores one. The run receipt's transcriptAvailable (run_get) says whether this returns 200 — branch on that rather than calling this to find out. For WHAT a run did, the digest on the receipt is the intended handoff; reach for the transcript when the digest is not enough: a run that misbehaved, a tool call to inspect, a denial to trace. Up to 1 MB. Requires the readRuns scope." +
|
|
230
|
+
RUNTIME_NOTE,
|
|
231
|
+
auth: "manager",
|
|
232
|
+
method: "get",
|
|
233
|
+
schema: {
|
|
234
|
+
runId: z.string().uuid().describe(RUN_ID_HINT),
|
|
235
|
+
},
|
|
236
|
+
path: (params) => `${API}/runs/${params.runId}/transcript`,
|
|
237
|
+
paramFilter: () => ({}),
|
|
238
|
+
annotations: READ_ONLY,
|
|
239
|
+
};
|
|
178
240
|
// ─── Two-way runs (ask / answer) ────────────────────────────────────────────
|
|
179
241
|
// A run that needs something from its owner ENDS by asking (status AwaitingInput)
|
|
180
242
|
// rather than blocking on a human while holding a request slot and a wallet
|
|
@@ -334,12 +396,17 @@ const SCHEDULE_TYPE_HINT = "EveryNMinutes (intervalValue 1–1440), EveryNHours
|
|
|
334
396
|
// is in `feature`, while `error` holds the literal string "feature_gated" — the
|
|
335
397
|
// one place on this surface where `error` is not the code.
|
|
336
398
|
const SCHEDULE_GATE_HINT = " Two plan walls return 402 {error:'feature_gated', feature, upgradeTrigger, message}: feature 'schedule_cadence' means minute-based schedules are not in this plan (use EveryNHours or DailyAtTime), and 'schedule_count' means the worker is at its recurring-schedule cap (a OneShot is never counted). Both are terminal — do NOT retry; either pick an allowed cadence or tell the human to upgrade.";
|
|
399
|
+
// The plan's per-worker concurrency is for runs started on demand. A schedule
|
|
400
|
+
// never overlaps itself, whatever the plan allows: two copies of the same
|
|
401
|
+
// scheduled job side by side duplicate its side effects.
|
|
402
|
+
const SCHEDULE_OVERLAP_NOTE = " A schedule never overlaps itself: a fire that finds any run of the worker in flight lands as a Skipped receipt (skipReason ConcurrencyLimit) whatever the plan's per-worker concurrency allows — space the schedule wider than a run takes. Runs started on demand may run alongside a scheduled one, up to the plan's limit.";
|
|
337
403
|
const createSchedule = {
|
|
338
404
|
name: "schedule_create",
|
|
339
405
|
title: "Create Schedule",
|
|
340
406
|
description: "Create a schedule for the worker. Per-type required fields: " + SCHEDULE_TYPE_HINT +
|
|
341
407
|
" Omit timeZoneId to follow the worker's own time zone (the normal case). Requires the manageSchedules scope." +
|
|
342
|
-
SCHEDULE_GATE_HINT
|
|
408
|
+
SCHEDULE_GATE_HINT +
|
|
409
|
+
SCHEDULE_OVERLAP_NOTE,
|
|
343
410
|
auth: "manager",
|
|
344
411
|
method: "post",
|
|
345
412
|
schema: {
|
|
@@ -368,7 +435,7 @@ const updateSchedule = {
|
|
|
368
435
|
name: "schedule_update",
|
|
369
436
|
title: "Update Schedule",
|
|
370
437
|
description: "Edit a schedule (partial — omitted fields stay unchanged; timeZoneId='' clears the override so the schedule follows the worker's zone again). nextRunUtc is recomputed on every edit. Per-type field rules: " +
|
|
371
|
-
SCHEDULE_TYPE_HINT + " Requires manageSchedules." + SCHEDULE_GATE_HINT,
|
|
438
|
+
SCHEDULE_TYPE_HINT + " Requires manageSchedules." + SCHEDULE_GATE_HINT + SCHEDULE_OVERLAP_NOTE,
|
|
372
439
|
auth: "manager",
|
|
373
440
|
method: "patch",
|
|
374
441
|
schema: {
|
|
@@ -639,7 +706,7 @@ const restoreInstructionVersion = {
|
|
|
639
706
|
const setWorkerEnabled = {
|
|
640
707
|
name: "worker_set_enabled",
|
|
641
708
|
title: "Start or Stop Worker",
|
|
642
|
-
description: "Start (enabled=true) or stop (enabled=false) a worker. Stopping pauses the WHOLE worker: its own API key stops working AND its schedules stop firing; re-enabling restores both. Returns {tokenId, isEnabled}. Idempotent. Requires the manageState scope.",
|
|
709
|
+
description: "Start (enabled=true) or stop (enabled=false) a worker. Stopping pauses the WHOLE worker: its own API key stops working AND its schedules stop firing; re-enabling restores both. THIS IS THE REVERSIBLE ONE — reach for it whenever someone says stop, pause, turn off or disable; worker_delete is permanent and nothing undoes it. Two things about stopping an ORCHESTRATOR that the response does not tell you: it CASCADES to that worker's sub-workers (children and grandchildren), and re-enabling the parent brings back ONLY the parent — each sub-worker needs its own worker_set_enabled(tokenId, true), so check workers_list afterwards rather than assuming the fleet came back. And re-enabling consumes a worker slot: at the plan's worker cap it is refused with 402 limit_exceeded, so a worker stopped before a downgrade can be stuck stopped until the owner upgrades or deletes another worker. Returns {tokenId, isEnabled}. Idempotent. Requires the manageState scope.",
|
|
643
710
|
auth: "manager",
|
|
644
711
|
method: "post",
|
|
645
712
|
schema: {
|
|
@@ -650,6 +717,19 @@ const setWorkerEnabled = {
|
|
|
650
717
|
bodyBuilder: (params) => ({ enabled: params.enabled }),
|
|
651
718
|
annotations: UPDATE,
|
|
652
719
|
};
|
|
720
|
+
const deleteWorker = {
|
|
721
|
+
name: "worker_delete",
|
|
722
|
+
title: "Delete Worker",
|
|
723
|
+
description: "Delete a worker PERMANENTLY. Not reversible by any call, on any surface: its own pe_ key stops working immediately (an agent holding it starts failing), its schedules stop firing, its instruction, memory, deployment and delivery destinations go with it, and it disappears from this API, MCP, the CLI and the dashboard alike. TO STOP A WORKER YOU MIGHT WANT BACK, USE worker_set_enabled WITH enabled:false — that pauses the key and the schedules together and is reversible (with two caveats it states: stopping cascades to sub-workers and re-enabling brings back only the worker you name, and re-enabling is refused with 402 at the plan's worker cap); THIS one cannot be undone at all, so confirm with the person before calling it, never infer it from 'get rid of', 'turn off' or 'stop'. THE SURPRISE: deleting an orchestrator DELETES ITS SUB-WORKERS TOO (children and grandchildren — a dead orchestrator must never leave live workers behind), and the response's subWorkersDeleted says how many went with it; report that number, because those workers had their own jobs. What SURVIVES: the apps stay connected for every other worker on the operator, and the run receipts stay readable through the account-wide reads (runs_feed, run_get) — a deleted worker's spending is still part of the account's history. A run in flight settles normally and is neither cancelled nor refunded; runsInFlight reports how many were running when the delete landed. Deleting FREES A WORKER SLOT, which is the fix for kit_install's 402 limit_exceeded when the owner would rather not upgrade. 404 means the worker does not exist or is not on this account — including a second delete of one already gone, so a 404 on a retry means the first call worked. Requires the deleteWorkers scope." +
|
|
724
|
+
NEW_SCOPE_NOTE,
|
|
725
|
+
auth: "manager",
|
|
726
|
+
method: "delete",
|
|
727
|
+
schema: {
|
|
728
|
+
tokenId: z.number().int().min(1).describe(TOKEN_ID_HINT),
|
|
729
|
+
},
|
|
730
|
+
path: (params) => `${API}/${params.tokenId}`,
|
|
731
|
+
annotations: DELETE,
|
|
732
|
+
};
|
|
653
733
|
// ─── Kit install ────────────────────────────────────────────────────────────
|
|
654
734
|
// The one place on this surface an agent can CREATE a worker: install a kit from
|
|
655
735
|
// the public directory. Both tools need the installKits scope (keys minted
|
|
@@ -682,7 +762,7 @@ const kitInstallPreview = {
|
|
|
682
762
|
const kitInstall = {
|
|
683
763
|
name: "kit_install",
|
|
684
764
|
title: "Install Kit",
|
|
685
|
-
description: "Install a directory kit as a NEW worker on this account. NOT idempotent: every successful call creates another worker — never retry a success, and on a timeout check workers_list (needs the readWorkers scope) before trying again. Requires the installKits scope. Call kit_install_preview first and supply every requiredInputs key in inputs (a missing or unknown key is a 400 naming it), answers to required memorySetup questions in memoryAnswers, and one categoryChoices entry per slot (member with connectionProvider set → also pass resourceId from the preview's operatorResources). CRITICAL — secrets shown ONCE: the response's install.rawKey (the worker's pe_ API key) and install.triggers[].signingSecret can NEVER be read again; deliver them to the human immediately and do not discard the response before doing so. The response also carries readiness (status ready|blocked with actionable issues, e.g. app_not_connected + candidateProviders; null means the readiness check itself failed AFTER the install succeeded — do not retry the install, read readiness via worker_get), workerUrl (the worker's dashboard page — hand it to the human), and connectAppsUrl (where the human connects missing apps in the browser; agents cannot connect apps). A 402 {error:'limit_exceeded'} is the plan's worker cap — terminal,
|
|
765
|
+
description: "Install a directory kit as a NEW worker on this account. NOT idempotent: every successful call creates another worker — never retry a success, and on a timeout check workers_list (needs the readWorkers scope) before trying again. Requires the installKits scope. Call kit_install_preview first and supply every requiredInputs key in inputs (a missing or unknown key is a 400 naming it), answers to required memorySetup questions in memoryAnswers, and one categoryChoices entry per slot (member with connectionProvider set → also pass resourceId from the preview's operatorResources). CRITICAL — secrets shown ONCE: the response's install.rawKey (the worker's pe_ API key) and install.triggers[].signingSecret can NEVER be read again; deliver them to the human immediately and do not discard the response before doing so. The response also carries readiness (status ready|blocked with actionable issues, e.g. app_not_connected + candidateProviders; null means the readiness check itself failed AFTER the install succeeded — do not retry the install, read readiness via worker_get), workerUrl (the worker's dashboard page — hand it to the human), and connectAppsUrl (where the human connects missing apps in the browser; agents cannot connect apps). A 402 {error:'limit_exceeded'} is the plan's worker cap — terminal, never retry the install. Two ways out: the human upgrades, or a worker is deleted to free the slot (worker_delete, with the deleteWorkers scope) — propose that only with the person's agreement, since deleting is permanent. Rate: 10 installs/hour per account. FINISHING THE JOB — installing does NOT make the worker run: without a deployment it fires no schedule and worker_run refuses it with not_deployed. Send deploy:true (optionally with modelSlug from models_list and the ceilings) to install and deploy in ONE call; the response then carries deployment. A deploy refused after the install still returns 201 with deploymentError naming what to fix — the worker exists either way, so never re-install; fix it and call worker_deploy on the same worker. deploy:true needs the manageDeployments scope IN ADDITION to installKits — a key without it is refused up front (403 OPERATION_NOT_ALLOWED naming the scope) and nothing is created, so drop deploy and install anyway, then ask the owner to re-scope the key before worker_deploy.",
|
|
686
766
|
auth: "manager",
|
|
687
767
|
method: "post",
|
|
688
768
|
schema: {
|
|
@@ -815,7 +895,7 @@ const BUDGET_WINDOW_NOTE = " Windows differ, deliberately: maxUsdPerDay and both
|
|
|
815
895
|
const getWorkerBudget = {
|
|
816
896
|
name: "budget_get",
|
|
817
897
|
title: "Get Worker Budget",
|
|
818
|
-
description: "One worker's spend and rate ceilings: maxUsdPerRun, maxUsdPerDay, maxRunsPerDay, maxConcurrentRuns, modelSlug, hasDeployment (plus workerId and its deprecated alias tokenId). Four readings an agent gets wrong by default. (1) maxRunsPerDay NULL MEANS THE PLATFORM DEFAULT, NOT UNLIMITED — the gate substitutes the platform's own number, so never report a null as 'no limit'. (2) maxUsdPerRun is the amount RESERVED from the wallet at dispatch, so it is also what a run must be able to AFFORD before it starts; and the day cap is counted against those RESERVATIONS rather than settled cost, so a worker reserving $0.50 under a $2/day cap is skipped on its fifth run of the day even if each one really cost a cent (the reservation is refunded when a later gate skips the run). (3) maxConcurrentRuns is
|
|
898
|
+
description: "One worker's spend and rate ceilings: maxUsdPerRun, maxUsdPerDay, maxRunsPerDay, maxConcurrentRuns, modelSlug, hasDeployment (plus workerId and its deprecated alias tokenId). Four readings an agent gets wrong by default. (1) maxRunsPerDay NULL MEANS THE PLATFORM DEFAULT, NOT UNLIMITED — the gate substitutes the platform's own number, so never report a null as 'no limit'. (2) maxUsdPerRun is the amount RESERVED from the wallet at dispatch, so it is also what a run must be able to AFFORD before it starts; and the day cap is counted against those RESERVATIONS rather than settled cost, so a worker reserving $0.50 under a $2/day cap is skipped on its fifth run of the day even if each one really cost a cent (the reservation is refunded when a later gate skips the run). (3) maxConcurrentRuns is SET BY THE ACCOUNT'S PLAN, not per worker — Free 5, Pro 20, Team 50, Enterprise uncapped — so budget_set has no parameter for it and raising it is an upgrade, not a request; it is reported so the number you see is the number the gate uses. It bounds runs started on demand (worker_run, run_bulk, webhooks); a schedule never overlaps itself whatever the plan allows. (4) hasDeployment FALSE means hosted runs are not set up for this worker, and then the dollar figures come back as 0 because there is no deployment to read them from — that 0 means 'no deployment', NOT 'capped at zero', so check hasDeployment before quoting any ceiling. Per-worker caps do not compose; the ceiling above them is fleet_budget_get. Requires the manageBudgets scope — reading a ceiling rides the same scope as changing it." +
|
|
819
899
|
BUDGET_WINDOW_NOTE +
|
|
820
900
|
NEW_SCOPE_NOTE,
|
|
821
901
|
auth: "manager",
|
|
@@ -830,7 +910,7 @@ const getWorkerBudget = {
|
|
|
830
910
|
const setWorkerBudget = {
|
|
831
911
|
name: "budget_set",
|
|
832
912
|
title: "Set Worker Budget",
|
|
833
|
-
description: "Change one worker's ceilings, and get the whole budget back as it now stands. PARTIAL: every field is optional and an OMITTED FIELD MEANS UNCHANGED, so you can raise one ceiling without restating the rest and without racing another writer's edit to a different field. Three traps. Setting maxUsdPerRun or maxUsdPerDay on a worker with NO HOSTED DEPLOYMENT is a 400 — there is nothing for a dollar cap to bind to, and budget_get's hasDeployment says which workers those are; maxRunsPerDay, by contrast, can be set on any worker. There is NO way to clear maxRunsPerDay back to the platform default here, because null already means 'leave it alone': send an explicit number instead. And LOWERING maxUsdPerRun below what a run needs does not fail loudly — it makes that worker's next run a Skipped receipt with a skipReason, which is a receipt an agent must go and read. maxConcurrentRuns is
|
|
913
|
+
description: "Change one worker's ceilings, and get the whole budget back as it now stands. PARTIAL: every field is optional and an OMITTED FIELD MEANS UNCHANGED, so you can raise one ceiling without restating the rest and without racing another writer's edit to a different field. Three traps. Setting maxUsdPerRun or maxUsdPerDay on a worker with NO HOSTED DEPLOYMENT is a 400 — there is nothing for a dollar cap to bind to, and budget_get's hasDeployment says which workers those are; maxRunsPerDay, by contrast, can be set on any worker. There is NO way to clear maxRunsPerDay back to the platform default here, because null already means 'leave it alone': send an explicit number instead. And LOWERING maxUsdPerRun below what a run needs does not fail loudly — it makes that worker's next run a Skipped receipt with a skipReason, which is a receipt an agent must go and read. maxConcurrentRuns is absent from this call by design: it is set by the account's plan (Free 5, Pro 20, Team 50), so raising it is an upgrade, not a request. A ZERO per-run cap is REFUSED (400), as is a day cap below the per-run cap: a zero reserve is a run that cannot start, not a worker that spends nothing — to stop a worker, use worker_set_enabled. maxRunsPerDay is clamped to the organization policy ceiling when one is enforced. The same call sets the question timeout: awaitInputTimeoutMinutes (how long a question the worker asks stays open; clearAwaitInputTimeout removes the bound). When it passes the question is closed out, never resumed with no answer, and a late answer still starts the run. Requires the manageBudgets scope." +
|
|
834
914
|
BUDGET_WINDOW_NOTE +
|
|
835
915
|
NEW_SCOPE_NOTE,
|
|
836
916
|
auth: "manager",
|
|
@@ -1464,11 +1544,15 @@ export const manageDescriptors = [
|
|
|
1464
1544
|
listWorkers,
|
|
1465
1545
|
getWorker,
|
|
1466
1546
|
runWorker,
|
|
1547
|
+
runWorkersBulk,
|
|
1467
1548
|
runsFeed,
|
|
1468
1549
|
fleetPulse,
|
|
1550
|
+
fleetHealth,
|
|
1551
|
+
accountUsage,
|
|
1469
1552
|
listRuns,
|
|
1470
1553
|
getRun,
|
|
1471
1554
|
getRunEvents,
|
|
1555
|
+
getRunTranscript,
|
|
1472
1556
|
getRunQuestion,
|
|
1473
1557
|
answerRunQuestion,
|
|
1474
1558
|
cancelRun,
|
|
@@ -1494,6 +1578,7 @@ export const manageDescriptors = [
|
|
|
1494
1578
|
getInstructionVersion,
|
|
1495
1579
|
restoreInstructionVersion,
|
|
1496
1580
|
setWorkerEnabled,
|
|
1581
|
+
deleteWorker,
|
|
1497
1582
|
kitInstallPreview,
|
|
1498
1583
|
kitInstall,
|
|
1499
1584
|
clonePreview,
|