@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
package/src/open-body.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
type UnknownActorLogic,
|
|
25
25
|
} from "xstate";
|
|
26
26
|
import { isAgent, type AgentDefinition, type WorkspaceAccess } from "./agent.ts";
|
|
27
|
+
import { ambientHandlesFor } from "./ambient.ts";
|
|
27
28
|
import {
|
|
28
29
|
admitChart,
|
|
29
30
|
chartDigest,
|
|
@@ -31,8 +32,10 @@ import {
|
|
|
31
32
|
ChartRefusal,
|
|
32
33
|
GENERIC_ACTIONS,
|
|
33
34
|
pathSegments,
|
|
35
|
+
READY_GUARD,
|
|
34
36
|
resolveSource,
|
|
35
37
|
resolveReferences,
|
|
38
|
+
slotFolderFault,
|
|
36
39
|
type AdmittedChart,
|
|
37
40
|
type ChartAction,
|
|
38
41
|
type ChartGuard,
|
|
@@ -43,11 +46,13 @@ import {
|
|
|
43
46
|
type ChartTransition,
|
|
44
47
|
type ChartTransitions,
|
|
45
48
|
} from "./chart.ts";
|
|
46
|
-
import {
|
|
49
|
+
import { inputShapeOf, isEffect, type Duration, type InputShape } from "./effect.ts";
|
|
47
50
|
import { fail, FAILURE_GUARD, failureGuard } from "./fail.ts";
|
|
48
51
|
import { agent } from "./harness-client.ts";
|
|
49
52
|
import { SENT_BY } from "./party.ts";
|
|
50
|
-
import { wrapperBodyOf } from "./parts.ts";
|
|
53
|
+
import { composesSandbox, sandboxPartsOf, wrapperBodyOf } from "./parts.ts";
|
|
54
|
+
import { isGateSlot } from "./gate.ts";
|
|
55
|
+
import { open } from "./open.ts";
|
|
51
56
|
import { actorPath, boundRun } from "./registration.ts";
|
|
52
57
|
import { COMPILED_CHART, jr2Setup } from "./setup.ts";
|
|
53
58
|
import { attachBoundMachine, boundMachineFor } from "./vocabulary.ts";
|
|
@@ -111,7 +116,9 @@ export function jsonOver(value: unknown, cap: number): boolean {
|
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
/** The parts of the Chart wrapper that a Chart can use, by their keys in `actors`, `guards`,
|
|
114
|
-
* `actions` and `delays`. `
|
|
119
|
+
* `actions` and `delays`. `gates` lends Gate slots (`gate({ … })`) that hear a Hook, by slot name:
|
|
120
|
+
* the door refuses a Chart that invokes one whose `delivers` names an event that is not in the
|
|
121
|
+
* Chart's `events`. `gate: true` lends the Gate, so that a Chart can wait for an answer from
|
|
115
122
|
* outside the run. `fail: true` lends the Part that fails the run, so that a Chart can end its run
|
|
116
123
|
* as a Failure (ADR-0073): the Machine decides which ends a Chart can choose. A Chart can use no
|
|
117
124
|
* other part. */
|
|
@@ -119,6 +126,7 @@ export type Lends = {
|
|
|
119
126
|
agents?: string[];
|
|
120
127
|
effects?: string[];
|
|
121
128
|
machines?: string[];
|
|
129
|
+
gates?: string[];
|
|
122
130
|
guards?: string[];
|
|
123
131
|
actions?: string[];
|
|
124
132
|
delays?: string[];
|
|
@@ -157,7 +165,7 @@ export type OpenBodySlot = { readonly openBody: OpenBodyDeclaration };
|
|
|
157
165
|
/** The logic `openBody()` returns: actor logic that carries the brand. */
|
|
158
166
|
export type OpenBodyLogic = UnknownActorLogic & OpenBodySlot;
|
|
159
167
|
|
|
160
|
-
const LEND_KINDS = ["agents", "effects", "machines", "guards", "actions", "delays"] as const;
|
|
168
|
+
const LEND_KINDS = ["agents", "effects", "machines", "gates", "guards", "actions", "delays"] as const;
|
|
161
169
|
const WORKSPACE: readonly WorkspaceAccess[] = ["write", "read", "none"];
|
|
162
170
|
const CEILING_KEYS = ["turns", "wallClock", "transitions", "fanOut", "size"] as const;
|
|
163
171
|
const DURATION = /^(\d+(\.\d+)?)(s|m|h)$/;
|
|
@@ -166,9 +174,9 @@ const MAX_WALL_CLOCK_MS = 2_147_483_647;
|
|
|
166
174
|
/** A name a Chart's grammar reads as its own, so a lent part by that name would be shadowed. */
|
|
167
175
|
const reservedName = (kind: (typeof LEND_KINDS)[number], v: string): string | undefined => {
|
|
168
176
|
if (v.includes(".")) return `"${v}" holds a dot; a lent name is a slot key, and dotted names are jr2's and xstate's`;
|
|
169
|
-
if ((kind === "agents" || kind === "effects" || kind === "machines") && v === "gate")
|
|
177
|
+
if ((kind === "agents" || kind === "effects" || kind === "machines" || kind === "gates") && v === "gate")
|
|
170
178
|
return `"gate" is the kit's Gate; lend a slot of another name`;
|
|
171
|
-
if ((kind === "agents" || kind === "effects" || kind === "machines") && v === "fail")
|
|
179
|
+
if ((kind === "agents" || kind === "effects" || kind === "machines" || kind === "gates") && v === "fail")
|
|
172
180
|
return `"fail" is the kit's Part that fails the run, lent as \`fail: true\`; lend a slot of another name`;
|
|
173
181
|
if (kind === "actions" && (GENERIC_ACTIONS as readonly string[]).includes(v))
|
|
174
182
|
return `"${v}" is a generic action every Chart has; lend an action of another name`;
|
|
@@ -516,7 +524,12 @@ const EMPTY_LENT: LentParts = { actors: {}, guards: {}, actions: {}, delays: {}
|
|
|
516
524
|
/** The lent names of a declaration, by the implementation map each resolves in. */
|
|
517
525
|
function lentNames(decl: OpenBodyDeclaration) {
|
|
518
526
|
return {
|
|
519
|
-
actors: [
|
|
527
|
+
actors: [
|
|
528
|
+
...(decl.lends.agents ?? []),
|
|
529
|
+
...(decl.lends.effects ?? []),
|
|
530
|
+
...(decl.lends.machines ?? []),
|
|
531
|
+
...(decl.lends.gates ?? []),
|
|
532
|
+
],
|
|
520
533
|
guards: [...(decl.lends.guards ?? [])],
|
|
521
534
|
actions: [...(decl.lends.actions ?? [])],
|
|
522
535
|
delays: [...(decl.lends.delays ?? [])],
|
|
@@ -573,9 +586,12 @@ export function admitBodyChart(
|
|
|
573
586
|
text: unknown,
|
|
574
587
|
decl: OpenBodyDeclaration,
|
|
575
588
|
lent: LentParts,
|
|
576
|
-
options: { inputKeys?: readonly string[] } = {},
|
|
589
|
+
options: { inputKeys?: readonly string[]; repoSlots?: readonly string[] } = {},
|
|
577
590
|
): AdmittedChart {
|
|
578
|
-
const admitted = admitChart(text, decl, lent,
|
|
591
|
+
const admitted = admitChart(text, decl, lent, {
|
|
592
|
+
...(options.inputKeys ? { inputKeys: options.inputKeys } : {}),
|
|
593
|
+
...(options.repoSlots ? { repoSlots: options.repoSlots } : {}),
|
|
594
|
+
});
|
|
579
595
|
try {
|
|
580
596
|
compileChart(admitted, lent, decl);
|
|
581
597
|
} catch (err) {
|
|
@@ -627,11 +643,23 @@ export function admitOpenBodyChart(
|
|
|
627
643
|
const logic = (inner.implementations.actors as Record<string, unknown>)[slot];
|
|
628
644
|
if (!isOpenBody(logic)) throw new Error(`machine "${machine.id}" has no Open body "${slot}"`);
|
|
629
645
|
const decl = openBodyDeclarationOf(logic);
|
|
646
|
+
const repoSlots = repoSlotsAround(machine);
|
|
630
647
|
return admitBodyChart(text, decl, lentIn(inner.implementations as Implementations, decl), {
|
|
631
648
|
...(inputKeys ? { inputKeys } : {}),
|
|
649
|
+
...(repoSlots ? { repoSlots } : {}),
|
|
632
650
|
});
|
|
633
651
|
}
|
|
634
652
|
|
|
653
|
+
/** The Repo Slots of the `workspace()` around a Chart wrapper, where the door can see one: the
|
|
654
|
+
* wrapper IS the `workspace()`. Undefined: an Open map, or a Workspace that a parent state invokes,
|
|
655
|
+
* whose slots this door cannot read. Then the Open body's own door reads them off the running
|
|
656
|
+
* Workspace, and a Turn's or an Effect's start refuses what no door could see. */
|
|
657
|
+
export function repoSlotsAround(machine: AnyStateMachine): readonly string[] | undefined {
|
|
658
|
+
if (!composesSandbox(machine)) return undefined;
|
|
659
|
+
const { repos } = sandboxPartsOf(machine);
|
|
660
|
+
return repos === open ? undefined : Object.keys(repos);
|
|
661
|
+
}
|
|
662
|
+
|
|
635
663
|
/**
|
|
636
664
|
* Admit a Chart field of a Chart wrapper's door (ADR-0070), the door a run's start runs before the
|
|
637
665
|
* run exists. The door cannot tell which Open body a field feeds, so the Chart is admitted against
|
|
@@ -648,7 +676,10 @@ export function admitWrapperChart(machine: AnyStateMachine, text: unknown): Admi
|
|
|
648
676
|
for (const { slot, logic } of bodies) {
|
|
649
677
|
const decl = openBodyDeclarationOf(logic);
|
|
650
678
|
try {
|
|
651
|
-
|
|
679
|
+
const repoSlots = repoSlotsAround(machine);
|
|
680
|
+
return admitBodyChart(text, decl, lentIn(inner.implementations as Implementations, decl), {
|
|
681
|
+
...(repoSlots ? { repoSlots } : {}),
|
|
682
|
+
});
|
|
652
683
|
} catch (err) {
|
|
653
684
|
if (!(err instanceof ChartRefusal)) throw err;
|
|
654
685
|
report.push(...err.report.map((line) => (bodies.length > 1 ? `body "${slot}": ${line}` : line)));
|
|
@@ -675,7 +706,7 @@ const scopeOf = (args: Args) => ({
|
|
|
675
706
|
input: chartInputOf((args.context?.[CHART_INPUT_KEY] as Record<string, unknown> | undefined) ?? {}),
|
|
676
707
|
});
|
|
677
708
|
|
|
678
|
-
/** An invoke's error whose message jr2 wrote for a Chart to read: a
|
|
709
|
+
/** An invoke's error whose message jr2 wrote for a Chart to read: a fault in an input the door could not see. */
|
|
679
710
|
class ChartInvokeFault extends Error {}
|
|
680
711
|
|
|
681
712
|
/**
|
|
@@ -839,6 +870,10 @@ function transitionsOf(ts: ChartTransitions): unknown {
|
|
|
839
870
|
return Array.isArray(ts) ? ts.map(transitionOf) : transitionOf(ts);
|
|
840
871
|
}
|
|
841
872
|
|
|
873
|
+
/** `jr2.ready`: is this cut's output `ready`? On an `onDone`. */
|
|
874
|
+
const readyGuard = ({ event }: { event: unknown }): boolean =>
|
|
875
|
+
(event as { output?: { outcome?: unknown } } | undefined)?.output?.outcome === "ready";
|
|
876
|
+
|
|
842
877
|
const mapValues = <T, U>(o: Record<string, T>, fn: (v: T) => U): Record<string, U> =>
|
|
843
878
|
Object.fromEntries(Object.entries(o).map(([k, v]) => [k, fn(v)]));
|
|
844
879
|
|
|
@@ -847,15 +882,17 @@ const mapValues = <T, U>(o: Record<string, T>, fn: (v: T) => U): Record<string,
|
|
|
847
882
|
* resolved object again at invoke time"), or undefined when it is. The door checked the literal
|
|
848
883
|
* parts; a reference may still resolve to a value that is no string.
|
|
849
884
|
*/
|
|
850
|
-
function effectInputFault(
|
|
885
|
+
function effectInputFault(shape: InputShape, value: unknown): string | undefined {
|
|
851
886
|
const given = typeof value === "object" && value !== null && !Array.isArray(value) ? Object.keys(value) : undefined;
|
|
887
|
+
const known = [...shape.required, ...shape.optional, ...(shape.oneOf ?? [])];
|
|
852
888
|
const ok =
|
|
853
889
|
given !== undefined &&
|
|
854
|
-
|
|
855
|
-
|
|
890
|
+
shape.required.every((k) => given.includes(k)) &&
|
|
891
|
+
given.every((k) => known.includes(k) && typeof (value as Record<string, unknown>)[k] === "string") &&
|
|
892
|
+
(shape.oneOf === undefined || shape.oneOf.filter((k) => given.includes(k)).length === 1);
|
|
856
893
|
return ok
|
|
857
894
|
? undefined
|
|
858
|
-
: `its input resolved to ${JSON.stringify(value)}; it takes
|
|
895
|
+
: `its input resolved to ${JSON.stringify(value)}; it takes ${known.join(", ") || "nothing"}, each a string (ADR-0070)`;
|
|
859
896
|
}
|
|
860
897
|
|
|
861
898
|
const checkedEffects = new WeakMap<object, UnknownActorLogic>();
|
|
@@ -867,13 +904,15 @@ const checkedEffects = new WeakMap<object, UnknownActorLogic>();
|
|
|
867
904
|
*/
|
|
868
905
|
function checkedEffect(slot: string, logic: UnknownActorLogic): UnknownActorLogic {
|
|
869
906
|
if (!isEffect(logic)) return logic;
|
|
870
|
-
const
|
|
871
|
-
if (
|
|
907
|
+
const shape = inputShapeOf(logic.effect);
|
|
908
|
+
if (shape === undefined) return logic;
|
|
872
909
|
const hit = checkedEffects.get(logic);
|
|
873
910
|
if (hit) return hit;
|
|
874
911
|
const checked = Object.create(logic) as UnknownActorLogic;
|
|
875
912
|
checked.getInitialSnapshot = (scope, input) => {
|
|
876
|
-
|
|
913
|
+
// An Effect that takes nothing, invoked with no input, is a whole input: the door let it through.
|
|
914
|
+
const fault =
|
|
915
|
+
input === undefined && shape.required.length === 0 && !shape.oneOf ? undefined : effectInputFault(shape, input);
|
|
877
916
|
if (fault === undefined) return logic.getInitialSnapshot(scope, input);
|
|
878
917
|
return {
|
|
879
918
|
status: "error",
|
|
@@ -885,9 +924,38 @@ function checkedEffect(slot: string, logic: UnknownActorLogic): UnknownActorLogi
|
|
|
885
924
|
return checked;
|
|
886
925
|
}
|
|
887
926
|
|
|
888
|
-
|
|
927
|
+
const checkedAgents = new WeakMap<object, UnknownActorLogic>();
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* An Agent as a Chart invokes it: the Agent itself, whose start refuses a resolved `cwd` that is a
|
|
931
|
+
* Repo Slot's folder. A reference hides that value from the door. The check is in `start`, because
|
|
932
|
+
* the Workspace's handles are registered at a start, and a Chart's first invoke resolves before
|
|
933
|
+
* that. The refusal is THAT invoke's error, as in {@link checkedEffect}.
|
|
934
|
+
*/
|
|
935
|
+
function checkedAgent(slot: string, logic: UnknownActorLogic): UnknownActorLogic {
|
|
936
|
+
const hit = checkedAgents.get(logic);
|
|
937
|
+
if (hit) return hit;
|
|
938
|
+
const checked = Object.create(logic) as UnknownActorLogic;
|
|
939
|
+
checked.start = (snapshot, scope) => {
|
|
940
|
+
const cwd = ((snapshot as { input?: unknown }).input as { cwd?: unknown } | undefined)?.cwd;
|
|
941
|
+
const reads = (logic as { definition?: { workspace?: unknown } }).definition?.workspace !== "none";
|
|
942
|
+
const repos = reads && typeof cwd === "string" ? ambientHandlesFor(scope.self)?.repos : undefined;
|
|
943
|
+
const fault = repos ? slotFolderFault(cwd as string, Object.keys(repos)) : undefined;
|
|
944
|
+
if (fault !== undefined) throw new ChartInvokeFault(`the Agent "${slot}": ${fault}`);
|
|
945
|
+
logic.start?.(snapshot, scope);
|
|
946
|
+
};
|
|
947
|
+
checkedAgents.set(logic, checked);
|
|
948
|
+
return checked;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/** The lent actors as a Chart invokes them: each Effect and Agent checked at its start. */
|
|
889
952
|
function chartActors(actors: Record<string, UnknownActorLogic>): Record<string, UnknownActorLogic> {
|
|
890
|
-
return Object.fromEntries(
|
|
953
|
+
return Object.fromEntries(
|
|
954
|
+
Object.entries(actors).map(([slot, logic]) => [
|
|
955
|
+
slot,
|
|
956
|
+
isAgent(logic) ? checkedAgent(slot, logic) : checkedEffect(slot, logic),
|
|
957
|
+
]),
|
|
958
|
+
);
|
|
891
959
|
}
|
|
892
960
|
|
|
893
961
|
/** An Agent Turn's input with `prompt` and `cwd` as strings: a whole placeholder may resolve to
|
|
@@ -918,7 +986,7 @@ function gateInput(value: unknown, self: AnyActorRef): unknown {
|
|
|
918
986
|
return { ...(value as Record<string, unknown>), gate: [...actorPath(self), id].join(".") };
|
|
919
987
|
}
|
|
920
988
|
|
|
921
|
-
function invokeOf(inv: ChartInvoke, agents: ReadonlySet<string>): unknown {
|
|
989
|
+
function invokeOf(inv: ChartInvoke, agents: ReadonlySet<string>, gates: ReadonlySet<string>): unknown {
|
|
922
990
|
const out: Record<string, unknown> = { src: inv.src };
|
|
923
991
|
if (inv.id !== undefined) out.id = inv.id;
|
|
924
992
|
if (inv.input !== undefined) {
|
|
@@ -926,7 +994,7 @@ function invokeOf(inv: ChartInvoke, agents: ReadonlySet<string>): unknown {
|
|
|
926
994
|
// Resolved at invoke time, with `{ context, event, input }` (ADR-0070).
|
|
927
995
|
out.input = agents.has(inv.src)
|
|
928
996
|
? (args: Args) => turnInput(resolveAt(template, args), placementOf(args.context?.[CHART_INPUT_KEY]))
|
|
929
|
-
: inv.src === "gate"
|
|
997
|
+
: inv.src === "gate" || gates.has(inv.src)
|
|
930
998
|
? (args: Args & { self: AnyActorRef }) => gateInput(resolveAt(template, args), args.self)
|
|
931
999
|
: (args: Args) => resolveAt(template, args);
|
|
932
1000
|
}
|
|
@@ -935,14 +1003,16 @@ function invokeOf(inv: ChartInvoke, agents: ReadonlySet<string>): unknown {
|
|
|
935
1003
|
return out;
|
|
936
1004
|
}
|
|
937
1005
|
|
|
938
|
-
function stateOf(st: ChartState, agents: ReadonlySet<string>): Record<string, unknown> {
|
|
1006
|
+
function stateOf(st: ChartState, agents: ReadonlySet<string>, gates: ReadonlySet<string>): Record<string, unknown> {
|
|
939
1007
|
const out: Record<string, unknown> = {};
|
|
940
1008
|
if (st.type !== undefined) out.type = st.type;
|
|
941
1009
|
if (st.initial !== undefined) out.initial = st.initial;
|
|
942
1010
|
if (st.history !== undefined) out.history = st.history;
|
|
943
|
-
if (st.states !== undefined) out.states = mapValues(st.states, (child) => stateOf(child, agents));
|
|
1011
|
+
if (st.states !== undefined) out.states = mapValues(st.states, (child) => stateOf(child, agents, gates));
|
|
944
1012
|
if (st.invoke !== undefined)
|
|
945
|
-
out.invoke = Array.isArray(st.invoke)
|
|
1013
|
+
out.invoke = Array.isArray(st.invoke)
|
|
1014
|
+
? st.invoke.map((inv) => invokeOf(inv, agents, gates))
|
|
1015
|
+
: invokeOf(st.invoke, agents, gates);
|
|
946
1016
|
if (st.on !== undefined) out.on = mapValues(st.on, transitionsOf);
|
|
947
1017
|
if (st.always !== undefined) out.always = transitionsOf(st.always);
|
|
948
1018
|
if (st.after !== undefined) out.after = mapValues(st.after, transitionsOf);
|
|
@@ -964,7 +1034,7 @@ export type CompileOptions = OpenBodyOptions & {
|
|
|
964
1034
|
/**
|
|
965
1035
|
* Build the Machine a Chart describes (ADR-0070), with `jr2Setup` over: the lent actors by their
|
|
966
1036
|
* slot names, `agent(def)` for each Agent the Chart mints, the kit's `gate`, and `fail()` where the
|
|
967
|
-
* body lends it; the lent guards, `jr2.sentBy` and `jr2.
|
|
1037
|
+
* body lends it; the lent guards, `jr2.sentBy`, `jr2.failure` and `jr2.ready`; the lent actions and the four
|
|
968
1038
|
* generic ones; the lent delays. Every reference resolves at invoke time, so the Machine holds the
|
|
969
1039
|
* text's shape and no run's data. The Chart's
|
|
970
1040
|
* input is the context key {@link CHART_INPUT_KEY}; a done Chart outputs `{ outcome: "done",
|
|
@@ -984,7 +1054,7 @@ export function compileChart(
|
|
|
984
1054
|
const mint = options.mintAgent ?? ((_slot: string, definition: AgentDefinition) => agent(definition));
|
|
985
1055
|
const minted = mapValues(admitted.agents, (def) => def);
|
|
986
1056
|
const actors: Record<string, UnknownActorLogic> = chartActors(lent.actors);
|
|
987
|
-
for (const [slot, def] of Object.entries(minted)) actors[slot] = mint(slot, def);
|
|
1057
|
+
for (const [slot, def] of Object.entries(minted)) actors[slot] = checkedAgent(slot, mint(slot, def));
|
|
988
1058
|
// The kit's Part that fails the run, where the body lends it (ADR-0073): no slot of the wrapper's.
|
|
989
1059
|
if (decl.lends.fail === true) actors.fail = fail();
|
|
990
1060
|
// The slots an invoke runs an Agent Turn in: the lent Agents and the Chart's own.
|
|
@@ -992,6 +1062,9 @@ export function compileChart(
|
|
|
992
1062
|
...Object.keys(lent.actors).filter((slot) => isAgent(lent.actors[slot])),
|
|
993
1063
|
...Object.keys(minted),
|
|
994
1064
|
]);
|
|
1065
|
+
// The lent Gate slots (ADR-0011): an authored gate id sits below the body's actor path, as the kit
|
|
1066
|
+
// Gate's does.
|
|
1067
|
+
const gateSlots = new Set(Object.keys(lent.actors).filter((slot) => isGateSlot(lent.actors[slot])));
|
|
995
1068
|
const initialContext = text.context ?? {};
|
|
996
1069
|
const config = {
|
|
997
1070
|
id: text.id ?? options.id ?? "chart",
|
|
@@ -1000,7 +1073,7 @@ export function compileChart(
|
|
|
1000
1073
|
[CHART_INPUT_KEY]: input ?? {},
|
|
1001
1074
|
}),
|
|
1002
1075
|
initial: text.initial,
|
|
1003
|
-
states: mapValues(text.states, (st) => stateOf(st, agentSlots)),
|
|
1076
|
+
states: mapValues(text.states, (st) => stateOf(st, agentSlots, gateSlots)),
|
|
1004
1077
|
output: ({ context, event }: Args) =>
|
|
1005
1078
|
({
|
|
1006
1079
|
outcome: "done",
|
|
@@ -1018,7 +1091,11 @@ export function compileChart(
|
|
|
1018
1091
|
events: admitted.events,
|
|
1019
1092
|
actors,
|
|
1020
1093
|
// `jr2.failure` is in every Chart, as `jr2.sentBy` is: a predicate, with no capability (ADR-0073).
|
|
1021
|
-
guards: {
|
|
1094
|
+
guards: {
|
|
1095
|
+
...(lent.guards as Record<string, unknown>),
|
|
1096
|
+
[FAILURE_GUARD]: failureGuard,
|
|
1097
|
+
[READY_GUARD]: readyGuard,
|
|
1098
|
+
} as never,
|
|
1022
1099
|
actions: { ...(lent.actions as Record<string, unknown>), ...GENERIC } as never,
|
|
1023
1100
|
delays: lent.delays as never,
|
|
1024
1101
|
}).createMachine(config as never) as unknown as AnyStateMachine;
|
|
@@ -1382,7 +1459,10 @@ export function openBodyLogic(decl: OpenBodyDeclaration, options: OpenBodyOption
|
|
|
1382
1459
|
/** Admit and compile a Chart text, and record the Machine the actor runs. Throws ChartRefusal. */
|
|
1383
1460
|
const bind = (self: AnyActorRef, text: unknown, inputKeys: readonly string[]) => {
|
|
1384
1461
|
const lent = liveLentOf(self, logic);
|
|
1385
|
-
|
|
1462
|
+
// A Chart that comes after the Workspace started finds its slots here. A Chart in the step that
|
|
1463
|
+
// starts the Workspace comes before them, and the wrapper's door or the Turn's start saw it.
|
|
1464
|
+
const repos = ambientHandlesFor(self)?.repos;
|
|
1465
|
+
const admitted = admitChart(text, decl, lent, { inputKeys, ...(repos ? { repoSlots: Object.keys(repos) } : {}) });
|
|
1386
1466
|
const src = (self as { src?: unknown }).src;
|
|
1387
1467
|
const machine = compiledFor(admitted, lent, decl, {
|
|
1388
1468
|
...options,
|
package/src/open-effect.ts
CHANGED
|
@@ -28,8 +28,9 @@ import type { Arg, EffectLogic, EffectParts, EffectSnapshot } from "./effect.ts"
|
|
|
28
28
|
import type { Secret, Text } from "./http-effect.ts";
|
|
29
29
|
|
|
30
30
|
/** The parts of an Effect a package may leave Open: an http url, a command's argv, a secret's name,
|
|
31
|
-
* a dispatch's target (its url and token together, ADR-0071)
|
|
32
|
-
|
|
31
|
+
* a dispatch's target (its url and token together, ADR-0071), an `mcp` Effect's server and tool
|
|
32
|
+
* (ADR-0079). */
|
|
33
|
+
export type OpenEffectPart = "url" | "argv" | "secret" | "target" | "server" | "tool";
|
|
33
34
|
|
|
34
35
|
// What a composer binds an Effect's Open parts to, each key one part (ADR-0054); a dispatch's
|
|
35
36
|
// target is its url and token, bound as one (ADR-0071). One object for an
|
|
@@ -39,7 +40,8 @@ export type OpenEffectPart = "url" | "argv" | "secret" | "target";
|
|
|
39
40
|
* The values that bind the Open parts of one Effect. A packaged Machine leaves a part of an Effect
|
|
40
41
|
* Open when it cannot know it. That part is the url of an `http` Effect, the argv of a `command`,
|
|
41
42
|
* the name of a secret, written `secret(open)`, or the target of a `dispatch`: the url of another
|
|
42
|
-
* Orchestrator and the secret that holds its Instance token, bound as one
|
|
43
|
+
* Orchestrator and the secret that holds its Instance token, bound as one, or the server or the tool
|
|
44
|
+
* of an `mcp` Effect. You bind it once, where you register the
|
|
43
45
|
* Machine, with `customize(machine, { effects: { <slot>: binding } })`. Each key binds one Open
|
|
44
46
|
* part. For an Effect with two Open parts, one object holds both keys.
|
|
45
47
|
*
|
|
@@ -101,6 +103,11 @@ export type EffectBinding = {
|
|
|
101
103
|
* `jr2.config.ts`. The Effector reads it from a file of that name. */
|
|
102
104
|
readonly secret?: string;
|
|
103
105
|
readonly target?: { readonly url: string; readonly token: Secret };
|
|
106
|
+
/** The server of an `mcp` Effect whose server is Open: a name of the `mcp` block of
|
|
107
|
+
* `jr2.config.ts`. The server's url and its secret are the config's. */
|
|
108
|
+
readonly server?: string;
|
|
109
|
+
/** The tool of an `mcp.call` Effect whose tool is Open: a tool name of the server. */
|
|
110
|
+
readonly tool?: string;
|
|
104
111
|
};
|
|
105
112
|
|
|
106
113
|
declare const openPart: unique symbol;
|
|
@@ -135,7 +142,11 @@ export function openPartsOf(parts: EffectParts): OpenEffectPart[] {
|
|
|
135
142
|
if (parts.kind === "http" && parts.url === open) out.push("url");
|
|
136
143
|
if (parts.kind === "command" && parts.argv === open) out.push("argv");
|
|
137
144
|
if (parts.kind === "dispatch" && parts.target === open) out.push("target");
|
|
138
|
-
if (parts.kind
|
|
145
|
+
if (parts.kind === "mcp") {
|
|
146
|
+
if (parts.server === open) out.push("server");
|
|
147
|
+
if (parts.tool === open) out.push("tool");
|
|
148
|
+
}
|
|
149
|
+
if (parts.kind !== "push" && parts.kind !== "mcp" && parts.openSecret) out.push("secret");
|
|
139
150
|
return out;
|
|
140
151
|
}
|
|
141
152
|
|
|
@@ -151,6 +162,8 @@ const BINDING_SAMPLE: Record<OpenEffectPart, string> = {
|
|
|
151
162
|
argv: 'argv: ["<program>", "<arg>"]',
|
|
152
163
|
secret: 'secret: "<name>"',
|
|
153
164
|
target: 'target: { url: "https://<host>", token: secret("<name>") }',
|
|
165
|
+
server: 'server: "<name>"',
|
|
166
|
+
tool: 'tool: "<tool>"',
|
|
154
167
|
};
|
|
155
168
|
|
|
156
169
|
/** One binding object for these Open parts — `{ url: "…", secret: "<name>" }` for two. */
|
package/src/open.ts
CHANGED
|
@@ -14,17 +14,30 @@
|
|
|
14
14
|
* - a Repo Slot: `repos: { app: open }`, or the whole map: `repos: open`;
|
|
15
15
|
* - an Agent's model: `agent({ model: open, … })`;
|
|
16
16
|
* - an Effect's url or argv: `http({ url: open, … })`, `command(open)`;
|
|
17
|
-
* - the secret of an Effect's auth, of a header, or of a command's `env`: `secret(open)
|
|
17
|
+
* - the secret of an Effect's auth, of a header, or of a command's `env`: `secret(open)`;
|
|
18
|
+
* - the look of a Gate slot: `gate({ …, look: open })`.
|
|
18
19
|
*
|
|
19
20
|
* `jr2 up` refuses a Workflow with an Open part that nobody bound, and prints the `customize()`
|
|
20
21
|
* line that binds it: ``refusing: workflow "<name>" leaves <part> open — bind it where the Machine
|
|
21
22
|
* is registered: export const machine = customize(<import>, …) (<adr>)``. A run never sees an
|
|
22
|
-
* Open part.
|
|
23
|
+
* Open part. An Open look is the one exception: `jr2 up` warns about it and does not refuse,
|
|
24
|
+
* because a person can still answer the Gate with `jr2 send`.
|
|
23
25
|
*
|
|
24
26
|
* @example
|
|
25
27
|
* ```ts
|
|
26
28
|
* import { z } from "zod";
|
|
27
|
-
* import {
|
|
29
|
+
* import {
|
|
30
|
+
* agent,
|
|
31
|
+
* customize,
|
|
32
|
+
* defineEvent,
|
|
33
|
+
* fail,
|
|
34
|
+
* isReady,
|
|
35
|
+
* jr2Setup,
|
|
36
|
+
* open,
|
|
37
|
+
* workspace,
|
|
38
|
+
* worktree,
|
|
39
|
+
* type Workspaced,
|
|
40
|
+
* } from "@jr2/orchestrator";
|
|
28
41
|
*
|
|
29
42
|
* const finish = defineEvent({
|
|
30
43
|
* name: "finish",
|
|
@@ -32,19 +45,40 @@
|
|
|
32
45
|
* input: z.object({}),
|
|
33
46
|
* });
|
|
34
47
|
*
|
|
48
|
+
* type Input = Workspaced<{}, "app">;
|
|
49
|
+
*
|
|
50
|
+
* const fixTree = (context: Input) => `${context.workspace.repos.app}/fix` as const;
|
|
51
|
+
*
|
|
35
52
|
* const body = jr2Setup({
|
|
53
|
+
* types: {} as { context: Input; input: Input },
|
|
36
54
|
* events: [finish],
|
|
37
|
-
* actors: {
|
|
55
|
+
* actors: {
|
|
56
|
+
* coder: agent({ model: open, instructions: "You fix the failing test." }),
|
|
57
|
+
* cut: worktree(),
|
|
58
|
+
* fail: fail(),
|
|
59
|
+
* },
|
|
38
60
|
* }).createMachine({
|
|
39
61
|
* id: "fix",
|
|
62
|
+
* context: ({ input }) => input,
|
|
40
63
|
* on: { "workspace.lost": ".lost", "agent.fault": ".failed" },
|
|
41
|
-
* initial: "
|
|
64
|
+
* initial: "cutting",
|
|
42
65
|
* states: {
|
|
66
|
+
* cutting: {
|
|
67
|
+
* invoke: {
|
|
68
|
+
* src: "cut",
|
|
69
|
+
* input: ({ context }) => ({ path: fixTree(context), branch: "jr2/fix" }),
|
|
70
|
+
* onDone: [{ guard: ({ event }) => isReady(event.output), target: "coding" }, { target: "notCut" }],
|
|
71
|
+
* },
|
|
72
|
+
* },
|
|
43
73
|
* coding: {
|
|
44
|
-
* invoke: {
|
|
74
|
+
* invoke: {
|
|
75
|
+
* src: "coder",
|
|
76
|
+
* input: ({ context }) => ({ prompt: "Make `node --test` pass.", cwd: fixTree(context) }),
|
|
77
|
+
* },
|
|
45
78
|
* on: { finish: "done" },
|
|
46
79
|
* },
|
|
47
80
|
* done: { type: "final" },
|
|
81
|
+
* notCut: { invoke: { src: "fail", input: { reason: "the Worktree was not cut" } } },
|
|
48
82
|
* failed: { invoke: { src: "fail", input: { reason: "the Agent's Turn could not go on" } } },
|
|
49
83
|
* lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
|
|
50
84
|
* },
|
|
@@ -53,7 +87,6 @@
|
|
|
53
87
|
* // What a package exports: the repository and the model are Open.
|
|
54
88
|
* export const fix = workspace(body, {
|
|
55
89
|
* repos: { app: open },
|
|
56
|
-
* spec: () => ({ branch: "jr2/fix" }),
|
|
57
90
|
* });
|
|
58
91
|
*
|
|
59
92
|
* // What an Instance's `workflows/fix.ts` exports: the same Machine, its Open parts bound.
|