@jr2/orchestrator 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/console/components/app.ts +55 -15
- package/console/components/bottom-drawer.ts +259 -0
- package/console/components/drawer.ts +14 -6
- package/console/components/fleet.ts +36 -13
- package/console/components/machine-pane.ts +61 -5
- package/console/components/nav.ts +54 -8
- package/console/conversation.ts +161 -0
- package/console/login.ts +123 -0
- package/console/main.ts +600 -60
- package/console/store.ts +611 -64
- package/console/style.css +231 -0
- package/docs/agents-block.md +2 -2
- package/docs/concepts/agents-and-turns.md +142 -29
- package/docs/concepts/architecture.md +60 -34
- package/docs/concepts/callers-and-hooks.md +205 -0
- package/docs/concepts/charts.md +13 -8
- package/docs/concepts/composition.md +10 -1
- package/docs/concepts/converge.md +7 -2
- package/docs/concepts/durable-runs.md +43 -16
- package/docs/concepts/effects.md +133 -50
- package/docs/concepts/gates.md +95 -25
- package/docs/concepts/machines-and-workflows.md +14 -4
- package/docs/concepts/pools-and-sources.md +193 -17
- package/docs/concepts/secrets-and-trust.md +186 -62
- package/docs/concepts/the-menu.md +14 -0
- package/docs/concepts/workspaces.md +135 -56
- package/docs/get-started/a-model-decides.md +14 -13
- package/docs/get-started/an-agent-in-a-sandbox.md +46 -35
- package/docs/get-started/connect-a-model.md +1 -1
- package/docs/get-started/create-an-instance.md +17 -14
- package/docs/get-started/have-your-assistant-write-a-machine.md +111 -40
- package/docs/get-started/install.md +4 -0
- package/docs/guides/add-tools-to-the-sandbox.md +72 -15
- package/docs/guides/answer-a-gate-from-a-forge.md +304 -0
- package/docs/guides/answer-a-gate.md +74 -37
- package/docs/guides/bind-open-parts.md +29 -12
- package/docs/guides/call-an-mcp-tool-from-a-machine.md +572 -0
- package/docs/guides/cancel-a-run.md +26 -16
- package/docs/guides/cut-a-worktree.md +560 -0
- package/docs/guides/fix-a-failed-converge.md +19 -7
- package/docs/guides/give-a-caller-a-scope.md +203 -0
- package/docs/guides/give-an-agent-mcp-tools.md +422 -0
- package/docs/guides/iterate-on-a-machine-on-kind.md +10 -9
- package/docs/guides/let-an-agent-write-a-chart.md +14 -7
- package/docs/guides/look-inside-a-sandbox.md +115 -42
- package/docs/guides/move-from-kind-to-a-shared-cluster.md +16 -0
- package/docs/guides/open-the-console.md +63 -14
- package/docs/guides/push-and-sign-a-branch.md +67 -21
- package/docs/guides/read-a-conversation.md +225 -0
- package/docs/guides/run-a-chart-by-name.md +17 -16
- package/docs/guides/run-a-command-or-call-a-url.md +84 -41
- package/docs/guides/run-one-worker-per-item.md +34 -27
- package/docs/guides/set-an-agents-access-and-dials.md +69 -22
- package/docs/guides/size-a-workspace.md +19 -6
- package/docs/guides/start-a-run-for-each-alert.md +290 -0
- package/docs/guides/start-a-run-from-a-run.md +18 -16
- package/docs/guides/start-a-run.md +24 -18
- package/docs/guides/steer-an-agent.md +332 -0
- package/docs/guides/use-a-hosted-provider.md +7 -1
- package/docs/guides/watch-a-run.md +146 -117
- package/docs/guides/write-a-hook-kind.md +238 -0
- package/docs/guides/write-a-tool-as-an-mcp-server.md +351 -0
- package/docs/guides/write-a-workflow.md +18 -8
- package/docs/llms.txt +110 -23
- package/docs/reference/authoring-surface/agent.md +35 -12
- package/docs/reference/authoring-surface/answer.md +20 -4
- package/docs/reference/authoring-surface/arg.md +28 -6
- package/docs/reference/authoring-surface/basic.md +1 -1
- package/docs/reference/authoring-surface/bearer.md +1 -1
- package/docs/reference/authoring-surface/branchname.md +15 -0
- package/docs/reference/authoring-surface/carry.md +23 -0
- package/docs/reference/authoring-surface/chartschema.md +1 -1
- package/docs/reference/authoring-surface/chartschemafor.md +1 -1
- package/docs/reference/authoring-surface/command.md +37 -22
- package/docs/reference/authoring-surface/customize.md +4 -1
- package/docs/reference/authoring-surface/defineconfig.md +1 -1
- package/docs/reference/authoring-surface/defineevent.md +1 -1
- package/docs/reference/authoring-surface/dispatch.md +5 -4
- package/docs/reference/authoring-surface/fail.md +18 -5
- package/docs/reference/authoring-surface/file.md +37 -17
- package/docs/reference/authoring-surface/frompick.md +1 -1
- package/docs/reference/authoring-surface/gate.md +118 -0
- package/docs/reference/authoring-surface/group-agents.md +15 -0
- package/docs/reference/authoring-surface/group-charts.md +16 -0
- package/docs/reference/authoring-surface/group-composition.md +25 -0
- package/docs/reference/authoring-surface/group-config.md +17 -0
- package/docs/reference/authoring-surface/group-effects.md +48 -0
- package/docs/reference/authoring-surface/group-failure.md +13 -0
- package/docs/reference/authoring-surface/group-gates.md +16 -0
- package/docs/reference/authoring-surface/group-machine-and-events.md +15 -0
- package/docs/reference/authoring-surface/group-steering.md +12 -0
- package/docs/reference/authoring-surface/group-types-these-signatures-name.md +137 -0
- package/docs/reference/authoring-surface/group-workspaces-and-repos.md +15 -0
- package/docs/reference/authoring-surface/http.md +109 -9
- package/docs/reference/authoring-surface/isfailure.md +1 -1
- package/docs/reference/authoring-surface/isready.md +14 -0
- package/docs/reference/authoring-surface/jr2setup.md +14 -4
- package/docs/reference/authoring-surface/mcp.md +107 -0
- package/docs/reference/authoring-surface/open.md +41 -8
- package/docs/reference/authoring-surface/openbody.md +1 -1
- package/docs/reference/authoring-surface/paramsof.md +23 -5
- package/docs/reference/authoring-surface/pool.md +79 -11
- package/docs/reference/authoring-surface/push.md +31 -13
- package/docs/reference/authoring-surface/readyof.md +21 -0
- package/docs/reference/authoring-surface/reread.md +19 -0
- package/docs/reference/authoring-surface/secret.md +26 -5
- package/docs/reference/authoring-surface/sentby.md +1 -1
- package/docs/reference/authoring-surface/skip.md +22 -0
- package/docs/reference/authoring-surface/source.md +59 -4
- package/docs/reference/authoring-surface/steer.md +93 -0
- package/docs/reference/authoring-surface/text.md +1 -1
- package/docs/reference/authoring-surface/type-agentdefinition.md +16 -3
- package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
- package/docs/reference/authoring-surface/type-agentslots.md +4 -1
- package/docs/reference/authoring-surface/type-anyframepath.md +14 -0
- package/docs/reference/authoring-surface/type-anyworktreepath.md +15 -0
- package/docs/reference/authoring-surface/type-bindactors.md +14 -0
- package/docs/reference/authoring-surface/type-binding.md +6 -7
- package/docs/reference/authoring-surface/type-caller.md +40 -0
- package/docs/reference/authoring-surface/type-callerrecord.md +32 -0
- package/docs/reference/authoring-surface/type-carry.md +19 -0
- package/docs/reference/authoring-surface/type-chainlink.md +3 -3
- package/docs/reference/authoring-surface/type-commandinput.md +4 -3
- package/docs/reference/authoring-surface/type-commandoptions.md +0 -22
- package/docs/reference/authoring-surface/type-commandoutput.md +23 -5
- package/docs/reference/authoring-surface/type-customize.md +20 -3
- package/docs/reference/authoring-surface/type-delivered.md +17 -0
- package/docs/reference/authoring-surface/type-deliveredevent.md +18 -0
- package/docs/reference/authoring-surface/type-dispatchdefinition.md +4 -3
- package/docs/reference/authoring-surface/type-dispatchoutput.md +9 -2
- package/docs/reference/authoring-surface/type-doorlessinput.md +19 -0
- package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
- package/docs/reference/authoring-surface/type-filebody.md +4 -8
- package/docs/reference/authoring-surface/type-framepath.md +14 -0
- package/docs/reference/authoring-surface/type-gatebinding.md +15 -0
- package/docs/reference/authoring-surface/type-gatehooks.md +12 -0
- package/docs/reference/authoring-surface/type-gatelook.md +37 -0
- package/docs/reference/authoring-surface/type-gateoutcome.md +32 -0
- package/docs/reference/authoring-surface/type-gatereply.md +19 -0
- package/docs/reference/authoring-surface/type-gateslot.md +21 -0
- package/docs/reference/authoring-surface/type-gateslotinput.md +13 -0
- package/docs/reference/authoring-surface/type-gateslotparts.md +18 -0
- package/docs/reference/authoring-surface/type-gateslots.md +12 -0
- package/docs/reference/authoring-surface/type-gatetypesat.md +13 -0
- package/docs/reference/authoring-surface/type-hostinjectedinput.md +3 -5
- package/docs/reference/authoring-surface/type-httpdefinition.md +6 -3
- package/docs/reference/authoring-surface/type-httpfileinput.md +20 -0
- package/docs/reference/authoring-surface/type-httpoutput.md +8 -2
- package/docs/reference/authoring-surface/type-jr2config.md +37 -2
- package/docs/reference/authoring-surface/type-lateroutcome.md +21 -0
- package/docs/reference/authoring-surface/type-lends.md +5 -1
- package/docs/reference/authoring-surface/type-lookoutput.md +14 -0
- package/docs/reference/authoring-surface/type-mcpcalloutput.md +78 -0
- package/docs/reference/authoring-surface/type-mcpnotreturned.md +42 -0
- package/docs/reference/authoring-surface/type-mcpoptions.md +47 -0
- package/docs/reference/authoring-surface/type-mcpoutput.md +50 -0
- package/docs/reference/authoring-surface/type-mcpreadoutput.md +53 -0
- package/docs/reference/authoring-surface/type-mcpremoteserver.md +50 -0
- package/docs/reference/authoring-surface/type-mcpserver.md +41 -0
- package/docs/reference/authoring-surface/type-mcpstdioserver.md +42 -0
- package/docs/reference/authoring-surface/type-namedsecret.md +4 -4
- package/docs/reference/authoring-surface/type-namestart.md +77 -0
- package/docs/reference/authoring-surface/type-noslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-notworktreekeys.md +12 -0
- package/docs/reference/authoring-surface/type-openbodydeclaration.md +1 -1
- package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
- package/docs/reference/authoring-surface/type-opencommandinput.md +7 -2
- package/docs/reference/authoring-surface/type-permissivenoslotworkspaceoptions.md +1 -6
- package/docs/reference/authoring-surface/type-permissiveworkspaceoptions.md +5 -10
- package/docs/reference/authoring-surface/type-poolnextinput.md +22 -0
- package/docs/reference/authoring-surface/type-poolspec.md +11 -6
- package/docs/reference/authoring-surface/type-pushinput.md +22 -3
- package/docs/reference/authoring-surface/type-pushoutput.md +33 -8
- package/docs/reference/authoring-surface/type-pushsourcespec.md +38 -0
- package/docs/reference/authoring-surface/type-readsourcespec.md +47 -0
- package/docs/reference/authoring-surface/type-reposlot.md +6 -6
- package/docs/reference/authoring-surface/type-reread.md +18 -0
- package/docs/reference/authoring-surface/type-runsconfig.md +41 -0
- package/docs/reference/authoring-surface/type-sandboxoptions.md +11 -4
- package/docs/reference/authoring-surface/type-sender.md +26 -1
- package/docs/reference/authoring-surface/type-sendercallerfield.md +14 -0
- package/docs/reference/authoring-surface/type-size.md +1 -1
- package/docs/reference/authoring-surface/type-skip.md +19 -0
- package/docs/reference/authoring-surface/type-slothandles.md +5 -13
- package/docs/reference/authoring-surface/type-sourcehooks.md +23 -0
- package/docs/reference/authoring-surface/type-sourcein.md +25 -0
- package/docs/reference/authoring-surface/type-sourcereply.md +18 -0
- package/docs/reference/authoring-surface/type-sourcespec.md +26 -17
- package/docs/reference/authoring-surface/type-sourceverdict.md +49 -0
- package/docs/reference/authoring-surface/type-standingpoolmachine.md +12 -0
- package/docs/reference/authoring-surface/type-standingpoolspec.md +51 -0
- package/docs/reference/authoring-surface/type-steerargs.md +20 -0
- package/docs/reference/authoring-surface/type-thinkinglevel.md +1 -1
- package/docs/reference/authoring-surface/type-usercontainer.md +1 -1
- package/docs/reference/authoring-surface/type-workspaced.md +30 -9
- package/docs/reference/authoring-surface/type-workspacehandles.md +5 -6
- package/docs/reference/authoring-surface/type-workspaceoptions.md +1 -13
- package/docs/reference/authoring-surface/type-worktreefound.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeinput.md +56 -0
- package/docs/reference/authoring-surface/type-worktreekey.md +14 -0
- package/docs/reference/authoring-surface/type-worktreeoptions.md +29 -0
- package/docs/reference/authoring-surface/type-worktreeoutput.md +45 -0
- package/docs/reference/authoring-surface/type-worktreepath.md +16 -0
- package/docs/reference/authoring-surface/type-worktreeready.md +37 -0
- package/docs/reference/authoring-surface/type-worktreerefused.md +21 -0
- package/docs/reference/authoring-surface/workspace.md +66 -38
- package/docs/reference/authoring-surface/worktree.md +71 -0
- package/docs/reference/authoring-surface.md +88 -147
- package/docs/reference/cli.md +413 -74
- package/docs/reference/config.md +248 -6
- package/docs/reference/decisions/0001-operator-owned-generic-sandbox.md +10 -9
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +81 -14
- package/docs/reference/decisions/0004-worktree-provisioning-model.md +27 -21
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +39 -25
- package/docs/reference/decisions/0006-agent-control-surface.md +6 -3
- package/docs/reference/decisions/0007-durable-machine-state.md +1 -1
- package/docs/reference/decisions/0009-cli-and-instance-interface.md +150 -49
- package/docs/reference/decisions/0010-bdd-acceptance-tests.md +5 -3
- package/docs/reference/decisions/0011-workflow-defined-events.md +256 -12
- package/docs/reference/decisions/0012-workspace-wrapper-machine.md +39 -32
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +54 -30
- package/docs/reference/decisions/0014-observation-is-open-run-state-is-not.md +53 -27
- package/docs/reference/decisions/0015-authoring-surface-absorbs-the-mechanism.md +26 -16
- package/docs/reference/decisions/0016-agent-turn-mechanics-are-internal.md +9 -7
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -10
- package/docs/reference/decisions/0018-instance-agents-are-definitions-jr2-assembles-the-harness.md +15 -7
- package/docs/reference/decisions/0019-one-converging-command-against-the-current-context.md +53 -27
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +16 -2
- package/docs/reference/decisions/0022-observation-is-a-level-triggered-feed.md +4 -4
- package/docs/reference/decisions/0023-the-harness-prints-the-conversation.md +124 -43
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +36 -38
- package/docs/reference/decisions/0025-cancel-ends-a-run-stop-parks-it.md +10 -5
- package/docs/reference/decisions/0027-the-harness-is-jr2s-own-server-flue-retires-the-wire-stays.md +16 -7
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +36 -19
- package/docs/reference/decisions/0029-a-menu-is-fixed-for-a-conversation-and-a-turn-is-told-its-allowed-picks.md +18 -10
- package/docs/reference/decisions/0030-a-snapshot-names-the-machine-it-was-written-under.md +3 -2
- package/docs/reference/decisions/0031-menu-only-agents-run-on-the-instance-harness.md +23 -15
- package/docs/reference/decisions/0032-the-console-unlocks-with-a-callers-credential.md +101 -0
- package/docs/reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md +22 -22
- package/docs/reference/decisions/0034-the-console-renders-with-preact-and-the-server-erases-the-types.md +6 -6
- package/docs/reference/decisions/0037-an-instance-builds-its-sandbox-images-jr2-injects-the-harness.md +13 -12
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +23 -23
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
- package/docs/reference/decisions/0051-a-repo-is-a-slot-on-the-workspace-and-a-cache-on-the-node.md +57 -46
- package/docs/reference/decisions/0052-a-sandbox-lands-where-an-ordinary-pod-lands-and-the-cache-follows-it.md +5 -0
- package/docs/reference/decisions/0053-a-fetch-inside-the-pod-asks-the-node-cache-and-the-cache-asks-the-remote.md +20 -8
- package/docs/reference/decisions/0054-the-kit-ships-machines-and-a-shipped-machine-leaves-its-parts-open.md +55 -40
- package/docs/reference/decisions/0055-a-release-is-a-pushed-tag-and-the-publish-guard-is-the-credential.md +14 -13
- package/docs/reference/decisions/0057-a-turn-is-its-frame-its-dials-and-whether-it-continues.md +31 -24
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +18 -10
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +137 -86
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +165 -91
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +7 -7
- package/docs/reference/decisions/0064-a-workspace-waits-for-capacity.md +2 -2
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-kept-for-a-set-time.md +109 -0
- package/docs/reference/decisions/0066-a-model-tier-runs-a-real-model-and-a-change-to-what-it-reads-runs-the-tier.md +53 -23
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +221 -153
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +161 -96
- package/docs/reference/decisions/0069-the-orchestrator-is-a-kit-image-and-an-instance-publishes-its-assembly.md +32 -9
- package/docs/reference/decisions/0070-a-machine-lends-its-parts-to-a-chart.md +48 -33
- package/docs/reference/decisions/0071-a-run-starts-a-run-through-a-dispatch-effect.md +56 -30
- package/docs/reference/decisions/0072-the-docs-ship-inside-the-kit-and-an-instances-agents-md-indexes-them.md +35 -25
- package/docs/reference/decisions/0073-a-machine-fails-a-run-with-fail-and-an-uncaught-failure-ends-it-failed.md +1 -1
- package/docs/reference/decisions/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +296 -0
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +347 -0
- package/docs/reference/decisions/0077-jr2-requires-landlock-on-every-sandbox-node.md +79 -0
- package/docs/reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md +285 -0
- package/docs/reference/decisions/0079-an-agent-holds-mcp-tools-a-machine-calls-them-as-an-effect-and-the-machine-is-the-approval.md +198 -0
- package/docs/reference/decisions.md +9 -4
- package/docs/reference/glossary.md +138 -45
- package/docs/reference/hooks.md +1077 -0
- package/docs/reference/http-api.md +988 -123
- package/docs/reference/machines.md +0 -1
- package/docs/why.md +7 -5
- package/package.json +10 -3
- package/src/actor.ts +194 -42
- package/src/agent.ts +56 -6
- package/src/ambient.ts +3 -5
- package/src/assembly-checks.ts +530 -4
- package/src/callers.ts +245 -0
- package/src/chart.ts +238 -26
- package/src/charts.ts +9 -2
- package/src/config.ts +566 -7
- package/src/conversations.ts +453 -0
- package/src/custodian.lua +17 -5
- package/src/custodian.ts +257 -77
- package/src/customize.ts +154 -7
- package/src/dispatch-effect.ts +142 -26
- package/src/durability.ts +2 -0
- package/src/duration.ts +20 -0
- package/src/effect-checks.ts +52 -4
- package/src/effect.ts +401 -132
- package/src/effector-wire.ts +278 -30
- package/src/fail.ts +17 -4
- package/src/gate-brand.ts +16 -0
- package/src/gate.ts +634 -48
- package/src/harness-client.ts +84 -35
- package/src/harness-env.ts +33 -0
- package/src/held-secrets.ts +197 -39
- package/src/holds.ts +5 -2
- package/src/hook-kinds/discord.ts +92 -0
- package/src/hook-kinds/door.ts +107 -0
- package/src/hook-kinds/github.ts +89 -0
- package/src/hook-kinds/gitlab.ts +72 -0
- package/src/hook-kinds/hook.ts +7 -0
- package/src/hook-kinds/index.ts +465 -0
- package/src/hook-kinds/slack.ts +151 -0
- package/src/hook-kinds/webhook.ts +113 -0
- package/src/hooks.ts +506 -0
- package/src/http-effect.ts +164 -70
- package/src/http.ts +933 -99
- package/src/index.ts +30 -5
- package/src/instance.ts +196 -26
- package/src/internal.ts +23 -3
- package/src/kube-client.ts +6 -3
- package/src/machine-doc.ts +29 -5
- package/src/mcp-effect.ts +424 -0
- package/src/model-keys.ts +24 -0
- package/src/mount-digest.ts +41 -7
- package/src/names.ts +82 -7
- package/src/notices.ts +576 -59
- package/src/open-body.ts +110 -30
- package/src/open-effect.ts +17 -4
- package/src/open.ts +40 -7
- package/src/parts.ts +125 -35
- package/src/party.ts +35 -1
- package/src/pick.ts +43 -9
- package/src/pool.ts +1172 -172
- package/src/registration.ts +249 -17
- package/src/repo-identity.ts +7 -3
- package/src/repos.ts +20 -2
- package/src/run-host.ts +1614 -190
- package/src/run-list.ts +191 -0
- package/src/sandbox-effect.ts +217 -66
- package/src/sandbox-kube.ts +116 -21
- package/src/secret-placement.ts +248 -35
- package/src/server.ts +53 -4
- package/src/setup.ts +158 -38
- package/src/snapshot-store.ts +565 -48
- package/src/steer.ts +111 -0
- package/src/stub-harness.ts +6 -2
- package/src/tokens.ts +362 -46
- package/src/vocabulary.ts +23 -4
- package/src/wire.ts +27 -10
- package/src/workspace.ts +314 -259
- package/src/worktree.ts +249 -0
- package/docs/reference/authoring-surface/type-noslotspec.md +0 -26
- package/docs/reference/authoring-surface/type-workspacespec.md +0 -37
- package/docs/reference/decisions/0032-the-console-unlocks-with-the-instance-token.md +0 -61
- package/docs/reference/decisions/0065-a-persist-survives-a-crash-and-history-is-a-week.md +0 -65
|
@@ -117,7 +117,7 @@ back to `listening`.
|
|
|
117
117
|
|
|
118
118
|
## See the runs
|
|
119
119
|
|
|
120
|
-
[`jr2 runs`](../reference/cli.md#runs) lists the two runs. The run of `triage` has `dispatchedBy
|
|
120
|
+
[`jr2 runs`](../reference/cli.md#runs) lists the two runs. The run of `triage` has `dispatchedBy`:
|
|
121
121
|
|
|
122
122
|
```sh
|
|
123
123
|
jr2 runs
|
|
@@ -126,29 +126,25 @@ jr2 runs
|
|
|
126
126
|
```text
|
|
127
127
|
…
|
|
128
128
|
→ context kind-jr2 / namespace my-instance
|
|
129
|
-
|
|
130
|
-
intake (machine)
|
|
131
|
-
ping (machine)
|
|
132
|
-
triage (machine)
|
|
133
|
-
[{"runId":"91ca85e1-5092-4e10-9ec6-d14e37811ca1","workflow":"intake","instanceId":"e51d124b-88e5-461c-b464-6a3660ee13dc","status":"active","value":"listening","context":{"started":["45b52048-0848-4015-ad56-6ff8ae33d817"],"request":"The greeting looks wrong sometimes.","last":{"outcome":"started","run":"45b52048-0848-4015-ad56-6ff8ae33d817"}},"children":[],"waiting":[],"held":[],"assembly":"3229103a2952","dispatched":[{"slot":"triage","run":"45b52048-0848-4015-ad56-6ff8ae33d817","at":"2026-10-24T06:20:43.465Z"}]},{"runId":"45b52048-0848-4015-ad56-6ff8ae33d817","dispatchedBy":{"run":"91ca85e1-5092-4e10-9ec6-d14e37811ca1","slot":"triage","effect":"08423831-751f-41e5-9d93-1fa063faaf61","depth":1},"workflow":"triage","instanceId":"a2ad6e54-6a52-45c2-81f4-89f408a27d1f","status":"active","value":"triaging","context":{"request":"The greeting looks wrong sometimes.","exchange":[]},"children":[],"waiting":[],"held":[],"assembly":"3229103a2952"}]
|
|
129
|
+
[{"runId":"e8a74de7-f3f3-4621-876e-e5f117af5fff","workflow":"triage","status":"active","startedBy":{"kind":"run","run":"f45bed48-9950-4e63-9cda-4df368e9a62f","slot":"triage"},"startedAt":"2026-11-06T19:23:24.220Z","assembly":"19d0bf0cbe10","openGates":0,"dispatchedBy":{"run":"f45bed48-9950-4e63-9cda-4df368e9a62f","slot":"triage","effect":"c63bce4d-e353-4fee-9035-6b13dfac4917","depth":1}},{"runId":"f45bed48-9950-4e63-9cda-4df368e9a62f","workflow":"intake","status":"active","startedBy":{"kind":"caller","via":"token","name":"instance","onBehalfOf":"kubernetes-admin"},"startedAt":"2026-11-06T19:23:21.744Z","assembly":"19d0bf0cbe10","openGates":1}]
|
|
134
130
|
```
|
|
135
131
|
|
|
136
|
-
The first line, `…`, is the line `→ .env:`, with the keys that the CLI took from `.env`.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
`intake`
|
|
132
|
+
The first line, `…`, is the line `→ .env:`, with the keys that the CLI took from `.env`. In `dispatchedBy`, `run` is the
|
|
133
|
+
run that started it, `slot` is the slot of the Effect, and `effect` is the id of that Effect in the record of the run
|
|
134
|
+
that started it. jr2 uses it as the key of the start, so that a start that jr2 sends again starts no second run. `depth`
|
|
135
|
+
is the number of runs before it in the chain. The list gives the newest start first, so `triage` comes before `intake`.
|
|
136
|
+
`jr2 status` of `intake` shows `dispatched`: each run that it started. Your ids, your time and your hash are different.
|
|
141
137
|
|
|
142
138
|
[`jr2 status`](../reference/cli.md#status) prints the link in both directions, on stderr. For the run of `intake`:
|
|
143
139
|
|
|
144
140
|
```text
|
|
145
|
-
dispatched:
|
|
141
|
+
dispatched: e8a74de7-f3f3-4621-876e-e5f117af5fff (triage)
|
|
146
142
|
```
|
|
147
143
|
|
|
148
144
|
For the run of `triage`:
|
|
149
145
|
|
|
150
146
|
```text
|
|
151
|
-
dispatched by:
|
|
147
|
+
dispatched by: f45bed48-9950-4e63-9cda-4df368e9a62f (triage), depth 1
|
|
152
148
|
```
|
|
153
149
|
|
|
154
150
|
The two runs are independent. A `CANCEL` of `intake` does not cancel the run of `triage`. Answer the `clarify` Gate of
|
|
@@ -174,7 +170,9 @@ To start a run on the Orchestrator of a different [Instance](../reference/glossa
|
|
|
174
170
|
definition: `target: { url: "https://ops.example.com", token: secret("ops-instance") }`.
|
|
175
171
|
|
|
176
172
|
- `url` is the origin of the other Orchestrator: the scheme, the host and the port. It has no path.
|
|
177
|
-
- `token` names a secret that holds the
|
|
173
|
+
- `token` names a secret that holds the token of a [Caller](../reference/glossary.md#caller) of the other Instance, with
|
|
174
|
+
the `start` scope for the Workflow, and also `read` when `wait` is `true`. A named Caller token of the other Instance
|
|
175
|
+
that has only these scopes is the safest ([Give a Caller a scope](give-a-caller-a-scope.md)). Put the secret in the
|
|
178
176
|
[`secrets`](../reference/config.md#secrets) list of `jr2.config.ts`, as for an `http` Effect. See
|
|
179
177
|
[Run a command or call a URL with an Effect](run-a-command-or-call-a-url.md).
|
|
180
178
|
- The Effect runs in the [Instance Effector](../reference/glossary.md#instance-effector), which holds the token.
|
|
@@ -201,7 +199,7 @@ the token together:
|
|
|
201
199
|
- The `url` of a target is an origin. The refusal starts with
|
|
202
200
|
`dispatch("<name>", { target }): "<url>" is not an origin — write the scheme and the host, with a port if it is not the scheme's, and no path, query or userinfo`.
|
|
203
201
|
- The `token` of a target is a secret:
|
|
204
|
-
`dispatch("<name>", { target }): the token is a secret("<name>") holding the target
|
|
202
|
+
`dispatch("<name>", { target }): the token is a secret("<name>") holding a Caller token of the target with start for the Workflow (ADR-0071)`
|
|
205
203
|
- An Open target is the whole target, not its secret:
|
|
206
204
|
``dispatch("<name>", { target }): secret(open) in a target — the target is the Open part, not its secret: leave the whole target Open (`target: open`) and let the composer bind its url and token together (ADR-0071)``
|
|
207
205
|
- With no target, the Assembly must have the Workflow. `jr2 up` stops:
|
|
@@ -214,11 +212,15 @@ the token together:
|
|
|
214
212
|
`warning: workflow "<workflow>" dispatches "<wrapper>/<name>": the Assembly has no Chart file workflows/<wrapper>/<name>.chart.json`.
|
|
215
213
|
- For a target, each problem that `jr2 up` finds is a warning. For example, when the other Orchestrator does not answer:
|
|
216
214
|
`warning: dispatch "<name>" at <url>: no answer from this host (<error>) — the other Instance may be down, or reached only from inside its cluster; while no door answers, the dispatch settles "unreachable" (ADR-0071)`
|
|
215
|
+
- When the input does not agree with the `input` schema of the slot, the invoke ends with an error, and no run starts.
|
|
216
|
+
The error starts with `dispatch "<slot>": its input does not match the slot's input schema —`. Before that, jr2 asks
|
|
217
|
+
for a run under the key of the start, with no target and with one. When a run has the key, the Effect gives that run,
|
|
218
|
+
and does not read the input. With a target, jr2 sends the key and no input, so the other Orchestrator starts nothing.
|
|
217
219
|
- When the Orchestrator starts no run, the Effect ends with `refused`, not with an error. `report` holds the lines of
|
|
218
220
|
the refusal, and `status` is its status code:
|
|
219
221
|
- `400`: the Workflow does not take the input.
|
|
220
222
|
- `404`: the current Assembly has no Workflow of that name.
|
|
221
|
-
- `409`: the named Chart cannot run now
|
|
223
|
+
- `409`: the named Chart cannot run now.
|
|
222
224
|
- `413`: the start is larger than the Effector reads.
|
|
223
225
|
- `422`: the door refuses the Chart in the input.
|
|
224
226
|
- `0`: the Effector refused the start before it sent it.
|
|
@@ -29,9 +29,9 @@ jr2 run ping --input '{"message":"hi"}'
|
|
|
29
29
|
|
|
30
30
|
```text
|
|
31
31
|
→ context <context> / namespace <namespace>
|
|
32
|
-
run
|
|
32
|
+
run 17b959ed-5200-4d98-adae-403dd706277b (ping) — attached
|
|
33
33
|
→ done "done"
|
|
34
|
-
{"runId":"
|
|
34
|
+
{"runId":"17b959ed-5200-4d98-adae-403dd706277b","workflow":"ping","instanceId":"32e6e954-8cc5-4b52-b6df-6c9ef6533192","startedAt":"2026-11-06T19:16:12.219Z","status":"done","value":"done","context":{"message":"hi","reply":"pong: hi"},"children":[],"waiting":[],"held":[],"assembly":"50e6f81e3bfb","startedBy":{"kind":"caller","via":"token","name":"instance","onBehalfOf":"kubernetes-admin"}}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Your run id, your instance id and your `assembly` hash are different. When your Instance folder has a `.env` file, the
|
|
@@ -47,7 +47,7 @@ output starts with one more line, `→ .env:`, with the keys that the CLI took f
|
|
|
47
47
|
- `jr2 run` stays attached until the run ends. A run that waits at a [Gate](../reference/glossary.md#gate) does not end,
|
|
48
48
|
so `jr2 run` waits too. To answer the Gate, use a second terminal. See [Answer a Gate](answer-a-gate.md).
|
|
49
49
|
- When you stop `jr2 run`, for example with Ctrl-C, the run continues in the Orchestrator. To attach again, run
|
|
50
|
-
`jr2
|
|
50
|
+
`jr2 watch <run id>`.
|
|
51
51
|
- `jr2 run` exits with `0` only when the run ends with the status `done`. It exits with `1` for each other end:
|
|
52
52
|
`failed`, `error`, `cancelled`, `lost` and `drifted`, and also when the run stops before it ends. For a run that ends
|
|
53
53
|
`failed`, the line `failed: <reason>` on stderr gives the reason.
|
|
@@ -65,15 +65,15 @@ jr2 run ping --input '{"message":"hi"}' --detach
|
|
|
65
65
|
{"runId":"fc8b82d1-bd73-498d-9057-ef13cf962240"}
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Use the run id, or its first 4 characters or more, with `jr2 status`, `jr2 logs` and `jr2 send`.
|
|
68
|
+
Use the run id, or its first 4 characters or more, with `jr2 status`, `jr2 watch`, `jr2 logs` and `jr2 send`.
|
|
69
69
|
|
|
70
70
|
## Start a run from the Console
|
|
71
71
|
|
|
72
|
-
You need
|
|
73
|
-
|
|
72
|
+
You need a credential with the `start` scope for the Workflow, such as the Instance token, to start a run from the
|
|
73
|
+
Console. [Open the Console](open-the-console.md) tells how to open it, how to get the token and how to log in.
|
|
74
74
|
|
|
75
75
|
1. Open the Console.
|
|
76
|
-
2. Type the
|
|
76
|
+
2. Type the token in the `Caller token` box in the nav, or click `log in`.
|
|
77
77
|
3. Push Enter. The badge beside the box shows `…`, then `live`.
|
|
78
78
|
4. In the Fleet rail on the left, find the Workflow. Click `start` beside its name.
|
|
79
79
|
5. Fill in the form. When the Machine declares its input, the form has one field for each property of the input. A field
|
|
@@ -94,7 +94,10 @@ cannot start one.
|
|
|
94
94
|
## Start a run with the HTTP API
|
|
95
95
|
|
|
96
96
|
Send [`POST /workflows/:name/runs`](../reference/http-api.md#post-workflows-name-runs) to the Orchestrator, with the
|
|
97
|
-
|
|
97
|
+
token of a [Caller](../reference/glossary.md#caller) that has the `start` scope for the Workflow. The body is the run
|
|
98
|
+
input. A script, a webhook handler or a CI job can start a run this way. A CI job uses a named Caller token, not the
|
|
99
|
+
Instance token: [Give a Caller a scope](give-a-caller-a-scope.md) makes it. The example below uses the Instance token,
|
|
100
|
+
because it can do everything.
|
|
98
101
|
|
|
99
102
|
`jr2 up` makes the Service `jr2-orchestrator` on port 4000, with no address outside the cluster. Thus a caller outside
|
|
100
103
|
the cluster uses a port forward, or an address that you make for the Service.
|
|
@@ -144,13 +147,14 @@ curl -s http://localhost:4000/workflows/ping -H "Accept: application/json"
|
|
|
144
147
|
```
|
|
145
148
|
|
|
146
149
|
[`GET /workflows`](../reference/http-api.md#get-workflows) gives all the Workflows, each with where it comes from, and
|
|
147
|
-
the named Charts of each Chart wrapper. It also needs no token. [`jr2
|
|
148
|
-
|
|
150
|
+
the named Charts of each Chart wrapper. It also needs no token. [`jr2 workflows`](../reference/cli.md#workflows) prints
|
|
151
|
+
the same list.
|
|
149
152
|
|
|
150
153
|
### Use the CLI without the Instance folder
|
|
151
154
|
|
|
152
155
|
The CLI can also speak to an Orchestrator at a URL. Then it does not look for the Instance folder or for a kubectl
|
|
153
|
-
context. Give the URL in `--url`, or in `JR2_URL`. Give the Instance token
|
|
156
|
+
context. Give the URL in `--url`, or in `JR2_URL`. Give a credential in `JR2_TOKEN`: the Instance token, or the token of
|
|
157
|
+
a [Caller](../reference/glossary.md#caller) with the `start` scope ([Give a Caller a scope](give-a-caller-a-scope.md)):
|
|
154
158
|
|
|
155
159
|
```sh
|
|
156
160
|
JR2_URL=http://localhost:4000 JR2_TOKEN=$TOKEN jr2 run ping --input '{"message":"hi"}' --detach
|
|
@@ -177,10 +181,12 @@ JR2_URL=http://localhost:4000 JR2_TOKEN=$TOKEN jr2 run ping --input '{"message":
|
|
|
177
181
|
`the body must be a JSON object`.
|
|
178
182
|
- `jr2 run` starts no run when `--input` is not valid JSON. It prints `error: <message>`, where `<message>` is the
|
|
179
183
|
message of the JSON parser, and exits with `1`.
|
|
180
|
-
- The Orchestrator refuses a start
|
|
184
|
+
- The Orchestrator refuses a start with no valid credential, with the status code `401`: `unauthorized`.
|
|
181
185
|
- The Orchestrator refuses a start with the token of a [Sandbox](../reference/glossary.md#sandbox), with the status code
|
|
182
|
-
`403`: `
|
|
183
|
-
[Agent](../reference/glossary.md#agent) cannot start a run.
|
|
186
|
+
`403`: `this route needs a Caller, and a Sandbox token is not one: no Agent reaches run state, run control or a Gate`.
|
|
187
|
+
Thus an [Agent](../reference/glossary.md#agent) cannot start a run.
|
|
188
|
+
- The Orchestrator refuses a start from a Caller that does not have the `start` scope for the Workflow, with the status
|
|
189
|
+
code `403`: `the Caller <via>/<name> needs the "start" scope for Workflow "<workflow>" (ADR-0078)`
|
|
184
190
|
- `jr2 run` outside an Instance folder, with no `--url` and no `JR2_URL`, starts no run:
|
|
185
191
|
`error: not inside a jr2 instance — no jr2.config.ts found walking up from cwd`
|
|
186
192
|
- `jr2 run` starts no run when the namespace holds no Instance:
|
|
@@ -189,9 +195,9 @@ JR2_URL=http://localhost:4000 JR2_TOKEN=$TOKEN jr2 run ping --input '{"message":
|
|
|
189
195
|
``error: no kube context — `kind create cluster` (or point kubectl at one), then `jr2 up` ``
|
|
190
196
|
- When the connection to the Orchestrator ends before the run ends, for example when the Orchestrator stops, `jr2 run`
|
|
191
197
|
prints `error: <message>` and exits with `1`. The run continues when the Orchestrator starts again. To attach again,
|
|
192
|
-
run `jr2
|
|
198
|
+
run `jr2 watch <run id>`.
|
|
193
199
|
- When the Orchestrator holds the run but did not continue it, `jr2 run` exits with `1`:
|
|
194
|
-
``run <run id> is parked: stopped before it settled — `jr2
|
|
200
|
+
``run <run id> is parked: stopped before it settled — `jr2 watch <run id>` follows it once restored``
|
|
195
201
|
|
|
196
202
|
## Read next
|
|
197
203
|
|
|
@@ -201,7 +207,7 @@ JR2_URL=http://localhost:4000 JR2_TOKEN=$TOKEN jr2 run ping --input '{"message":
|
|
|
201
207
|
Orchestrator.
|
|
202
208
|
- [ADR-0033](../reference/decisions/0033-a-machine-declares-the-input-that-starts-it.md): the input that a Machine
|
|
203
209
|
declares.
|
|
204
|
-
- [ADR-
|
|
205
|
-
|
|
210
|
+
- [ADR-0078](../reference/decisions/0078-a-caller-comes-from-one-authenticator-seam-and-acts-within-its-scopes.md): the
|
|
211
|
+
Callers, and the `start` scope.
|
|
206
212
|
- [Answer a Gate](answer-a-gate.md)
|
|
207
213
|
- [Watch a run](watch-a-run.md)
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Steer an Agent
|
|
3
|
+
description: Send free text to one Agent of a live run, from the CLI, from HTTP, or from the Machine itself.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Steer an Agent
|
|
7
|
+
|
|
8
|
+
Send free text to one [Agent](../reference/glossary.md#agent) of a live run, from the CLI, from HTTP, or from the
|
|
9
|
+
[Machine](../reference/glossary.md#machine) itself.
|
|
10
|
+
|
|
11
|
+
A [Steering message](../reference/glossary.md#steering-message) is not a pick and not an event. No guard reads it, and
|
|
12
|
+
no [Gate](../reference/glossary.md#gate) takes it. The Agent hears it one time, and nothing interrupts the Agent. Then
|
|
13
|
+
the Agent decides what to do, and it acts on the run only with its picks. To move the run, answer a Gate:
|
|
14
|
+
[Answer a Gate](answer-a-gate.md).
|
|
15
|
+
|
|
16
|
+
The examples on this page use the [Workflow](../reference/glossary.md#workflow) `notes`. A writer writes release notes,
|
|
17
|
+
and a reviewer reads them. When the reviewer sends a note, the Machine relays it to the writer as a Steering message.
|
|
18
|
+
Save the file as `workflows/notes.ts` in your [Instance](../reference/glossary.md#instance). Then run `jr2 up`:
|
|
19
|
+
|
|
20
|
+
**Anthropic**
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { assign } from "xstate";
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
import { agent, defineEvent, fail, jr2Setup, steer } from "@jr2/orchestrator";
|
|
26
|
+
|
|
27
|
+
// The writer's pick: the draft is ready for review.
|
|
28
|
+
const done = defineEvent({
|
|
29
|
+
name: "done",
|
|
30
|
+
description: "The draft is ready. Give the whole draft.",
|
|
31
|
+
input: z.object({ draft: z.string().min(1) }),
|
|
32
|
+
});
|
|
33
|
+
// The reviewer's two picks.
|
|
34
|
+
const note = defineEvent({
|
|
35
|
+
name: "note",
|
|
36
|
+
description: "Send the draft back to the writer, with what to change.",
|
|
37
|
+
input: z.object({ text: z.string().min(1) }),
|
|
38
|
+
});
|
|
39
|
+
const approve = defineEvent({
|
|
40
|
+
name: "approve",
|
|
41
|
+
description: "The draft is good.",
|
|
42
|
+
input: z.object({}),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
type Context = { version: string; draft?: string; fault?: string };
|
|
46
|
+
|
|
47
|
+
export const machine = jr2Setup({
|
|
48
|
+
types: {} as { input: { version: string }; context: Context },
|
|
49
|
+
events: [done, note, approve],
|
|
50
|
+
actors: {
|
|
51
|
+
writer: agent({
|
|
52
|
+
model: "anthropic/claude-haiku-5-5",
|
|
53
|
+
instructions: "You write short release notes.",
|
|
54
|
+
workspace: "none",
|
|
55
|
+
}),
|
|
56
|
+
// A Caller cannot steer the reviewer. The Machine can.
|
|
57
|
+
reviewer: agent({
|
|
58
|
+
model: "anthropic/claude-haiku-5-5",
|
|
59
|
+
instructions: "You review release notes for clear and correct words.",
|
|
60
|
+
workspace: "none",
|
|
61
|
+
steerable: false,
|
|
62
|
+
}),
|
|
63
|
+
fail: fail(),
|
|
64
|
+
},
|
|
65
|
+
}).createMachine({
|
|
66
|
+
id: "notes",
|
|
67
|
+
input: z.object({ version: z.string() }),
|
|
68
|
+
context: ({ input }) => ({ version: input.version }),
|
|
69
|
+
initial: "writing",
|
|
70
|
+
// A Turn that fails in either state ends the run `failed`, with the reason of the Turn.
|
|
71
|
+
on: { "agent.fault": { target: ".failed", actions: assign({ fault: ({ event }) => event.reason }) } },
|
|
72
|
+
states: {
|
|
73
|
+
writing: {
|
|
74
|
+
invoke: {
|
|
75
|
+
src: "writer",
|
|
76
|
+
// The writer continues its conversation, so it keeps its draft from Turn to Turn.
|
|
77
|
+
input: ({ context }) => ({ prompt: `Write the release notes for ${context.version}.`, continue: true }),
|
|
78
|
+
},
|
|
79
|
+
on: { done: { target: "reviewing", actions: assign({ draft: ({ event }) => event.draft }) } },
|
|
80
|
+
},
|
|
81
|
+
reviewing: {
|
|
82
|
+
invoke: {
|
|
83
|
+
src: "reviewer",
|
|
84
|
+
input: ({ context }) => ({ prompt: `Review these release notes:\n\n${context.draft ?? ""}` }),
|
|
85
|
+
},
|
|
86
|
+
on: {
|
|
87
|
+
// The reviewer's note goes to the writer's next Turn as a Steering message. `from` names the
|
|
88
|
+
// reviewer, so the writer reads it as information from a peer, not as an instruction.
|
|
89
|
+
note: {
|
|
90
|
+
target: "writing",
|
|
91
|
+
actions: steer("writer", ({ event }) => event.text, { from: ({ event }) => event.sender }),
|
|
92
|
+
},
|
|
93
|
+
approve: "published",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
published: { type: "final" },
|
|
97
|
+
failed: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.fault ?? "the Turn failed" }) } },
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Local**
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { assign } from "xstate";
|
|
106
|
+
import { z } from "zod";
|
|
107
|
+
import { agent, defineEvent, fail, jr2Setup, steer } from "@jr2/orchestrator";
|
|
108
|
+
|
|
109
|
+
// The writer's pick: the draft is ready for review.
|
|
110
|
+
const done = defineEvent({
|
|
111
|
+
name: "done",
|
|
112
|
+
description: "The draft is ready. Give the whole draft.",
|
|
113
|
+
input: z.object({ draft: z.string().min(1) }),
|
|
114
|
+
});
|
|
115
|
+
// The reviewer's two picks.
|
|
116
|
+
const note = defineEvent({
|
|
117
|
+
name: "note",
|
|
118
|
+
description: "Send the draft back to the writer, with what to change.",
|
|
119
|
+
input: z.object({ text: z.string().min(1) }),
|
|
120
|
+
});
|
|
121
|
+
const approve = defineEvent({
|
|
122
|
+
name: "approve",
|
|
123
|
+
description: "The draft is good.",
|
|
124
|
+
input: z.object({}),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
type Context = { version: string; draft?: string; fault?: string };
|
|
128
|
+
|
|
129
|
+
export const machine = jr2Setup({
|
|
130
|
+
types: {} as { input: { version: string }; context: Context },
|
|
131
|
+
events: [done, note, approve],
|
|
132
|
+
actors: {
|
|
133
|
+
writer: agent({
|
|
134
|
+
model: "local/qwen3.6-35b-a3b",
|
|
135
|
+
instructions: "You write short release notes.",
|
|
136
|
+
workspace: "none",
|
|
137
|
+
}),
|
|
138
|
+
// A Caller cannot steer the reviewer. The Machine can.
|
|
139
|
+
reviewer: agent({
|
|
140
|
+
model: "local/qwen3.6-35b-a3b",
|
|
141
|
+
instructions: "You review release notes for clear and correct words.",
|
|
142
|
+
workspace: "none",
|
|
143
|
+
steerable: false,
|
|
144
|
+
}),
|
|
145
|
+
fail: fail(),
|
|
146
|
+
},
|
|
147
|
+
}).createMachine({
|
|
148
|
+
id: "notes",
|
|
149
|
+
input: z.object({ version: z.string() }),
|
|
150
|
+
context: ({ input }) => ({ version: input.version }),
|
|
151
|
+
initial: "writing",
|
|
152
|
+
// A Turn that fails in either state ends the run `failed`, with the reason of the Turn.
|
|
153
|
+
on: { "agent.fault": { target: ".failed", actions: assign({ fault: ({ event }) => event.reason }) } },
|
|
154
|
+
states: {
|
|
155
|
+
writing: {
|
|
156
|
+
invoke: {
|
|
157
|
+
src: "writer",
|
|
158
|
+
// The writer continues its conversation, so it keeps its draft from Turn to Turn.
|
|
159
|
+
input: ({ context }) => ({ prompt: `Write the release notes for ${context.version}.`, continue: true }),
|
|
160
|
+
},
|
|
161
|
+
on: { done: { target: "reviewing", actions: assign({ draft: ({ event }) => event.draft }) } },
|
|
162
|
+
},
|
|
163
|
+
reviewing: {
|
|
164
|
+
invoke: {
|
|
165
|
+
src: "reviewer",
|
|
166
|
+
input: ({ context }) => ({ prompt: `Review these release notes:\n\n${context.draft ?? ""}` }),
|
|
167
|
+
},
|
|
168
|
+
on: {
|
|
169
|
+
// The reviewer's note goes to the writer's next Turn as a Steering message. `from` names the
|
|
170
|
+
// reviewer, so the writer reads it as information from a peer, not as an instruction.
|
|
171
|
+
note: {
|
|
172
|
+
target: "writing",
|
|
173
|
+
actions: steer("writer", ({ event }) => event.text, { from: ({ event }) => event.sender }),
|
|
174
|
+
},
|
|
175
|
+
approve: "published",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
published: { type: "final" },
|
|
179
|
+
failed: { invoke: { src: "fail", input: ({ context }) => ({ reason: context.fault ?? "the Turn failed" }) } },
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The Agents use the model of the tab.
|
|
185
|
+
|
|
186
|
+
In the commands, replace these values:
|
|
187
|
+
|
|
188
|
+
- `<namespace>`: the namespace of your Instance. It is the [`name`](../reference/config.md#name) in `jr2.config.ts`.
|
|
189
|
+
When `jr2.config.ts` sets no `name`, it is the name of the Instance folder.
|
|
190
|
+
- `<run id>`: the run id, or its first 4 characters or more. `jr2 run` prints the run id in the line
|
|
191
|
+
`run <run id> (<workflow>) — attached`.
|
|
192
|
+
|
|
193
|
+
Give each `jr2` command in the Instance folder.
|
|
194
|
+
|
|
195
|
+
## Start a run
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
jr2 run notes --input '{"version":"1.4.0"}'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
→ context <context> / namespace <namespace>
|
|
203
|
+
run 7058fde8-4c32-4513-82f0-e6c095d8707b (notes) — attached
|
|
204
|
+
→ active "writing"
|
|
205
|
+
→ active "writing"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Your run id is different. Give the commands in the next steps in a second terminal.
|
|
209
|
+
|
|
210
|
+
## Find the Agent slot
|
|
211
|
+
|
|
212
|
+
A message goes to an Agent slot: the path of the Machine and the name of the Agent. The Agents of the root Machine have
|
|
213
|
+
the path `root`. An Agent in a child Machine has the path of that Machine, such as `review/reviewer`. Give
|
|
214
|
+
[`jr2 steer`](../reference/cli.md#steer) the run id alone to list the slots:
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
jr2 steer 7058
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
```text
|
|
221
|
+
→ context <context> / namespace <namespace>
|
|
222
|
+
[{"agent":"root/writer","open":true,"steerable":true},{"agent":"root/reviewer","open":false,"steerable":false}]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
- `open` is `true` when a [Turn](../reference/glossary.md#turn) of the slot is open now.
|
|
226
|
+
- `steerable` is `false` when the definition of the Agent says `steerable: false`. A Caller cannot steer it.
|
|
227
|
+
|
|
228
|
+
The list has each Agent of each Machine instance that is live now, also an Agent with no open Turn.
|
|
229
|
+
|
|
230
|
+
## Send the message
|
|
231
|
+
|
|
232
|
+
```sh
|
|
233
|
+
jr2 steer 7058 root/writer "Put the breaking change first."
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```text
|
|
237
|
+
→ context <context> / namespace <namespace>
|
|
238
|
+
sent a Steering message to root/writer on 7058fde8-4c32-4513-82f0-e6c095d8707b: its open Turn hears it at its next step boundary, or its next Turn hears it if this Turn ends first
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Then one of these things occurs:
|
|
242
|
+
|
|
243
|
+
- When a Turn of the slot is open, the Harness adds the message to the Turn before the next model request.
|
|
244
|
+
- When the Turn ends with a pick before its next model request, the message waits for the next Turn of the slot.
|
|
245
|
+
- When no Turn of the slot is open, the message waits. The next Turn of the slot in the same Machine instance hears it,
|
|
246
|
+
and `jr2 steer` prints `its next Turn hears it`.
|
|
247
|
+
- When that Machine instance ends first, the message is not delivered.
|
|
248
|
+
|
|
249
|
+
## Read what became of the message
|
|
250
|
+
|
|
251
|
+
[`jr2 status`](../reference/cli.md#status) prints the record of the messages of the run in its `steering` field. Each
|
|
252
|
+
entry has the slot, the author, the text, the time, and the `outcome`: `held` while it waits, `heard` when a Turn heard
|
|
253
|
+
it, or `not-delivered` when its Machine instance ended first.
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
jr2 status 7058
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```text
|
|
260
|
+
→ context <context> / namespace <namespace>
|
|
261
|
+
{"runId":"7058fde8-4c32-4513-82f0-e6c095d8707b","workflow":"notes",…,"steering":[{"id":"c46a31f0-db82-4d80-b7f1-8908c2d9b121","agent":"root/writer","author":{"kind":"caller","via":"token","name":"instance","onBehalfOf":"kubernetes-admin"},"text":"Put the breaking change first.","at":"2026-11-06T20:56:33.005Z","outcome":"heard"},{"id":"f788b1f6-2b93-44be-a54e-e91f83685493","agent":"root/writer","author":{"kind":"machine","from":{"party":"agent","id":"reviewer"}},"text":"The release notes are well-structured, but I suggest a change for clarity in the **Notifications** section:\n\n\"Real-time notifications are now **persisted** across device logins.\"\n\n\"Persisted\" is technical jargon referring to data storage. If the intended meaning is that notifications appear on different devices, \"**synchronized**\" (or \"synced\") is the standard and clearer term for users.\n\nSuggested edit: \"Real-time notifications are now **synchronized** across devices.\"","at":"2026-11-06T20:57:35.442Z","outcome":"heard"}],…}
|
|
262
|
+
started by: token/instance on behalf of kubernetes-admin
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
The model reads the message after the notices of the Turn and before its Allowed picks. The Harness tells the model that
|
|
266
|
+
the message is an instruction from outside the run, and gives your name as a [Caller](../reference/glossary.md#caller).
|
|
267
|
+
|
|
268
|
+
## Send the message from the Console
|
|
269
|
+
|
|
270
|
+
With a credential that has the `steer` scope for the Workflow, the [Console](../reference/glossary.md#console) shows a
|
|
271
|
+
box beside the conversation in the bottom drawer. Select the run, and click the tab of the Agent slot. Type the message
|
|
272
|
+
in the box under `steer <slot>`, and click `send`. The box shows `<slot> cannot be steered now` when the definition of
|
|
273
|
+
the Agent says `steerable: false`, or when the Machine instance of the slot ended. The conversation shows the message
|
|
274
|
+
where the model read it. [Open the Console](open-the-console.md#read-a-conversation) tells how to open the drawer.
|
|
275
|
+
|
|
276
|
+
## Send the message from HTTP
|
|
277
|
+
|
|
278
|
+
A client that is not the CLI sends the message to
|
|
279
|
+
[`POST /runs/:runId/steering`](../reference/http-api.md#post-runs-runid-steering), with the credential of a Caller that
|
|
280
|
+
has the `steer` scope for the Workflow of the run. [Give a Caller a scope](give-a-caller-a-scope.md) makes such a token.
|
|
281
|
+
The path takes the full run id, not a prefix.
|
|
282
|
+
[`GET /runs/:runId/agents`](../reference/http-api.md#get-runs-runid-agents) lists the slots. This example reaches the
|
|
283
|
+
Orchestrator through the port forward in [Open the Console](open-the-console.md):
|
|
284
|
+
|
|
285
|
+
```sh
|
|
286
|
+
curl -X POST http://localhost:4000/runs/<run id>/steering \
|
|
287
|
+
-H "authorization: Bearer <token>" \
|
|
288
|
+
-d '{"agent":"root/writer","text":"Put the breaking change first."}'
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```text
|
|
292
|
+
{"id":"29e54d63-e858-4249-a789-f7e5506f433a","agent":"root/writer","open":true}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The status is 202.
|
|
296
|
+
|
|
297
|
+
## Steer from the Machine
|
|
298
|
+
|
|
299
|
+
The Machine sends a Steering message with the [`steer`](../reference/authoring-surface/steer.md) action, in a
|
|
300
|
+
transition. In `notes.ts`, the `note` pick of the reviewer sends the writer back to `writing`, and `steer` gives the
|
|
301
|
+
reviewer's text to the writer's next Turn.
|
|
302
|
+
|
|
303
|
+
`from` names the [Sender](../reference/glossary.md#sender) of the event: here, the reviewer. Then the writer reads the
|
|
304
|
+
text as information from a peer, not as an instruction. When `from` is a Gate, the writer reads the text as what the
|
|
305
|
+
Gate received, not as an order: the workflow did not write it. A `steer` with no `from` is the text of the workflow
|
|
306
|
+
itself. Agents tell each other things only in this way: jr2 gives an Agent no tool to message another Agent.
|
|
307
|
+
|
|
308
|
+
The Machine can steer an Agent whose definition says `steerable: false`. That refuses Callers only.
|
|
309
|
+
|
|
310
|
+
## Rules
|
|
311
|
+
|
|
312
|
+
- A message is at most 16 KiB of UTF-8. `POST /runs/:runId/steering` refuses a longer text with the status 413:
|
|
313
|
+
`the text is longer than 16384 bytes (16 KiB)`. The `steer` action cuts a longer text and adds
|
|
314
|
+
`[jr2 cut this message at 16 KiB]`.
|
|
315
|
+
- A body with no `agent`, or no `text`, gets the status 400.
|
|
316
|
+
- A slot that no live Machine instance of the run holds gets the status 409, with the slots of the run in `agents`:
|
|
317
|
+
`no live Machine instance of run "<run id>" holds the Agent slot "<agent>" (its slots: <slots>)`. A run that has ended
|
|
318
|
+
gets 409 too: `run "<run id>" is not live: no Agent of it can hear a message`.
|
|
319
|
+
- A slot whose Agent says `steerable: false` gets the status 403:
|
|
320
|
+
`the Agent slot "<agent>" is not steerable: its definition says steerable: false`.
|
|
321
|
+
- A Caller with no `steer` scope for the Workflow of the run gets the status 403:
|
|
322
|
+
`the Caller <via>/<name> needs the "steer" scope for Workflow "<workflow>" (ADR-0078)`.
|
|
323
|
+
- An unknown run gets the status 404: `no run "<run id>"`.
|
|
324
|
+
- The record keeps the newest 100 messages of a run, and each message that waits.
|
|
325
|
+
|
|
326
|
+
## Read next
|
|
327
|
+
|
|
328
|
+
- [Agents and Turns](../concepts/agents-and-turns.md#steering-messages)
|
|
329
|
+
- [`jr2 steer`](../reference/cli.md#steer) and [`steer`](../reference/authoring-surface/steer.md)
|
|
330
|
+
- [ADR-0002](../reference/decisions/0002-duplex-streaming-actor.md#steering-messages): Steering messages
|
|
331
|
+
- [ADR-0062](../reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md): one ledger for notices
|
|
332
|
+
and Steering messages
|
|
@@ -186,10 +186,16 @@ custom provider, with `harness.provider` and `apiKey`. The guide
|
|
|
186
186
|
- `jr2 up` refuses a gateway address that is not `https://`:
|
|
187
187
|
`harness.catalog.<id>.baseUrl must be an https:// URL — the Custodian carries TLS only (ADR-0059). Read it from .env: catalog: { anthropic: { baseUrl: process.env.LITELLM_URL ?? "" } }`.
|
|
188
188
|
- `jr2 up` warns about a key that no pod gets:
|
|
189
|
-
`warning: secrets[<i>] (<NAME>) is named by nothing; goes nowhere — no workspace() lists it, no Agent's provider reads it, and no Effect names it (ADR-0059, ADR-0068)`.
|
|
189
|
+
`warning: secrets[<i>] (<NAME>) is named by nothing; goes nowhere — no workspace() lists it, no Agent's provider reads it, and no Effect or Hook names it (ADR-0059, ADR-0068)`.
|
|
190
190
|
- A credential that signs each request, such as `AWS_ACCESS_KEY_ID`, cannot be a Held secret. `jr2 up` warns when
|
|
191
191
|
`harness.env` sets one. Send the calls through a gateway that holds the credential, and hold the key of the gateway:
|
|
192
192
|
`warning: harness.env sets <NAME>: a signing credential cannot be held (a Stand-in cannot be swapped into a signature), so the Agent can read it — route the provider through a gateway that holds it, and hold the gateway's key instead (ADR-0059)`.
|
|
193
|
+
- The Harness process reads the file that a credential-file name in `harness.env` names, such as `AWS_CONFIG_FILE` or
|
|
194
|
+
`GOOGLE_APPLICATION_CREDENTIALS`. `jr2 up` refuses a path in a folder that the Agent's code writes, or a path that is
|
|
195
|
+
not absolute:
|
|
196
|
+
`harness.env[<i>] sets <NAME> to "<path>", which is in <folder>, a folder the Agent's code writes: the Harness process reads that file, and code that writes it acts outside the Agent's confinement (ADR-0076). Point it at a file of the image that the Sandbox's user cannot write.`
|
|
197
|
+
For another path, it warns:
|
|
198
|
+
`warning: harness.env sets <NAME>: the Harness process reads "<path>", so the Sandbox's user must not be able to write it — a folder of the image that the user owns is one the Agent's code writes (ADR-0076)`.
|
|
193
199
|
- The Harness refuses a model that is not in the catalog when it admits the Turn:
|
|
194
200
|
`harness admission failed (400): agent "<agent>": model "<provider>/<modelId>" resolves to nothing — not in pi's catalog, and no custom provider "<provider>" is configured (ADR-0018)`.
|
|
195
201
|
|