@archmax-ai/harness 0.9.0 → 1.0.1
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 +58 -14
- package/dist/agent.d.ts +4 -6
- package/dist/agent.js +4 -6
- package/dist/agent.js.map +1 -1
- package/dist/assembly/compose.d.ts +5 -24
- package/dist/assembly/compose.js +28 -42
- package/dist/assembly/compose.js.map +1 -1
- package/dist/assembly/delegation-registry.js +3 -14
- package/dist/assembly/delegation-registry.js.map +1 -1
- package/dist/assembly/index.d.ts +8 -15
- package/dist/assembly/index.js +21 -28
- package/dist/assembly/index.js.map +1 -1
- package/dist/assembly/plain.js +1 -2
- package/dist/assembly/plain.js.map +1 -1
- package/dist/authoring-skill/archmax-harness/README.md +5 -5
- package/dist/authoring-skill/archmax-harness/SKILL.md +72 -30
- package/dist/authoring-skill/archmax-harness/references/backend-integration.md +33 -24
- package/dist/authoring-skill/archmax-harness/references/cases.md +41 -8
- package/dist/authoring-skill/archmax-harness/references/{hook-and-test-scripts.md → code-state-and-test-scripts.md} +599 -339
- package/dist/authoring-skill/archmax-harness/references/code-states-and-scripts.md +115 -0
- package/dist/authoring-skill/archmax-harness/references/diagnostics.md +40 -7
- package/dist/authoring-skill/archmax-harness/references/wiring.md +19 -10
- package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +404 -293
- package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +151 -62
- package/dist/cli/state-flow.d.ts +1 -1
- package/dist/cli/state-flow.js +18 -28
- package/dist/cli/state-flow.js.map +1 -1
- package/dist/cli/turn.d.ts +1 -1
- package/dist/cli/turn.js +1 -1
- package/dist/core/code-description.d.ts +3 -3
- package/dist/core/code-description.js +3 -3
- package/dist/core/deepagents.d.ts +5 -12
- package/dist/core/deepagents.js +4 -17
- package/dist/core/deepagents.js.map +1 -1
- package/dist/core/events.d.ts +23 -42
- package/dist/core/events.js +21 -24
- package/dist/core/events.js.map +1 -1
- package/dist/core/message-readers.d.ts +4 -5
- package/dist/core/message-readers.js +3 -8
- package/dist/core/message-readers.js.map +1 -1
- package/dist/core/messages.d.ts +0 -22
- package/dist/core/messages.js +1 -32
- package/dist/core/messages.js.map +1 -1
- package/dist/core/mounts.js +3 -3
- package/dist/core/platform-prompt.generated.js +1 -1
- package/dist/core/platform-prompt.generated.js.map +1 -1
- package/dist/core/session-zone.d.ts +1 -1
- package/dist/core/session-zone.js +1 -1
- package/dist/core/workspace-context.d.ts +1 -1
- package/dist/core/workspace.d.ts +1 -1
- package/dist/core/workspace.js +1 -1
- package/dist/core/zones.d.ts +4 -4
- package/dist/core/zones.js +5 -5
- package/dist/core/zones.js.map +1 -1
- package/dist/env.d.ts +9 -9
- package/dist/index.d.ts +3 -7
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/kernel/kernel.d.ts +31 -61
- package/dist/kernel/kernel.js +54 -112
- package/dist/kernel/kernel.js.map +1 -1
- package/dist/machine/lint-spec.js +53 -12
- package/dist/machine/lint-spec.js.map +1 -1
- package/dist/machine/machine.d.ts +36 -18
- package/dist/machine/machine.js +62 -51
- package/dist/machine/machine.js.map +1 -1
- package/dist/machine/spec-schema.d.ts +32 -180
- package/dist/machine/spec-schema.js +52 -113
- package/dist/machine/spec-schema.js.map +1 -1
- package/dist/machine/tool-names.d.ts +34 -16
- package/dist/machine/tool-names.js +41 -16
- package/dist/machine/tool-names.js.map +1 -1
- package/dist/machine/types.d.ts +14 -46
- package/dist/machine/types.js +0 -2
- package/dist/machine/types.js.map +1 -1
- package/dist/machine/validate-spec.d.ts +1 -1
- package/dist/public/sandbox.d.ts +59 -95
- package/dist/public/sandbox.js +22 -23
- package/dist/public/sandbox.js.map +1 -1
- package/dist/public/spec.d.ts +13 -20
- package/dist/public/spec.js +12 -20
- package/dist/public/spec.js.map +1 -1
- package/dist/runtime/contract.d.ts +11 -12
- package/dist/runtime/contract.js +16 -16
- package/dist/runtime/contract.js.map +1 -1
- package/dist/sandbox/assets/parts/code-state.js +17 -0
- package/dist/sandbox/executor.d.ts +25 -7
- package/dist/sandbox/executor.js +56 -57
- package/dist/sandbox/executor.js.map +1 -1
- package/dist/sandbox/imports.d.ts +10 -10
- package/dist/sandbox/imports.js +11 -11
- package/dist/sandbox/imports.js.map +1 -1
- package/dist/sandbox/prelude.d.ts +5 -6
- package/dist/sandbox/prelude.js +38 -35
- package/dist/sandbox/prelude.js.map +1 -1
- package/dist/sandbox/ptc-gateway.d.ts +19 -18
- package/dist/sandbox/ptc-gateway.js +26 -22
- package/dist/sandbox/ptc-gateway.js.map +1 -1
- package/dist/sessions/resume.d.ts +2 -2
- package/dist/sessions/resume.js +1 -1
- package/dist/sessions/resume.js.map +1 -1
- package/dist/sessions/scope.d.ts +0 -10
- package/dist/sessions/scope.js +0 -17
- package/dist/sessions/scope.js.map +1 -1
- package/dist/sessions/summary.d.ts +1 -1
- package/dist/testing/assertions.js +9 -4
- package/dist/testing/assertions.js.map +1 -1
- package/dist/testing/driver.js +3 -0
- package/dist/testing/driver.js.map +1 -1
- package/dist/testing/interpreter.d.ts +2 -2
- package/dist/testing/runner.d.ts +2 -2
- package/dist/validate/validate.d.ts +1 -1
- package/dist/validate/validate.js +39 -70
- package/dist/validate/validate.js.map +1 -1
- package/dist/workflow/automated-controls.d.ts +63 -0
- package/dist/workflow/automated-controls.js +158 -0
- package/dist/workflow/automated-controls.js.map +1 -0
- package/dist/workflow/automated.d.ts +112 -0
- package/dist/workflow/automated.js +163 -0
- package/dist/workflow/automated.js.map +1 -0
- package/dist/workflow/code-state.d.ts +46 -0
- package/dist/workflow/code-state.js +26 -0
- package/dist/workflow/code-state.js.map +1 -0
- package/dist/workflow/control-tools.d.ts +54 -23
- package/dist/workflow/control-tools.js +99 -79
- package/dist/workflow/control-tools.js.map +1 -1
- package/dist/workflow/file-values.d.ts +4 -4
- package/dist/workflow/file-values.js +1 -1
- package/dist/workflow/file-values.js.map +1 -1
- package/dist/workflow/governance.d.ts +11 -22
- package/dist/workflow/governance.js +47 -104
- package/dist/workflow/governance.js.map +1 -1
- package/dist/workflow/grader-state.d.ts +55 -0
- package/dist/workflow/grader-state.js +182 -0
- package/dist/workflow/grader-state.js.map +1 -0
- package/dist/workflow/history.d.ts +11 -0
- package/dist/{lifecycle/transcript.js → workflow/history.js} +24 -8
- package/dist/workflow/history.js.map +1 -0
- package/dist/workflow/middleware.d.ts +14 -17
- package/dist/workflow/middleware.js +109 -95
- package/dist/workflow/middleware.js.map +1 -1
- package/dist/workflow/move-events.d.ts +21 -0
- package/dist/workflow/move-events.js +20 -0
- package/dist/workflow/move-events.js.map +1 -0
- package/dist/workflow/on-error.js +0 -2
- package/dist/workflow/on-error.js.map +1 -1
- package/dist/workflow/parks.d.ts +9 -2
- package/dist/workflow/parks.js +16 -10
- package/dist/workflow/parks.js.map +1 -1
- package/dist/workflow/paths.d.ts +9 -9
- package/dist/workflow/paths.js +19 -19
- package/dist/workflow/paths.js.map +1 -1
- package/dist/workflow/render-prompt.d.ts +7 -5
- package/dist/workflow/render-prompt.js +22 -37
- package/dist/workflow/render-prompt.js.map +1 -1
- package/dist/workflow/signature-checks.d.ts +2 -2
- package/dist/workflow/snapshot.js +5 -29
- package/dist/workflow/snapshot.js.map +1 -1
- package/dist/workflow/state.d.ts +14 -42
- package/dist/workflow/state.js +20 -33
- package/dist/workflow/state.js.map +1 -1
- package/dist/workflow/sub-workflow.d.ts +3 -3
- package/dist/workflow/sub-workflow.js +3 -7
- package/dist/workflow/sub-workflow.js.map +1 -1
- package/dist/workflow/tool-service.d.ts +1 -9
- package/dist/workflow/tool-service.js +21 -24
- package/dist/workflow/tool-service.js.map +1 -1
- package/dist/workflow/turn-boundary.d.ts +2 -2
- package/dist/workflow/turn-boundary.js +10 -15
- package/dist/workflow/turn-boundary.js.map +1 -1
- package/dist/workflow/turn-runner.js +5 -6
- package/dist/workflow/turn-runner.js.map +1 -1
- package/package.json +2 -2
- package/skills/archmax-harness/README.md +5 -5
- package/skills/archmax-harness/SKILL.md +72 -30
- package/skills/archmax-harness/references/backend-integration.md +33 -24
- package/skills/archmax-harness/references/cases.md +41 -8
- package/skills/archmax-harness/references/{hook-and-test-scripts.md → code-state-and-test-scripts.md} +599 -339
- package/skills/archmax-harness/references/code-states-and-scripts.md +115 -0
- package/skills/archmax-harness/references/diagnostics.md +40 -7
- package/skills/archmax-harness/references/wiring.md +19 -10
- package/skills/archmax-harness/references/workflow-schema.md +404 -293
- package/skills/archmax-harness/references/workflow-yaml.md +151 -62
- package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +0 -89
- package/dist/lifecycle/hook-shape.d.ts +0 -44
- package/dist/lifecycle/hook-shape.js +0 -66
- package/dist/lifecycle/hook-shape.js.map +0 -1
- package/dist/lifecycle/runner.d.ts +0 -197
- package/dist/lifecycle/runner.js +0 -419
- package/dist/lifecycle/runner.js.map +0 -1
- package/dist/lifecycle/tool-calls.d.ts +0 -9
- package/dist/lifecycle/tool-calls.js +0 -57
- package/dist/lifecycle/tool-calls.js.map +0 -1
- package/dist/lifecycle/transcript.d.ts +0 -31
- package/dist/lifecycle/transcript.js.map +0 -1
- package/dist/rubrics/rubrics.d.ts +0 -135
- package/dist/rubrics/rubrics.js +0 -145
- package/dist/rubrics/rubrics.js.map +0 -1
- package/dist/sandbox/assets/parts/core.js +0 -22
- package/dist/sandbox/assets/parts/lifecycle-hook.js +0 -47
- package/dist/sandbox/bridge.d.ts +0 -16
- package/dist/sandbox/bridge.js +0 -95
- package/dist/sandbox/bridge.js.map +0 -1
- package/dist/workflow/visits.d.ts +0 -21
- package/dist/workflow/visits.js +0 -45
- package/dist/workflow/visits.js.map +0 -1
- package/skills/archmax-harness/references/hooks-and-scripts.md +0 -89
|
@@ -14,7 +14,7 @@ instructions: |- # standing direction for the whole run (warning
|
|
|
14
14
|
Records live in skills/order-data/assets/orders.json; write artifacts under scratchpad/.
|
|
15
15
|
|
|
16
16
|
Answer only from records you have read; never fabricate.
|
|
17
|
-
runtime: { engine: archmax-harness, version: "
|
|
17
|
+
runtime: { engine: archmax-harness, version: "3" } # 3 is the only contract; omitted = 3
|
|
18
18
|
disabled: false # true = out of service: no new turns; parked runs still drain
|
|
19
19
|
settings: # sandbox limits: timeoutMs, memoryLimitBytes, maxPtcCalls,
|
|
20
20
|
timeoutMs: 15000 # maxResultChars, prompt_cache: { enabled, ttl }
|
|
@@ -23,9 +23,7 @@ tests: # case suite config (no tests.config.js exists)
|
|
|
23
23
|
maxConcurrency: 1 # only 1 accepted
|
|
24
24
|
caseTimeoutMs: 120000 # per-case wall clock, distinct from settings.timeoutMs
|
|
25
25
|
judge: {} # required for grade:; {} = env default model, or { model, modelOptions }
|
|
26
|
-
|
|
27
|
-
metadata: { canvas: {} } # host data, never read; accepted at root, state, rubric — leave as found
|
|
28
|
-
extensions: { hooks: [] } # host-registered hook kinds; rarely authored
|
|
26
|
+
metadata: { canvas: {} } # host data, never read; accepted at root and on a state — leave as found
|
|
29
27
|
|
|
30
28
|
tools: # tool governance, workflow level
|
|
31
29
|
allow_always: # granted in EVERY state; a state's allow adds to or narrows it.
|
|
@@ -48,7 +46,7 @@ skills: # skill governance, workflow level — SLUGS, n
|
|
|
48
46
|
|
|
49
47
|
states:
|
|
50
48
|
triage: # key = slug = identity (^[a-z0-9]+(-[a-z0-9]+)*$)
|
|
51
|
-
type: agent # agent (default) | human
|
|
49
|
+
type: agent # agent (default) | human | grader | code (grader/code = automated)
|
|
52
50
|
title: Triage request # label for people/hosts; reaches no model call
|
|
53
51
|
summary: Record the refund decision for review. # ditto: an authoring/host label, NOT in the prompt
|
|
54
52
|
triggers: # a trigger is declared on the state it ENTERS; key = id
|
|
@@ -66,17 +64,8 @@ states:
|
|
|
66
64
|
# entry types: string integer number boolean date date-time object array file
|
|
67
65
|
instructions: >-
|
|
68
66
|
Record the decision in scratchpad/refund.json, then archmax_advance to
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- script: hooks/check-requester.js
|
|
72
|
-
after: # gates the archmax_advance out (or completion, when terminal)
|
|
73
|
-
- script: hooks/check-policy.js
|
|
74
|
-
max_iterations: 2 # how many `correct`s before a hard veto (per hook; default 0)
|
|
75
|
-
- rubric: # LLM grader, inline; the agent never sees it
|
|
76
|
-
instructions: |- # the only required key: criteria + verdict (ok/correct/veto + reason)
|
|
77
|
-
Judge the tone of the last assistant message …
|
|
78
|
-
max_iterations: 1
|
|
79
|
-
model: gpt-4.1-mini # optional override
|
|
67
|
+
check-policy; never close the case yourself. If a note sends the case
|
|
68
|
+
back, fix what it names and advance again.
|
|
80
69
|
tools:
|
|
81
70
|
allow: # adds to allow_always; entry = name | { tool, args: {<arg>: [globs]} } | { tool, paths }
|
|
82
71
|
- lookup_customer
|
|
@@ -94,13 +83,27 @@ states:
|
|
|
94
83
|
on_error: closed # where a terminal failure of this segment routes
|
|
95
84
|
metadata: { x: 40, y: 180 }
|
|
96
85
|
transitions: # none => terminal state
|
|
97
|
-
- to:
|
|
98
|
-
description: The decision is recorded
|
|
86
|
+
- to: check-policy # slug; must exist
|
|
87
|
+
description: The decision is recorded in scratchpad/refund.json. # what the agent routes
|
|
99
88
|
# on. Say WHEN, never where. Omit it to route on the target's
|
|
100
89
|
# instructions instead (target must have some); REQUIRED on a
|
|
101
|
-
# human state's transitions
|
|
90
|
+
# human state's transitions (the button label) and on every edge
|
|
91
|
+
# INTO a grader or code state, like this one.
|
|
102
92
|
type: none # approve | reject | refine | none — semantic on human states
|
|
103
93
|
|
|
94
|
+
check-policy: # CODE state: the runtime runs its script on entry, NO model call
|
|
95
|
+
type: code
|
|
96
|
+
script: scripts/check-policy.js # REQUIRED on a code state, refused on any other type; resolves
|
|
97
|
+
# to workflows/<slug>/scripts/check-policy.js (.js|.mjs, no `..`)
|
|
98
|
+
summary: Re-derive the decision from the refund policy. # instructions/model/budget/evidence/
|
|
99
|
+
# approvers here are validate ERRORS: nothing reads them
|
|
100
|
+
skills: { allow: [order-data] } # the script's tools are THIS state's surface: grant here
|
|
101
|
+
# what it reads or calls (another state's grant never reaches it)
|
|
102
|
+
on_error: closed # a throw, a timeout, or finishing undecided routes here
|
|
103
|
+
transitions: # the script takes one: tools.archmax_advance({ to, reason })
|
|
104
|
+
- { to: review, description: The recorded decision matches the policy. }
|
|
105
|
+
- { to: triage, description: The decision contradicts the policy; send it back with the fix. }
|
|
106
|
+
|
|
104
107
|
review: # human state: parks with a decision record; a PERSON picks the edge
|
|
105
108
|
type: human
|
|
106
109
|
title: Review refund
|
|
@@ -110,27 +113,57 @@ states:
|
|
|
110
113
|
approvers: [finance@acme.com]
|
|
111
114
|
evidence: [scratchpad/refund.json] # plus whatever archmax_advance attached via `evidence:`
|
|
112
115
|
transitions: # required; no self-edge; one target per labeled type
|
|
113
|
-
- { to:
|
|
116
|
+
- { to: reply, type: approve, description: Approve; tell the customer. }
|
|
114
117
|
- { to: triage, type: refine, description: Send back with a comment. }
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
reply: # agent state (type omitted)
|
|
120
|
+
instructions: >-
|
|
121
|
+
Draft the customer's email in scratchpad/reply.md, then archmax_advance to
|
|
122
|
+
grade-reply; if a note sends it back, revise the draft as it says.
|
|
123
|
+
transitions:
|
|
124
|
+
- { to: grade-reply, description: The email is drafted in scratchpad/reply.md. }
|
|
125
|
+
|
|
126
|
+
grade-reply: # GRADER state: an isolated grader judges WORK HANDED ON (a draft,
|
|
127
|
+
type: grader # a report), never a live answer: a turn's reply is every text
|
|
128
|
+
# the agent said, a draft sent back included
|
|
129
|
+
instructions: |- # REQUIRED: its criteria, appended to a compiled-in grader preamble
|
|
130
|
+
Judge only the tone of scratchpad/reply.md.
|
|
131
|
+
- Friendly and professional: advance to `send-reply`.
|
|
132
|
+
- Curt or cold: advance back to `reply`, saying exactly what to change.
|
|
133
|
+
- If archmax_get_history's trail already holds two steps with kind
|
|
134
|
+
"grader" and to "reply", raise `reply-tone` instead of sending it back.
|
|
135
|
+
model: gpt-4.1-mini # optional; resolved under the `grader` model role
|
|
136
|
+
budget: { maxTurns: 4, timeoutMs: 60000 } # ITS OWN model calls / run time; no maxParks
|
|
137
|
+
on_error: closed # fails closed: an undecided grader routes here
|
|
138
|
+
transitions: # REQUIRED, at least one; no evidence/approvers on a grader
|
|
139
|
+
- { to: send-reply, description: The draft is friendly and professional. }
|
|
140
|
+
- { to: reply, description: The tone is off; send it back naming what to change. }
|
|
141
|
+
|
|
142
|
+
send-reply: # TERMINAL code state: the session completes when the script
|
|
143
|
+
type: code # returns — "approve, then end" with no further model call
|
|
144
|
+
script: scripts/send-reply.js
|
|
145
|
+
tools: { allow: [send_email] } # the host tool its script calls, granted HERE
|
|
146
|
+
|
|
147
|
+
closed: # bare key = terminal (agent) state with no declarations
|
|
117
148
|
```
|
|
118
149
|
|
|
119
150
|
## Machine rules
|
|
120
151
|
|
|
121
152
|
- **Movement.** The agent moves only by `archmax_advance({ to, reason, evidence? })`
|
|
122
|
-
— one per message, edge validated, then the
|
|
123
|
-
|
|
124
|
-
transitions is terminal; the run ends when the agent finishes there.
|
|
125
|
-
decisions
|
|
153
|
+
— one per message, edge and `requires` validated, then the target's tools
|
|
154
|
+
unlock (or, for a grader or code target, the target runs at once). A state
|
|
155
|
+
with no transitions is terminal; the run ends when the agent finishes there.
|
|
156
|
+
Human decisions, `on_error`, and grader and code states' own `archmax_advance`
|
|
157
|
+
are the other movers. `archmax_reset({ reason })`
|
|
126
158
|
returns to the entry state (forbid it via `forbid_always` when a run must
|
|
127
159
|
never restart). No fan-out: sequence states; concurrency lives in
|
|
128
160
|
sub-workflow calls.
|
|
129
161
|
- **Entry.** At least one state declares `triggers`; one state per trigger id;
|
|
130
162
|
`manual` is the entry the CLI, a host firing and a caller all use. A
|
|
131
163
|
re-invoked finished session is a **new turn in the state it ended in**, not
|
|
132
|
-
at the entry
|
|
133
|
-
|
|
164
|
+
at the entry (one that completed in a terminal code state opens at its
|
|
165
|
+
trigger's entry) — give a state re-entry transitions if a conversation must
|
|
166
|
+
move on, or park instead of finishing.
|
|
134
167
|
- **Variables.** One flat checkpointed `name → value` store, never declared.
|
|
135
168
|
Host seeds (`--variables`, `createAgent({ variables })`, a delivery) are
|
|
136
169
|
**locked**; the agent uses `archmax_get_variables`/`archmax_set_variables`
|
|
@@ -156,7 +189,8 @@ states:
|
|
|
156
189
|
judgement and any state with a big tool surface or several transitions on
|
|
157
190
|
the default, since a small model that routes badly costs more in retries
|
|
158
191
|
than it saves. Repeating the workflow's id on a state is a validate warning.
|
|
159
|
-
A
|
|
192
|
+
A grader state's `model` is resolved under the `grader` model role
|
|
193
|
+
(`modelFactory("grader", env, id)`), a sub-workflow uses its own spec's, and a
|
|
160
194
|
host that passes an explicit `model` instance to `createAgent` outranks
|
|
161
195
|
every declared id (it must pass `modelFactory` to honour them).
|
|
162
196
|
- **Parking.** A state that needs an event or a time calls
|
|
@@ -170,9 +204,9 @@ states:
|
|
|
170
204
|
- **Failing.** When the work cannot be completed, the agent calls
|
|
171
205
|
`archmax_raise({ code, reason })` (alone in its message; any state): the
|
|
172
206
|
session ends at once `failed`, with the agent's free-form `code` and
|
|
173
|
-
`reason` as the outcome's `exit` — no `on_error` route, no
|
|
174
|
-
|
|
175
|
-
|
|
207
|
+
`reason` as the outcome's `exit` — no `on_error` route, no `returns`
|
|
208
|
+
check. A session that never raises is a success, so it is for failure
|
|
209
|
+
only. Forbid it (`forbid_always`, or a state's `forbid`) where the
|
|
176
210
|
agent must not end the run itself; a child that raises fails its caller's
|
|
177
211
|
call with kind `raised`.
|
|
178
212
|
- **Human states** park with a record built from `instructions`, `evidence`
|
|
@@ -182,23 +216,54 @@ states:
|
|
|
182
216
|
reply-only turn (every tool call refused) and re-parks unchanged; only
|
|
183
217
|
`decide` moves the run. A
|
|
184
218
|
`refine` edge delivers the reviewer's comment as correction.
|
|
185
|
-
- **
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
219
|
+
- **Grader and code states** (automated states). A **code** state runs
|
|
220
|
+
`script: scripts/<x>.js` in the sandbox; a **grader** state runs an isolated
|
|
221
|
+
grader whose criteria are the state's `instructions`. Both read the session
|
|
222
|
+
with `archmax_get_history` (`{ messages, trail }`: the whole transcript, a
|
|
223
|
+
tool result inline in its tool message's `text`, and the trail; a script
|
|
224
|
+
calls `JSON.parse(await tools.archmax_get_history())`). Both run on
|
|
225
|
+
entry — however the session got there — with **no call of the agent's model**
|
|
226
|
+
(a chain of code states makes none at all), and leave like every state:
|
|
227
|
+
`archmax_advance` along one of their transitions, whose `reason` reaches the
|
|
228
|
+
next state as a `[code]`/`[grader]` runtime note and a `kind: code|grader`
|
|
229
|
+
trail step, or `archmax_raise`. A **terminal** code state completes the
|
|
230
|
+
session when its script returns. Throwing, timing out, a spent grader budget,
|
|
231
|
+
or a non-terminal state that finishes without either call **fails closed** →
|
|
232
|
+
`on_error`. Each is offered exactly its own state's surface (its grants and
|
|
233
|
+
one control set for both types: `archmax_advance`, `archmax_raise`, the
|
|
234
|
+
variable tools, `archmax_get_history`), governed like the agent's calls — never
|
|
235
|
+
`write_todos`, `archmax_eval`, `archmax_run`, `archmax_wait`,
|
|
236
|
+
`archmax_reset`, even when `allow_always` lists one (a state's own
|
|
237
|
+
`tools.allow` naming one is an error): an automated state cannot park.
|
|
238
|
+
There is no iteration budget: a state that gives up after N rounds counts
|
|
239
|
+
them in the trail. Per type, `validate` errors on: a code state's
|
|
240
|
+
`instructions`/`model`/`budget`/`evidence`/`approvers`; a grader without
|
|
241
|
+
`instructions` or without a transition, or with `evidence`/`approvers`/
|
|
242
|
+
`budget.maxParks`. There are **no `before:`/`after:` hooks and no root
|
|
243
|
+
`extensions:`** — a leftover key is a load error naming it. Script contract:
|
|
244
|
+
[`code-states-and-scripts.md`](code-states-and-scripts.md).
|
|
245
|
+
- **Automated-state patterns.** A deterministic check **in front of** a state:
|
|
246
|
+
make the trigger's entry (or the edge's target) a code state that advances
|
|
247
|
+
to the work or to a state that declines it. A check **behind** a state: point
|
|
248
|
+
the state's transition at a code state that advances onward, or back with
|
|
249
|
+
the fix as its `reason` — the agent reads it and advances again. **Approve,
|
|
250
|
+
then end**: approve into a terminal code state, which costs no model call.
|
|
251
|
+
Judgment (tone, completeness): a grader behind the graded state with an edge
|
|
252
|
+
back; its `instructions` say when to raise ("after two send-backs" = two
|
|
253
|
+
trail steps `{ kind: grader, to: <graded state> }`). Grade work the agent
|
|
254
|
+
hands on (a report, a draft), not a live answer: a turn's `reply` is every
|
|
255
|
+
text the agent said in it, so a draft sent back has reached the person.
|
|
194
256
|
- **Budgets and `on_error`.** `budget.maxTurns`/`timeoutMs`/`maxParks` bound
|
|
195
|
-
a state's segment
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
257
|
+
a state's segment (on a grader: its own model calls and run time; a code
|
|
258
|
+
state takes no `budget`, `settings.timeoutMs` bounds its script). There is
|
|
259
|
+
no root `budget` (declaring one is a load error): a whole turn is bounded by
|
|
260
|
+
LangGraph's `recursionLimit` (400 unless the host's invoke config sets one),
|
|
261
|
+
and a turn that hits it — a cycle between states, say — ends the session
|
|
262
|
+
`failed` (`recursion-limit`). A terminal failure (exhausted budget, exhausted parks, a
|
|
263
|
+
grader or code state that fails) routes to `on_error` instead of failing the
|
|
264
|
+
run; recoverable rejections (invalid edge, unmet `requires`) keep the agent
|
|
265
|
+
in place. Declare `on_error` on every automated state and on bounded loops.
|
|
266
|
+
A **tool that throws** is neither: the call is answered with an error-status tool message carrying
|
|
202
267
|
the error, the agent stays in the state and can retry or switch tools, and
|
|
203
268
|
`on_error` never sees it (a park or a cancelled run still propagates).
|
|
204
269
|
- **Sub-workflows are tools.** Allow `archmax_workflow_<slug>` (slug verbatim)
|
|
@@ -226,10 +291,12 @@ states:
|
|
|
226
291
|
sub-run; fan out with parallel tool calls or `Promise.all` in a script
|
|
227
292
|
(bounds: depth 3, 4 concurrent). A child's human state parks the child;
|
|
228
293
|
a script's delegation cannot park and fails closed.
|
|
229
|
-
- **Choosing a mechanism.** Deterministic work
|
|
230
|
-
script.
|
|
231
|
-
|
|
232
|
-
|
|
294
|
+
- **Choosing a mechanism.** Deterministic work the agent triggers → an
|
|
295
|
+
`archmax_run` script. Deterministic work the graph runs at a fixed point (a
|
|
296
|
+
screen, a policy check, a record) → a code state. Delegated work that is itself
|
|
297
|
+
a process or reused across workflows → a sub-workflow. Judging work already
|
|
298
|
+
done → a grader state. Neither automated kind is callable by the agent (`task`
|
|
299
|
+
is disclosed nowhere and not grantable).
|
|
233
300
|
- **Prompt economy.** The static prompt + tool schemas are re-sent every
|
|
234
301
|
model call. The static part carries the workflow's `title` + `instructions`
|
|
235
302
|
and **no state of the graph**; a state's `instructions` and its **own**
|
|
@@ -245,14 +312,19 @@ states:
|
|
|
245
312
|
|
|
246
313
|
Only the state it is in. Every model call is handed that state's outgoing edges
|
|
247
314
|
and nothing else of the machine — no other state's slug, `title`, `summary`,
|
|
248
|
-
|
|
315
|
+
script, criteria or transitions, and no count of the states:
|
|
249
316
|
|
|
250
317
|
```
|
|
251
318
|
Transitions — choose one with `archmax_advance` when this state's work is done:
|
|
319
|
+
- to `check-policy` (code) — The decision is recorded in scratchpad/refund.json.
|
|
252
320
|
- to `review` (human decision node) — The decision is recorded and needs a person's approval.
|
|
321
|
+
- to `grade-reply` (grader) — The email is drafted in scratchpad/reply.md.
|
|
253
322
|
- to `closed` (terminal) — Nothing to refund; the case is answered.
|
|
254
323
|
```
|
|
255
324
|
|
|
325
|
+
A `(grader)` or `(code)` target runs on its own and may send the run straight
|
|
326
|
+
back with a note saying what to change.
|
|
327
|
+
|
|
256
328
|
Two rules follow, and they are the ones authors get wrong:
|
|
257
329
|
|
|
258
330
|
1. **Write the `description` for the source state, not the target.** The agent
|
|
@@ -260,12 +332,19 @@ Two rules follow, and they are the ones authors get wrong:
|
|
|
260
332
|
`The refund is over $50, or the customer has asked twice.` Not `Go to
|
|
261
333
|
refund-review.` — that tells a reader who already knows the graph something
|
|
262
334
|
they cannot use, and tells this reader nothing.
|
|
263
|
-
2. **Routing conditions cannot live downstream.** A target's `summary`
|
|
264
|
-
|
|
265
|
-
condition is "when the order is over 30 days old", it
|
|
335
|
+
2. **Routing conditions cannot live downstream.** A target's `summary` is never
|
|
336
|
+
disclosed to the state routing into it, nor its `instructions` across a
|
|
337
|
+
described edge. If the condition is "when the order is over 30 days old", it
|
|
338
|
+
belongs on the edge.
|
|
266
339
|
|
|
267
|
-
|
|
268
|
-
|
|
340
|
+
An **undescribed** edge (no `description`, or a blank one) routes on its target's
|
|
341
|
+
`instructions` instead, quoted under the edge's line as what the agent will do
|
|
342
|
+
once there: leave one undescribed only when those instructions already say when
|
|
343
|
+
it applies. It is a **load error** where the target has no instructions, on a
|
|
344
|
+
human state's transitions (the description is the button label), and into a
|
|
345
|
+
grader or code state (a grader's instructions are criteria the work is never
|
|
346
|
+
shown; a code state has none). A code state's own edges may go undescribed: its
|
|
347
|
+
script routes. There is no other way to see more of the graph.
|
|
269
348
|
|
|
270
349
|
## Governance
|
|
271
350
|
|
|
@@ -282,6 +361,14 @@ Closed by default; **deny beats allow, and no narrower level widens a denial.**
|
|
|
282
361
|
`essentialTools`. Any other tool needs an `allow`/`allow_always` entry. A
|
|
283
362
|
state entry naming a granted tool **narrows** it there, and one naming a
|
|
284
363
|
default tool the list omits grants it there. `task` is ungrantable (error).
|
|
364
|
+
- **In a grader or code state** the surface is what the state is granted (the
|
|
365
|
+
workflow-wide grant included), minus `write_todos`, `archmax_eval`,
|
|
366
|
+
`archmax_run`, `archmax_wait` and `archmax_reset` even when `allow_always` lists
|
|
367
|
+
them (naming one in the state's
|
|
368
|
+
own `tools.allow` is an error), plus one control set for both types:
|
|
369
|
+
`archmax_advance`, `archmax_raise`, `archmax_get_variables`,
|
|
370
|
+
`archmax_set_variables` and `archmax_get_history` — never `archmax_wait` or
|
|
371
|
+
`archmax_reset`.
|
|
285
372
|
- **Entries**: bare name; `{ tool, args: { <arg>: ["glob", …] } }` (matches
|
|
286
373
|
if any glob matches; `${{var}}` allowed). An argument the tool declares as a
|
|
287
374
|
path (else `file_path`) is canonicalized first; any other argument (a URL, an
|
|
@@ -303,8 +390,10 @@ Closed by default; **deny beats allow, and no narrower level widens a denial.**
|
|
|
303
390
|
in the prompt). `allow` adds, `forbid` subtracts, `allow: []` denies
|
|
304
391
|
nothing. A `tools.allow` entry may still narrow *within* an enabled bundle.
|
|
305
392
|
A state enabling no skill can run no script at all.
|
|
306
|
-
- **Scripts' `tools.*` calls** are governed per call
|
|
307
|
-
is bound like the model (grant every tool it
|
|
308
|
-
the
|
|
309
|
-
|
|
310
|
-
|
|
393
|
+
- **Scripts' `tools.*` calls** are governed per call against the state they
|
|
394
|
+
run in: an `archmax_run` script is bound like the model (grant every tool it
|
|
395
|
+
calls in the agent's state); a code state's script is bound by **its own**
|
|
396
|
+
state's grants (`tools`, `skills`, `mounts`) — there is no runtime authority.
|
|
397
|
+
`tools` holds exactly that state's surface: anything else is `undefined`.
|
|
398
|
+
Neither may read `workflows/**` or write a read-only mount. A refused call
|
|
399
|
+
rejects inside the script.
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# Hook scripts and `archmax_run` scripts — contracts
|
|
2
|
-
|
|
3
|
-
Load this when writing a `workflows/<slug>/hooks/*.js` gate or a
|
|
4
|
-
`skills/<cap>/scripts/*.js` source. Worked examples and the sandbox details:
|
|
5
|
-
[`hook-and-test-scripts.md`](hook-and-test-scripts.md) Part 1.
|
|
6
|
-
|
|
7
|
-
## Hook script contract
|
|
8
|
-
|
|
9
|
-
Default-export function; its return value is the verdict. Verdict helpers are
|
|
10
|
-
globals (typed import optional: `import { ok, veto, correct } from "@archmax-ai/harness/sandbox";`,
|
|
11
|
-
placed below the JSDoc; no other import is allowed).
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
/**
|
|
15
|
-
* Requester gate — the request must name a requester the order records know.
|
|
16
|
-
*
|
|
17
|
-
* Reads the first user message, extracts the first email address, loads
|
|
18
|
-
* skills/order-data/assets/orders.json through the bridge and matches the
|
|
19
|
-
* address against every record's `email`, case-insensitively.
|
|
20
|
-
*
|
|
21
|
-
* Vetoes when the file cannot be parsed, no address is present, or none
|
|
22
|
-
* matches — each with the reason. Otherwise ok.
|
|
23
|
-
*/
|
|
24
|
-
export default async function hook({ state, phase, trigger, variables, messages, tools, from, to, reason }) {
|
|
25
|
-
let orders;
|
|
26
|
-
try { orders = JSON.parse(await tools.readFile({ file_path: "skills/order-data/assets/orders.json" })); }
|
|
27
|
-
catch { return veto("Could not load skills/order-data/assets/orders.json."); }
|
|
28
|
-
const text = messages.find((m) => m.role === "user")?.text ?? "";
|
|
29
|
-
const email = text.match(/[\w.+-]+@[\w.-]+\.\w{2,}/)?.[0];
|
|
30
|
-
if (!email) return veto("Include your email address so we can look up your account.");
|
|
31
|
-
if (!orders.some((o) => o.email?.toLowerCase() === email.toLowerCase())) return veto(`"${email}" is not in the order database.`);
|
|
32
|
-
return ok();
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
| Input | Meaning |
|
|
37
|
-
| --- | --- |
|
|
38
|
-
| `state`, `phase` | state slug; `"before"` or `"after"` |
|
|
39
|
-
| `trigger` | trigger id string (payload is in `variables`) |
|
|
40
|
-
| `variables` | read-only `name → value` map incl. `trigger`; structured values whole |
|
|
41
|
-
| `messages` | the **current visit**, newest last: everything since the session entered the state it is in (on an advance, the state being left; it can span turns). `{ role, text, toolCalls? }`; roles `user`/`assistant`/`tool`/`system`/`runtime` (a runtime note; match `role === "runtime"`, never a `[bracket]`). A `tool` entry has `tool`, `id` and an empty `text`: read results with `toolCalls` |
|
|
42
|
-
| `toolCalls(filter?)` | async: the session's tool calls with results, every visit, oldest first, `{ id, name, args, result, status, state, visit }`; filter by `name`, `state`, `visit` (number or `"current"`), `status`, `last`. No control tools. Only what it returns enters the sandbox |
|
|
43
|
-
| `from`, `to`, `reason` | `after` only: the attempted transition and the agent's reason |
|
|
44
|
-
| `tools` | async camelCased bridge: `tools.readFile`, `tools.writeFile`, `tools.archmaxWorkflowEnrichOrder(...)`; no control tools; a hook's lists every tool on the bridge, not only the state's |
|
|
45
|
-
|
|
46
|
-
| Return | Effect |
|
|
47
|
-
| --- | --- |
|
|
48
|
-
| `ok()`, nothing, `true`/number/string | proceed |
|
|
49
|
-
| `veto(reason)` | block; the reason is shown to the agent — make it actionable |
|
|
50
|
-
| `correct(reason)` | `after` only: retry with the reason, within `max_iterations` |
|
|
51
|
-
| `false` | veto ("precondition not met") |
|
|
52
|
-
| any other object, a throw | veto with keys/error named — never silently ok |
|
|
53
|
-
|
|
54
|
-
`console.log` goes to the trail. A file with no default export uses its
|
|
55
|
-
completion value as the verdict. Parse inputs defensively; turn a failure that
|
|
56
|
-
should not block into an explicit `ok()`.
|
|
57
|
-
|
|
58
|
-
## `archmax_run` script contract
|
|
59
|
-
|
|
60
|
-
`skills/<cap>/scripts/<x>.js`: plain script, top-level `await`, `tools.*`,
|
|
61
|
-
`console.log`; the **last expression** is the tool result. Input is the global
|
|
62
|
-
`args`: the arguments the model passed plus `args.variables` (read-only snapshot).
|
|
63
|
-
No `archmax_advance`, `archmax_set_variables` or `task`. Fan-out shape:
|
|
64
|
-
|
|
65
|
-
```js
|
|
66
|
-
/** One sub-run per requested order, all in flight at once; returns [{ order_id, ...returns }]. */
|
|
67
|
-
const orders = args.variables?.orders_to_enrich ?? [];
|
|
68
|
-
await Promise.all(orders.map(async (o) => {
|
|
69
|
-
const answer = await tools.archmaxWorkflowEnrichOrder({ order_id: o.order_id });
|
|
70
|
-
return { order_id: o.order_id, ...JSON.parse(answer).returns };
|
|
71
|
-
}));
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
The calling state must allow every tool the script calls (here
|
|
75
|
-
`archmax_workflow_enrich-order`). A script's `tools` lists exactly the calling
|
|
76
|
-
state's tools, re-scoped at every evaluation (so after an advance the same REPL
|
|
77
|
-
lists the next state's); a tool the state does not offer is unlisted, and
|
|
78
|
-
calling it by name is refused with governance's reason. The listing is
|
|
79
|
-
camelCased, but a tool's own name reaches the same function
|
|
80
|
-
(`tools["archmax_workflow_enrich-order"]`, `tools.read_file`); a hook's `tools`
|
|
81
|
-
takes the camelCased names alone.
|
|
82
|
-
|
|
83
|
-
**Return into a variable.** A script's result reaches the model as one tool
|
|
84
|
-
message and no further — it is not written to the variable store, and a script
|
|
85
|
-
cannot write there itself. Return structured data and name the variable in the
|
|
86
|
-
calling state's `requires:`; the model then records it with
|
|
87
|
-
`archmax_set_variables`, which is what makes it survive the state, guard a
|
|
88
|
-
`tools.allow` glob, and be quotable downstream as `${{name}}` instead of retyped.
|
|
89
|
-
A result worth computing is worth naming.
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Readers for the shape of one authored hook: a tagged object whose single key
|
|
3
|
-
* names its kind (`script`, `rubric`, or a custom kind an executor is
|
|
4
|
-
* registered for), optionally beside the reserved `max_iterations` sidecar.
|
|
5
|
-
*/
|
|
6
|
-
import type { Hook, HookSpec } from "../machine/types.js";
|
|
7
|
-
/** Reserved sidecar keys ignored by hook kind detection. */
|
|
8
|
-
export declare const HOOK_SIDECAR_KEYS: ReadonlySet<string>;
|
|
9
|
-
/** Normalize a `before`/`after` field into an ordered list of tagged hooks. */
|
|
10
|
-
export declare function normalizeHooks(spec: HookSpec | undefined): Hook[];
|
|
11
|
-
/**
|
|
12
|
-
* The kind of a tagged hook — its single key other than the sidecars — or
|
|
13
|
-
* `undefined` for a malformed hook, which callers treat as an error
|
|
14
|
-
* (fail-closed veto / validation error).
|
|
15
|
-
*/
|
|
16
|
-
export declare function hookKind(hook: Hook): string | undefined;
|
|
17
|
-
/** The target value of a tagged hook (the script path, rubric name, …). */
|
|
18
|
-
export declare function hookValue(hook: Hook): string | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* The hook-level `max_iterations` sidecar — the bounded grade-and-retry budget
|
|
21
|
-
* for an `after` hook of any kind — or `undefined` when absent or not a
|
|
22
|
-
* non-negative number. It wins over the named rubric's own `max_iterations`,
|
|
23
|
-
* because the sidecar describes *this* state's retry loop.
|
|
24
|
-
*/
|
|
25
|
-
export declare function hookMaxIterations(hook: Hook): number | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Short, human-readable label for a hook, for operator surfaces (events, the CLI
|
|
28
|
-
* state flow). `{ script }` renders as the bare path; a `{ rubric }` renders as
|
|
29
|
-
* `rubric#<index>`, because an inline grader has no name and its position is
|
|
30
|
-
* what distinguishes it from the next one in the same phase; every other kind
|
|
31
|
-
* renders as `<kind>:<value>`.
|
|
32
|
-
*/
|
|
33
|
-
export declare function afterHookLabel(hook: Hook, index?: number): string;
|
|
34
|
-
/**
|
|
35
|
-
* The key one hook's grade-and-retry budget is counted under. Per hook, not per
|
|
36
|
-
* state: `max_iterations` is declared on a hook, so two `after` hooks on one
|
|
37
|
-
* state have independent budgets and neither can reset the other's count.
|
|
38
|
-
*
|
|
39
|
-
* Keyed by **position** rather than by label, so the identity does not move when
|
|
40
|
-
* a script is renamed, and so two inline rubrics — which have no names at all —
|
|
41
|
-
* are always distinguishable. Reordering a phase's hooks re-keys them, which is
|
|
42
|
-
* the same class of edit as any other spec change (it moves the spec hash).
|
|
43
|
-
*/
|
|
44
|
-
export declare function iterationKey(state: string, phase: "before" | "after", index: number): string;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/** Reserved sidecar keys ignored by hook kind detection. */
|
|
2
|
-
export const HOOK_SIDECAR_KEYS = new Set(["max_iterations"]);
|
|
3
|
-
/** Normalize a `before`/`after` field into an ordered list of tagged hooks. */
|
|
4
|
-
export function normalizeHooks(spec) {
|
|
5
|
-
if (spec == null)
|
|
6
|
-
return [];
|
|
7
|
-
return Array.isArray(spec) ? spec : [spec];
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* The kind of a tagged hook — its single key other than the sidecars — or
|
|
11
|
-
* `undefined` for a malformed hook, which callers treat as an error
|
|
12
|
-
* (fail-closed veto / validation error).
|
|
13
|
-
*/
|
|
14
|
-
export function hookKind(hook) {
|
|
15
|
-
if (!hook || typeof hook !== "object" || Array.isArray(hook))
|
|
16
|
-
return undefined;
|
|
17
|
-
const keys = Object.keys(hook).filter((key) => !HOOK_SIDECAR_KEYS.has(key));
|
|
18
|
-
return keys.length === 1 ? keys[0] : undefined;
|
|
19
|
-
}
|
|
20
|
-
/** The target value of a tagged hook (the script path, rubric name, …). */
|
|
21
|
-
export function hookValue(hook) {
|
|
22
|
-
const kind = hookKind(hook);
|
|
23
|
-
return kind ? hook[kind] : undefined;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* The hook-level `max_iterations` sidecar — the bounded grade-and-retry budget
|
|
27
|
-
* for an `after` hook of any kind — or `undefined` when absent or not a
|
|
28
|
-
* non-negative number. It wins over the named rubric's own `max_iterations`,
|
|
29
|
-
* because the sidecar describes *this* state's retry loop.
|
|
30
|
-
*/
|
|
31
|
-
export function hookMaxIterations(hook) {
|
|
32
|
-
if (!hook || typeof hook !== "object" || Array.isArray(hook))
|
|
33
|
-
return undefined;
|
|
34
|
-
const value = hook.max_iterations;
|
|
35
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Short, human-readable label for a hook, for operator surfaces (events, the CLI
|
|
39
|
-
* state flow). `{ script }` renders as the bare path; a `{ rubric }` renders as
|
|
40
|
-
* `rubric#<index>`, because an inline grader has no name and its position is
|
|
41
|
-
* what distinguishes it from the next one in the same phase; every other kind
|
|
42
|
-
* renders as `<kind>:<value>`.
|
|
43
|
-
*/
|
|
44
|
-
export function afterHookLabel(hook, index = 0) {
|
|
45
|
-
const kind = hookKind(hook);
|
|
46
|
-
if (kind === undefined)
|
|
47
|
-
return "hook";
|
|
48
|
-
if (kind === "rubric")
|
|
49
|
-
return `rubric#${index}`;
|
|
50
|
-
const value = hook[kind];
|
|
51
|
-
return kind === "script" ? value : `${kind}:${value}`;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* The key one hook's grade-and-retry budget is counted under. Per hook, not per
|
|
55
|
-
* state: `max_iterations` is declared on a hook, so two `after` hooks on one
|
|
56
|
-
* state have independent budgets and neither can reset the other's count.
|
|
57
|
-
*
|
|
58
|
-
* Keyed by **position** rather than by label, so the identity does not move when
|
|
59
|
-
* a script is renamed, and so two inline rubrics — which have no names at all —
|
|
60
|
-
* are always distinguishable. Reordering a phase's hooks re-keys them, which is
|
|
61
|
-
* the same class of edit as any other spec change (it moves the spec hash).
|
|
62
|
-
*/
|
|
63
|
-
export function iterationKey(state, phase, index) {
|
|
64
|
-
return `${state}::${phase}::${index}`;
|
|
65
|
-
}
|
|
66
|
-
//# sourceMappingURL=hook-shape.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hook-shape.js","sourceRoot":"","sources":["../../src/lifecycle/hook-shape.ts"],"names":[],"mappings":"AAOA,4DAA4D;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAElF,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,IAA0B;IACvD,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAU;IACjC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,SAAS,CAAC,IAAU;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,CAAC,CAAE,IAA+B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAU;IAC1C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,MAAM,KAAK,GAAI,IAAgC,CAAC,cAAc,CAAC;IAC/D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/F,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAU,EAAE,KAAK,GAAG,CAAC;IAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACtC,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,UAAU,KAAK,EAAE,CAAC;IAChD,MAAM,KAAK,GAAI,IAA+B,CAAC,IAAI,CAAC,CAAC;IACrD,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,KAAyB,EAAE,KAAa;IAClF,OAAO,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;AACxC,CAAC"}
|