@jr2/orchestrator 0.3.0 → 0.5.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 +20 -2
- package/bin/server.ts +7 -4
- package/console/canvas.ts +27 -14
- package/console/components/app.ts +12 -1
- package/console/components/fleet.ts +52 -6
- package/console/components/machine-pane.ts +128 -2
- package/console/components/nav.ts +1 -1
- package/console/components/schema-form.ts +12 -4
- package/console/json-field.ts +23 -0
- package/console/main.ts +122 -39
- package/console/store.ts +321 -21
- package/console/style.css +111 -0
- package/docs/agents-block.md +5 -0
- package/docs/concepts/agents-and-turns.md +442 -0
- package/docs/concepts/architecture.md +230 -0
- package/docs/concepts/charts.md +143 -0
- package/docs/concepts/composition.md +357 -0
- package/docs/concepts/converge.md +254 -0
- package/docs/concepts/durable-runs.md +189 -0
- package/docs/concepts/effects.md +603 -0
- package/docs/concepts/gates.md +208 -0
- package/docs/concepts/machines-and-workflows.md +289 -0
- package/docs/concepts/pools-and-sources.md +230 -0
- package/docs/concepts/secrets-and-trust.md +222 -0
- package/docs/concepts/the-menu.md +378 -0
- package/docs/concepts/workspaces.md +678 -0
- package/docs/get-started/a-model-decides.md +563 -0
- package/docs/get-started/an-agent-in-a-sandbox.md +381 -0
- package/docs/get-started/connect-a-model.md +248 -0
- package/docs/get-started/create-an-instance.md +194 -0
- package/docs/get-started/have-your-assistant-write-a-machine.md +922 -0
- package/docs/get-started/install.md +126 -0
- package/docs/guides/add-tools-to-the-sandbox.md +295 -0
- package/docs/guides/answer-a-gate.md +304 -0
- package/docs/guides/bind-open-parts.md +223 -0
- package/docs/guides/cancel-a-run.md +146 -0
- package/docs/guides/clean-up.md +206 -0
- package/docs/guides/fix-a-failed-converge.md +361 -0
- package/docs/guides/give-the-cluster-git-credentials.md +222 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +190 -0
- package/docs/guides/let-an-agent-write-a-chart.md +226 -0
- package/docs/guides/look-inside-a-sandbox.md +174 -0
- package/docs/guides/mirror-the-kit-images.md +176 -0
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +302 -0
- package/docs/guides/open-the-console.md +91 -0
- package/docs/guides/publish-a-machine-as-an-npm-package.md +350 -0
- package/docs/guides/push-and-sign-a-branch.md +486 -0
- package/docs/guides/run-a-chart-by-name.md +270 -0
- package/docs/guides/run-a-command-or-call-a-url.md +544 -0
- package/docs/guides/run-one-worker-per-item.md +321 -0
- package/docs/guides/set-an-agents-access-and-dials.md +375 -0
- package/docs/guides/size-a-workspace.md +204 -0
- package/docs/guides/start-a-run-from-a-run.md +237 -0
- package/docs/guides/start-a-run.md +207 -0
- package/docs/guides/upgrade-the-kit-version.md +240 -0
- package/docs/guides/use-a-hosted-provider.md +208 -0
- package/docs/guides/use-a-local-model.md +313 -0
- package/docs/guides/watch-a-run.md +326 -0
- package/docs/guides/write-a-workflow.md +318 -0
- package/docs/index.md +44 -0
- package/docs/llms.txt +216 -0
- package/docs/reference/authoring-surface/agent.md +128 -0
- package/docs/reference/authoring-surface/answer.md +140 -0
- package/docs/reference/authoring-surface/arg.md +60 -0
- package/docs/reference/authoring-surface/basic.md +62 -0
- package/docs/reference/authoring-surface/bearer.md +53 -0
- package/docs/reference/authoring-surface/chartschema.md +23 -0
- package/docs/reference/authoring-surface/chartschemafor.md +48 -0
- package/docs/reference/authoring-surface/command.md +191 -0
- package/docs/reference/authoring-surface/customize.md +64 -0
- package/docs/reference/authoring-surface/defineconfig.md +41 -0
- package/docs/reference/authoring-surface/defineevent.md +114 -0
- package/docs/reference/authoring-surface/dispatch.md +126 -0
- package/docs/reference/authoring-surface/fail.md +83 -0
- package/docs/reference/authoring-surface/file.md +122 -0
- package/docs/reference/authoring-surface/frompick.md +277 -0
- package/docs/reference/authoring-surface/http.md +159 -0
- package/docs/reference/authoring-surface/isfailure.md +58 -0
- package/docs/reference/authoring-surface/jr2setup.md +237 -0
- package/docs/reference/authoring-surface/open.md +74 -0
- package/docs/reference/authoring-surface/openbody.md +86 -0
- package/docs/reference/authoring-surface/paramsof.md +125 -0
- package/docs/reference/authoring-surface/pool.md +186 -0
- package/docs/reference/authoring-surface/push.md +112 -0
- package/docs/reference/authoring-surface/secret.md +118 -0
- package/docs/reference/authoring-surface/sentby.md +83 -0
- package/docs/reference/authoring-surface/source.md +51 -0
- package/docs/reference/authoring-surface/text.md +62 -0
- package/docs/reference/authoring-surface/type-agentdeclaration.md +27 -0
- package/docs/reference/authoring-surface/type-agentdefinition.md +80 -0
- package/docs/reference/authoring-surface/type-agentlogic.md +15 -0
- package/docs/reference/authoring-surface/type-agentslots.md +12 -0
- package/docs/reference/authoring-surface/type-answeraction.md +12 -0
- package/docs/reference/authoring-surface/type-arg.md +19 -0
- package/docs/reference/authoring-surface/type-argnames.md +12 -0
- package/docs/reference/authoring-surface/type-binding.md +62 -0
- package/docs/reference/authoring-surface/type-bindingof.md +12 -0
- package/docs/reference/authoring-surface/type-bodyacceptsdoor.md +15 -0
- package/docs/reference/authoring-surface/type-bodyacceptsslots.md +17 -0
- package/docs/reference/authoring-surface/type-ceilings.md +41 -0
- package/docs/reference/authoring-surface/type-chainlink.md +19 -0
- package/docs/reference/authoring-surface/type-chartaction.md +46 -0
- package/docs/reference/authoring-surface/type-chartagent.md +28 -0
- package/docs/reference/authoring-surface/type-chartevent.md +20 -0
- package/docs/reference/authoring-surface/type-chartguard.md +20 -0
- package/docs/reference/authoring-surface/type-chartinvoke.md +28 -0
- package/docs/reference/authoring-surface/type-chartjson.md +14 -0
- package/docs/reference/authoring-surface/type-chartstate.md +46 -0
- package/docs/reference/authoring-surface/type-charttext.md +40 -0
- package/docs/reference/authoring-surface/type-charttransition.md +22 -0
- package/docs/reference/authoring-surface/type-charttransitions.md +14 -0
- package/docs/reference/authoring-surface/type-chartvalue.md +15 -0
- package/docs/reference/authoring-surface/type-childat.md +12 -0
- package/docs/reference/authoring-surface/type-childslots.md +12 -0
- package/docs/reference/authoring-surface/type-commandenv.md +15 -0
- package/docs/reference/authoring-surface/type-commandinput.md +19 -0
- package/docs/reference/authoring-surface/type-commandoptions.md +78 -0
- package/docs/reference/authoring-surface/type-commandoutput.md +104 -0
- package/docs/reference/authoring-surface/type-customize.md +109 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +39 -0
- package/docs/reference/authoring-surface/type-dispatchinput.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-dispatchoutput.md +65 -0
- package/docs/reference/authoring-surface/type-duration.md +15 -0
- package/docs/reference/authoring-surface/type-effectbinding.md +93 -0
- package/docs/reference/authoring-surface/type-effectlogic.md +12 -0
- package/docs/reference/authoring-surface/type-envopenparts.md +14 -0
- package/docs/reference/authoring-surface/type-eventaudience.md +27 -0
- package/docs/reference/authoring-surface/type-eventdef.md +45 -0
- package/docs/reference/authoring-surface/type-eventfrom.md +16 -0
- package/docs/reference/authoring-surface/type-eventsemantics.md +26 -0
- package/docs/reference/authoring-surface/type-execoutcome.md +34 -0
- package/docs/reference/authoring-surface/type-failslot.md +14 -0
- package/docs/reference/authoring-surface/type-failure.md +19 -0
- package/docs/reference/authoring-surface/type-failureinput.md +20 -0
- package/docs/reference/authoring-surface/type-filebody.md +41 -0
- package/docs/reference/authoring-surface/type-frominput.md +14 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +58 -0
- package/docs/reference/authoring-surface/type-httpdefinition.md +101 -0
- package/docs/reference/authoring-surface/type-httpinput.md +12 -0
- package/docs/reference/authoring-surface/type-httpmethod.md +14 -0
- package/docs/reference/authoring-surface/type-httpopenparts.md +12 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +89 -0
- package/docs/reference/authoring-surface/type-httprequestparts.md +33 -0
- package/docs/reference/authoring-surface/type-jr2config.md +126 -0
- package/docs/reference/authoring-surface/type-lends.md +38 -0
- package/docs/reference/authoring-surface/type-logicat.md +12 -0
- package/docs/reference/authoring-surface/type-markedif.md +12 -0
- package/docs/reference/authoring-surface/type-mergedactors.md +12 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +25 -0
- package/docs/reference/authoring-surface/type-noslotspec.md +26 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +32 -0
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +40 -0
- package/docs/reference/authoring-surface/type-openbodylogic.md +14 -0
- package/docs/reference/authoring-surface/type-openbodyoutput.md +42 -0
- package/docs/reference/authoring-surface/type-openbodyslot.md +18 -0
- package/docs/reference/authoring-surface/type-opencommandinput.md +17 -0
- package/docs/reference/authoring-surface/type-openeffect.md +12 -0
- package/docs/reference/authoring-surface/type-openeffectslots.md +12 -0
- package/docs/reference/authoring-surface/type-openof.md +12 -0
- package/docs/reference/authoring-surface/type-opensecret.md +23 -0
- package/docs/reference/authoring-surface/type-opensecretmark.md +12 -0
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +31 -0
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +32 -0
- package/docs/reference/authoring-surface/type-poolmachine.md +28 -0
- package/docs/reference/authoring-surface/type-poolspec.md +60 -0
- package/docs/reference/authoring-surface/type-pushinput.md +15 -0
- package/docs/reference/authoring-surface/type-pushoptions.md +79 -0
- package/docs/reference/authoring-surface/type-pushoutput.md +124 -0
- package/docs/reference/authoring-surface/type-pushwireoutput.md +12 -0
- package/docs/reference/authoring-surface/type-quantity.md +14 -0
- package/docs/reference/authoring-surface/type-reached.md +12 -0
- package/docs/reference/authoring-surface/type-reposlot.md +70 -0
- package/docs/reference/authoring-surface/type-reposlotsof.md +16 -0
- package/docs/reference/authoring-surface/type-sandboxoptions.md +77 -0
- package/docs/reference/authoring-surface/type-secret.md +25 -0
- package/docs/reference/authoring-surface/type-sender.md +19 -0
- package/docs/reference/authoring-surface/type-sentbyguards.md +12 -0
- package/docs/reference/authoring-surface/type-size.md +85 -0
- package/docs/reference/authoring-surface/type-slothandles.md +32 -0
- package/docs/reference/authoring-surface/type-sourcenextresult.md +17 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +44 -0
- package/docs/reference/authoring-surface/type-syncstate.md +12 -0
- package/docs/reference/authoring-surface/type-text.md +19 -0
- package/docs/reference/authoring-surface/type-textpart.md +24 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +39 -0
- package/docs/reference/authoring-surface/type-toparameterizedobject.md +14 -0
- package/docs/reference/authoring-surface/type-toprovidedactor.md +14 -0
- package/docs/reference/authoring-surface/type-unknown.md +21 -0
- package/docs/reference/authoring-surface/type-usercontainer.md +77 -0
- package/docs/reference/authoring-surface/type-withoutemptyindex.md +20 -0
- package/docs/reference/authoring-surface/type-workflowevent.md +46 -0
- package/docs/reference/authoring-surface/type-workspaceaccess.md +16 -0
- package/docs/reference/authoring-surface/type-workspaced.md +94 -0
- package/docs/reference/authoring-surface/type-workspacehandles.md +23 -0
- package/docs/reference/authoring-surface/type-workspacemachine.md +29 -0
- package/docs/reference/authoring-surface/type-workspaceof.md +13 -0
- package/docs/reference/authoring-surface/type-workspaceoptions.md +39 -0
- package/docs/reference/authoring-surface/type-workspacespec.md +37 -0
- package/docs/reference/authoring-surface/workspace.md +259 -0
- package/docs/reference/authoring-surface.md +197 -0
- package/docs/reference/cli.md +433 -0
- package/docs/reference/config.md +756 -0
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +113 -0
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +110 -0
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +124 -0
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +230 -0
- package/docs/reference/decisions/0006-agent-control-surface.md +47 -0
- package/docs/reference/decisions/0007-durable-machine-state.md +109 -0
- package/docs/reference/decisions/0008-orchestrator-as-deployed-app.md +60 -0
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +275 -0
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +160 -0
- package/docs/reference/decisions/0011-workflow-defined-events.md +141 -0
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +103 -0
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +157 -0
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +95 -0
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +265 -0
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +124 -0
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +69 -0
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +111 -0
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +275 -0
- package/docs/reference/decisions/0020-private-ca-trust-is-a-named-concept.md +60 -0
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +100 -0
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +103 -0
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +176 -0
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +439 -0
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +65 -0
- package/docs/reference/decisions/0026-a-turn-that-is-over-is-never-prompted.md +62 -0
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +237 -0
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +89 -0
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +154 -0
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +100 -0
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +190 -0
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +61 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +127 -0
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +57 -0
- package/docs/reference/decisions/0035-a-runaway-turn-is-ended-rerolled-once-then-a-fault.md +92 -0
- package/docs/reference/decisions/0036-a-turn-compacts-its-own-context-mid-flight.md +138 -0
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +196 -0
- package/docs/reference/decisions/0038-jr2-up-builds-every-image-it-deploys.md +170 -0
- package/docs/reference/decisions/0039-image-garbage-collects-by-reachability.md +115 -0
- package/docs/reference/decisions/0041-a-build-the-host-already-holds-is-not-spent-again.md +64 -0
- package/docs/reference/decisions/0042-ready-is-not-routable-an-admission-retries-its-connection.md +142 -0
- package/docs/reference/decisions/0043-the-kit-is-tested-as-installed-a-local-registry-stands-in-for-npm.md +170 -0
- package/docs/reference/decisions/0044-kit-images-live-at-a-canonical-home-a-self-host-mirrors-it.md +85 -0
- package/docs/reference/decisions/0045-the-platform-joins-the-image-address-and-the-cluster-chooses-it.md +82 -0
- package/docs/reference/decisions/0046-a-converge-failure-carries-its-diagnosis.md +34 -0
- package/docs/reference/decisions/0047-the-git-ssh-key-source-is-the-users-choice.md +47 -0
- package/docs/reference/decisions/0048-the-orchestrator-boots-without-its-repos.md +36 -0
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +126 -0
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +73 -0
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +227 -0
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +81 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +111 -0
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +126 -0
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +107 -0
- package/docs/reference/decisions/0056-a-global-jr2-hands-off-to-the-instances-own-and-an-instance-has-one-kit-version.md +62 -0
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +152 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +106 -0
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +384 -0
- package/docs/reference/decisions/0060-a-workspace-states-its-size-and-jr2-reserves-all-of-it.md +111 -0
- package/docs/reference/decisions/0061-a-memory-kill-ends-the-agents-processes-not-the-harness.md +83 -0
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +212 -0
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +83 -0
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +79 -0
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +65 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +550 -0
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +430 -0
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +464 -0
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +180 -0
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +323 -0
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +183 -0
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +144 -0
- package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +122 -0
- package/docs/reference/decisions/0074-an-unrouted-mechanism-event-is-refused-at-load-and-faults-the-run.md +76 -0
- package/docs/reference/decisions.md +83 -0
- package/docs/reference/glossary.md +648 -0
- package/docs/reference/http-api.md +1348 -0
- package/docs/reference/machines.md +190 -0
- package/docs/reference/mechanism-events.md +72 -0
- package/docs/why.md +206 -0
- package/package.json +6 -4
- package/src/actor.ts +976 -61
- package/src/agent.ts +114 -38
- package/src/ambient.ts +4 -1
- package/src/assembly-checks.ts +347 -0
- package/src/assembly-tar.ts +494 -0
- package/src/assembly.ts +721 -0
- package/src/cause.ts +234 -0
- package/src/chart.ts +2182 -0
- package/src/charts.ts +748 -0
- package/src/config.ts +520 -162
- package/src/content-hash.ts +105 -0
- package/src/custodian.lua +6 -5
- package/src/custodian.ts +143 -39
- package/src/customize.ts +388 -55
- package/src/dispatch-effect.ts +945 -0
- package/src/door-compat.ts +217 -0
- package/src/durability.ts +11 -4
- package/src/effect-checks.ts +557 -0
- package/src/effect.ts +1202 -0
- package/src/effector-wire.ts +674 -0
- package/src/fail.ts +209 -0
- package/src/fingerprint.ts +4 -3
- package/src/gate.ts +8 -0
- package/src/git-clone.ts +65 -0
- package/src/git-push.ts +336 -0
- package/src/harness-client.ts +764 -48
- package/src/held-secrets.ts +82 -26
- package/src/holds.ts +156 -0
- package/src/http-effect.ts +1423 -0
- package/src/http.ts +916 -113
- package/src/images.ts +47 -21
- package/src/index.ts +62 -43
- package/src/instance.ts +505 -59
- package/src/internal.ts +84 -0
- package/src/kube-client.ts +333 -0
- package/src/machine-doc.ts +106 -6
- package/src/mechanism-routes.ts +168 -0
- package/src/model-keys.generated.ts +53 -0
- package/src/model-keys.ts +18 -58
- package/src/mount-digest.ts +53 -0
- package/src/names.ts +66 -8
- package/src/notices.ts +141 -0
- package/src/open-body.ts +1580 -0
- package/src/open-effect.ts +217 -0
- package/src/open.ts +59 -6
- package/src/parts.ts +709 -41
- package/src/party.ts +534 -0
- package/src/pick.ts +761 -0
- package/src/pool.ts +248 -37
- package/src/registration.ts +382 -19
- package/src/repo-fetch.ts +60 -85
- package/src/repos.ts +65 -75
- package/src/rest.ts +133 -0
- package/src/run-host.ts +2383 -115
- package/src/run-output.ts +38 -0
- package/src/sandbox-effect.ts +1126 -0
- package/src/sandbox-effector.ts +111 -0
- package/src/sandbox-kube.ts +1721 -0
- package/src/sandbox-watch.ts +260 -0
- package/src/secret-placement.ts +529 -0
- package/src/server.ts +284 -84
- package/src/setup.ts +819 -117
- package/src/size.ts +454 -0
- package/src/snapshot-store.ts +115 -20
- package/src/stub-harness.ts +49 -16
- package/src/sync-client.ts +54 -0
- package/src/timers.ts +191 -0
- package/src/tokens.ts +35 -4
- package/src/vocabulary.ts +135 -15
- package/src/wire.ts +238 -10
- package/src/workspace.ts +1195 -338
- package/src/sandbox-kubectl.ts +0 -1108
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Gates
|
|
3
|
+
description: How a run waits for an event from a person, the CLI, the Console, a webhook or a CI job.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gates
|
|
7
|
+
|
|
8
|
+
A [Gate](../reference/glossary.md#gate) is an input that a run waits for from outside the run. A person, a CI job or a
|
|
9
|
+
webhook can send it. A state of a [Machine](../reference/glossary.md#machine) opens a Gate when it invokes the `gate`
|
|
10
|
+
actor, and the Gate closes when the state exits. While the Gate is open, a caller can send one of its events.
|
|
11
|
+
|
|
12
|
+
## Why Gates exist
|
|
13
|
+
|
|
14
|
+
Some decisions do not belong to a model. A person approves a release. A CI job reports that the tests pass. An
|
|
15
|
+
[Agent](../reference/glossary.md#agent) must not approve its own work. A Gate is the place in the Machine where such a
|
|
16
|
+
decision comes in. You see it as a state in the graph of the Machine before a run starts.
|
|
17
|
+
|
|
18
|
+
A Gate has an address, because more than one Gate can be open at the same time. For example, a
|
|
19
|
+
[Pool](../reference/glossary.md#pool) can run three workers that each wait at a review Gate. A caller sends an event to
|
|
20
|
+
one Gate by its id, and not to the run.
|
|
21
|
+
|
|
22
|
+
## How a Gate behaves
|
|
23
|
+
|
|
24
|
+
In this [Workflow](../reference/glossary.md#workflow), `ci-release`, a CI job answers the first Gate, and a person
|
|
25
|
+
answers the second one:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { assign } from "xstate";
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
import { defineEvent, fail, jr2Setup } from "@jr2/orchestrator";
|
|
31
|
+
|
|
32
|
+
// The events that a CI job sends to the `checks` Gate.
|
|
33
|
+
const ciPassed = defineEvent({
|
|
34
|
+
name: "ci_passed",
|
|
35
|
+
description: "The CI job for this version passed.",
|
|
36
|
+
input: z.object({ url: z.string().describe("The URL of the CI job.") }),
|
|
37
|
+
});
|
|
38
|
+
const ciFailed = defineEvent({
|
|
39
|
+
name: "ci_failed",
|
|
40
|
+
description: "The CI job for this version failed.",
|
|
41
|
+
input: z.object({ url: z.string().describe("The URL of the CI job.") }),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// The events that a person sends to the `review` Gate.
|
|
45
|
+
const approve = defineEvent({
|
|
46
|
+
name: "approve",
|
|
47
|
+
description: "Release this version.",
|
|
48
|
+
input: z.object({}),
|
|
49
|
+
});
|
|
50
|
+
const reject = defineEvent({
|
|
51
|
+
name: "reject",
|
|
52
|
+
description: "Do not release this version.",
|
|
53
|
+
input: z.object({ reason: z.string().min(1).describe("Why, in one sentence.") }),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const door = z.object({ version: z.string().describe("The version to release, such as 1.4.0.") });
|
|
57
|
+
|
|
58
|
+
type Input = z.infer<typeof door>;
|
|
59
|
+
type Ctx = Input & { ci?: string; reason?: string };
|
|
60
|
+
// The output of a run that ends `done`. A run whose CI job failed, or that a person rejected, has no
|
|
61
|
+
// output of this type: it ends `failed`, and its output is the reason and the detail of the Failure.
|
|
62
|
+
type Output = { version: string };
|
|
63
|
+
|
|
64
|
+
export const machine = jr2Setup({
|
|
65
|
+
types: {} as { context: Ctx; input: Input; output: Output },
|
|
66
|
+
events: [ciPassed, ciFailed, approve, reject],
|
|
67
|
+
actors: { fail: fail() },
|
|
68
|
+
}).createMachine({
|
|
69
|
+
id: "ci-release",
|
|
70
|
+
input: door,
|
|
71
|
+
context: ({ input }) => ({ version: input.version }),
|
|
72
|
+
initial: "checks",
|
|
73
|
+
states: {
|
|
74
|
+
// A CI job answers this Gate. The Gate's id is "checks", the key of its state.
|
|
75
|
+
checks: {
|
|
76
|
+
invoke: { src: "gate", input: ({ context }) => ({ meta: { version: context.version } }) },
|
|
77
|
+
on: {
|
|
78
|
+
ci_passed: { target: "review", actions: assign({ ci: ({ event }) => event.url }) },
|
|
79
|
+
ci_failed: { target: "failed", actions: assign({ ci: ({ event }) => event.url }) },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
// A person answers this Gate, from the CLI or the Console. The meta tells them what to check.
|
|
83
|
+
review: {
|
|
84
|
+
invoke: {
|
|
85
|
+
src: "gate",
|
|
86
|
+
input: ({ context }) => ({ meta: { version: context.version, ci: context.ci } }),
|
|
87
|
+
},
|
|
88
|
+
on: {
|
|
89
|
+
approve: "released",
|
|
90
|
+
reject: { target: "rejected", actions: assign({ reason: ({ event }) => event.reason }) },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
released: { type: "final", output: ({ context }): Output => ({ version: context.version }) },
|
|
94
|
+
// Not a final state: the run ends `failed`, and `jr2 run` exits 1.
|
|
95
|
+
failed: {
|
|
96
|
+
invoke: { src: "fail", input: ({ context }) => ({ reason: "the CI job failed", detail: { ci: context.ci } }) },
|
|
97
|
+
},
|
|
98
|
+
// A person stopped the release. The run ends `failed` too, with the person's reason.
|
|
99
|
+
rejected: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.reason! }) } },
|
|
100
|
+
},
|
|
101
|
+
// The output of the run. xstate reads only this root `output` as the output of the Machine. It
|
|
102
|
+
// gets the output of the final state that ended the run as `event.output`.
|
|
103
|
+
output: ({ event }) => event.output as Output,
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
You do not import the `gate` actor. `jr2Setup` adds it, and a state invokes it as `invoke: { src: "gate" }`. Its input
|
|
108
|
+
is optional. It can hold `meta`, and an authored `gate` id.
|
|
109
|
+
|
|
110
|
+
### The id
|
|
111
|
+
|
|
112
|
+
By default, jr2 makes the id of a Gate from the keys of the states. It joins the keys from the root of its Machine down
|
|
113
|
+
to the state that invokes it, with a `.` between them. In the example, the ids are `checks` and `review`. When the
|
|
114
|
+
Machine runs inside a different Machine, the id starts with the invoke ids above it. For example, the `review` Gate of a
|
|
115
|
+
Machine that [`workspace()`](../reference/authoring-surface/workspace.md) wraps has the id `body.review`. In a Pool, the
|
|
116
|
+
id of each worker's Gate includes the id of its item. Thus two workers that wait at the same state have different Gate
|
|
117
|
+
ids.
|
|
118
|
+
|
|
119
|
+
To give a Gate a name of your own, set `gate` in its input, for example `{ gate: "F-12" }`. Then you must make sure that
|
|
120
|
+
no two open Gates of the run have that id. jr2 refuses the second one when it opens. jr2 keeps the Gate ids of each run
|
|
121
|
+
apart, so two runs can use the same id.
|
|
122
|
+
|
|
123
|
+
### The events that a Gate takes
|
|
124
|
+
|
|
125
|
+
A Gate takes the events of the `on` keys of its own state, and of its child states that invoke no party. It also takes
|
|
126
|
+
the events of its parent states that belong to no other party. The position of the `on` key decides this, as it does for
|
|
127
|
+
the [Menu](../reference/glossary.md#menu) of an Agent. [The Menu](the-menu.md) gives the full rule. Set
|
|
128
|
+
[`audience`](../reference/authoring-surface/type-eventaudience.md) on an event only to give it to the other party too.
|
|
129
|
+
|
|
130
|
+
A Gate takes some of its events now and other events later, because of the guards. `acceptsNow` is the list of events
|
|
131
|
+
that the run takes from the Gate now. jr2 refuses an event that is not in `acceptsNow`, and the run does not move. When
|
|
132
|
+
`acceptsNow` is empty, the Gate waits.
|
|
133
|
+
|
|
134
|
+
### The meta
|
|
135
|
+
|
|
136
|
+
`meta` is data for the caller. It tells a person what to decide, and it lets a webhook find the correct Gate. In the
|
|
137
|
+
example, the `review` Gate shows the version and the URL of the CI job. jr2 does not read `meta`.
|
|
138
|
+
|
|
139
|
+
### The callers
|
|
140
|
+
|
|
141
|
+
A caller finds the open Gates of a run with [`GET /runs/:runId`](../reference/http-api.md#get-runs-runid). Each Gate
|
|
142
|
+
gives its id, its events with their input schemas, `acceptsNow` and `meta` (see
|
|
143
|
+
[`GateView`](../reference/http-api.md#type-gateview)). Then the caller sends one event, with its input. These callers
|
|
144
|
+
use the same route,
|
|
145
|
+
[`POST /runs/:runId/gates/:gate/events`](../reference/http-api.md#post-runs-runid-gates-gate-events), with the
|
|
146
|
+
[Instance](../reference/glossary.md#instance) token:
|
|
147
|
+
|
|
148
|
+
- **The [jr2 CLI](../reference/glossary.md#jr2-cli).** [`jr2 status`](../reference/cli.md#status) prints the open Gates
|
|
149
|
+
of a run under `gates`. [`jr2 send`](../reference/cli.md#send) with `--gate` sends an event to one of them.
|
|
150
|
+
- **The [Console](../reference/glossary.md#console).** When you type the Instance token, the Attention tab shows a card
|
|
151
|
+
for each open Gate. The card has a form for each event.
|
|
152
|
+
- **A webhook or a CI job.** Any client that can reach the [Orchestrator](../reference/glossary.md#orchestrator), and
|
|
153
|
+
that holds the Instance token, can send to a Gate. It can call the route, or run `jr2 send` with `--url` and
|
|
154
|
+
`JR2_TOKEN`.
|
|
155
|
+
|
|
156
|
+
The [Sender](../reference/glossary.md#sender) of the event is the Gate, by its invoke id, and not the person or the
|
|
157
|
+
system behind it. The invoke id is not always the id that a caller uses. [The Menu](the-menu.md) tells how to use the
|
|
158
|
+
Sender.
|
|
159
|
+
|
|
160
|
+
### A run that waits
|
|
161
|
+
|
|
162
|
+
A run that waits at a Gate does not end. `jr2 run` stays attached until the run ends. The run also waits through a
|
|
163
|
+
restart of the Orchestrator (see [Durable runs](durable-runs.md)). A [Workspace](../reference/glossary.md#workspace)
|
|
164
|
+
whose Machine waits at a Gate keeps its [Sandbox](../reference/glossary.md#sandbox), so that you can look at the work
|
|
165
|
+
(see [Workspaces](workspaces.md)).
|
|
166
|
+
|
|
167
|
+
A Gate can be inside the state of an Agent. Then the Agent's pick that opened the Gate stays
|
|
168
|
+
[outstanding](../reference/glossary.md#outstanding) until the Gate's event moves the Machine out of the Gate's state. By
|
|
169
|
+
default, the Gate's event is the answer to the pick. The Gate takes its own events. It does not take the picks of the
|
|
170
|
+
Agent, unless an event's `audience` is `"any"`. [The Menu](the-menu.md) tells how jr2 answers the pick.
|
|
171
|
+
|
|
172
|
+
After each answer, the Agent can pick again, so it can ask and get answers with no end. To stop this loop, put a guard
|
|
173
|
+
on the pick. For example, `guard: ({ context }) => context.replies < 1` allows one question only. A guard that reads
|
|
174
|
+
only the context removes the pick from the [Allowed picks](the-menu.md#allowed-picks).
|
|
175
|
+
|
|
176
|
+
A Pool that has a `wake` event serves it as a Gate with the id `source` (see [Pools and Sources](pools-and-sources.md)).
|
|
177
|
+
|
|
178
|
+
## Rules
|
|
179
|
+
|
|
180
|
+
- jr2 refuses an event from an Agent to a Gate, because a Sandbox token cannot send to the Gates route. Thus an Agent
|
|
181
|
+
cannot approve its own work.
|
|
182
|
+
- jr2 refuses these events to a Gate, and nothing moves:
|
|
183
|
+
- an event that the Gate does not take
|
|
184
|
+
- an input that does not agree with the event's schema
|
|
185
|
+
- an event that is not in `acceptsNow`
|
|
186
|
+
- jr2 refuses an event to a Gate that is not open: its state has exited, or the run has ended.
|
|
187
|
+
- jr2 refuses an event body that has a `sender` field. Only the Orchestrator writes the Sender.
|
|
188
|
+
- A Gate that takes no events does not open. Its invoke fails with an error that names the Gate.
|
|
189
|
+
- jr2 refuses a second open Gate with the same id in one run.
|
|
190
|
+
- `jr2 up` warns about a Gate above an Agent's state that takes an event that the Agent can also reach. The Gate's
|
|
191
|
+
caller can send the event, and the Agent cannot.
|
|
192
|
+
|
|
193
|
+
## Read next
|
|
194
|
+
|
|
195
|
+
- [Answer a Gate](../guides/answer-a-gate.md)
|
|
196
|
+
- [Open the Console](../guides/open-the-console.md)
|
|
197
|
+
- [The Menu](the-menu.md), [Pools and Sources](pools-and-sources.md) and [Durable runs](durable-runs.md)
|
|
198
|
+
- Reference: [`jr2 send`](../reference/cli.md#send), [`jr2 status`](../reference/cli.md#status),
|
|
199
|
+
[`GET /runs/:runId`](../reference/http-api.md#get-runs-runid),
|
|
200
|
+
[`POST /runs/:runId/gates/:gate/events`](../reference/http-api.md#post-runs-runid-gates-gate-events),
|
|
201
|
+
[`GateView`](../reference/http-api.md#type-gateview) and [`sentBy`](../reference/authoring-surface/sentby.md)
|
|
202
|
+
- [ADR-0011](../reference/decisions/0011-workflow-defined-events.md): a Gate is an addressable resource on a run
|
|
203
|
+
- [ADR-0013](../reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md): an Agent
|
|
204
|
+
cannot send to a Gate, and a send that the run does not take is refused
|
|
205
|
+
- [ADR-0015](../reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md): the position of an `on` key gives
|
|
206
|
+
its event to a Gate or to an Agent
|
|
207
|
+
- [ADR-0032](../reference/decisions/0032-the-console-unlocks-with-the-instance-token.md): the Console sends to a Gate
|
|
208
|
+
with the Instance token
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Machines and Workflows
|
|
3
|
+
description: What a Machine and a Workflow are, the door of a run, the Vocabulary, and Emits.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Machines and Workflows
|
|
7
|
+
|
|
8
|
+
A [Machine](../reference/glossary.md#machine) is an [xstate](https://xstate.js.org) state machine that you write. It
|
|
9
|
+
holds the control flow of your work. The control flow is the states, the events that move a run between them, and what
|
|
10
|
+
each state does. A [Workflow](../reference/glossary.md#workflow) is a Machine that your
|
|
11
|
+
[Instance](../reference/glossary.md#instance) registers under a name. You start a run of a Workflow with
|
|
12
|
+
`jr2 run <name>`. This page tells how a Machine gets the input of a run, which events it takes, and how it tells you
|
|
13
|
+
what it does.
|
|
14
|
+
|
|
15
|
+
## Why the control flow is a Machine
|
|
16
|
+
|
|
17
|
+
A model does not always do the same thing for the same prompt. If a model decides the order of the work, you cannot know
|
|
18
|
+
before a run what the run will do. In jr2, the Machine decides the order. An [Agent](../reference/glossary.md#agent)
|
|
19
|
+
does the work of one state, then picks an event from its [Menu](../reference/glossary.md#menu). The Machine decides what
|
|
20
|
+
that event does.
|
|
21
|
+
|
|
22
|
+
A Machine is code that you can read before a run starts. The [Console](../reference/glossary.md#console) draws its
|
|
23
|
+
states, and it shows the states of each run while the run continues. Thus you review how the work happens, and not only
|
|
24
|
+
the code that comes out of it. The [Orchestrator](../reference/glossary.md#orchestrator) keeps the state of each run, so
|
|
25
|
+
a run continues after a restart. [Durable runs](durable-runs.md) tells how.
|
|
26
|
+
|
|
27
|
+
## A Workflow is a file
|
|
28
|
+
|
|
29
|
+
Each `.ts` file in the `workflows/` folder of the Instance is a Workflow. The name of the file, without `.ts`, is the
|
|
30
|
+
name of the Workflow. Thus `workflows/refund.ts` is the Workflow `refund`, and you start it with `jr2 run refund`. The
|
|
31
|
+
name has only lower-case letters, digits and `-`, so `jr2 run` and a `dispatch` Effect write it the same way. The file
|
|
32
|
+
exports its Machine as `machine`. jr2 reads no other export.
|
|
33
|
+
|
|
34
|
+
A Workflow is only a name. The Machine holds all that it needs: its events, its Agents, its
|
|
35
|
+
[Effects](../reference/glossary.md#effect) and its [Sandbox Image](../reference/glossary.md#sandbox-image). Thus one
|
|
36
|
+
Machine can be a Workflow of your Instance, a child of a different Machine, or a part of an npm package.
|
|
37
|
+
[Composition](composition.md) tells how one Machine invokes a different Machine.
|
|
38
|
+
|
|
39
|
+
A Workflow can also be a named [Chart](../reference/glossary.md#chart): a Machine written as data, which runs under a
|
|
40
|
+
Machine of the Instance. Its name is `<wrapper>/<name>`, such as `notes/summary`. It comes from a Chart file,
|
|
41
|
+
`workflows/<wrapper>/<name>.chart.json`, or from a runtime Chart that the Orchestrator keeps. [Charts](charts.md) tells
|
|
42
|
+
how.
|
|
43
|
+
|
|
44
|
+
`jr2 up` loads each Workflow before it changes the cluster. It runs the typecheck of the Instance, then it loads each
|
|
45
|
+
Machine and examines its parts. An error that the typecheck or the load finds stops `jr2 up`, so a run never starts with
|
|
46
|
+
that error. The Orchestrator runs the Machines that the last `jr2 up` gave it. After you change a Machine, run `jr2 up`
|
|
47
|
+
again.
|
|
48
|
+
|
|
49
|
+
## An example
|
|
50
|
+
|
|
51
|
+
This Workflow takes a refund request, and it waits for a person to approve or reject it. It has no Agent:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { z } from "zod";
|
|
55
|
+
import { assign, emit } from "xstate";
|
|
56
|
+
import { defineEvent, fail, jr2Setup } from "@jr2/orchestrator";
|
|
57
|
+
|
|
58
|
+
// The Vocabulary: the events that this Machine takes.
|
|
59
|
+
const approve = defineEvent({
|
|
60
|
+
name: "approve",
|
|
61
|
+
description: "Pay the refund.",
|
|
62
|
+
input: z.object({}),
|
|
63
|
+
});
|
|
64
|
+
const reject = defineEvent({
|
|
65
|
+
name: "reject",
|
|
66
|
+
description: "Do not pay the refund, and say why.",
|
|
67
|
+
input: z.object({ reason: z.string().min(1) }),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// The door: the input that starts a run. jr2 refuses a start that does not match it.
|
|
71
|
+
const runInput = z.object({
|
|
72
|
+
order: z.string(),
|
|
73
|
+
amount: z.number().positive(),
|
|
74
|
+
});
|
|
75
|
+
type RunInput = z.infer<typeof runInput>;
|
|
76
|
+
|
|
77
|
+
export const machine = jr2Setup({
|
|
78
|
+
types: {} as {
|
|
79
|
+
input: RunInput;
|
|
80
|
+
context: RunInput & { reason?: string };
|
|
81
|
+
emitted: { type: "decided"; approved: boolean };
|
|
82
|
+
},
|
|
83
|
+
events: [approve, reject],
|
|
84
|
+
actors: { fail: fail() },
|
|
85
|
+
}).createMachine({
|
|
86
|
+
id: "refund",
|
|
87
|
+
input: runInput,
|
|
88
|
+
context: ({ input }) => ({ order: input.order, amount: input.amount }),
|
|
89
|
+
initial: "review",
|
|
90
|
+
states: {
|
|
91
|
+
// A Gate: the run waits here until jr2 send, the Console or a webhook sends approve or reject.
|
|
92
|
+
review: {
|
|
93
|
+
invoke: {
|
|
94
|
+
src: "gate",
|
|
95
|
+
input: ({ context }) => ({ meta: { order: context.order, amount: context.amount } }),
|
|
96
|
+
},
|
|
97
|
+
on: {
|
|
98
|
+
// An Emit tells the people who watch the run what happened. Nothing in the Machine reads it.
|
|
99
|
+
approve: { target: "approved", actions: emit({ type: "decided", approved: true }) },
|
|
100
|
+
reject: {
|
|
101
|
+
target: "rejected",
|
|
102
|
+
actions: [assign({ reason: ({ event }) => event.reason }), emit({ type: "decided", approved: false })],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
approved: { type: "final" },
|
|
107
|
+
// A person stopped the refund, and the run ends here. Not a final state: the run ends `failed`,
|
|
108
|
+
// with the person's reason.
|
|
109
|
+
rejected: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.reason! }) } },
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The parts of this file are the subjects of the sections below: the door (`runInput`), the
|
|
115
|
+
[Vocabulary](../reference/glossary.md#vocabulary) (`approve` and `reject`), and the
|
|
116
|
+
[Emit](../reference/glossary.md#emit) (`decided`). The `review` state invokes a [Gate](../reference/glossary.md#gate),
|
|
117
|
+
which waits for an event from outside the run. [Gates](gates.md) tells how.
|
|
118
|
+
|
|
119
|
+
## The door
|
|
120
|
+
|
|
121
|
+
The door of a Machine is the input that starts a run. A Machine declares its door as a zod object in the `input` of
|
|
122
|
+
`createMachine`. [`jr2Setup`](../reference/authoring-surface/jr2setup.md) adds this option to `createMachine`. The same
|
|
123
|
+
schema, through `z.infer`, gives `types.input`, so TypeScript and jr2 agree about one shape.
|
|
124
|
+
|
|
125
|
+
With a door, jr2 does these things:
|
|
126
|
+
|
|
127
|
+
- It examines each start against the schema. When the input does not agree with the schema, the Orchestrator refuses the
|
|
128
|
+
start, and no run starts. Thus a wrong input stops at the start, and not in the middle of a run.
|
|
129
|
+
- It starts the run with the input that zod parsed. Thus the defaults of the schema apply, and a plain `z.object`
|
|
130
|
+
removes the keys that it does not declare.
|
|
131
|
+
- It serves the schema as JSON Schema, at [`GET /workflows/:name`](../reference/http-api.md#get-workflows-name). This
|
|
132
|
+
route needs no token. The Console makes its start form from the schema.
|
|
133
|
+
|
|
134
|
+
Without a door, a run starts with any input, and the start form of the Console is a field for JSON.
|
|
135
|
+
|
|
136
|
+
The root Machine of a run also gets `instanceId`, an id that jr2 makes for the run. It is not the run id. It is not a
|
|
137
|
+
part of the door, because no caller sends it.
|
|
138
|
+
[`HostInjectedInput`](../reference/authoring-surface/type-hostinjectedinput.md) is its type.
|
|
139
|
+
|
|
140
|
+
A [`workspace()`](../reference/authoring-surface/workspace.md) or a [`pool()`](../reference/authoring-surface/pool.md)
|
|
141
|
+
has a door of its own. It does not use the door of the Machine inside it, because that Machine gets other input. A
|
|
142
|
+
`workspace()` body gets the run input and the Workspace handles. A [Pool](../reference/glossary.md#pool) worker gets its
|
|
143
|
+
item. Thus the wrapper declares the door, with its `input` option. `workspace()` refuses a body that has a zod `input`,
|
|
144
|
+
also a body that `setup()` made.
|
|
145
|
+
|
|
146
|
+
## The Vocabulary
|
|
147
|
+
|
|
148
|
+
The Vocabulary of a Machine is the list of the workflow events that it takes. Each event comes from
|
|
149
|
+
[`defineEvent`](../reference/authoring-surface/defineevent.md): a name, a zod schema for its payload and, if you want, a
|
|
150
|
+
description. `jr2Setup` lists the events. Each name is an `on` key of the states that take it.
|
|
151
|
+
|
|
152
|
+
jr2 makes three things from the Vocabulary:
|
|
153
|
+
|
|
154
|
+
- **The Menu of each Agent.** Each event that an Agent can send is a tool for its model. The description of the event is
|
|
155
|
+
the description of the tool. [The Menu](the-menu.md) tells how.
|
|
156
|
+
- **The events that a Gate accepts.** `jr2 send`, the Console and a webhook can send only those events.
|
|
157
|
+
- **The check of each delivery.** jr2 parses the payload of each event with its schema before the Machine gets the
|
|
158
|
+
event.
|
|
159
|
+
|
|
160
|
+
The position of an `on` key tells which party can send the event. The key belongs to the party that its state invokes,
|
|
161
|
+
or to the party that the nearest state above it invokes. A party is an Agent or a Gate. The `audience` of an event can
|
|
162
|
+
change this. [The Menu](the-menu.md) gives the rule. Each event that a party sends carries its
|
|
163
|
+
[Sender](../reference/glossary.md#sender).
|
|
164
|
+
|
|
165
|
+
A Vocabulary belongs to one Machine. A child Machine keeps its own Vocabulary. The Machine that invokes it does not see
|
|
166
|
+
the events of the child, and does not declare them again. Thus two Machines in one run can each have an `approve` event,
|
|
167
|
+
with different payloads.
|
|
168
|
+
|
|
169
|
+
jr2 also sends its own events into each Machine that `jr2Setup` makes: `agent.fault` and `workspace.lost`. They are not
|
|
170
|
+
in the Vocabulary. Their names have a dot, and the name of a workflow event cannot have a dot. Each one must have a
|
|
171
|
+
route: `jr2 check` refuses a state that invokes an Agent, or an Open body that can run one, with no `agent.fault` route
|
|
172
|
+
on it or on a state above it, and a `workspace()` body with no `workspace.lost` route.
|
|
173
|
+
[Mechanism events](../reference/mechanism-events.md) gives them.
|
|
174
|
+
|
|
175
|
+
## The output of a run
|
|
176
|
+
|
|
177
|
+
The output of a run is the root `output` of its Machine: the `output` beside `id` and `states` in `createMachine`. The
|
|
178
|
+
status of the run shows it. A Machine that invokes this Machine gets it as `event.output` in `onDone`. xstate reads the
|
|
179
|
+
`output` of a final state only as the `event.output` of the root `output`. Thus a Machine with an `output` only on its
|
|
180
|
+
final states has no output, and jr2 refuses it when the module loads.
|
|
181
|
+
[Write a Workflow](../guides/write-a-workflow.md#give-the-run-an-output) gives the two forms of a root `output`.
|
|
182
|
+
|
|
183
|
+
## How a run ends
|
|
184
|
+
|
|
185
|
+
A run that ended has one [Run status](../reference/glossary.md#run-status). These are the statuses that a Machine
|
|
186
|
+
causes:
|
|
187
|
+
|
|
188
|
+
- `done`: the Machine got to a final state. A final state means that the work succeeded.
|
|
189
|
+
- `failed`: a state invoked [`fail`](../reference/authoring-surface/fail.md), and no state caught the
|
|
190
|
+
[Failure](../reference/glossary.md#failure). The output of the run is the `{ reason, detail }` of the Failure, not the
|
|
191
|
+
root `output`.
|
|
192
|
+
- `error`: the run faulted. A throw from a promise, or a mechanism event that no transition took, is a fault. The fault
|
|
193
|
+
of the run gives the error.
|
|
194
|
+
|
|
195
|
+
To fail a run, put `fail: fail()` under `actors`, and invoke it from a state. Its input is `{ reason, detail? }`.
|
|
196
|
+
`reason` is text for a person, and `detail` is optional JSON for a script:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
failed: { invoke: { src: "fail", input: { reason: "the tests did not pass", detail: { code: 1 } } } },
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- Do not use a final state for work that did not succeed. A final state means `done`.
|
|
203
|
+
- Do not throw to fail. A throw is a defect: the run ends `error`, with no output, and nobody can tell it from a bug in
|
|
204
|
+
the kit.
|
|
205
|
+
- A decision of a person that ends the run, such as a `reject` at a Gate, goes to a state that invokes `fail` with the
|
|
206
|
+
reason of the person, as the `rejected` state of `refund` does. A decision that sends the work back is a usual route.
|
|
207
|
+
When the job of the Machine is the decision itself, such as a triage where "no" is a correct answer, the decision is a
|
|
208
|
+
final state, and the Machine puts it in its output.
|
|
209
|
+
- A Failure goes up from the state that invokes `fail`, through each parent Machine. To catch it, write an `onError`
|
|
210
|
+
with the guard [`isFailure`](../reference/authoring-surface/isfailure.md):
|
|
211
|
+
`onError: [{ guard: ({ event }) => isFailure(event.error), target: "replan" }, { target: "broken" }]`. A broad
|
|
212
|
+
`onError` with no guard catches a Failure too.
|
|
213
|
+
- A Failure that goes through a [`workspace()`](../reference/authoring-surface/workspace.md) deletes its
|
|
214
|
+
[Sandbox](../reference/glossary.md#sandbox). To keep the work for a person to read, wait at a
|
|
215
|
+
[Gate](../reference/glossary.md#gate) before the state that fails.
|
|
216
|
+
|
|
217
|
+
[`jr2 run`](../reference/cli.md#run) exits 0 only for `done`. It exits 1 for `failed`, `error` and each other end.
|
|
218
|
+
`jr2 up` and `jr2 check` list each state that invokes `fail`, under `failures`.
|
|
219
|
+
|
|
220
|
+
## Emits
|
|
221
|
+
|
|
222
|
+
An Emit is a message that a Machine sends to the people and the tools that watch a run, such as "the review is done". A
|
|
223
|
+
Machine sends it with xstate's `emit()` action. jr2 has no function of its own for it. jr2 gives the Emits of each actor
|
|
224
|
+
in the run to the feeds, also those of each child Machine.
|
|
225
|
+
|
|
226
|
+
You see an Emit in these places:
|
|
227
|
+
|
|
228
|
+
- `jr2 run`, and `jr2 logs -f`, write each Emit on stderr while they are attached to the run. The line holds `emit`,
|
|
229
|
+
then the Emit as JSON. `jr2 logs` without `-f` writes no Emit.
|
|
230
|
+
- The Activity tab of the Console shows the type of each Emit that comes while the page is open.
|
|
231
|
+
- The [Harness](../reference/glossary.md#harness) of each [Workspace](../reference/glossary.md#workspace) writes the
|
|
232
|
+
Emits of its run in its log, beside the conversation of its Agents.
|
|
233
|
+
- The feed of a run, [`GET /runs/:runId/events`](../reference/http-api.md#get-runs-runid-events), carries each Emit with
|
|
234
|
+
its payload. This feed needs the Instance token.
|
|
235
|
+
|
|
236
|
+
The feeds that need no token carry the type of an Emit, but not its payload. The payload is your data, as the context of
|
|
237
|
+
a run is.
|
|
238
|
+
|
|
239
|
+
An Emit does not control the run. No part of the run acts on an Emit, and an Emit does not move a Machine. Only an event
|
|
240
|
+
moves a Machine.
|
|
241
|
+
|
|
242
|
+
## Rules
|
|
243
|
+
|
|
244
|
+
- A Workflow is a `.ts` file in `workflows/`, and its name is the name of the file without `.ts`. The name has only
|
|
245
|
+
lower-case letters, digits and `-`. A named Chart is a Workflow too, with the name `<wrapper>/<name>`.
|
|
246
|
+
- jr2 does not register a file whose name starts with `_`, or a `.d.ts` file. Put a Machine that only other Machines
|
|
247
|
+
import in such a file. A file in `workflows/` that a different Workflow imports is also a Workflow of its own.
|
|
248
|
+
- A Workflow file must export `machine`. jr2 refuses a file without it.
|
|
249
|
+
- The name of an event has only letters, digits, `_` and `-`.
|
|
250
|
+
- Each `on` key of a `jr2Setup` Machine is an event of its Vocabulary, a jr2 or xstate event, which has a dot, or the
|
|
251
|
+
wildcard `*`. `createMachine` refuses an `on` key that no event declares.
|
|
252
|
+
- Each event in the Vocabulary is an `on` key of a state. `createMachine` refuses an event that no state takes.
|
|
253
|
+
- A payload schema is a flat `z.object`, and it has no `sender` field. jr2 writes `sender` on each event that a party
|
|
254
|
+
sends.
|
|
255
|
+
- When a Machine declares a door, the Orchestrator refuses a start whose input does not agree with it.
|
|
256
|
+
- The body of a `workspace()` declares no door. `workspace()` refuses a body that declares one.
|
|
257
|
+
- The output of a run is the root `output` of its Machine. jr2 refuses an `output` on a final state directly below the
|
|
258
|
+
root when the root has no `output`.
|
|
259
|
+
- An Emit never moves a Machine.
|
|
260
|
+
- The input of `fail` has a `reason` that is not empty. Else the run ends `error`:
|
|
261
|
+
`fail: the input must be { reason: string; detail?: unknown } with a reason that is not empty (got <value>) — invoke: { src: "fail", input: { reason: "the tests failed" } } (ADR-0073)`.
|
|
262
|
+
|
|
263
|
+
[Write a Workflow](../guides/write-a-workflow.md) gives the exact text of each refusal.
|
|
264
|
+
|
|
265
|
+
## Read next
|
|
266
|
+
|
|
267
|
+
- [Write a Workflow](../guides/write-a-workflow.md)
|
|
268
|
+
- [Start a run](../guides/start-a-run.md)
|
|
269
|
+
- [Agents and Turns](agents-and-turns.md), [The Menu](the-menu.md), [Gates](gates.md) and [Charts](charts.md)
|
|
270
|
+
- Reference: [`jr2Setup`](../reference/authoring-surface/jr2setup.md),
|
|
271
|
+
[`defineEvent`](../reference/authoring-surface/defineevent.md), [`fail`](../reference/authoring-surface/fail.md),
|
|
272
|
+
[`isFailure`](../reference/authoring-surface/isfailure.md),
|
|
273
|
+
[`HostInjectedInput`](../reference/authoring-surface/type-hostinjectedinput.md), [`jr2 run`](../reference/cli.md#run),
|
|
274
|
+
[`POST /workflows/:name/runs`](../reference/http-api.md#post-workflows-name-runs) and
|
|
275
|
+
[Mechanism events](../reference/mechanism-events.md)
|
|
276
|
+
- [ADR-0011](../reference/decisions/0011-workflow-defined-events.md): the events are the Workflow's, and jr2 delivers
|
|
277
|
+
them
|
|
278
|
+
- [ADR-0015](../reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md): the Vocabulary and the Menus come
|
|
279
|
+
from the Machine
|
|
280
|
+
- [ADR-0033](../reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md): a Machine declares the input
|
|
281
|
+
that starts it
|
|
282
|
+
- [ADR-0049](../reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md): a Machine carries its
|
|
283
|
+
parts
|
|
284
|
+
- [ADR-0050](../reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md): what
|
|
285
|
+
only the CLI names, jr2 finds by its file name
|
|
286
|
+
- [ADR-0014](../reference/decisions/0014-observation-is-open-run-state-is-not.md): observation is open, and the state of
|
|
287
|
+
a run is not
|
|
288
|
+
- [ADR-0073](../reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md): a
|
|
289
|
+
Machine fails a run with `fail()`, and an uncaught Failure ends it `failed`
|