@workflow/core 5.0.0-beta.50 → 5.0.0-beta.51
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/README.md +5 -0
- package/dist/events-consumer.d.ts +26 -0
- package/dist/events-consumer.d.ts.map +1 -1
- package/dist/events-consumer.js +28 -1
- package/dist/flushable-stream.d.ts +41 -0
- package/dist/flushable-stream.d.ts.map +1 -1
- package/dist/flushable-stream.js +169 -1
- package/dist/log-format.js +13 -6
- package/dist/replay-divergence.d.ts +25 -0
- package/dist/replay-divergence.d.ts.map +1 -0
- package/dist/replay-divergence.js +61 -0
- package/dist/runtime/helpers.d.ts +75 -1
- package/dist/runtime/helpers.d.ts.map +1 -1
- package/dist/runtime/helpers.js +129 -2
- package/dist/runtime/quickjs-entrypoint.d.ts +30 -8
- package/dist/runtime/quickjs-entrypoint.d.ts.map +1 -1
- package/dist/runtime/quickjs-entrypoint.js +209 -32
- package/dist/runtime/quickjs-log-view.d.ts +129 -0
- package/dist/runtime/quickjs-log-view.d.ts.map +1 -0
- package/dist/runtime/quickjs-log-view.js +229 -0
- package/dist/runtime/step-executor.d.ts +2 -21
- package/dist/runtime/step-executor.d.ts.map +1 -1
- package/dist/runtime/step-executor.js +85 -80
- package/dist/runtime/suspension-handler.d.ts +0 -22
- package/dist/runtime/suspension-handler.d.ts.map +1 -1
- package/dist/runtime/suspension-handler.js +126 -75
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +262 -91
- package/dist/serialization.d.ts +2 -2
- package/dist/serialization.d.ts.map +1 -1
- package/dist/serialization.js +16 -13
- package/dist/step/context-storage.d.ts +2 -0
- package/dist/step/context-storage.d.ts.map +1 -1
- package/dist/step/context-storage.js +1 -1
- package/dist/step/writable-stream.d.ts.map +1 -1
- package/dist/step/writable-stream.js +14 -10
- package/dist/telemetry/semantic-conventions.d.ts +36 -0
- package/dist/telemetry/semantic-conventions.d.ts.map +1 -1
- package/dist/telemetry/semantic-conventions.js +23 -1
- package/dist/test-support/orchestrator-context.d.ts.map +1 -1
- package/dist/test-support/orchestrator-context.js +8 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +8 -3
- package/docs/foundations/streaming.mdx +1 -1
- package/docs/how-it-works/event-sourcing.mdx +27 -0
- package/package.json +6 -6
|
@@ -419,7 +419,7 @@ export async function aiAssistantWorkflow(userMessage: string) {
|
|
|
419
419
|
"use workflow";
|
|
420
420
|
|
|
421
421
|
const agent = new WorkflowAgent({
|
|
422
|
-
model: "
|
|
422
|
+
model: "spacexai/grok-4.6",
|
|
423
423
|
instructions: "You are a helpful flight assistant.",
|
|
424
424
|
tools: {
|
|
425
425
|
searchFlights: tool({
|
|
@@ -267,6 +267,33 @@ Both kinds of skip are logged at `debug`, so neither reaches the console unless
|
|
|
267
267
|
|
|
268
268
|
The observability UI grays out events it can identify this way and shows the reason on hover. Its set is narrower than the runtime's because it reads the log without consumer state. A consumer for an entity that is still open can legitimately claim a repeat because each step retry writes another `step_started`. The UI marks a repeat only when no consumer can remain for it: after a terminal event for the same entity or at a second `run_started`, of which the log records one per run. The UI marks nothing on a partial log view, such as one page of a paginated list or search results, because identifying the first copy requires the entire log.
|
|
269
269
|
|
|
270
|
+
## Events returned on a write
|
|
271
|
+
|
|
272
|
+
Concurrent invocations of one run write to a shared log, and a write is decided against the log the writer had loaded. When the write lands above other events the writer had not seen, the World can hand those events back on the write's own success response, so the writer merges them and continues rather than discovering the gap on its next read. Two parameters of `events.create()` ask for this:
|
|
273
|
+
|
|
274
|
+
- **`eventCount`** says how many events the writer held. When the write commits at a higher position than `eventCount + 1`, the World returns the events on the positions in between (the *skipped-slot report*).
|
|
275
|
+
- **`sinceCursor`** is the `events.list()` cursor the writer had read to. The World returns everything after it, the write itself included (the *inline delta*), in the same `events` / `cursor` / `hasMore` shape as a list page.
|
|
276
|
+
|
|
277
|
+
Both save a reload, so the rule for which writes send them is not about the event type. It is about whether the process that writes **holds a loaded log it will keep deciding from**: its own next writes, or the replay it resumes after the write. A writer with no log has nothing to merge a page into, and whoever decides next is a fresh replay that loads the log anyway. Three things must hold for a page to come back: the writer named a position, the World reads a page for that event type (a backend may decline for types whose writer never holds a log), and there is something to return (the report only when positions were skipped; the delta always).
|
|
278
|
+
|
|
279
|
+
| Event | Writer | Sends | Why |
|
|
280
|
+
|-------|--------|-------|-----|
|
|
281
|
+
| `run_created` | `start()` | Nothing | No log exists yet. |
|
|
282
|
+
| `run_started` | Replay, first write of a delivery | `eventCount` when a log is loaded; no cursor | The `run_started` response already carries the full log as a preload. |
|
|
283
|
+
| `step_created`, `wait_created`, `hook_disposed`, `attr_set` | Suspension handler | `eventCount` | The handler keeps writing from this log and the replay resumes from it. |
|
|
284
|
+
| `hook_created` | Suspension handler | `eventCount` and `sinceCursor` (only when the suspension creates exactly one hook) | The delta is how a hook whose payload already arrived resolves without another invocation. Two creates diffing against one cursor would give two deltas of which only the first could be taken. |
|
|
285
|
+
| `hook_received` | Replay resuming a hook | `eventCount` | The replay continues from the log right after. |
|
|
286
|
+
| `hook_received` | Webhook or `resumeHook()` | Nothing | Out-of-band. It enqueues a delivery that loads the log. |
|
|
287
|
+
| `wait_completed` | Replay completing an elapsed wait | `eventCount` | The replay continues from the log right after. |
|
|
288
|
+
| `step_started`, `step_retrying` | Step executor | Nothing | The executor holds no log. The next decision is a replay that reloads, or receives the delta on the step's terminal write. |
|
|
289
|
+
| `step_completed`, `step_failed` | Step executor | `sinceCursor` when a single step runs inline; nothing from a queued delivery | Inline, this is where the invocation gets its log back without a list. From a queue, a fresh replay loads the log anyway. |
|
|
290
|
+
| `attr_set` | `setAttributes()` outside a workflow | Nothing | Out-of-band. |
|
|
291
|
+
| `run_completed`, `run_failed`, `run_cancelled` | Replay, or `cancel()` | Never `sinceCursor` | Terminal. Nothing replays the log afterwards, so a page would be read by no one. |
|
|
292
|
+
|
|
293
|
+
Batched writes (`events.createBatch()`) carry no position and get no page. Both runtime engines follow this table: the `node:vm` engine merges a returned page into the log it replays from, and the QuickJS engine queues it for delivery to its live VM, in position order, ahead of its next `events.list()`.
|
|
294
|
+
|
|
295
|
+
A World that supports this returns the page in `events`, `cursor`, and `hasMore` on the `EventResult`. A World that does not simply returns the created event, and the runtime lists. See [Building a World](/worlds/building-a-world#event-id-allocation) for the World-side contract.
|
|
296
|
+
|
|
270
297
|
## Sealed positions (noop events)
|
|
271
298
|
|
|
272
299
|
Runs at `specVersion` 7 and above use a *sealed log*. The backend gives each write its position from a per-run sequencer **before** the write commits, so concurrent writers hold distinct positions and never race for a slot. New runs use this behavior by default. [`WORKFLOW_SEALED_LOG=0`](/docs/configuration/runtime-tuning#workflow_sealed_log) returns a deployment to the previous scheme. Every runtime reads a sealed log regardless, and a run's version is fixed at creation, so changing the setting never affects an in-flight run. However, a writer can claim a position and then stop because of a crashed process or canceled transaction. This leaves a hole that no writer will fill, and a hole looks like an event the reader failed to load.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workflow/core",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.51",
|
|
4
4
|
"description": "Core runtime and engine for Workflow SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -88,18 +88,18 @@
|
|
|
88
88
|
"@workflow/errors": "5.0.0-beta.21",
|
|
89
89
|
"@workflow/serde": "5.0.0-beta.2",
|
|
90
90
|
"@workflow/utils": "5.0.0-beta.10",
|
|
91
|
-
"@workflow/world": "5.0.0-beta.
|
|
92
|
-
"@workflow/world-local": "5.0.0-beta.
|
|
93
|
-
"@workflow/world-vercel": "5.0.0-beta.
|
|
91
|
+
"@workflow/world": "5.0.0-beta.35",
|
|
92
|
+
"@workflow/world-local": "5.0.0-beta.44",
|
|
93
|
+
"@workflow/world-vercel": "5.0.0-beta.46",
|
|
94
94
|
"debug": "4.4.3",
|
|
95
|
-
"devalue": "5.9.
|
|
95
|
+
"devalue": "5.9.2",
|
|
96
96
|
"ms": "2.1.3",
|
|
97
97
|
"nanoid": "5.1.6",
|
|
98
98
|
"quickjs-wasi": "3.4.0",
|
|
99
99
|
"seedrandom": "3.0.5",
|
|
100
100
|
"semver": "7.7.4",
|
|
101
101
|
"ulid": "~3.0.1",
|
|
102
|
-
"zod": "~4.
|
|
102
|
+
"zod": "~4.5.4"
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
105
|
"@opentelemetry/api": "1.9.0",
|