@jr2/orchestrator 0.6.0 → 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 +86 -9
- package/docs/concepts/architecture.md +41 -28
- package/docs/concepts/callers-and-hooks.md +205 -0
- package/docs/concepts/charts.md +7 -5
- package/docs/concepts/composition.md +10 -1
- package/docs/concepts/converge.md +4 -2
- package/docs/concepts/durable-runs.md +43 -16
- package/docs/concepts/effects.md +50 -22
- package/docs/concepts/gates.md +95 -25
- package/docs/concepts/machines-and-workflows.md +5 -4
- package/docs/concepts/pools-and-sources.md +187 -11
- package/docs/concepts/secrets-and-trust.md +73 -33
- package/docs/concepts/the-menu.md +11 -0
- package/docs/concepts/workspaces.md +6 -5
- package/docs/get-started/a-model-decides.md +14 -13
- package/docs/get-started/an-agent-in-a-sandbox.md +43 -34
- package/docs/get-started/connect-a-model.md +1 -1
- package/docs/get-started/create-an-instance.md +17 -14
- package/docs/guides/add-tools-to-the-sandbox.md +55 -11
- 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 +24 -8
- 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/fix-a-failed-converge.md +18 -6
- 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 +9 -6
- package/docs/guides/look-inside-a-sandbox.md +101 -31
- package/docs/guides/open-the-console.md +63 -14
- package/docs/guides/read-a-conversation.md +225 -0
- package/docs/guides/run-a-chart-by-name.md +17 -16
- package/docs/guides/run-one-worker-per-item.md +15 -9
- package/docs/guides/set-an-agents-access-and-dials.md +2 -0
- 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 +1 -1
- package/docs/guides/watch-a-run.md +127 -121
- 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 +17 -7
- package/docs/llms.txt +81 -15
- package/docs/reference/authoring-surface/agent.md +1 -1
- package/docs/reference/authoring-surface/answer.md +1 -1
- package/docs/reference/authoring-surface/arg.md +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/docs/reference/authoring-surface/file.md +1 -1
- 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 +1 -1
- package/docs/reference/authoring-surface/isfailure.md +1 -1
- package/docs/reference/authoring-surface/isready.md +1 -1
- package/docs/reference/authoring-surface/jr2setup.md +13 -3
- package/docs/reference/authoring-surface/mcp.md +107 -0
- package/docs/reference/authoring-surface/open.md +5 -3
- package/docs/reference/authoring-surface/openbody.md +1 -1
- package/docs/reference/authoring-surface/paramsof.md +1 -1
- package/docs/reference/authoring-surface/pool.md +77 -9
- package/docs/reference/authoring-surface/push.md +1 -1
- package/docs/reference/authoring-surface/readyof.md +1 -1
- package/docs/reference/authoring-surface/reread.md +19 -0
- package/docs/reference/authoring-surface/secret.md +1 -1
- 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 +56 -1
- 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 +14 -1
- package/docs/reference/authoring-surface/type-agentmcpserver.md +54 -0
- package/docs/reference/authoring-surface/type-anyframepath.md +1 -1
- package/docs/reference/authoring-surface/type-anyworktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-binding.md +1 -1
- 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-commandoutput.md +1 -1
- package/docs/reference/authoring-surface/type-customize.md +16 -1
- 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 +1 -1
- package/docs/reference/authoring-surface/type-effectbinding.md +12 -2
- package/docs/reference/authoring-surface/type-framepath.md +1 -1
- 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 +1 -1
- package/docs/reference/authoring-surface/type-httpoutput.md +1 -1
- package/docs/reference/authoring-surface/type-jr2config.md +37 -2
- package/docs/reference/authoring-surface/type-lateroutcome.md +1 -1
- 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-openbodydeclaration.md +1 -1
- package/docs/reference/authoring-surface/type-openbodyoutput.md +1 -1
- package/docs/reference/authoring-surface/type-poolnextinput.md +1 -1
- package/docs/reference/authoring-surface/type-poolspec.md +11 -6
- package/docs/reference/authoring-surface/type-pushoutput.md +1 -1
- 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 +1 -1
- 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-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-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 +16 -7
- 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 +1 -1
- package/docs/reference/authoring-surface/type-worktreefound.md +3 -3
- package/docs/reference/authoring-surface/type-worktreeinput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoptions.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeoutput.md +1 -1
- package/docs/reference/authoring-surface/type-worktreepath.md +1 -1
- package/docs/reference/authoring-surface/type-worktreeready.md +1 -1
- package/docs/reference/authoring-surface/type-worktreerefused.md +4 -4
- package/docs/reference/authoring-surface/workspace.md +1 -1
- package/docs/reference/authoring-surface/worktree.md +1 -1
- package/docs/reference/authoring-surface.md +88 -167
- package/docs/reference/cli.md +413 -74
- package/docs/reference/config.md +235 -2
- package/docs/reference/decisions/0002-duplex-streaming-actor.md +71 -11
- package/docs/reference/decisions/0005-sandbox-pod-composition.md +14 -10
- package/docs/reference/decisions/0006-agent-control-surface.md +4 -4
- 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 +9 -2
- package/docs/reference/decisions/0013-the-agent-reaches-its-machine-through-a-container-it-cannot-read.md +20 -14
- 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 +18 -14
- package/docs/reference/decisions/0017-pool-over-a-source-port.md +226 -12
- 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 +32 -18
- package/docs/reference/decisions/0021-workspace-continuity-is-a-lease-that-answers-back.md +14 -1
- 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 +116 -34
- package/docs/reference/decisions/0024-an-agents-turn-ends-with-the-state-that-asked-for-it.md +38 -37
- 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 +7 -6
- package/docs/reference/decisions/0028-what-an-agent-may-do-to-the-workspace-is-part-of-its-definition.md +23 -7
- 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 -18
- 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 +4 -3
- 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 +5 -4
- package/docs/reference/decisions/0049-a-machine-carries-its-parts-and-composes-by-invoke.md +19 -19
- package/docs/reference/decisions/0050-what-code-names-config-declares-what-the-cli-names-discovery-finds.md +6 -1
- 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 +7 -0
- package/docs/reference/decisions/0058-a-harness-answers-the-orchestrator-alone.md +13 -7
- package/docs/reference/decisions/0059-a-harness-holds-stand-ins-and-the-custodian-holds-the-keys.md +38 -30
- package/docs/reference/decisions/0062-jr2-briefs-the-agent-on-its-seat-never-on-its-task.md +64 -17
- package/docs/reference/decisions/0063-the-orchestrator-watches-the-cluster.md +2 -1
- 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 +51 -23
- package/docs/reference/decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md +94 -54
- package/docs/reference/decisions/0068-an-effector-holds-an-effects-secrets-and-signs-its-wire.md +101 -47
- 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 +17 -13
- 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/0075-a-machine-cuts-a-worktree-and-the-workspace-only-clones.md +4 -3
- package/docs/reference/decisions/0076-an-agents-control-credential-lives-only-where-no-workspace-code-runs.md +37 -10
- 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 +6 -4
- package/docs/reference/glossary.md +96 -42
- package/docs/reference/hooks.md +1077 -0
- package/docs/reference/http-api.md +976 -149
- package/docs/why.md +2 -1
- package/package.json +10 -3
- package/src/actor.ts +36 -10
- package/src/agent.ts +50 -0
- package/src/assembly-checks.ts +530 -4
- package/src/callers.ts +245 -0
- package/src/chart.ts +52 -7
- package/src/config.ts +550 -1
- package/src/conversations.ts +453 -0
- package/src/custodian.ts +8 -2
- package/src/customize.ts +143 -4
- package/src/dispatch-effect.ts +142 -26
- package/src/durability.ts +2 -0
- package/src/duration.ts +20 -0
- package/src/effect-checks.ts +2 -1
- package/src/effect.ts +60 -7
- package/src/effector-wire.ts +272 -27
- package/src/gate-brand.ts +16 -0
- package/src/gate.ts +634 -48
- package/src/harness-client.ts +10 -4
- package/src/held-secrets.ts +72 -23
- package/src/holds.ts +2 -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 +76 -38
- package/src/http.ts +889 -94
- package/src/index.ts +16 -5
- package/src/instance.ts +196 -26
- package/src/internal.ts +22 -3
- package/src/machine-doc.ts +26 -1
- package/src/mcp-effect.ts +424 -0
- package/src/mount-digest.ts +41 -7
- package/src/names.ts +64 -2
- package/src/notices.ts +138 -10
- package/src/open-body.ts +25 -11
- package/src/open-effect.ts +17 -4
- package/src/open.ts +4 -2
- package/src/parts.ts +87 -9
- package/src/party.ts +2 -1
- package/src/pick.ts +2 -2
- package/src/pool.ts +1142 -163
- package/src/registration.ts +203 -13
- package/src/run-host.ts +1509 -171
- package/src/run-list.ts +191 -0
- package/src/sandbox-kube.ts +53 -5
- package/src/secret-placement.ts +239 -33
- package/src/server.ts +53 -4
- package/src/setup.ts +72 -32
- package/src/snapshot-store.ts +565 -48
- package/src/steer.ts +111 -0
- package/src/stub-harness.ts +6 -2
- package/src/tokens.ts +263 -22
- package/src/wire.ts +17 -0
- package/src/workspace.ts +50 -6
- package/src/worktree.ts +3 -3
- 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
|
@@ -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,7 +186,7 @@ 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)`.
|