You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8644de0
Browse filesBrowse the repository at this point in the historyBrowse files
feat(mcp): `resume_run` continues a flow run that paused on a screen, behind the same gates as `run_action` (#15705)
7
+
8
+
Clause-②: yes
9
+
10
+
**What changed.**`run_action` on a flow action whose flow stops on a `screen` node answers `status: "paused"` with a `runId` and the `screen` to fill in. Until now nothing on the MCP surface could submit that screen, so the run stayed parked: an agent could start such an action but never finish it. The new MCP tool `resume_run({ runId, values?, confirm? })` submits the screen's field values (keyed by the names in `screen.fields`) and the run continues. It answers with `run_action`'s envelope, `{ ok, action, objectName, recordId?, result }`. A run that pauses on its next screen comes back paused again, so a multi-screen wizard is walked by calling `resume_run` once per screen.
11
+
12
+
**Which runs it continues, and no others.** The runtime's bridge admits a call only where `run_action` would admit starting the same flow on the same record for this caller now:
13
+
14
+
-**Only the caller's own run.** The run's trigger identity must be the caller. Another user's run, an unknown id and a finished run all answer the same `404 RESOURCE_NOT_FOUND`. A resumed run continues under the identity of the user who started it, so only that user may continue it.
15
+
-**`run_action`'s gates, with `run_action`'s helpers.** A `type: 'flow'` action whose `target` is the run's flow, on the run's object, must be AI-exposed (`ai.exposed`), must pass the caller's `requiredPermissions` and must not be switched off (`ACTION_DISABLED`, `409`). An action flagged `ai.requiresConfirmation` needs `confirm: true` on the resume too (`ACTION_CONFIRMATION_REQUIRED`, `428`), because the flow's writes happen after the screen. The exposure and permission refusals answer `403 PERMISSION_DENIED`. So does a run that no flow action targets.
16
+
-**The subject record is read again as the caller.** A record the caller can no longer read is refused `404 RECORD_NOT_FOUND`, which is how `run_action` refuses it.
17
+
-**Screen pauses only.** A run waiting on anything else (a timer `wait`, an approval) is refused `409 RESOURCE_CONFLICT` and left as it is.
18
+
19
+
Every refusal happens before the engine is asked, so the run stays parked. The engine's own answers (a screen submission missing a required field, a concurrent resume, a run that resumed and then failed) reach the caller with the code, status, message and `details` that `POST /api/v1/automation/:name/runs/:runId/resume` gives for the same result. The two doors now share one classification of the engine's answer. It was moved out of the REST route unchanged, and the route's answers are byte-identical.
20
+
21
+
**For hosts.**`McpActionBridge` gains an OPTIONAL member, `resumeRun(runId, { values?, confirm? })`. A bridge that implements it gets `resume_run` beside `run_action`, under the same `actions:execute` OAuth scope, on both the HTTP and the stdio transport. A bridge without it is unchanged and does not list the tool. `run_action`'s description names `resume_run` only where it is registered. `@objectstack/runtime`'s MCP bridge implements the member.
Copy file name to clipboardExpand all lines: .changeset/19580-retire-connector-connection-timeout-ms.md
+35-18Lines changed: 35 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,13 +25,20 @@ The key was bounded (`min(1000).max(300000)`), defaulted (`30000`),
25
25
| removed | what to write instead |
26
26
| --- | --- |
27
27
|`connector.connectionTimeoutMs` (on `Connector` and on `DeclarativeConnectorEntry`, so `stack.connectors[]` and `PUT /meta/connector/:name`) |`requestTimeoutMs` — the deadline the platform keeps, applied as `resilientFetch`'s per-attempt timeout. For a connect-only bound, configure it at a connector provider or upstream gateway on a transport that can separate the phases. |
28
-
|`ConnectorProviderContext.connectionTimeoutMs` (handed to every `ConnectorProviderFactory`) |`ctx.requestTimeoutMs`, or the factory's own `providerConfig` where the provider owns the vocabulary. |
28
+
|`ConnectorProviderContext.connectionTimeoutMs` (handed to every `ConnectorProviderFactory` — added after `@objectstack/spec@17.4.0` and never in a release, see below) |`ctx.requestTimeoutMs`, or the factory's own `providerConfig` where the provider owns the vocabulary. |
29
29
| The `ZodObject` combinators on `ConnectorSchema` and `DeclarativeConnectorEntrySchema` — `.extend()`, `.omit()`, `.pick()`, `.partial()`, `.merge()`, `.strict()`, `.keyof()`, `.safeExtend()`| Both exports are now `z.preprocess`**pipes** (the residue stage below), so those methods no longer exist on them. **Build on the object and re-wrap:**`acceptRetiredDefaultResidue(<your extended object>, { connectionTimeoutMs: 30000 })`, the `EffectiveObjectPermissionSchema` route. ⚠️ `.superRefine()` still *exists* on a pipe but returns a schema with no read-through `shape`, so refine before wrapping, not after. Parsing, `z.input` / `z.infer`, and the read-through `.shape` are unchanged. |
30
30
31
-
**The one-line fix: delete the key** — and, for a custom provider factory, stop
32
-
reading `ctx.connectionTimeoutMs`. `os migrate meta --from 17` lists the
31
+
**The one-line fix: delete the key.**`os migrate meta --from 17` lists the
33
32
mechanical edits for existing sources; apply them by hand.
34
33
34
+
The three interface members withdrawn with it were **never in a release**:
35
+
`ConnectorProviderContext.connectionTimeoutMs`,
36
+
`RestConnectorOptions.connectionTimeoutMs` and
37
+
`OpenApiConnectorConfig.connectionTimeoutMs` all entered with `b929e0a662`,
38
+
after the `@objectstack/*@17.4.0` tag, and leave in this same release. A factory
39
+
or caller built against a released version never saw them; only code written
40
+
against an unreleased `main` in between can read them, and it stops.
41
+
35
42
⚠️ Runtime behaviour is **unchanged for every shipped provider**, because none
36
43
ever applied the value: a connector that authored `connectionTimeoutMs: 1000`
37
44
made exactly the same calls, with exactly the same deadlines, as one that did
@@ -41,7 +48,8 @@ not. What does change is observable and intended: the def served by
41
48
### ⭐ This is NOT the zero-mention retirement shape
42
49
43
50
Measured with `git grep -n connectionTimeoutMs SHA -- . ':!packages/spec'` at
44
-
`origin/main`: **thirteen** non-test source occurrences over seven files in five
51
+
`e07843b5a6`, the tree this retirement landed on: **thirteen** non-test source
0 commit comments