@workerkit/core 0.3.13 → 0.3.15
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 +29 -0
- package/README.md +5 -5
- package/dist/descriptors/actions.js +2 -1
- package/dist/descriptors/actions.js.map +1 -1
- package/dist/descriptors/decision-authoring.js +2 -1
- package/dist/descriptors/decision-authoring.js.map +1 -1
- package/dist/descriptors/directory.js +7 -22
- package/dist/descriptors/directory.js.map +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.js +57 -28
- package/dist/descriptors/manage.js.map +1 -1
- package/dist/descriptors/support.d.ts +2 -0
- package/dist/descriptors/support.js +35 -0
- package/dist/descriptors/support.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The
|
|
1
|
+
// The 97 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.
|
|
@@ -7,6 +7,7 @@ import { appDiscoveryDescriptors } from "./app-discovery.js";
|
|
|
7
7
|
import { compactDecisionReceipt } from "./decision-receipt.js";
|
|
8
8
|
import { createDecisionWorker } from "./decision-authoring.js";
|
|
9
9
|
import { onboardingDescriptors } from "./onboarding.js";
|
|
10
|
+
import { supportDescriptors } from "./support.js";
|
|
10
11
|
import { z } from "../zod.js";
|
|
11
12
|
import { CREATE, DELETE, READ_ONLY, TRIGGER, UPDATE } from "./types.js";
|
|
12
13
|
// The graded-outcome vocabulary, taught wherever a score can be read or written.
|
|
@@ -15,8 +16,8 @@ import { CREATE, DELETE, READ_ONLY, TRIGGER, UPDATE } from "./types.js";
|
|
|
15
16
|
const SCORE_NOTE = " Grading: selfScore (0-100) is the run's OWN assessment of how much of its task it accomplished — a self-report, not a measurement; ownerScore (0-100) is the human's grade and OVERRIDES it wherever both exist; selfScoreReason explains selfScore in one line. All three are null when the run was never assessed (stateless workers and very short runs are not graded): null means NOT ASSESSED, never zero — never report it as 0 or average nulls into a success rate.";
|
|
16
17
|
const API = "/api/manage/workers";
|
|
17
18
|
// ─── Shared phrasing ────────────────────────────────────────────────────────
|
|
18
|
-
const TOKEN_ID_HINT = "The worker's numeric tokenId, as returned by workers_list. 404 not_found = no such worker on this account (another account's
|
|
19
|
-
const RUN_ID_HINT = "The run's UUID, as returned by worker_run (runId), workers_list (currentRunId / lastRun.runId), or worker_runs.";
|
|
19
|
+
const TOKEN_ID_HINT = "The worker's numeric tokenId, as returned by workers_list. 404 not_found = no such worker on this account, or one outside this key's worker selection (another account's and an unselected one are indistinguishable by design; key_info says which workers the key reaches).";
|
|
20
|
+
const RUN_ID_HINT = "The run's UUID, as returned by worker_run (runId), workers_list (currentRunId / lastRun.runId), or worker_runs. 404 not_found = no such run, or its worker is outside this key's worker selection.";
|
|
20
21
|
const DECISION_PROFILE_HINT = "Classifier choice: a profileId from models_list.decisionProfiles, independent of the language model. Platform-funded for decision and hybrid workers. Review sample results and confidence thresholds when changing providers. Omit to keep the configured classifier (Jev by default).";
|
|
21
22
|
// The whole runs family shares this degradation mode; teach it once per tool so
|
|
22
23
|
// agents never retry-loop a 422.
|
|
@@ -31,12 +32,12 @@ const HYBRID_NOTE = " Hybrid workers classify a bounded source window, then run
|
|
|
31
32
|
// existed that day. Taught on key_info and on every tool behind a scope that is
|
|
32
33
|
// younger than the surface, so a 403 there is read as "re-scope the key", not
|
|
33
34
|
// "retry".
|
|
34
|
-
const NEW_SCOPE_NOTE = " A key minted before this scope existed does not carry it (even one minted with \"all\"):
|
|
35
|
+
const NEW_SCOPE_NOTE = " A key minted before this scope existed does not carry it (even one minted with \"all\"): ask its owner or an account Admin to review its scope and authority at https://workerkit.ai, never retry automatically — check key_info's scopes first.";
|
|
35
36
|
// ─── Key ────────────────────────────────────────────────────────────────────
|
|
36
37
|
const getKeyInfo = {
|
|
37
38
|
name: "key_info",
|
|
38
39
|
title: "Key Info",
|
|
39
|
-
description: "What the presented manager key IS: accountId, accountTitle, keyName, keyPrefix (a display prefix — never the key itself), scopes, expiresAt, and serverTimeUtc. CALL THIS FIRST, before planning any work: the scopes list is exactly what the other tools on this surface will accept, so read it up front rather than discovering a wall mid-task. Any valid key may ask — this is the one tool that needs NO scope. A call outside the list fails 403 OPERATION_NOT_ALLOWED naming the missing scope, and
|
|
40
|
+
description: "What the presented manager key IS: accountId, accountTitle, subjectUserId, accountWideAuthority, keyName, keyPrefix (a display prefix — never the key itself), scopes, allWorkers, workerIds, expiresAt, and serverTimeUtc. accountWideAuthority:false limits all permissions to the subject member's own workers. Membership removal or role change invalidates the key and requires new consent. Admin-only setup operations remain unavailable to member keys, regardless of scopes. CALL THIS FIRST, before planning any work: the scopes list is exactly what the other tools on this surface will accept, so read it up front rather than discovering a wall mid-task. allWorkers false means the key reaches only workerIds (plus any worker it creates): workers_list, fleet_health, runs_feed, fleet_pulse and deployments_list then show those workers only, and any other worker or run id is 404 not_found exactly like one that does not exist — the credential owner or an account Admin can change the selection at https://workerkit.ai, within the subject's live authority. Any valid key may ask — this is the one tool that needs NO scope. A call outside the list fails 403 OPERATION_NOT_ALLOWED naming the missing scope, and the credential owner or an account Admin can change its scopes at https://workerkit.ai within the existing grant ceiling — never retry a 403. A scope added to the product AFTER a key was minted does NOT reach that key, INCLUDING a key minted with \"all\" (which stored the bitmask of the scopes that existed that day), so a tool can 403 on a key its owner believes has everything: this list is the only truth about it. Compute expiry and elapsed times against serverTimeUtc, never your own clock.",
|
|
40
41
|
auth: "manager",
|
|
41
42
|
method: "get",
|
|
42
43
|
schema: {},
|
|
@@ -47,7 +48,7 @@ const getKeyInfo = {
|
|
|
47
48
|
const listWorkers = {
|
|
48
49
|
name: "workers_list",
|
|
49
50
|
title: "List Workers",
|
|
50
|
-
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), modelType (language | decision | hybrid | none — see worker_get), deployment (null = this worker is NOT on the hosted runtime and will never run, whatever readiness says; worker_deploy fixes that — except on an Action worker, modelType none, which is never deployed or run: worker_tools lists its tools and worker_tool_call calls one), 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
|
|
51
|
+
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), modelType (language | decision | hybrid | none — see worker_get), deployment (null = this worker is NOT on the hosted runtime and will never run, whatever readiness says; worker_deploy fixes that — except on an Action worker, modelType none, which is never deployed or run: worker_tools lists its tools and worker_tool_call calls one), 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, over the workers this key reaches: 0 means nothing the key can reach is installed yet (key_info says whether the key is limited to selected workers; shortlist a kit with kits_search on the Directory server and kit_install it with deploy:true — a key limited to selected workers gains the worker it installs), 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).",
|
|
51
52
|
auth: "manager",
|
|
52
53
|
method: "get",
|
|
53
54
|
schema: {
|
|
@@ -55,6 +56,7 @@ const listWorkers = {
|
|
|
55
56
|
deployed: z.boolean().optional().describe("true = only workers on the hosted runtime (the ones that can run); false = only workers without a deployment, which includes every Action worker (modelType none: never deployed, called with worker_tool_call). Omit for both."),
|
|
56
57
|
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."),
|
|
57
58
|
q: z.string().max(100).optional().describe("Case-insensitive substring of the worker's title."),
|
|
59
|
+
ownerUserId: z.number().int().positive().optional().describe("Filter by ownerUserId from a worker row. This only narrows the workers the key already reaches."),
|
|
58
60
|
},
|
|
59
61
|
path: API,
|
|
60
62
|
annotations: READ_ONLY,
|
|
@@ -131,7 +133,7 @@ const runWorkersBulk = {
|
|
|
131
133
|
strictInput: true,
|
|
132
134
|
name: "run_bulk",
|
|
133
135
|
title: "Run Workers in Bulk",
|
|
134
|
-
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, modelSlug, decisionProfileId, sourceArgs, answers and maxItems. 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." +
|
|
136
|
+
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, modelSlug, decisionProfileId, sourceArgs, answers and maxItems. IT IS NOT ATOMIC AND IT DOES NOT STOP: every worker passes the mint gauntlet on its own, so an unknown id (or one outside this key's worker selection, which reads the same), 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." +
|
|
135
137
|
RUNTIME_NOTE,
|
|
136
138
|
auth: "manager",
|
|
137
139
|
method: "post",
|
|
@@ -157,12 +159,13 @@ const runWorkersBulk = {
|
|
|
157
159
|
};
|
|
158
160
|
// ─── Fleet-wide run reads ───────────────────────────────────────────────────
|
|
159
161
|
// The two calls that watch a WHOLE fleet without fanning out per worker. Both are
|
|
160
|
-
//
|
|
161
|
-
// deliberately money-free: cost
|
|
162
|
+
// scoped by the key itself — its account, and its worker selection when it has
|
|
163
|
+
// one — so neither takes a worker id, and both are deliberately money-free: cost
|
|
164
|
+
// lives on the run receipt.
|
|
162
165
|
const runsFeed = {
|
|
163
166
|
name: "runs_feed",
|
|
164
167
|
title: "Account Run Feed",
|
|
165
|
-
description: "Every worker's runs in ONE account-
|
|
168
|
+
description: "Every reachable worker's runs in ONE feed (the whole account for an all-workers key), 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." +
|
|
166
169
|
RUNTIME_NOTE,
|
|
167
170
|
auth: "manager",
|
|
168
171
|
method: "get",
|
|
@@ -185,7 +188,7 @@ const runsFeed = {
|
|
|
185
188
|
const fleetPulse = {
|
|
186
189
|
name: "fleet_pulse",
|
|
187
190
|
title: "Fleet Pulse",
|
|
188
|
-
description: "Every run IN FLIGHT on the
|
|
191
|
+
description: "Every run IN FLIGHT right now on the workers this key reaches, in one call — the other fleet-watching call, and the single authority for \"who is working\". Use it instead of sweeping workers_list for isRunning, or worker_runs per worker. Returns serverTimeUtc plus activeRuns[]: runId, workerId, tokenTitle, status (Pending | Dispatched | Running — a QUEUED run is not yet working, so never say \"running for 3m\" about one), createDate, startedAtUtc (null while Pending/Dispatched, so render elapsed from startedAtUtc ?? createDate and label the queued case differently), triggerKind, scheduleTitle, activitySummary, lastTool + toolActive (true = the run is INSIDE that tool — 'using X'; false = that call has ended and the name is the trailing record — 'last used X'), recentToolCalls[] (newest first, ≤25, each with a seq: accumulate across polls by appending anything whose seq beats the highest you kept for that run), toolCallCount (every call the run has made — if your kept list is shorter, the run out-ran the window and the rest is in run_events), activityUpdatedAtUtc, and liveness (live|stalled while Running). ALWAYS compute elapsed times against the response's serverTimeUtc, never your own clock. Capped at 100 rows with NO paging — truncated:true says the cap bit; an empty activeRuns[] is the normal, healthy answer, not an error or a failure to look. No cost fields: money lives on the run receipt (run_get). Requires the readRuns scope." +
|
|
189
192
|
RUNTIME_NOTE,
|
|
190
193
|
auth: "manager",
|
|
191
194
|
method: "get",
|
|
@@ -413,6 +416,20 @@ const deleteMemoryItem = {
|
|
|
413
416
|
annotations: DELETE,
|
|
414
417
|
};
|
|
415
418
|
// ─── Schedules ──────────────────────────────────────────────────────────────
|
|
419
|
+
const setWorkerTimeZone = {
|
|
420
|
+
name: "worker_timezone_set",
|
|
421
|
+
title: "Set Worker Timezone",
|
|
422
|
+
description: "Set the worker's own timezone. It decides the worker's local dates, the local times in its app results (calendar events, emails and other apps) and the times in the reports it writes. Use the owner's intended zone, for example America/New_York for Eastern time. Recomputes the next run of every daily schedule that follows the worker; explicit schedule timezone overrides remain unchanged, and a schedule's timezone never changes the worker's. Reports already saved keep their times. Requires the manageSchedules scope. Returns timeZoneId, effectiveTimeZoneId and schedules.",
|
|
423
|
+
auth: "manager",
|
|
424
|
+
method: "put",
|
|
425
|
+
schema: {
|
|
426
|
+
tokenId: z.number().int().min(1).describe(TOKEN_ID_HINT),
|
|
427
|
+
timeZoneId: z.string().max(64).nullable().describe("IANA timezone, such as America/New_York. Required: send null or an empty string to choose UTC."),
|
|
428
|
+
},
|
|
429
|
+
path: (params) => `${API}/${params.tokenId}/timezone`,
|
|
430
|
+
bodyBuilder: (params) => ({ timeZoneId: params.timeZoneId }),
|
|
431
|
+
annotations: UPDATE,
|
|
432
|
+
};
|
|
416
433
|
const listSchedules = {
|
|
417
434
|
name: "schedules_list",
|
|
418
435
|
title: "List Schedules",
|
|
@@ -435,11 +452,16 @@ const SCHEDULE_GATE_HINT = " Two plan walls return 402 {error:'feature_gated', f
|
|
|
435
452
|
// never overlaps itself, whatever the plan allows: two copies of the same
|
|
436
453
|
// scheduled job side by side duplicate its side effects.
|
|
437
454
|
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.";
|
|
455
|
+
// A schedule's zone and the worker's zone are separate settings. Taught on both
|
|
456
|
+
// schedule writes, so an agent fixing a report's times does not reach for the
|
|
457
|
+
// schedule: that only moves when it fires.
|
|
458
|
+
const SCHEDULE_ZONE_NOTE = " A schedule's own timeZoneId only decides when that schedule fires: the worker's local dates and reports follow the worker's timezone, which worker_timezone_set changes.";
|
|
438
459
|
const createSchedule = {
|
|
439
460
|
name: "schedule_create",
|
|
440
461
|
title: "Create Schedule",
|
|
441
462
|
description: "Create a schedule for the worker. Per-type required fields: " + SCHEDULE_TYPE_HINT +
|
|
442
|
-
" Omit timeZoneId to follow the worker's own time zone (the normal case).
|
|
463
|
+
" Omit timeZoneId to follow the worker's own time zone (the normal case)." + SCHEDULE_ZONE_NOTE +
|
|
464
|
+
" An Action worker (modelType none) takes no schedules: it is called, never run. Requires the manageSchedules scope." +
|
|
443
465
|
SCHEDULE_GATE_HINT +
|
|
444
466
|
SCHEDULE_OVERLAP_NOTE,
|
|
445
467
|
auth: "manager",
|
|
@@ -469,7 +491,8 @@ const createSchedule = {
|
|
|
469
491
|
const updateSchedule = {
|
|
470
492
|
name: "schedule_update",
|
|
471
493
|
title: "Update Schedule",
|
|
472
|
-
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.
|
|
494
|
+
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." +
|
|
495
|
+
SCHEDULE_ZONE_NOTE + " Per-type field rules: " +
|
|
473
496
|
SCHEDULE_TYPE_HINT + " Requires manageSchedules." + SCHEDULE_GATE_HINT + SCHEDULE_OVERLAP_NOTE,
|
|
474
497
|
auth: "manager",
|
|
475
498
|
method: "patch",
|
|
@@ -765,7 +788,7 @@ const restoreInstructionVersion = {
|
|
|
765
788
|
const setWorkerEnabled = {
|
|
766
789
|
name: "worker_set_enabled",
|
|
767
790
|
title: "Start or Stop Worker",
|
|
768
|
-
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.",
|
|
791
|
+
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. A key limited to selected workers is refused with 409 sub_workers_outside_key when stopping would cascade to a sub-worker outside its selection — an account Admin adds those sub-workers to the key at https://workerkit.ai, or stops them separately. Returns {tokenId, isEnabled}. Idempotent. Requires the manageState scope.",
|
|
769
792
|
auth: "manager",
|
|
770
793
|
method: "post",
|
|
771
794
|
schema: {
|
|
@@ -779,7 +802,7 @@ const setWorkerEnabled = {
|
|
|
779
802
|
const deleteWorker = {
|
|
780
803
|
name: "worker_delete",
|
|
781
804
|
title: "Delete Worker",
|
|
782
|
-
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
|
|
805
|
+
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, is not on this account, or is outside this key's worker selection — including a second delete of one already gone, so a 404 on a retry means the first call worked. 409 sub_workers_outside_key = a key limited to selected workers would delete sub-workers outside its selection, so the delete is refused rather than widened; an account Admin adds them to the key first. Requires the deleteWorkers scope." +
|
|
783
806
|
NEW_SCOPE_NOTE,
|
|
784
807
|
auth: "manager",
|
|
785
808
|
method: "delete",
|
|
@@ -790,10 +813,11 @@ const deleteWorker = {
|
|
|
790
813
|
annotations: DELETE,
|
|
791
814
|
};
|
|
792
815
|
// ─── Kit install ────────────────────────────────────────────────────────────
|
|
793
|
-
//
|
|
794
|
-
// the
|
|
795
|
-
// before the scope existed — including old "all"
|
|
796
|
-
// account admin re-scopes them).
|
|
816
|
+
// Install a kit from the public directory — the vetted route to a new worker
|
|
817
|
+
// (createWorkers covers the from-scratch and clone routes). Both tools need the
|
|
818
|
+
// installKits scope (keys minted before the scope existed — including old "all"
|
|
819
|
+
// keys — lack it until an account admin re-scopes them). A key limited to
|
|
820
|
+
// selected workers gains the worker it installs.
|
|
797
821
|
const KITS_API = "/api/manage/kits";
|
|
798
822
|
const KIT_SLUG_HINT = "The kit's slug, as returned by kits_search / kit_get on the public WorkerKit Directory server. 404 not_found = no such kit (or another account's private kit — indistinguishable by design).";
|
|
799
823
|
// Pinned to the backend's slug alphabet ([a-z0-9-], ≤120). Not cosmetic: encodeURIComponent
|
|
@@ -847,6 +871,7 @@ const kitInstall = {
|
|
|
847
871
|
operatorId: z.string().uuid().optional().describe("Operator (workspace) to install into. Omit to use the account's default operator."),
|
|
848
872
|
title: z.string().max(100).optional().describe("Name for the new worker (≤100 chars). Omit to use the kit's name."),
|
|
849
873
|
avatar: z.string().max(40).optional().describe("Avatar slug for the new worker. Omit for the default."),
|
|
874
|
+
timeZoneId: z.string().trim().min(1).max(64).optional().describe("The worker's timezone, as an IANA id such as America/New_York: it decides the worker's local dates and reports, and is set before the kit's schedules are created. Ask the worker creator for it if it is not already known; never guess it from connected calendars or the server's clock. Omitted means UTC. install.effectiveTimeZoneId in the response is the zone applied."),
|
|
850
875
|
slackConnectionId: z.number().int().positive().optional().describe("Action kits: pin a Slack bot from actionConnections in the install preview. No model or deployment is needed."),
|
|
851
876
|
githubSelection: GITHUB_SELECTION.optional().describe("Explicit GitHub targets for the new worker. Discover them with app_github_accounts, app_github_repos and app_github_branches (discoverAppResources scope). connectionId also appears as githubAccounts[].id in kit_install_preview. Use repositoryMode 'selected' with 1-500 stable repositoryIds for a specific job. 'all' includes future repositories granted to that account: choose it only when intended. accounts:[] leaves setup for later. Required for a GitHub kit when the key has discoverAppResources; legacy keys retain the single-account fallback. Discovery and branch inputs do not grant extra access."),
|
|
852
877
|
categoryChoices: z.array(z.object({
|
|
@@ -871,6 +896,7 @@ const kitInstall = {
|
|
|
871
896
|
operatorId: params.operatorId,
|
|
872
897
|
title: params.title,
|
|
873
898
|
avatar: params.avatar,
|
|
899
|
+
timeZoneId: params.timeZoneId,
|
|
874
900
|
githubSelection: params.githubSelection,
|
|
875
901
|
categoryChoices: params.categoryChoices,
|
|
876
902
|
inputs: params.inputs,
|
|
@@ -1072,7 +1098,7 @@ const listModels = {
|
|
|
1072
1098
|
const listDeployments = {
|
|
1073
1099
|
name: "deployments_list",
|
|
1074
1100
|
title: "List Deployments",
|
|
1075
|
-
description: "Every DEPLOYED worker
|
|
1101
|
+
description: "Every DEPLOYED worker this key reaches (the whole account for an all-workers key) with its model, spend ceilings and deployment status — the fleet answer to \"what is actually able to run\". A worker that appears in workers_list but NOT here is not on the runtime, however complete it looks: that is the single most common reason a newly built worker never produces a run. Action workers (modelType none) never appear here, by design: they are not deployed, and their tools are called with worker_tool_call. Scoped by the key — its account and its worker selection — so it takes no worker id. Requires readWorkers." +
|
|
1076
1102
|
RUNTIME_NOTE,
|
|
1077
1103
|
auth: "manager",
|
|
1078
1104
|
method: "get",
|
|
@@ -1173,7 +1199,7 @@ const undeployWorker = {
|
|
|
1173
1199
|
const getWorkerPermissions = {
|
|
1174
1200
|
name: "worker_permissions_get",
|
|
1175
1201
|
title: "Get Worker Permissions",
|
|
1176
|
-
description: "What the worker may touch, in the kit-authoring vocabulary: apps[] ({code, operations, visibleFields, allowAll, writeEnabled, providers, …} — the same shape a kit's content.apps takes), categorySlots[], contactAllowAll, blockedSenderCategories, timeframePastDays / timeframeFutureDays, maxChildTokens, and ruleCounts (per rule table, PRESENCE only — rule values never leave the worker). Read-only: permissions
|
|
1202
|
+
description: "What the worker may touch, in the kit-authoring vocabulary: apps[] ({code, operations, visibleFields, allowAll, writeEnabled, providers, …} — the same shape a kit's content.apps takes), categorySlots[], contactAllowAll, blockedSenderCategories, timeframePastDays / timeframeFutureDays, maxChildTokens, and ruleCounts (per rule table, PRESENCE only — rule values never leave the worker). Read-only: no tool changes a worker's permissions. To add an app or an operation, tell the user what to switch on under the worker's Apps & access on the dashboard, then read this again to confirm the change. A new worker with different permissions comes from a kit instead (kit_publish private, then kit_install). ruleCounts decides between the two ways to multiply a worker: worker_clone carries the rules, kit_publish from sourceWorkerId never does — so a worker with rules would install MORE permissively as a kit than it runs today. Requires the readWorkers scope.",
|
|
1177
1203
|
auth: "manager",
|
|
1178
1204
|
method: "get",
|
|
1179
1205
|
schema: {
|
|
@@ -1185,10 +1211,11 @@ const getWorkerPermissions = {
|
|
|
1185
1211
|
};
|
|
1186
1212
|
// ─── Kits (authoring) ───────────────────────────────────────────────────────
|
|
1187
1213
|
//
|
|
1188
|
-
// The publishKits lane. A PRIVATE kit installed with kit_install is
|
|
1189
|
-
//
|
|
1190
|
-
//
|
|
1191
|
-
// and the vocabulary on the Directory server,
|
|
1214
|
+
// The publishKits lane. A PRIVATE kit installed with kit_install is the kit route
|
|
1215
|
+
// to a worker from scratch (action_worker_create, decision_worker_create and
|
|
1216
|
+
// cloning are the createWorkers routes), so these descriptors teach the flow as
|
|
1217
|
+
// much as the wire: read the guide and the vocabulary on the Directory server,
|
|
1218
|
+
// validate, publish private, install.
|
|
1192
1219
|
const KIT_REF = z.string().min(1).max(120);
|
|
1193
1220
|
const KIT_REF_HINT = "The kit's slug, as returned by my_kits_list / kit_publish (its legacy numeric id is also accepted). Resolution is account-scoped: 404 not_found means no such kit on THIS account — another account's kit is indistinguishable from a nonexistent one.";
|
|
1194
1221
|
const AUTHORING_FLOW_NOTE = " Authoring flow: read kit_authoring_guide (index, then schema and rules) and kit_vocabulary on the public WorkerKit Directory server first; kit_validate the exact body you will publish; publish PRIVATE (visibility 'private') and kit_install it; promote with kit_replace (visibility 'public') once a run (an Action kit: a tool call) has proved it. Requires the publishKits scope." +
|
|
@@ -1283,14 +1310,14 @@ const validateKit = {
|
|
|
1283
1310
|
const publishKit = {
|
|
1284
1311
|
name: "kit_publish",
|
|
1285
1312
|
title: "Publish Kit",
|
|
1286
|
-
description: "Publish a NEW kit on this account — from authored content, or from any worker
|
|
1313
|
+
description: "Publish a NEW kit on this account — from authored content, or from any worker this key reaches (sourceWorkerId: its instruction, texts, permissions, schedules and triggers become the kit; rule VALUES never travel, only that rules exist; a worker outside the key's selection is 404 not_found). Exactly one of content / sourceWorkerId. NOT idempotent: every successful call creates another listing — never retry a success; on a timeout read my_kits_list before trying again. visibility 'private' (recommended first) makes a kit only this account can install: kit_install its slug and you have a worker built from scratch through the reviewed manifest pipeline. 'public' (default) lists it in the directory after the fail-closed supply-chain scan — 503 kit_scan_unavailable means retry later with the SAME body, or publish private. 400 names the FIRST failing rule (run kit_validate first to see them all). 403 = the source worker was installed from a protected kit, whose text belongs to that kit's publisher. 409 = publisherName taken (first publish only). Caps: 20 publishes/hour per account, 100 PUBLIC kits per account (private kits are unlimited; an unlisted or admin-removed listing still holds its slot). Returns the listing (slug, status, moderationStatus, requiredInputs, lintWarnings, …); a public listing can still be flagged minutes later by the semantic scan — re-read my_kits_list, and kit_scan_get has the findings." +
|
|
1287
1314
|
AUTHORING_FLOW_NOTE,
|
|
1288
1315
|
auth: "manager",
|
|
1289
1316
|
method: "post",
|
|
1290
1317
|
schema: {
|
|
1291
1318
|
...LISTING_SCHEMA,
|
|
1292
1319
|
content: CONTENT_SCHEMA.optional(),
|
|
1293
|
-
sourceWorkerId: z.string().uuid().optional().describe("Publish from this worker instead of content (any worker
|
|
1320
|
+
sourceWorkerId: z.string().uuid().optional().describe("Publish from this worker instead of content (any worker this key reaches — its workerId from workers_list; one outside the key's selection is 404 not_found). Never together with content."),
|
|
1294
1321
|
},
|
|
1295
1322
|
path: KITS_API,
|
|
1296
1323
|
annotations: CREATE,
|
|
@@ -1398,7 +1425,7 @@ const makeKitPrivate = {
|
|
|
1398
1425
|
const deleteKit = {
|
|
1399
1426
|
name: "kit_delete",
|
|
1400
1427
|
title: "Delete Kit",
|
|
1401
|
-
description: "Hard-delete a listing (204). PERMANENT
|
|
1428
|
+
description: "Hard-delete a listing (204). PERMANENT; kit_unpublish is the reversible alternative. Workers installed from it are untouched. The second call is a 404. Requires the publishKits scope." +
|
|
1402
1429
|
NEW_SCOPE_NOTE,
|
|
1403
1430
|
auth: "manager",
|
|
1404
1431
|
method: "delete",
|
|
@@ -1632,6 +1659,7 @@ const deleteMcpServer = {
|
|
|
1632
1659
|
export const manageDescriptors = [
|
|
1633
1660
|
...appDiscoveryDescriptors,
|
|
1634
1661
|
...onboardingDescriptors,
|
|
1662
|
+
...supportDescriptors,
|
|
1635
1663
|
createDecisionWorker,
|
|
1636
1664
|
...actionDescriptors,
|
|
1637
1665
|
setWorkerDecision,
|
|
@@ -1657,6 +1685,7 @@ export const manageDescriptors = [
|
|
|
1657
1685
|
addMemoryItem,
|
|
1658
1686
|
updateMemoryItem,
|
|
1659
1687
|
deleteMemoryItem,
|
|
1688
|
+
setWorkerTimeZone,
|
|
1660
1689
|
listSchedules,
|
|
1661
1690
|
createSchedule,
|
|
1662
1691
|
updateSchedule,
|