@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
package/src/http-effect.ts
CHANGED
|
@@ -50,6 +50,7 @@ import type {
|
|
|
50
50
|
EffectLogic,
|
|
51
51
|
EffectMarker,
|
|
52
52
|
EffectRow,
|
|
53
|
+
EffectParts,
|
|
53
54
|
EffectSnapshot,
|
|
54
55
|
HttpParts,
|
|
55
56
|
OpenHttpParts,
|
|
@@ -106,9 +107,9 @@ declare const openSecretMark: unique symbol;
|
|
|
106
107
|
*/
|
|
107
108
|
export type OpenSecretMark = { readonly [openSecretMark]: true };
|
|
108
109
|
|
|
109
|
-
/** A
|
|
110
|
-
* secret — a dispatch's target (ADR-0071) — the secret is bound with it, to a name, so the
|
|
111
|
-
* `secret(open)` carries may not be present. One type for the definition and the binding. */
|
|
110
|
+
/** A secret bound to a name, never `secret(open)`. Where a definition's Open part is a whole that
|
|
111
|
+
* holds a secret — a dispatch's target (ADR-0071) — the secret is bound with it, to a name, so the
|
|
112
|
+
* mark `secret(open)` carries may not be present. One type for the definition and the binding. */
|
|
112
113
|
export type NamedSecret = Secret & { readonly [K in keyof OpenSecretMark]?: never };
|
|
113
114
|
|
|
114
115
|
/** `secret(open)`: a secret a packaged Machine names in its auth, a header or a command's env, and
|
|
@@ -1067,8 +1068,58 @@ export function httpWith<S extends z.ZodType | undefined = undefined>(
|
|
|
1067
1068
|
const unbound = openHttpOf(def, (bound) => httpWith(portFactory, bound));
|
|
1068
1069
|
if (unbound) return unbound as EffectLogic<HttpInput<S>, HttpOutput>;
|
|
1069
1070
|
const parts = httpParts(def);
|
|
1070
|
-
|
|
1071
|
-
|
|
1071
|
+
return instanceEffectLogic<HttpInput<S>, HttpOutput>(
|
|
1072
|
+
parts,
|
|
1073
|
+
{
|
|
1074
|
+
kind: "http",
|
|
1075
|
+
idempotent: parts.idempotent,
|
|
1076
|
+
label: `${parts.method} ${hostText(parts)}`,
|
|
1077
|
+
request: (input, slot) => {
|
|
1078
|
+
if (def.input !== undefined) {
|
|
1079
|
+
const parsed = def.input.safeParse(input);
|
|
1080
|
+
if (!parsed.success) {
|
|
1081
|
+
throw new Error(
|
|
1082
|
+
`http "${slot}": its input does not match the definition's input schema — ` +
|
|
1083
|
+
parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; "),
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
input = parsed.data;
|
|
1087
|
+
}
|
|
1088
|
+
const runParts = def.request ? (def.request as (i: unknown) => HttpRequestParts)(input) : {};
|
|
1089
|
+
return startRequestOf(parts, runParts ?? {});
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
portFactory,
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* What the Instance Effector's driver needs of one kind that runs there and has no stop: `http`
|
|
1098
|
+
* and `mcp` (ADR-0068, ADR-0079). The driver is the same for both: the write-ahead intent row, the
|
|
1099
|
+
* restore rule, a forged answer, and D1.
|
|
1100
|
+
*/
|
|
1101
|
+
export type InstanceKind = {
|
|
1102
|
+
readonly kind: "http" | "mcp";
|
|
1103
|
+
/** The author's mark: a restore that finds no replica that holds it sends it again. */
|
|
1104
|
+
readonly idempotent: boolean;
|
|
1105
|
+
/** What the `started` marker says: `POST https://host`, `mcp slack-acme/post_message`. */
|
|
1106
|
+
readonly label: string;
|
|
1107
|
+
/** The run's start, from the invoke's input. It throws on a defect of the Machine, and then
|
|
1108
|
+
* nothing is sent. */
|
|
1109
|
+
readonly request: (input: unknown, slot: string) => StartRequest;
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* The slot logic of an Effect that the Instance Effector runs, over an injected port factory: the
|
|
1114
|
+
* seam `httpWith` and `mcpWith` share.
|
|
1115
|
+
*
|
|
1116
|
+
* @internal
|
|
1117
|
+
*/
|
|
1118
|
+
export function instanceEffectLogic<I, O>(
|
|
1119
|
+
parts: EffectParts,
|
|
1120
|
+
spec: InstanceKind,
|
|
1121
|
+
portFactory: EffectorPortFactory,
|
|
1122
|
+
): EffectLogic<I, O> {
|
|
1072
1123
|
const logic: ActorLogic<EffectSnapshot<O, I>, EventObject, I> = {
|
|
1073
1124
|
getInitialSnapshot: (_scope, input) => ({
|
|
1074
1125
|
status: "active",
|
|
@@ -1086,7 +1137,7 @@ export function httpWith<S extends z.ZodType | undefined = undefined>(
|
|
|
1086
1137
|
return { ...snapshot, status: "error", error: (event as Fault).error, input: undefined };
|
|
1087
1138
|
}
|
|
1088
1139
|
if (event.type === "xstate.stop") {
|
|
1089
|
-
stopped(self, system, snapshot.effectId);
|
|
1140
|
+
stopped(self, system, snapshot.effectId, spec.kind);
|
|
1090
1141
|
return { ...snapshot, status: "stopped", input: undefined };
|
|
1091
1142
|
}
|
|
1092
1143
|
return snapshot;
|
|
@@ -1095,7 +1146,7 @@ export function httpWith<S extends z.ZodType | undefined = undefined>(
|
|
|
1095
1146
|
if (snapshot.status !== "active") return;
|
|
1096
1147
|
const run: Running = { controller: new AbortController() };
|
|
1097
1148
|
running.set(self, run);
|
|
1098
|
-
void drive(self, system, snapshot,
|
|
1149
|
+
void drive(self, system, snapshot, spec, portFactory, run).catch((error: unknown) => {
|
|
1099
1150
|
if (run.controller.signal.aborted) return;
|
|
1100
1151
|
if (self.getSnapshot().status === "active") self.send({ type: "jr2.effect.error", error } as Fault);
|
|
1101
1152
|
});
|
|
@@ -1111,8 +1162,7 @@ async function drive<I, O>(
|
|
|
1111
1162
|
self: AnyActorRef,
|
|
1112
1163
|
system: AnyActorSystem,
|
|
1113
1164
|
snapshot: EffectSnapshot<O, I>,
|
|
1114
|
-
|
|
1115
|
-
def: HttpDefinition<z.ZodType | undefined>,
|
|
1165
|
+
spec: InstanceKind,
|
|
1116
1166
|
portFactory: EffectorPortFactory,
|
|
1117
1167
|
run: Running,
|
|
1118
1168
|
): Promise<void> {
|
|
@@ -1123,11 +1173,11 @@ async function drive<I, O>(
|
|
|
1123
1173
|
const now = (): string => new Date().toISOString();
|
|
1124
1174
|
const mark = (marker: Omit<EffectMarker, "kind" | "slot" | "effect">): void =>
|
|
1125
1175
|
binding?.marker?.({ kind: "effect", slot, effect: id, ...marker });
|
|
1126
|
-
const settle = (output:
|
|
1176
|
+
const settle = (output: NonNullable<EffectMarker["output"]>): void => {
|
|
1127
1177
|
if (signal.aborted || self.getSnapshot().status !== "active") return;
|
|
1128
1178
|
// The settled row first, saved at the write: a restart before the transition is saved delivers
|
|
1129
1179
|
// this output, and sends nothing.
|
|
1130
|
-
binding?.recordEffect?.(id, { state: "settled", kind:
|
|
1180
|
+
binding?.recordEffect?.(id, { state: "settled", kind: spec.kind, slot, output, at: now() });
|
|
1131
1181
|
mark({ stage: "settled", output });
|
|
1132
1182
|
self.send({ type: "jr2.effect.settle", output } satisfies Settle);
|
|
1133
1183
|
};
|
|
@@ -1149,8 +1199,8 @@ async function drive<I, O>(
|
|
|
1149
1199
|
const target = binding?.effector?.("instance");
|
|
1150
1200
|
if (!target) {
|
|
1151
1201
|
throw new Error(
|
|
1152
|
-
|
|
1153
|
-
|
|
1202
|
+
`${spec.kind} "${slot}" runs in the Instance Effector, and this Orchestrator knows none — \`jr2 up\` ` +
|
|
1203
|
+
`converges it when a registered Machine carries an ${spec.kind} Effect (ADR-0068)`,
|
|
1154
1204
|
);
|
|
1155
1205
|
}
|
|
1156
1206
|
const port = portFactory(target);
|
|
@@ -1180,7 +1230,7 @@ async function drive<I, O>(
|
|
|
1180
1230
|
await follow(found);
|
|
1181
1231
|
return;
|
|
1182
1232
|
}
|
|
1183
|
-
if (!
|
|
1233
|
+
if (!spec.idempotent) {
|
|
1184
1234
|
settle(
|
|
1185
1235
|
unknown(
|
|
1186
1236
|
"it was in flight when the Orchestrator restarted, and no Effector replica holds it; not sent again " +
|
|
@@ -1189,7 +1239,7 @@ async function drive<I, O>(
|
|
|
1189
1239
|
);
|
|
1190
1240
|
return;
|
|
1191
1241
|
}
|
|
1192
|
-
mark({ stage: "started", text: `${
|
|
1242
|
+
mark({ stage: "started", text: `${spec.label} (sent again: it is idempotent)` });
|
|
1193
1243
|
await send(requestFor());
|
|
1194
1244
|
return;
|
|
1195
1245
|
}
|
|
@@ -1207,29 +1257,17 @@ async function drive<I, O>(
|
|
|
1207
1257
|
// request leaves.
|
|
1208
1258
|
binding?.recordEffect?.(id, {
|
|
1209
1259
|
state: "intent",
|
|
1210
|
-
kind:
|
|
1260
|
+
kind: spec.kind,
|
|
1211
1261
|
slot,
|
|
1212
1262
|
placement: "instance",
|
|
1213
|
-
idempotent:
|
|
1263
|
+
idempotent: spec.idempotent,
|
|
1214
1264
|
at: now(),
|
|
1215
1265
|
});
|
|
1216
|
-
mark({ stage: "started", text:
|
|
1266
|
+
mark({ stage: "started", text: spec.label });
|
|
1217
1267
|
await send(req);
|
|
1218
1268
|
|
|
1219
1269
|
function requestFor(): StartRequest {
|
|
1220
|
-
|
|
1221
|
-
if (def.input !== undefined) {
|
|
1222
|
-
const parsed = def.input.safeParse(input);
|
|
1223
|
-
if (!parsed.success) {
|
|
1224
|
-
throw new Error(
|
|
1225
|
-
`http "${slot}": its input does not match the definition's input schema — ` +
|
|
1226
|
-
parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; "),
|
|
1227
|
-
);
|
|
1228
|
-
}
|
|
1229
|
-
input = parsed.data;
|
|
1230
|
-
}
|
|
1231
|
-
const runParts = def.request ? (def.request as (i: unknown) => HttpRequestParts)(input) : {};
|
|
1232
|
-
return startRequestOf(parts, runParts ?? {});
|
|
1270
|
+
return spec.request(snapshot.input, slot);
|
|
1233
1271
|
}
|
|
1234
1272
|
|
|
1235
1273
|
/** Send the start, and follow it. A start that never reached a replica is sent again; one whose
|
|
@@ -1256,7 +1294,7 @@ async function drive<I, O>(
|
|
|
1256
1294
|
await follow(found);
|
|
1257
1295
|
return;
|
|
1258
1296
|
}
|
|
1259
|
-
if (!
|
|
1297
|
+
if (!spec.idempotent) {
|
|
1260
1298
|
settle(unknown("its start may have reached the Effector, and no replica holds it now; not sent again"));
|
|
1261
1299
|
return;
|
|
1262
1300
|
}
|
|
@@ -1277,7 +1315,7 @@ async function drive<I, O>(
|
|
|
1277
1315
|
let replica: Replica = first.replica;
|
|
1278
1316
|
for (;;) {
|
|
1279
1317
|
if (state.state === "settled" && state.output) {
|
|
1280
|
-
settle(state.output as
|
|
1318
|
+
settle(state.output as NonNullable<EffectMarker["output"]>);
|
|
1281
1319
|
return;
|
|
1282
1320
|
}
|
|
1283
1321
|
if (state.state === "unknown") {
|
|
@@ -1285,7 +1323,7 @@ async function drive<I, O>(
|
|
|
1285
1323
|
if (!asked || signal.aborted) return;
|
|
1286
1324
|
const { found } = asked;
|
|
1287
1325
|
if (!found) {
|
|
1288
|
-
if (
|
|
1326
|
+
if (spec.idempotent) {
|
|
1289
1327
|
await send(requestFor());
|
|
1290
1328
|
return;
|
|
1291
1329
|
}
|
|
@@ -1316,15 +1354,15 @@ async function drive<I, O>(
|
|
|
1316
1354
|
* unknown": an http Effect has no stop route, so the Effector finishes the call and drops an
|
|
1317
1355
|
* outcome nobody reads. The Machine never hears it.
|
|
1318
1356
|
*/
|
|
1319
|
-
function stopped(self: AnyActorRef, system: AnyActorSystem, effectId: string): void {
|
|
1357
|
+
function stopped(self: AnyActorRef, system: AnyActorSystem, effectId: string, kind: "http" | "mcp"): void {
|
|
1320
1358
|
const run = running.get(self);
|
|
1321
1359
|
running.delete(self);
|
|
1322
1360
|
run?.controller.abort();
|
|
1323
1361
|
const binding = boundRun(system);
|
|
1324
1362
|
if (binding?.hostStopping) return;
|
|
1325
1363
|
const row = binding?.effectRow?.(effectId);
|
|
1326
|
-
if (row?.state !== "intent" || row.kind !==
|
|
1327
|
-
const aborted: EffectRow = { state: "aborted", kind
|
|
1364
|
+
if (row?.state !== "intent" || row.kind !== kind) return;
|
|
1365
|
+
const aborted: EffectRow = { state: "aborted", kind, slot: row.slot, at: new Date().toISOString() };
|
|
1328
1366
|
binding?.recordEffect?.(effectId, aborted, "with-transition");
|
|
1329
1367
|
binding?.marker?.({
|
|
1330
1368
|
kind: "effect",
|
|
@@ -1337,7 +1375,7 @@ function stopped(self: AnyActorRef, system: AnyActorSystem, effectId: string): v
|
|
|
1337
1375
|
|
|
1338
1376
|
/** A start over the bytes the Effector reads is output `refused` (ADR-0068): the Effector could not
|
|
1339
1377
|
* verify it, and a body built from context or a pick's param can reach the bound. */
|
|
1340
|
-
function tooLarge(req: StartRequest):
|
|
1378
|
+
function tooLarge(req: StartRequest): { outcome: "refused"; reason: string } | undefined {
|
|
1341
1379
|
const bytes = Buffer.byteLength(JSON.stringify(req), "utf8");
|
|
1342
1380
|
if (bytes <= MAX_START_BYTES) return undefined;
|
|
1343
1381
|
return {
|