@acsetra/runner 0.1.92 → 0.1.94
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/bin/runner.js +1 -1
- package/lib/grammar.json +123 -4
- package/lib/verbs.js +1 -1
- package/package.json +1 -1
package/bin/runner.js
CHANGED
|
@@ -190,7 +190,7 @@ async function main() {
|
|
|
190
190
|
const argv = process.argv.slice(2);
|
|
191
191
|
if (!argv.length || ["-h", "--help"].includes(argv[0])) { console.log(renderTop()); return 0; }
|
|
192
192
|
const [cmd, ...rest] = argv;
|
|
193
|
-
if (["version", "--version", "-V"].includes(cmd)) { console.log("runner (@acsetra/runner) 0.1.
|
|
193
|
+
if (["version", "--version", "-V"].includes(cmd)) { console.log("runner (@acsetra/runner) 0.1.94"); return 0; }
|
|
194
194
|
|
|
195
195
|
// help — top-level, `help <topic>`, and per-verb `<cmd> … --help` (lexical, before toOp)
|
|
196
196
|
if (cmd === "help") {
|
package/lib/grammar.json
CHANGED
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"muted",
|
|
53
53
|
"probe",
|
|
54
54
|
"replace",
|
|
55
|
-
"run"
|
|
55
|
+
"run",
|
|
56
|
+
"tools"
|
|
56
57
|
],
|
|
57
58
|
"primary_json": {
|
|
58
59
|
"set.put": "meta",
|
|
@@ -1161,8 +1162,8 @@
|
|
|
1161
1162
|
"desc": "render-level check: dead wiring, behavior↔surface mismatch, ctx typos. --map = per-node design-as-data; --run executes mount(ctx) and catches throws"
|
|
1162
1163
|
},
|
|
1163
1164
|
"pipe": {
|
|
1164
|
-
"usage": "pipe <code> -S <scope> [-w code:label | -w scope/code] [--rate N] [--timeout N] [--keep]\n pipe show <code> | pipe list | pipe remove <code>",
|
|
1165
|
-
"desc": "create/upsert a pipeline envelope (resets workers unless --keep)"
|
|
1165
|
+
"usage": "pipe <code> -S <scope> [-w code:label | -w scope/code] [--rate N] [--timeout N] [--keep]\n [--cost-class free|metered|paid] [--requires '{\"approval\":true,\"per_user_daily\":N,\"owner_of\":\"<set>\"}']\n pipe show <code> | pipe list | pipe catalog [-S scope] [--tools] | pipe remove <code>",
|
|
1166
|
+
"desc": "create/upsert a pipeline envelope (resets workers unless --keep). `pipe remove` detaches TERMINAL run history onto the launches (audit preserved) and refuses only ACTIVE launches. `pipe catalog` = the live machine-readable org catalog (accepts/reads/writes/calls/callers/schedules/cost per pipeline; --tools adds OpenAI function schemas) — feed agents THIS, never a hand-synced registry set. `--requires` gates are enforced at admission for EVERY producer (browser, CLI, schedules, pipeline tier); a per_user_daily cap makes /run answer `remaining`"
|
|
1166
1167
|
},
|
|
1167
1168
|
"pipes": {
|
|
1168
1169
|
"usage": "pipes",
|
|
@@ -1185,7 +1186,24 @@
|
|
|
1185
1186
|
" (a real child launch; -s '{\"pick\":[…],\"input\":{…}}' shapes its input)",
|
|
1186
1187
|
" batch -s '{\"over\":\"items\",\"each\":{\"tier\":…,\"spec\":{…}},\"concurrency\":8}'",
|
|
1187
1188
|
" ONE run fans a sub-worker over a list: bounded (default 8, max 32), one item's",
|
|
1188
|
-
" failure is its own {error,index}, the answer counts ok/failed — never loop ctx.run"
|
|
1189
|
+
" failure is its own {error,index}, the answer counts ok/failed — never loop ctx.run",
|
|
1190
|
+
"Every tier: -s '{\"as\":\"key\"}' lands the worker's WHOLE payload under one bag key;",
|
|
1191
|
+
" '{\"when\":{\"<bag key>\": value|[values]}}' gates the step on the bag (skip, never force-run).",
|
|
1192
|
+
"snippet also: '{\"reads\":[keys]}' hands the snippet ONLY those bag keys (+ __ stamps, item).",
|
|
1193
|
+
"llm also: messages_from (full chat array from the bag), response_format, reasoning (effort),",
|
|
1194
|
+
" max_tokens (clamped to the model's registry ceiling) — no more raw-httpx model calls.",
|
|
1195
|
+
"read also: key_from, fields:[…], where/where_from (mode all), default, transient.",
|
|
1196
|
+
"Errors: RAISE is the one error channel — a raised worker fails the launch with a receipt;",
|
|
1197
|
+
" output={'error':…} is just data and settles nothing.",
|
|
1198
|
+
"The full per-tier key map lives in the manifest's worker_spec (CI-checked against the kernel).",
|
|
1199
|
+
"Cross-tier -s keys (census wave 2): pick/drop (payload projection at the merge),",
|
|
1200
|
+
" retry (per-worker attempts), until/every/max_polls (poll the SAME worker until a",
|
|
1201
|
+
" condition matches — no more time.sleep in snippets), writes '{\"set\":\"bag key\"}'",
|
|
1202
|
+
" (multi-set atomic writes from ONE worker), writes_to_from (data-driven target),",
|
|
1203
|
+
" emit (pipeline-tier output contract), imports (snippet_lib modules; `import",
|
|
1204
|
+
" runner_lib` — the framework stdlib — is always available).",
|
|
1205
|
+
"Zero-worker pipelines are refused at admission; terminal output carries __verdict",
|
|
1206
|
+
" (steps/ran/skipped/rows_written/sets) so done ≠ silently-did-nothing."
|
|
1189
1207
|
]
|
|
1190
1208
|
},
|
|
1191
1209
|
"op": {
|
|
@@ -1254,5 +1272,106 @@
|
|
|
1254
1272
|
"op"
|
|
1255
1273
|
]
|
|
1256
1274
|
}
|
|
1275
|
+
},
|
|
1276
|
+
"worker_spec": {
|
|
1277
|
+
"_comment": "Per-tier worker spec keys — THE discoverability source of truth for what a worker's -s '{json}' understands. tests/test_grammar_manifest.py scans the kernel for every spec key it reads and FAILS when one is missing here (the when/reads-invisible-for-weeks class). _common keys apply to every tier.",
|
|
1278
|
+
"_common": {
|
|
1279
|
+
"as": "land this worker's ENTIRE payload under this ONE bag key instead of merging top-level (the universal namespacing rule; read/llm resolve `as` in-tier as the rows/reply key)",
|
|
1280
|
+
"when": "{\"<bag key>\": value | [values]} — run this step only while every named key's bag value matches; otherwise SKIP it (no attempt, cursor advances). Authored spec, never a client flag",
|
|
1281
|
+
"pick": "[keys] — keep ONLY these keys of a dict payload before it merges/nests (read/llm resolve their own shape; on the pipeline tier `pick` narrows the CHILD's input — use `emit` for its output)",
|
|
1282
|
+
"drop": "[keys] — remove these keys from the payload before it merges, so a provider's 41-key envelope never enters the bag (retires the terminal null-out ritual)",
|
|
1283
|
+
"retry": "per-worker retries: an int, or {\"attempts\": N, \"backoff\": s} — overrides the pipeline policy for THIS step only (max 10)",
|
|
1284
|
+
"until": "{\"<bag key>\": value | [values]} — POLL-UNTIL: re-run this worker until the condition matches its merged result (the `when` grammar); exhausting max_polls is a LOUD error, never a silent miss",
|
|
1285
|
+
"every": "seconds between polls (with `until`; default 5, clamped 1–300)",
|
|
1286
|
+
"max_polls": "poll ceiling (with `until`; default 12, max 60)",
|
|
1287
|
+
"writes": "{\"<set> | <scope>/<set>\": \"<bag key>\", …} — MULTI-SET WRITES: each named set receives that key of this worker's result (a list writes rows, a dict one envelope, a missing key skips), atomically in the same step; own-scope targets are minted at authoring, cross-scope targets must exist. Kills the one-writer-per-set stub tail",
|
|
1288
|
+
"writes_to_from": "bag key naming the target set at RUN time ('<code>' or '<scope>/<code>' of an EXISTING same-org set) — this worker's own result lands there; an empty value skips. The data-driven writes_to (no more N cloned router workers)"
|
|
1289
|
+
},
|
|
1290
|
+
"snippet": {
|
|
1291
|
+
"body": "the Python source — reads `input`, sets `output` (one row) or output={\"rows\":[…]} (many); DB-isolated subprocess",
|
|
1292
|
+
"reads": "[keys] — hand the snippet ONLY these bag keys (plus the __ stamps and a batch `item`); a pass-through stub stops serialising the whole multi-MB bag",
|
|
1293
|
+
"imports": "[modules] — rows of the scope's `snippet_lib` set (row code = module name, meta.body = Python source), materialized beside the body so `import <name>` works; `import runner_lib` (the framework stdlib: sv, rows_of, meta_of, latest, cur, by_code, sha, slug, iso, clamp, chunk, …) is ALWAYS available with no spec change"
|
|
1294
|
+
},
|
|
1295
|
+
"read": {
|
|
1296
|
+
"set": "value set CODE to resolve",
|
|
1297
|
+
"scope": "read a set of ANOTHER scope of this org (default: nearest set at the launch scope)",
|
|
1298
|
+
"mode": "latest (one row) | all (the list)",
|
|
1299
|
+
"key": "literal row key — ONE indexed point read",
|
|
1300
|
+
"key_from": "dotted bag key(s), first non-empty wins — one authored worker serves every row",
|
|
1301
|
+
"shape": "\"row\" answers the full row with revision/etag (record heads)",
|
|
1302
|
+
"fields": "[…] — carry ONLY these meta keys into the bag (minimal-data projection)",
|
|
1303
|
+
"where": "{k: v} — meta equality filters applied IN THE QUERY (mode all)",
|
|
1304
|
+
"where_from": "{k: \"<dotted bag key>\"} — where values read from the bag",
|
|
1305
|
+
"limit": "max rows (mode all)",
|
|
1306
|
+
"order": "\"-ordinal\" for newest-first",
|
|
1307
|
+
"default": "value answered when a latest/keyed read finds nothing",
|
|
1308
|
+
"include_deleted": "a keyed read may answer a tombstoned family's last write",
|
|
1309
|
+
"transient": "keep this read's rows OUT of the persisted launch output",
|
|
1310
|
+
"optional": "true — a mode:all read of a set that does not EXIST answers [] instead of failing; default is a loud failure (distinct denial vs empty — an existing-but-empty set always answers []). me/me_* sets are always tolerant (minted per-user on first write)"
|
|
1311
|
+
},
|
|
1312
|
+
"llm": {
|
|
1313
|
+
"provider": "provider entry (default openai); with `url`, any OpenAI-compatible endpoint",
|
|
1314
|
+
"url": "override the provider endpoint",
|
|
1315
|
+
"model": "model id (default: the registry's DEFAULT_MODEL)",
|
|
1316
|
+
"keys": "key specs — a connection service (user key PARKS the run until connected) or \"$secrets.NAME\" from the org vault",
|
|
1317
|
+
"system": "literal system prompt",
|
|
1318
|
+
"system_from": "bag key holding the system prompt",
|
|
1319
|
+
"user_from": "bag key holding the user message (default `ask`)",
|
|
1320
|
+
"messages_from": "bag key holding a FULL chat `messages` array — multi-turn conversations without a snippet",
|
|
1321
|
+
"response_format": "passed through to the provider (json_schema / json_object)",
|
|
1322
|
+
"reasoning": "effort for reasoning models (none|minimal|low|medium|high|xhigh → reasoning_effort)",
|
|
1323
|
+
"max_tokens": "output cap, clamped to the model's registry ceiling (sent as max_completion_tokens to api.openai.com)",
|
|
1324
|
+
"response_path": "dotted path to the reply text (default: the provider's)"
|
|
1325
|
+
},
|
|
1326
|
+
"agent": {
|
|
1327
|
+
"model": "model id — routed by the registry (gpt* → OpenAI, else Anthropic; HOUSE keys)",
|
|
1328
|
+
"system": "literal system prompt",
|
|
1329
|
+
"system_from": "bag key holding the system prompt",
|
|
1330
|
+
"user_from": "bag key holding the ask (default: bag `ask`/`text`)",
|
|
1331
|
+
"reasoning": "thinking effort (low|medium|high; OpenAI also none|minimal|xhigh)",
|
|
1332
|
+
"search": "web search is ON by default (the model decides whether to use it) — false disables"
|
|
1333
|
+
},
|
|
1334
|
+
"httpx": {
|
|
1335
|
+
"url": "the AUTHORED base — scheme+host are never data-driven (the SSRF gate and the key-carrying host are fixed at authoring)",
|
|
1336
|
+
"method": "GET|POST|PUT|PATCH|DELETE|HEAD (default POST)",
|
|
1337
|
+
"method_from": "dotted bag key naming the method (allowlisted)",
|
|
1338
|
+
"path_from": "dotted bag key holding an ABSOLUTE path(+query) appended to the base — ids in paths without one worker per id",
|
|
1339
|
+
"body_from": "dotted bag key holding the JSON body (default: the whole bag on mutating methods; GET/HEAD send none)",
|
|
1340
|
+
"keys": "key specs — each carries a user/house connection token or \"$secrets.NAME\" (org vault) in its OWN header; a missing USER key parks the run; {\"token_from\": \"<bag key>\", \"header\"?, \"scheme\"?} sends a token MINTED BY THIS RUN (a prior session-mint step) — no more `import httpx` inside a snippet to carry it",
|
|
1341
|
+
"allow_hosts": "pin the SSRF gate tighter than the default private/internal block",
|
|
1342
|
+
"max_bytes": "response size ceiling in bytes — over it the worker fails loudly instead of dragging megabytes into the bag",
|
|
1343
|
+
"follow_redirects": "follow up to N redirect hops (max 5): each hop re-proves the SSRF gate, and auth keys are DROPPED the moment the host changes"
|
|
1344
|
+
},
|
|
1345
|
+
"batch": {
|
|
1346
|
+
"over": "bag key holding the list (default `items`)",
|
|
1347
|
+
"each": "{tier, spec} — the sub-worker each item runs (it sees the bag plus `item`); one item's failure is ITS result, never the batch's",
|
|
1348
|
+
"concurrency": "parallel items (default 8, max 32)",
|
|
1349
|
+
"input_map": "(inside `each`) {\"<child key>\": \"<dotted path>\"} — name item fields into the child's input ({\"source_id\": \"item.source_id\"}) instead of forcing every fan-out child to open with an unwrap worker for the fixed `item` key"
|
|
1350
|
+
},
|
|
1351
|
+
"pipeline": {
|
|
1352
|
+
"pipeline": "'<code>' or '<scope>/<code>' — an EXISTING pipeline of this org, run as a REAL child launch driven in-process (own receipts/rows/feed events)",
|
|
1353
|
+
"pick": "[keys] — narrow the bag handed to the child",
|
|
1354
|
+
"input": "overlay object templated over the bag before the child launches",
|
|
1355
|
+
"emit": "[keys] — the child call's OUTPUT contract: only these keys of the child's terminal bag join the parent (without it the whole child bag lands — nine production bridge workers existed only to null that back out)"
|
|
1356
|
+
},
|
|
1357
|
+
"storage": {
|
|
1358
|
+
"op": "store_bytes | start_upload | finalize_upload | fetch_upload — the byte-asset choreography (tenant code never sees bucket credentials)",
|
|
1359
|
+
"from": "store_bytes: bag key holding base64 bytes (default `bytes_b64`)",
|
|
1360
|
+
"accept": "content-type allowlist (exact or family wildcard, e.g. [\"image/*\"])",
|
|
1361
|
+
"max_bytes": "size ceiling (default 25 MB)",
|
|
1362
|
+
"kind": "asset kind for the emitted row (file | image | …)",
|
|
1363
|
+
"visibility": "public (default) | …",
|
|
1364
|
+
"class": "storage class (default managed)",
|
|
1365
|
+
"content_type": "explicit content type (else from data / sniffed)",
|
|
1366
|
+
"ext": "explicit file extension (else derived from the content type)",
|
|
1367
|
+
"ttl": "fetch_upload: source-fetch timeout seconds (default 60); start_upload: presign TTL (default 600)",
|
|
1368
|
+
"asset_code": "explicit asset row code (else from data.asset_code/code)",
|
|
1369
|
+
"app_key": "storage key namespace (default: the scope leaf)",
|
|
1370
|
+
"rel_scope": "where under the app the object key is filed (default root)",
|
|
1371
|
+
"timeout": "fetch_upload: HTTP timeout seconds for the source fetch (default 60)"
|
|
1372
|
+
},
|
|
1373
|
+
"internal": {
|
|
1374
|
+
"handler": "a NAMED vetted function from the internal registry (`record` = declarative row envelope from the input)"
|
|
1375
|
+
}
|
|
1257
1376
|
}
|
|
1258
1377
|
}
|
package/lib/verbs.js
CHANGED
|
@@ -102,7 +102,7 @@ export function toOp(verb, rest) {
|
|
|
102
102
|
}
|
|
103
103
|
if (verb === "ls") { const { flags } = walk(rest); return ["set.list", assemble("set.list", [], flags)]; }
|
|
104
104
|
if (verb === "pipe") {
|
|
105
|
-
if (rest.length && ["show", "list", "remove"].includes(rest[0])) {
|
|
105
|
+
if (rest.length && ["show", "list", "remove", "catalog"].includes(rest[0])) {
|
|
106
106
|
const op = "pipe." + rest[0];
|
|
107
107
|
const { positionals, flags } = walk(rest.slice(1));
|
|
108
108
|
return [op, assemble(op, positionals, flags)];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acsetra/runner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.94",
|
|
4
4
|
"description": "Runner CLI — author and run hosted Runner apps from your terminal (the `runner` command).",
|
|
5
5
|
"keywords": ["runner", "acsetra", "cli", "agent", "low-code"],
|
|
6
6
|
"license": "MIT",
|