@foldrun/core 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -10
- package/dist/src/approvals.d.ts +104 -1
- package/dist/src/approvals.js +192 -2
- package/dist/src/budget.d.ts +32 -0
- package/dist/src/budget.js +177 -0
- package/dist/src/catalog.js +2 -1
- package/dist/src/confine.js +6 -1
- package/dist/src/deploy.js +4 -2
- package/dist/src/egress.d.ts +19 -2
- package/dist/src/egress.js +2 -1
- package/dist/src/evals.d.ts +4 -0
- package/dist/src/evals.js +20 -11
- package/dist/src/flow-lint.d.ts +4 -0
- package/dist/src/flow-lint.js +108 -0
- package/dist/src/host-env.d.ts +8 -0
- package/dist/src/host-env.js +48 -0
- package/dist/src/json-schema.d.ts +12 -0
- package/dist/src/json-schema.js +202 -0
- package/dist/src/library.js +13 -1
- package/dist/src/notify.d.ts +79 -1
- package/dist/src/notify.js +243 -9
- package/dist/src/paths.d.ts +5 -0
- package/dist/src/paths.js +32 -0
- package/dist/src/platform.d.ts +112 -2
- package/dist/src/platform.js +20 -2
- package/dist/src/provider-health.d.ts +55 -0
- package/dist/src/provider-health.js +232 -0
- package/dist/src/run-container.d.ts +80 -4
- package/dist/src/run-container.js +176 -37
- package/dist/src/runner.d.ts +41 -5
- package/dist/src/runner.js +513 -81
- package/dist/src/script-tools.d.ts +12 -0
- package/dist/src/script-tools.js +10 -2
- package/dist/src/secret-health.d.ts +59 -0
- package/dist/src/secret-health.js +155 -0
- package/dist/src/secrets.d.ts +19 -1
- package/dist/src/secrets.js +44 -12
- package/dist/src/starter.js +4 -0
- package/dist/src/step-exec.d.ts +62 -6
- package/dist/src/step-exec.js +199 -68
- package/dist/src/store.d.ts +300 -3
- package/dist/src/store.js +574 -26
- package/dist/src/tar.js +2 -1
- package/dist/src/test-mode.d.ts +111 -0
- package/dist/src/test-mode.js +285 -0
- package/dist/src/tool-test.js +48 -21
- package/dist/src/translator.js +2 -1
- package/dist/src/trigger-log.d.ts +43 -0
- package/dist/src/trigger-log.js +122 -0
- package/dist/src/triggers.d.ts +20 -0
- package/dist/src/triggers.js +91 -10
- package/dist/src/webhook.d.ts +15 -3
- package/dist/src/webhook.js +11 -11
- package/package.json +6 -5
- package/src/approvals.ts +253 -2
- package/src/budget.ts +178 -0
- package/src/catalog.ts +2 -1
- package/src/confine.ts +6 -1
- package/src/deploy.ts +4 -1
- package/src/egress.ts +20 -4
- package/src/evals.ts +25 -9
- package/src/flow-lint.ts +118 -0
- package/src/host-env.ts +51 -0
- package/src/json-schema.ts +184 -0
- package/src/library.ts +13 -1
- package/src/notify.ts +272 -11
- package/src/paths.ts +29 -0
- package/src/platform.ts +119 -3
- package/src/provider-health.ts +274 -0
- package/src/run-container.ts +215 -35
- package/src/runner.ts +525 -73
- package/src/script-tools.ts +18 -2
- package/src/secret-health.ts +185 -0
- package/src/secrets.ts +44 -10
- package/src/starter.ts +4 -0
- package/src/step-exec.ts +176 -21
- package/src/storage.ts +8 -2
- package/src/store.ts +785 -25
- package/src/tar.ts +2 -1
- package/src/test-mode.ts +311 -0
- package/src/tool-test.ts +49 -20
- package/src/translator.ts +2 -1
- package/src/trigger-log.ts +159 -0
- package/src/triggers.ts +92 -10
- package/src/webhook.ts +17 -11
package/dist/src/store.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { singleWorkspace } from "./paths.ts";
|
|
2
|
+
import type { TestEffect } from "./test-mode.ts";
|
|
2
3
|
/**
|
|
3
4
|
* The frontmatter of one markdown file, as the runtime reads it. Exported
|
|
4
5
|
* for the CLI: `foldrun probe` used to import gray-matter itself, which is
|
|
@@ -249,6 +250,12 @@ export interface AgentInfo {
|
|
|
249
250
|
* list withholds all of them. */
|
|
250
251
|
skills: string[] | null;
|
|
251
252
|
secrets: string[];
|
|
253
|
+
/** `budget:` — the most this agent may spend in ONE run, in USD, across
|
|
254
|
+
* every step it takes in it; null is no cap. Per run and nothing else:
|
|
255
|
+
* an agent has no calendar, the workspace and the account do. */
|
|
256
|
+
budget: number | null;
|
|
257
|
+
/** What is wrong with the `budget:` line, or null. */
|
|
258
|
+
budgetProblem: string | null;
|
|
252
259
|
}
|
|
253
260
|
export declare const MODEL_TIERS: Record<string, string>;
|
|
254
261
|
export type Tier = keyof typeof MODEL_TIERS;
|
|
@@ -291,11 +298,14 @@ export interface FlowStep {
|
|
|
291
298
|
effort?: string;
|
|
292
299
|
/** Pause for a human before running this step. */
|
|
293
300
|
approve?: boolean;
|
|
294
|
-
/** Run only if the previous
|
|
295
|
-
*
|
|
301
|
+
/** Run only if the previous group's result has a line beginning with
|
|
302
|
+
* this marker (case-insensitive). The previous group is the nearest
|
|
303
|
+
* earlier one that produced a result. Independent: every matching
|
|
304
|
+
* `when:` step in a group runs. */
|
|
296
305
|
when?: string;
|
|
297
306
|
/** Exclusive routing: of a group's `case:` steps, only the FIRST whose
|
|
298
|
-
*
|
|
307
|
+
* marker leads a line of the previous group's result runs; the rest are
|
|
308
|
+
* routed past. */
|
|
299
309
|
case?: string;
|
|
300
310
|
/** The route of last resort: runs only when none of its group's `case:`
|
|
301
311
|
* steps matched. */
|
|
@@ -357,9 +367,29 @@ export interface FlowStep {
|
|
|
357
367
|
* cannot, and hands the value to the next group losslessly — the narrow
|
|
358
368
|
* move the grammar ADR allowed instead of variables. */
|
|
359
369
|
output?: "json";
|
|
370
|
+
/** `schema:` — the JSON Schema an `output: json` value must satisfy,
|
|
371
|
+
* written inline (one-line JSON, or a YAML block under the key) and
|
|
372
|
+
* checked where the reply is; a value that does not fit fails the step
|
|
373
|
+
* with the field named. */
|
|
374
|
+
schema?: Record<string, unknown> | boolean;
|
|
375
|
+
/** `schema: <path>` — the same, in a file under the workspace, read when
|
|
376
|
+
* the step runs. */
|
|
377
|
+
schemaPath?: string;
|
|
378
|
+
/** `parallel:` — how many of an `each:` step's instances run at once.
|
|
379
|
+
* Unset is all of them, which is what fan-out always did. */
|
|
380
|
+
parallel?: number;
|
|
381
|
+
/** `max_turns:` — the most model turns this step may take before it is
|
|
382
|
+
* stopped, beside `budget:` (money) and `timeout:` (time). */
|
|
383
|
+
maxTurns?: number;
|
|
360
384
|
/** 1-indexed line in the flow file. Diagnostics without a line make you
|
|
361
385
|
* search; every real linter emits file:line. */
|
|
362
386
|
line?: number;
|
|
387
|
+
/** What is wrong with an option's VALUE, in the author's words — `timeout:
|
|
388
|
+
* abc`, `retry: 9`, `each: columns`. The parser keeps the step (a run
|
|
389
|
+
* still has a shape) and the lint reports each of these as an error, so
|
|
390
|
+
* `foldrun check` fails on a value that would otherwise be read as
|
|
391
|
+
* something the author never wrote: `timeout: 15m` used to be one second. */
|
|
392
|
+
problems?: string[];
|
|
363
393
|
}
|
|
364
394
|
export interface FlowInfo {
|
|
365
395
|
name: string;
|
|
@@ -378,12 +408,20 @@ export interface FlowInfo {
|
|
|
378
408
|
* overlap) — a default that changed underfoot would surprise every flow
|
|
379
409
|
* that legitimately runs in parallel. */
|
|
380
410
|
overlap: "skip" | "queue" | null;
|
|
411
|
+
/** Where this flow's runs stand in the queue against everyone else's:
|
|
412
|
+
* "high" is claimed before the round-robin, "low" after it. Adds to the
|
|
413
|
+
* account's own priority; the account's cap still bounds how many run
|
|
414
|
+
* at once, so a high lane never starves the rest outright. Unset is
|
|
415
|
+
* normal — first come, fair across accounts. */
|
|
416
|
+
priority: "high" | "normal" | "low" | null;
|
|
381
417
|
/** The most one run of this flow may spend, in USD. A literal, never an
|
|
382
418
|
* expression — the cap is readable off the file, which is the property
|
|
383
419
|
* the whole grammar exists to keep. Checked between groups: the group
|
|
384
420
|
* that crosses it is the last one that runs. Null: no cap of its own
|
|
385
421
|
* (the workspace's monthly `budget:` still applies). */
|
|
386
422
|
budget: number | null;
|
|
423
|
+
/** What is wrong with the `budget:` line, or null. */
|
|
424
|
+
budgetProblem: string | null;
|
|
387
425
|
/** `trigger: flow` — start when this other flow of the workspace finishes,
|
|
388
426
|
* with `on:` saying which endings count. The finished run's summary and
|
|
389
427
|
* result become this run's task. */
|
|
@@ -406,6 +444,50 @@ export interface FlowInfo {
|
|
|
406
444
|
/** `trigger: storage` — a path prefix under storage/; a file landing
|
|
407
445
|
* there starts the flow with the path as its task. */
|
|
408
446
|
path: string | null;
|
|
447
|
+
/** `idempotency:` — the name of the field that identifies a delivery, so
|
|
448
|
+
* the same one twice starts one run. A header on the request
|
|
449
|
+
* ("x-github-delivery"), or "body:<key>" for a top-level field of a JSON
|
|
450
|
+
* body. A name, never an expression: the value is read from the delivery,
|
|
451
|
+
* not computed from it. Null: every delivery is its own event. */
|
|
452
|
+
idempotency: string | null;
|
|
453
|
+
/** `debounce:` — seconds of quiet before a fired trigger becomes a run.
|
|
454
|
+
* A burst of deliveries, storage writes or watched changes collapses into
|
|
455
|
+
* one run once they stop. The task is the LAST event's, since that is the
|
|
456
|
+
* state the flow is reacting to. Null: every event starts a run. */
|
|
457
|
+
debounce: number | null;
|
|
458
|
+
/** `throttle:` — the least time between two runs of this flow. A trigger
|
|
459
|
+
* arriving inside the window is dropped, and the trace of the run that
|
|
460
|
+
* held the window says how many. Null: no floor. */
|
|
461
|
+
throttle: number | null;
|
|
462
|
+
/** `catchup:` — what a scheduled flow does about a fire it missed while
|
|
463
|
+
* the platform was not running. "last" is the behaviour that always
|
|
464
|
+
* applied: one make-up run for however many were missed. "none" skips
|
|
465
|
+
* them, for a flow whose moment has passed by the time anyone notices.
|
|
466
|
+
* Null reads as "last". */
|
|
467
|
+
catchup: "last" | "none" | null;
|
|
468
|
+
/** `disable_after:` — consecutive failed runs after which the platform
|
|
469
|
+
* stops firing this flow's schedule and says so. A nightly desk that has
|
|
470
|
+
* failed all week is not going to fix itself, and every one of those runs
|
|
471
|
+
* costs money and sends mail. Null: never quarantined. */
|
|
472
|
+
disableAfter: number | null;
|
|
473
|
+
/** `sla:` — seconds a run of this flow is expected to take. A run still
|
|
474
|
+
* going well past it is reported once, as a notification, and keeps
|
|
475
|
+
* running: this is a smoke alarm, not a timeout. Null: no expectation. */
|
|
476
|
+
sla: number | null;
|
|
477
|
+
/** `approvers:` — the email addresses that may decide this flow's gates,
|
|
478
|
+
* or the single word "admins" for anyone at admin or above. Empty means
|
|
479
|
+
* the account's existing rule: any member who can run the workspace.
|
|
480
|
+
* Nobody may approve their own run's gate whatever this says. */
|
|
481
|
+
approvers: string[] | null;
|
|
482
|
+
/** `approve_within:` — how long a gate waits for a person before the run
|
|
483
|
+
* is rejected and fails. A gate with no expiry holds its run, and its
|
|
484
|
+
* place in the account's concurrency, for as long as nobody looks.
|
|
485
|
+
* Null: it waits indefinitely, which stays the default. */
|
|
486
|
+
approveWithin: number | null;
|
|
487
|
+
/** `live: true` — this flow's runs are real even where the platform would
|
|
488
|
+
* default them to test: in a preview workspace, and as an eval's subject.
|
|
489
|
+
* Only ever an opt-out of the safe default, never the other way round. */
|
|
490
|
+
live: boolean;
|
|
409
491
|
steps: FlowStep[];
|
|
410
492
|
}
|
|
411
493
|
export declare const FLOW_TRIGGERS: readonly ["manual", "schedule", "webhook", "email", "flow", "once", "watch", "storage"];
|
|
@@ -416,9 +498,25 @@ export interface AgentAssets {
|
|
|
416
498
|
}
|
|
417
499
|
export declare function agentAssets(tenant: string, workspace: string, agent: string): AgentAssets;
|
|
418
500
|
export declare function listAgents(tenant: string, workspace: string): AgentInfo[];
|
|
501
|
+
/** The most fan-out instances `parallel:` may run at once — the fan-out's
|
|
502
|
+
* own hard cap, since more slots than items is no cap. */
|
|
503
|
+
export declare const PARALLEL_CAP = 20;
|
|
504
|
+
/** The most turns `max_turns:` may allow. A turn is one model reply, tool
|
|
505
|
+
* calls included; a step that needs more than this is not one step. */
|
|
506
|
+
export declare const MAX_TURNS_CAP = 500;
|
|
419
507
|
/** "90s", "30m", "4h", "3d" — or a bare number of seconds. Clamped to 30
|
|
420
508
|
* days: a wait is a pause in a flow, not a second scheduler. */
|
|
421
509
|
export declare function parseWait(value: string): number | undefined;
|
|
510
|
+
/** The one duration grammar every key shares — `wait:`, `timeout:`, the
|
|
511
|
+
* flow's `throttle:`/`debounce:`/`sla:` — as whole seconds, at least 1.
|
|
512
|
+
* Undefined for anything that is not one: the caller says what the key
|
|
513
|
+
* was, because "not a duration" is only useful with the line it names. */
|
|
514
|
+
export declare function parseDuration(value: string): number | undefined;
|
|
515
|
+
/** `timeout:` — the same units `wait:` takes, and no ceiling: the platform
|
|
516
|
+
* sets no clock of its own, so the author's number stands as written.
|
|
517
|
+
* `timeout: 15m` was `Math.max(1, Number("15m") || 0)` — one second — and
|
|
518
|
+
* every step wearing it was cut off before its first tool call returned. */
|
|
519
|
+
export declare function parseTimeout(value: string): number | undefined;
|
|
422
520
|
/** An ISO 8601 instant (YAML may already have parsed it into a Date), or
|
|
423
521
|
* null for anything that is not one — a `once` flow with an unreadable
|
|
424
522
|
* `at:` never fires, and `foldrun check` says so. */
|
|
@@ -443,7 +541,48 @@ export declare function parseInstant(raw: unknown): string | null;
|
|
|
443
541
|
* they are two pairs, not one wrapper.
|
|
444
542
|
*/
|
|
445
543
|
export declare function unquote(raw: string): string;
|
|
544
|
+
/**
|
|
545
|
+
* Does this text carry the marker a `when:` is looking for?
|
|
546
|
+
*
|
|
547
|
+
* At the START OF A LINE, not anywhere in the prose. A plain substring
|
|
548
|
+
* search is the obvious implementation and it is wrong in a way that is
|
|
549
|
+
* very hard to see: an agent writing
|
|
550
|
+
*
|
|
551
|
+
* There are no BLOCKED items this week.
|
|
552
|
+
*
|
|
553
|
+
* opened a `when: BLOCKED` gate, because the word is right there. Saying a
|
|
554
|
+
* marker is absent necessarily names it, so the more carefully an agent
|
|
555
|
+
* explains itself the more likely it is to trip its own condition. It bit
|
|
556
|
+
* one desk on its first run and sat latent in another.
|
|
557
|
+
*
|
|
558
|
+
* A verdict is written as a headline — the line leads with it — so leading
|
|
559
|
+
* position is what distinguishes "this is my verdict" from "here is a word
|
|
560
|
+
* I am using in a sentence". Markdown decoration in front of it is fine: a
|
|
561
|
+
* heading, a bullet or bold is still a line that leads with the marker.
|
|
562
|
+
*
|
|
563
|
+
* The marker must also END at a boundary, so BLOCKED does not match
|
|
564
|
+
* BLOCKEDBY.
|
|
565
|
+
*/
|
|
566
|
+
export declare function markerPresent(text: string | null | undefined, marker: string): boolean;
|
|
446
567
|
export declare function parseFlow(file: string, raw: string): FlowInfo;
|
|
568
|
+
/** A schema written out: JSON, or YAML (parsed as frontmatter is, by the
|
|
569
|
+
* same engine). The result must be an object — a schema is a document,
|
|
570
|
+
* and `schema: 3` or `schema: [a, b]` describes nothing. */
|
|
571
|
+
export declare function parseSchemaText(text: string): {
|
|
572
|
+
schema: Record<string, unknown> | boolean;
|
|
573
|
+
} | {
|
|
574
|
+
problem: string;
|
|
575
|
+
};
|
|
576
|
+
/** May this person decide a gate of this flow? `approvers:` is an allowlist
|
|
577
|
+
* of addresses plus the word "admins"; an empty list defers to whatever
|
|
578
|
+
* permission the caller already needed to reach the route.
|
|
579
|
+
*
|
|
580
|
+
* Self-approval is refused separately (see approvals.ts): who STARTED a run
|
|
581
|
+
* is a property of the run, not of the flow file. */
|
|
582
|
+
export declare function mayApprove(flow: Pick<FlowInfo, "approvers"> | null | undefined, who: {
|
|
583
|
+
email?: string | null;
|
|
584
|
+
role?: string | null;
|
|
585
|
+
}): boolean;
|
|
447
586
|
/** A live run of this flow — the fact overlap: decisions are made on. */
|
|
448
587
|
export declare function flowHasLiveRun(tenant: string, workspace: string, flowName: string): boolean;
|
|
449
588
|
/**
|
|
@@ -489,6 +628,10 @@ export declare function addFlowStep(raw: string, step: {
|
|
|
489
628
|
/** Drop one step, by its index in the flow's parsed steps. */
|
|
490
629
|
export declare function removeFlowStep(raw: string, index: number): string;
|
|
491
630
|
export declare function listFlows(tenant: string, workspace: string): FlowInfo[];
|
|
631
|
+
/** One flow of a workspace by name, or null. The same read listFlows makes,
|
|
632
|
+
* named so callers that want a single flow — the approval rules, the
|
|
633
|
+
* runner's budget stamp — do not each re-implement the directory walk. */
|
|
634
|
+
export declare function readFlow(tenant: string, workspace: string, flowName: string): FlowInfo | null;
|
|
492
635
|
export interface WorkspaceSummary {
|
|
493
636
|
name: string;
|
|
494
637
|
description: string;
|
|
@@ -565,6 +708,9 @@ export interface ChangeMeta {
|
|
|
565
708
|
message?: string;
|
|
566
709
|
}
|
|
567
710
|
export declare function writeWorkspaceFile(tenant: string, workspace: string, rel: string, content: string, meta?: ChangeMeta): void;
|
|
711
|
+
/** Tell the platform, and never let its listener fail a write. */
|
|
712
|
+
declare function workspaceChanged(tenant: string, workspace: string, why: "write" | "deploy" | "push" | "delete"): void;
|
|
713
|
+
export { workspaceChanged as notifyWorkspaceChanged };
|
|
568
714
|
export declare function syncBundleFor(file: string, change?: "Creation" | "Update"): void;
|
|
569
715
|
/**
|
|
570
716
|
* Rename one editable file. Both ends pass the same gate as a write — a
|
|
@@ -633,7 +779,32 @@ export interface RunEvent {
|
|
|
633
779
|
call?: string;
|
|
634
780
|
ms?: number;
|
|
635
781
|
err?: boolean;
|
|
782
|
+
/** Set on a test run's event that reports what the platform did instead
|
|
783
|
+
* of the real thing — a refused send, a redirected email, a diverted
|
|
784
|
+
* state write, a withheld secret. The run page lists these; the text is
|
|
785
|
+
* still the trace's line. See test-mode.ts. */
|
|
786
|
+
effect?: TestEffect;
|
|
636
787
|
}
|
|
788
|
+
/** One attempt of a step — see StepRecord.tries. */
|
|
789
|
+
export interface StepAttempt {
|
|
790
|
+
/** Which attempt, 1-based: `attempts` on the step at the time. */
|
|
791
|
+
n: number;
|
|
792
|
+
status: "completed" | "failed";
|
|
793
|
+
costUsd: number | null;
|
|
794
|
+
tokens: {
|
|
795
|
+
input: number;
|
|
796
|
+
output: number;
|
|
797
|
+
} | null;
|
|
798
|
+
computeSecs: number | null;
|
|
799
|
+
startedAt: string;
|
|
800
|
+
finishedAt: string;
|
|
801
|
+
/** The last error event this attempt wrote, when it failed. */
|
|
802
|
+
error?: string;
|
|
803
|
+
}
|
|
804
|
+
/** The step's totals across its attempts, from the rows. Null where no
|
|
805
|
+
* attempt reported the figure — an in-process step rents no sandbox, and
|
|
806
|
+
* billing reads null as zero, not as "unknown, charge something". */
|
|
807
|
+
export declare function sumAttempts(tries: StepAttempt[]): Pick<StepAttempt, "costUsd" | "tokens" | "computeSecs">;
|
|
637
808
|
export interface StepRecord {
|
|
638
809
|
agent: string;
|
|
639
810
|
instruction: string;
|
|
@@ -653,6 +824,32 @@ export interface StepRecord {
|
|
|
653
824
|
verify?: string;
|
|
654
825
|
/** Attempts made so far, for the run trace. */
|
|
655
826
|
attempts?: number;
|
|
827
|
+
/**
|
|
828
|
+
* One row per attempt, oldest first: what each cost and how it ended.
|
|
829
|
+
* `costUsd`, `tokens` and `computeSecs` on the step are the SUM of these
|
|
830
|
+
* rows — a retried step spent every attempt's money, and the run's spend,
|
|
831
|
+
* the flow's `budget:` and the platform's bill all read the step's
|
|
832
|
+
* figure, so the figure is the total. Before this the step carried only
|
|
833
|
+
* the last attempt's cost and a `retry: 2` step could spend three shares
|
|
834
|
+
* of the budget while reporting one. A loop cycle that re-runs the step
|
|
835
|
+
* appends here too, so its earlier cycles are not lost from the bill.
|
|
836
|
+
*/
|
|
837
|
+
tries?: StepAttempt[];
|
|
838
|
+
/** The sandbox this step is executing in, while it is: which executor,
|
|
839
|
+
* its handle (a pod name), and how many of its output lines the driver
|
|
840
|
+
* has already applied to this record. What a driver that inherits the
|
|
841
|
+
* run — after a deploy rolled the last one, or it crashed — needs to
|
|
842
|
+
* re-attach and carry on rather than run the step again. Cleared when
|
|
843
|
+
* the step settles. */
|
|
844
|
+
sandbox?: {
|
|
845
|
+
kind: string;
|
|
846
|
+
ref: string;
|
|
847
|
+
consumed: number;
|
|
848
|
+
since: string;
|
|
849
|
+
} | null;
|
|
850
|
+
/** A size class a retry moved the step up to (an evicted or OOM-killed
|
|
851
|
+
* attempt), overriding the agent's own `size:` for the attempts after. */
|
|
852
|
+
sizeUp?: "large" | "heavy";
|
|
656
853
|
/** When the step actually started and finished executing — not when the
|
|
657
854
|
* run reached it. A step's events approximate this (first and last), but
|
|
658
855
|
* a model can think for minutes before its first tool call, and a step
|
|
@@ -675,6 +872,10 @@ export interface StepRecord {
|
|
|
675
872
|
max?: number;
|
|
676
873
|
/** Carried from the flow — see FlowStep. */
|
|
677
874
|
output?: "json";
|
|
875
|
+
schema?: Record<string, unknown> | boolean;
|
|
876
|
+
schemaPath?: string;
|
|
877
|
+
parallel?: number;
|
|
878
|
+
maxTurns?: number;
|
|
678
879
|
/** The parsed JSON an `output: json` step returned. Kept beside the prose
|
|
679
880
|
* result rather than instead of it: the reply is still what a person
|
|
680
881
|
* reads on the run page, and the data is what the next step computes on. */
|
|
@@ -808,6 +1009,26 @@ export interface RunRecord {
|
|
|
808
1009
|
* the agents decided was worth remembering, listed so a person can review
|
|
809
1010
|
* the lesson without diffing the folder. */
|
|
810
1011
|
memoryWrites?: string[];
|
|
1012
|
+
/** Who asked for this run, when a person did: their email address. A
|
|
1013
|
+
* schedule, a webhook and a chained flow have no one, and leave it unset.
|
|
1014
|
+
* Kept so a gate can refuse the one approval nobody should be able to
|
|
1015
|
+
* give — your own. */
|
|
1016
|
+
startedBy?: string | null;
|
|
1017
|
+
/** When this run's gate stops waiting, stamped the moment it parks from
|
|
1018
|
+
* the flow's `approve_within:`. A gate nobody answers by then is rejected
|
|
1019
|
+
* and the run fails, rather than holding a concurrency slot forever. */
|
|
1020
|
+
approveBy?: string | null;
|
|
1021
|
+
/** A test run: every step runs for real, against the real files and the
|
|
1022
|
+
* real read APIs, but nothing outward happens — sends are refused or
|
|
1023
|
+
* sunk at the egress proxy, send-capable secrets never enter the
|
|
1024
|
+
* sandbox, and state/ and storage/ writes land under this run's own
|
|
1025
|
+
* directory. On the record, not in an env var, so a script cannot turn
|
|
1026
|
+
* it off; carried onto every rerun of this run. See test-mode.ts. */
|
|
1027
|
+
test?: boolean;
|
|
1028
|
+
/** Digests of the emailed approval links that have already decided a
|
|
1029
|
+
* step of this run — never the tokens. A link is good once; the second
|
|
1030
|
+
* click is a 409, not a second approval. Written by approvals.ts. */
|
|
1031
|
+
approvalLinksUsed?: string[];
|
|
811
1032
|
steps: StepRecord[];
|
|
812
1033
|
}
|
|
813
1034
|
export declare function runFilePath(tenant: string, workspace: string, runId: string): string;
|
|
@@ -854,7 +1075,81 @@ export declare function writeRun(tenant: string, workspace: string, run: RunReco
|
|
|
854
1075
|
export interface RunWithWorkspace extends RunRecord {
|
|
855
1076
|
workspace: string;
|
|
856
1077
|
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Every run in the account, newest first, off the per-workspace index.
|
|
1080
|
+
*
|
|
1081
|
+
* A finished run comes back as the index knows it: id, flow, status,
|
|
1082
|
+
* summary, times, and each step's agent, group, status, cost, tokens,
|
|
1083
|
+
* seconds, skip reason and last error — with `instruction` empty, `events`
|
|
1084
|
+
* holding only that error, and `result` null. That is what every list and
|
|
1085
|
+
* every rollup reads (runCost, runFailure, runDurationSecs, the usage
|
|
1086
|
+
* window, the graph's stats). A run that is still live — queued, running,
|
|
1087
|
+
* or parked at a gate — is read whole, because the gate's question and its
|
|
1088
|
+
* events are what the approvals list shows. Anything wanting a finished
|
|
1089
|
+
* run's reply or trace opens it with readRun.
|
|
1090
|
+
*
|
|
1091
|
+
* This used to parse every run file of every workspace on every call, and
|
|
1092
|
+
* the dashboard calls it every twenty seconds per open tab.
|
|
1093
|
+
*/
|
|
857
1094
|
export declare function listAllRuns(tenant: string): RunWithWorkspace[];
|
|
1095
|
+
/** What a list knows about one step. */
|
|
1096
|
+
export interface RunSummaryStep {
|
|
1097
|
+
agent: string;
|
|
1098
|
+
group: number;
|
|
1099
|
+
status: StepRecord["status"];
|
|
1100
|
+
costUsd: number | null;
|
|
1101
|
+
tokens?: {
|
|
1102
|
+
input: number;
|
|
1103
|
+
output: number;
|
|
1104
|
+
} | null;
|
|
1105
|
+
computeSecs?: number | null;
|
|
1106
|
+
skipReason?: string;
|
|
1107
|
+
/** The last error event, for a failed step — what runFailure reads. */
|
|
1108
|
+
error?: string;
|
|
1109
|
+
item?: string;
|
|
1110
|
+
waitFor?: "event";
|
|
1111
|
+
ask?: string;
|
|
1112
|
+
/** The step's instruction, kept for a parked step so the approvals banner can show the question without the record. */
|
|
1113
|
+
instruction?: string;
|
|
1114
|
+
/** When a parked step last spoke — the moment the banner sorts by. */
|
|
1115
|
+
waitingSince?: string;
|
|
1116
|
+
startedAt?: string;
|
|
1117
|
+
finishedAt?: string;
|
|
1118
|
+
}
|
|
1119
|
+
/** What a list knows about one run. */
|
|
1120
|
+
export interface RunSummary {
|
|
1121
|
+
id: string;
|
|
1122
|
+
flow: string;
|
|
1123
|
+
status: RunRecord["status"];
|
|
1124
|
+
summary: string | null;
|
|
1125
|
+
startedAt: string;
|
|
1126
|
+
finishedAt: string | null;
|
|
1127
|
+
stopRequested?: boolean;
|
|
1128
|
+
test?: boolean;
|
|
1129
|
+
budgetUsd?: number | null;
|
|
1130
|
+
tags?: string[];
|
|
1131
|
+
startedBy?: string | null;
|
|
1132
|
+
parkedAt?: string | null;
|
|
1133
|
+
/** A step is parked for a person — what the approvals banner counts. */
|
|
1134
|
+
awaitingApproval: boolean;
|
|
1135
|
+
steps: RunSummaryStep[];
|
|
1136
|
+
}
|
|
1137
|
+
/** One run's row. */
|
|
1138
|
+
export declare function summarizeRun(run: RunRecord): RunSummary;
|
|
1139
|
+
/** A RunRecord with the shape a list reads and nothing else — see listAllRuns. */
|
|
1140
|
+
export declare function runFromSummary(s: RunSummary): RunRecord;
|
|
1141
|
+
/**
|
|
1142
|
+
* The workspace's runs as the index knows them, newest first — the call a
|
|
1143
|
+
* list makes. Reconciled against the directory on every read: rows for
|
|
1144
|
+
* records that are gone are dropped, records with no row or a moved mtime
|
|
1145
|
+
* are re-read, and the index is rewritten if anything changed. A missing
|
|
1146
|
+
* or unreadable index is a full scan that leaves one behind.
|
|
1147
|
+
*/
|
|
1148
|
+
export declare function listRunSummaries(tenant: string, workspace: string): RunSummary[];
|
|
1149
|
+
/** Every workspace's runs as summaries, tagged with the workspace. */
|
|
1150
|
+
export declare function listAllRunSummaries(tenant: string): (RunSummary & {
|
|
1151
|
+
workspace: string;
|
|
1152
|
+
})[];
|
|
858
1153
|
/**
|
|
859
1154
|
* The status a person should see. "failed" and "someone stopped it" are
|
|
860
1155
|
* different facts — the record keeps them apart (stopRequested), and the
|
|
@@ -973,6 +1268,8 @@ export interface AgentStep {
|
|
|
973
1268
|
* step-io-model, which is the pure copy the client can import. */
|
|
974
1269
|
export declare function deniedPaths(step: Pick<StepRecord, "events">): number;
|
|
975
1270
|
export declare function listAgentSteps(tenant: string, workspace: string, agent: string): AgentStep[];
|
|
1271
|
+
/** Every run of the workspace, whole, newest first. Parses every record;
|
|
1272
|
+
* a list that needs only what a list needs reads listRunSummaries. */
|
|
976
1273
|
export declare function listRuns(tenant: string, workspace: string): RunRecord[];
|
|
977
1274
|
/**
|
|
978
1275
|
* `provider:` — which endpoint the model calls run against, and the two
|