eve 0.54.2 → 0.54.4
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/CHANGELOG.md +22 -0
- package/dist/src/cli/commands/init-agent-workspace.js +1 -1
- package/dist/src/cli/commands/init-project.d.ts +46 -0
- package/dist/src/cli/commands/init-project.js +1 -0
- package/dist/src/cli/commands/init-self-modification.d.ts +7 -0
- package/dist/src/cli/commands/init-self-modification.js +1 -0
- package/dist/src/cli/commands/init-target.js +2 -2
- package/dist/src/cli/commands/init-telemetry.d.ts +6 -0
- package/dist/src/cli/commands/init-telemetry.js +1 -0
- package/dist/src/cli/commands/init.d.ts +3 -0
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +1 -1
- package/dist/src/cli/telemetry/index.d.ts +1 -1
- package/dist/src/compiled/.vendor-stamp.json +8 -6
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +2 -2
- package/dist/src/compiled/@ai-sdk/google/index.js +7 -7
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.js +4 -4
- package/dist/src/compiled/@opentelemetry/api/index.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +26 -0
- package/dist/src/compiled/@workflow/core/flushable-stream.d.ts +41 -0
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/replay-divergence.d.ts +25 -0
- package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +75 -1
- package/dist/src/compiled/@workflow/core/runtime/quickjs-entrypoint.d.ts +30 -8
- package/dist/src/compiled/@workflow/core/runtime/quickjs-log-view.d.ts +129 -0
- package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +2 -21
- package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +0 -22
- package/dist/src/compiled/@workflow/core/runtime.js +3 -3
- package/dist/src/compiled/@workflow/core/serialization.d.ts +2 -2
- package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +36 -0
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/world/analytics.d.ts +23 -23
- package/dist/src/compiled/@workflow/world/events.d.ts +4 -2
- package/dist/src/compiled/@workflow/world/queue.d.ts +84 -0
- package/dist/src/compiled/@workflow/world-local/index.js +5 -5
- package/dist/src/compiled/@workflow/world-vercel/index.js +18 -13
- package/dist/src/compiled/_chunks/workflow/attribute-changes-BAcgmlXp.js +20 -0
- package/dist/src/compiled/_chunks/workflow/coerce-ro2dOxbr.js +1 -0
- package/dist/src/compiled/_chunks/workflow/dist-KPieTJHT.js +25 -0
- package/dist/src/compiled/_chunks/workflow/dist-PLkAQ-U7.js +2 -0
- package/dist/src/compiled/_chunks/workflow/frames-BvATzM2t.js +3 -0
- package/dist/src/compiled/_chunks/workflow/{functions-C02-JHBK.js → functions-wMCGZAVk.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-BEHe0Uut.js +1 -0
- package/dist/src/compiled/_chunks/workflow/run-ChHLjaCt.js +1 -0
- package/dist/src/compiled/_chunks/workflow/schemas-DR7NTzNe.js +50 -0
- package/dist/src/compiled/_chunks/workflow/sleep-BB2HuVie.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{wrapper-BxECO5nh.js → wrapper-CKui_eTd.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/ws-transport-CVezyWwZ.js +1 -0
- package/dist/src/compiled/just-secrets/LICENSE +21 -0
- package/dist/src/compiled/just-secrets/index.d.ts +20 -0
- package/dist/src/compiled/just-secrets/index.js +2 -0
- package/dist/src/compiled/just-secrets/windows.ps1 +138 -0
- package/dist/src/compiler/extension-compatibility.d.ts +12 -12
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/normalize-manifest-helpers.d.ts +2 -1
- package/dist/src/compiler/normalize-manifest-helpers.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/resolve-workspace-subagent.d.ts +13 -0
- package/dist/src/compiler/resolve-workspace-subagent.js +1 -0
- package/dist/src/context/dynamic-model-lifecycle.d.ts +0 -6
- package/dist/src/context/dynamic-model-lifecycle.js +1 -1
- package/dist/src/context/dynamic-resolve-context.js +1 -1
- package/dist/src/context/effective-model.d.ts +5 -0
- package/dist/src/context/effective-model.js +1 -0
- package/dist/src/context/keys.d.ts +2 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/dynamic/definition.d.ts +4 -0
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/types.d.ts +9 -7
- package/dist/src/execution/durable-session-migrations/snapshot.d.ts +0 -16
- package/dist/src/execution/durable-session-migrations/snapshot.js +1 -1
- package/dist/src/execution/eve-workflow-attributes.d.ts +1 -1
- package/dist/src/execution/run-session-limits.js +1 -1
- package/dist/src/execution/session.js +1 -1
- package/dist/src/execution/tools/sleep-workflow.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/compaction.js +1 -1
- package/dist/src/harness/messages.d.ts +1 -1
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/step-hooks.d.ts +16 -10
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/instrumentation/parent-lineage.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/routes/index.d.ts +6 -0
- package/dist/src/internal/nitro/routes/index.js +7 -7
- package/dist/src/internal/vercel/assemble-eve-services.js +1 -1
- package/dist/src/internal/vercel/build-agent-workspace.js +1 -1
- package/dist/src/internal/vercel/build-multi-agent-landing-page.d.ts +3 -0
- package/dist/src/internal/vercel/build-multi-agent-landing-page.js +1 -0
- package/dist/src/internal/vercel/eve-service-contribution.d.ts +4 -0
- package/dist/src/internal/vercel/eve-service-contribution.js +1 -1
- package/dist/src/internal/vercel/vercel-services-config.js +1 -1
- package/dist/src/protocol/baggage.d.ts +6 -0
- package/dist/src/protocol/baggage.js +1 -1
- package/dist/src/protocol/traceparent.d.ts +13 -0
- package/dist/src/protocol/traceparent.js +1 -1
- package/dist/src/public/definitions/workspace-agent.d.ts +25 -0
- package/dist/src/public/definitions/workspace-agent.js +1 -0
- package/dist/src/public/index.d.ts +1 -0
- package/dist/src/public/index.js +1 -1
- package/dist/src/public/models/openai/chatgpt/codex-app-server.d.ts +41 -0
- package/dist/src/public/models/openai/chatgpt/codex-app-server.js +1 -0
- package/dist/src/public/models/openai/chatgpt/credential-store.d.ts +26 -4
- package/dist/src/public/models/openai/chatgpt/credential-store.js +1 -1
- package/dist/src/public/models/openai/chatgpt/oauth.d.ts +6 -4
- package/dist/src/public/models/openai/chatgpt/token-broker.d.ts +7 -7
- package/dist/src/public/models/openai/chatgpt/token-broker.js +1 -1
- package/dist/src/public/models/openai/chatgpt/token.d.ts +13 -0
- package/dist/src/public/models/openai/chatgpt/token.js +1 -0
- package/dist/src/public/models/openai/chatgpt/transport.d.ts +2 -1
- package/dist/src/public/models/openai/index.d.ts +3 -2
- package/dist/src/public/vercel/index.d.ts +50 -0
- package/dist/src/public/vercel/index.js +1 -0
- package/dist/src/self-modification/setup.js +7 -2
- package/dist/src/setup/flows/chatgpt-auth.d.ts +2 -1
- package/dist/src/setup/flows/chatgpt-auth.js +1 -1
- package/dist/src/setup/flows/model.d.ts +0 -2
- package/dist/src/setup/flows/model.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/subagents/remote-dispatch.d.ts +3 -1
- package/dist/src/subagents/remote-dispatch.js +1 -1
- package/dist/src/tracing/agent-otel-attributes.js +1 -1
- package/dist/src/tracing/agent-otel-runtime-context.js +1 -1
- package/docs/agent-config.md +3 -3
- package/docs/guides/deployment/vercel.mdx +52 -1
- package/docs/guides/dynamic-capabilities.md +19 -7
- package/docs/guides/instrumentation-providers.md +1 -1
- package/docs/guides/instrumentation.md +25 -6
- package/docs/guides/remote-agents.md +5 -5
- package/docs/reference/cli.md +2 -2
- package/docs/reference/telemetry.md +1 -1
- package/docs/reference/typescript-api.md +14 -7
- package/docs/subagents/index.mdx +31 -0
- package/package.json +13 -6
- package/dist/src/compiled/_chunks/workflow/attribute-changes-C6H-fRVP.js +0 -20
- package/dist/src/compiled/_chunks/workflow/dist-DDeH-1ER.js +0 -40
- package/dist/src/compiled/_chunks/workflow/dist-DhncQSl7.js +0 -74
- package/dist/src/compiled/_chunks/workflow/frames-DsEqSDes.js +0 -3
- package/dist/src/compiled/_chunks/workflow/resume-hook-BRDLAb67.js +0 -1
- package/dist/src/compiled/_chunks/workflow/run-BM2OFphk.js +0 -1
- package/dist/src/compiled/_chunks/workflow/sleep-6cG0F99-.js +0 -1
- package/dist/src/compiled/_chunks/workflow/ws-transport-DuK82LLz.js +0 -1
|
@@ -76,6 +76,13 @@ export interface EventsConsumerOptions {
|
|
|
76
76
|
*/
|
|
77
77
|
isDeliveryIdle: () => boolean;
|
|
78
78
|
}
|
|
79
|
+
/** See {@link EventsConsumer.describe}. */
|
|
80
|
+
export interface EventsConsumerSnapshot {
|
|
81
|
+
index: number;
|
|
82
|
+
length: number;
|
|
83
|
+
parked: number;
|
|
84
|
+
lastConsumedEventId: string | undefined;
|
|
85
|
+
}
|
|
79
86
|
export declare class EventsConsumer {
|
|
80
87
|
eventIndex: number;
|
|
81
88
|
readonly events: Event[];
|
|
@@ -113,6 +120,13 @@ export declare class EventsConsumer {
|
|
|
113
120
|
private pendingUnconsumedCheck;
|
|
114
121
|
private pendingUnconsumedTimeout;
|
|
115
122
|
private unconsumedCheckVersion;
|
|
123
|
+
/**
|
|
124
|
+
* The event a callback most recently claimed, for {@link describe}. Tracked
|
|
125
|
+
* separately from {@link eventIndex} because the walk also steps over events
|
|
126
|
+
* (parked, sealed no-ops, duplicates) without anyone consuming them, so
|
|
127
|
+
* `events[eventIndex - 1]` does not say what replay last acted on.
|
|
128
|
+
*/
|
|
129
|
+
private lastConsumed;
|
|
116
130
|
constructor(events: Event[], options: EventsConsumerOptions);
|
|
117
131
|
/**
|
|
118
132
|
* The oldest event the walk stepped over that no consumer has claimed yet,
|
|
@@ -137,6 +151,18 @@ export declare class EventsConsumer {
|
|
|
137
151
|
eventId: string;
|
|
138
152
|
eventType: Event['eventType'];
|
|
139
153
|
} | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Where the walk stands, for a divergence message. Everything here is
|
|
156
|
+
* already known to the consumer; the point of the method is that the
|
|
157
|
+
* orchestrator can print it without reaching into private state.
|
|
158
|
+
*
|
|
159
|
+
* `index` is the ordered walk's position (the offset of the event it is
|
|
160
|
+
* stuck on, when it is stuck), `length` the log as this consumer holds it,
|
|
161
|
+
* `parked` how many events the walk stepped over and still holds, and
|
|
162
|
+
* `lastConsumedEventId` the id of the event a callback most recently
|
|
163
|
+
* claimed, `undefined` before the first claim.
|
|
164
|
+
*/
|
|
165
|
+
describe(): EventsConsumerSnapshot;
|
|
140
166
|
append(events: Event[]): void;
|
|
141
167
|
/**
|
|
142
168
|
* Registers a callback function to be called after an event has been consumed
|
|
@@ -82,6 +82,30 @@ export declare const LOCK_POLL_INTERVAL_MS = 10;
|
|
|
82
82
|
export interface FlushableStreamState extends PromiseWithResolvers<void> {
|
|
83
83
|
/** Number of write operations currently in flight to the server */
|
|
84
84
|
pendingOps: number;
|
|
85
|
+
/** Frames emitted by this pipe's producer. */
|
|
86
|
+
producedFrames: number;
|
|
87
|
+
/** Produced frames accepted by this pipe's sink. */
|
|
88
|
+
acceptedFrames: number;
|
|
89
|
+
/** Terminal pipe error, retained for snapshots registered after failure. */
|
|
90
|
+
pipeError?: unknown;
|
|
91
|
+
/**
|
|
92
|
+
* If the user-facing writable is unlocked, enqueue an ordered checkpoint and
|
|
93
|
+
* durably drain every write ahead of it. Returns false while a writer remains
|
|
94
|
+
* locked, so lock-held streams never block step completion.
|
|
95
|
+
*/
|
|
96
|
+
settleReleasedWrites?: () => Promise<boolean>;
|
|
97
|
+
/** Whether release settlement waits for explicit step-end arming. */
|
|
98
|
+
deferReleaseSettlement?: boolean;
|
|
99
|
+
/** Whether step-end processing has armed released-writer settlement. */
|
|
100
|
+
releaseSettlementArmed?: boolean;
|
|
101
|
+
/** Whether the user-facing writable has begun a normal close. */
|
|
102
|
+
userWritableClosing?: boolean;
|
|
103
|
+
/** Step-end snapshot waiters blocked until their target reaches the sink. */
|
|
104
|
+
frameWaiters: Array<{
|
|
105
|
+
target: number;
|
|
106
|
+
resolve: () => void;
|
|
107
|
+
reject: (error: unknown) => void;
|
|
108
|
+
}>;
|
|
85
109
|
/** Whether the `done` promise has been resolved */
|
|
86
110
|
doneResolved: boolean;
|
|
87
111
|
/** Whether the underlying stream has actually closed/errored */
|
|
@@ -99,6 +123,23 @@ export interface FlushableStreamState extends PromiseWithResolvers<void> {
|
|
|
99
123
|
drainBarrier?: DrainBarrier;
|
|
100
124
|
}
|
|
101
125
|
export declare function createFlushableState(): FlushableStreamState;
|
|
126
|
+
/**
|
|
127
|
+
* Capture a step-end producer watermark, wait until the pipe has handed every
|
|
128
|
+
* frame through that watermark to its sink, then await the sink's durability
|
|
129
|
+
* barrier. Unlike {@link FlushableStreamState.promise}, this never waits for a
|
|
130
|
+
* user writer lock to be released.
|
|
131
|
+
*/
|
|
132
|
+
export declare function drainFlushableSnapshot(state: FlushableStreamState): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Mark byte-stream chunks at the producer side of a flushable pipe. Serialized
|
|
135
|
+
* streams should instead use `getSerializeStream`'s synchronous output hook.
|
|
136
|
+
*/
|
|
137
|
+
/**
|
|
138
|
+
* Wrap the user-facing producer boundary of a flushable writable. A completed
|
|
139
|
+
* write through this handle has a sequence number before step-end snapshots,
|
|
140
|
+
* while the original writable remains the input to the serialization pipe.
|
|
141
|
+
*/
|
|
142
|
+
export declare function trackFlushableWritable<T>(writable: WritableStream<T>, state: FlushableStreamState, WritableStreamConstructor?: typeof WritableStream): WritableStream<T>;
|
|
102
143
|
/**
|
|
103
144
|
* Polls a WritableStream to check if the user has released their lock.
|
|
104
145
|
* Resolves the done promise when lock is released and no pending ops remain.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import"../../_chunks/workflow/dist-
|
|
2
|
-
`)}`)}return await
|
|
1
|
+
import"../../_chunks/workflow/dist-PLkAQ-U7.js";import{Ar as e,B as t,Br as n,Cr as r,Hr as i,L as a,O as o,Or as s,Sr as c,Tr as l,Vr as u,_r as d,br as f,cr as p,jr as m,kr as h,nt as g,t as _,tt as v,wr as y}from"../../_chunks/workflow/attribute-changes-BAcgmlXp.js";import{i as b,u as x}from"../../_chunks/workflow/dist-xTushGCp.js";import{n as S}from"../../_chunks/workflow/resume-hook-BEHe0Uut.js";import{t as C}from"../../_chunks/workflow/sleep-BB2HuVie.js";function w(e){u(`createHook()`,`https://workflow-sdk.dev/docs/api-reference/workflow/create-hook`,w)}function T(e){u(`createWebhook()`,`https://workflow-sdk.dev/docs/api-reference/workflow/create-webhook`,T)}function E({schema:e}={}){function t(e){u(`defineHook().create()`,`https://workflow-sdk.dev/docs/api-reference/workflow/define-hook`,t)}return{create:t,async resume(t,n){if(!e?.[`~standard`])return await S(t,n);let r=e[`~standard`].validate(n);if(r instanceof Promise&&(r=await r),r.issues){let e=r.issues.map(e=>{let t=e.path?.map(e=>String(typeof e==`object`&&e?e.key:e)).join(`.`);return t?` at "${t}": ${e.message}`:` ${e.message}`});throw Error(`Hook payload did not match the defined schema:\n${e.join(`
|
|
2
|
+
`)}`)}return await S(t,r.value)}}}async function D(e,t={}){let n=g.getStore(),r=n?.workflowMetadata?.workflowRunId;if(!r)throw new b(`setAttributes() must be called from a 'use workflow' or 'use step' function. Calling it from plain host code is not supported.`);let i=_(e,t);if(i.length!==0){if(n.runReadyBarrier)try{await n.runReadyBarrier}catch{}await(await f()).events.create(r,{eventType:`attr_set`,specVersion:7,eventData:{changes:i,writer:{type:`step`,stepId:n.stepMetadata.stepId,attempt:n.stepMetadata.attempt},...t.allowReservedAttributes===!0?{allowReservedAttributes:!0}:{}}})}}function O(){let e=g.getStore();return e||n(`getStepMetadata()`,`https://workflow-sdk.dev/docs/api-reference/workflow/get-step-metadata`,O),e.stepMetadata}function k(){let e=g.getStore();return e||i(`getWorkflowMetadata()`,`https://workflow-sdk.dev/docs/api-reference/workflow/get-workflow-metadata`,k),e.workflowMetadata}function A(n={}){let u=g.getStore();u||i(`getWritable()`,`https://workflow-sdk.dev/docs/api-reference/workflow/get-writable`,A);let{namespace:f}=n,_=u.workflowMetadata.workflowRunId,b=v(_,f);u.writables??=new Map;let x=u.writables,S=x.get(b);if(S)return S.writable;let C=c();C.deferReleaseSettlement=u.streamStates!==void 0;let w=t(a(globalThis,u.ops,_,u.encryptionKey,!0,u.runReadyBarrier),u.encryptionKey),T=new o(_,b,u.runReadyBarrier);u.streamStates??=[],u.streamStates.push(C),u.ops.push(C.promise),r(w.readable,T,C).catch(()=>{});let E=l(w.writable,C);return y(E,C),Object.defineProperty(E,s,{value:b,writable:!1}),Object.defineProperty(E,m,{value:_,writable:!1}),u.workflowDeploymentId&&Object.defineProperty(E,h,{value:u.workflowDeploymentId,writable:!1}),p(u.encryptionKey)&&Object.defineProperty(E,e,{value:d(u.encryptionKey.keyPair.publicKey),writable:!1}),x.set(b,{writable:E,state:C}),E}export{b as FatalError,x as RetryableError,w as createHook,T as createWebhook,E as defineHook,O as getStepMetadata,k as getWorkflowMetadata,A as getWritable,D as setAttributes,C as sleep};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Event } from '#compiled/@workflow/world/index.js';
|
|
2
|
+
import type { EventsConsumer } from './events-consumer.js';
|
|
3
|
+
import type { QueueItem } from './global.js';
|
|
4
|
+
/**
|
|
5
|
+
* Step, wait, hook and attribute correlation ids share one ULID draw per
|
|
6
|
+
* entity, prefixed by kind (`step_<ulid>`, `wait_<ulid>`, `hook_<ulid>`,
|
|
7
|
+
* `attr_<ulid>`). A replay that drew the same ordinal for a different kind of
|
|
8
|
+
* entity than the one the log recorded there produces an event nobody can
|
|
9
|
+
* consume, and the decisive fact for diagnosing that is which pending
|
|
10
|
+
* invocation currently holds the ordinal. This looks it up by the shared ULID
|
|
11
|
+
* body, so a `wait_created` the log holds at a position where the replay is
|
|
12
|
+
* waiting on `step_<same ulid>` names that step.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findPendingItemAtOrdinal(invocationsQueue: Map<string, QueueItem>, correlationId: string): QueueItem | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The detail appended to a `ReplayDivergenceError` raised because the replay
|
|
17
|
+
* could not place an event. Callers keep their own leading sentence (tests and
|
|
18
|
+
* users match on it) and append this after it.
|
|
19
|
+
*
|
|
20
|
+
* Example:
|
|
21
|
+
* `pending at this id: step drainStep (step_01K…). consumer: index=41,
|
|
22
|
+
* length=44, parked=0, lastConsumed=evnt_01K…`
|
|
23
|
+
*/
|
|
24
|
+
export declare function describeDivergenceContext(event: Event, invocationsQueue: Map<string, QueueItem>, eventsConsumer: EventsConsumer): string;
|
|
25
|
+
//# sourceMappingURL=replay-divergence.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateEventParams, CreateEventRequest, Event, EventResult, HealthCheckPayload, ValidQueueName, WorkflowRun, World } from '#compiled/@workflow/world/index.js';
|
|
1
|
+
import type { CreateEventParams, CreateEventRequest, Event, EventResult, HealthCheckPayload, RunDispatchContext, ValidQueueName, WorkflowRun, World } from '#compiled/@workflow/world/index.js';
|
|
2
2
|
import { type PayloadKey } from '../serialization/encryption.js';
|
|
3
3
|
/**
|
|
4
4
|
* Validates a workflow name and returns the corresponding queue name.
|
|
@@ -329,6 +329,53 @@ export interface SlotSnapshotParams {
|
|
|
329
329
|
* Empty for an empty log, which is the state a `run_created` write is issued
|
|
330
330
|
* from: there is no position held yet to name.
|
|
331
331
|
*
|
|
332
|
+
* ## Who names a position
|
|
333
|
+
*
|
|
334
|
+
* A World can hand events back on a write's success response through two
|
|
335
|
+
* params (`CreateEventParams` in `@workflow/world`): `eventCount`, which is
|
|
336
|
+
* answered with the events on the positions the write skipped over (the
|
|
337
|
+
* skipped-slot report), and `sinceCursor`, which is answered with everything
|
|
338
|
+
* after that cursor (the inline delta). Both exist to save the writer a
|
|
339
|
+
* reload. So the rule for which writes send them is not about the event type;
|
|
340
|
+
* it is about whether **the process that writes holds a loaded log it will
|
|
341
|
+
* keep deciding from**, its own next writes or the replay it resumes. A writer
|
|
342
|
+
* with no log has nothing to merge a page into, and whoever decides next is a
|
|
343
|
+
* fresh replay that loads the log anyway.
|
|
344
|
+
*
|
|
345
|
+
* Three gates, all of which must pass for a page to come back:
|
|
346
|
+
*
|
|
347
|
+
* 1. The writer names a position. Only the replay loop's `createEvent` seam
|
|
348
|
+
* (runtime.ts) and the suspension handler's `createGuarded` do; the QuickJS
|
|
349
|
+
* engine's `createEvent` (quickjs-entrypoint.ts) follows the same rule. Raw
|
|
350
|
+
* `world.events.create` calls send nothing.
|
|
351
|
+
* 2. The World reads a page for that event type. A World may decline for types
|
|
352
|
+
* whose writer never holds a log (step executor writes, run-terminal
|
|
353
|
+
* writes), whatever the client sent.
|
|
354
|
+
* 3. There is something to hand back: the report only when the write landed
|
|
355
|
+
* more than one position above `eventCount`; the delta always.
|
|
356
|
+
*
|
|
357
|
+
* | Event | Writer | Sends | Why |
|
|
358
|
+
* |---|---|---|---|
|
|
359
|
+
* | `run_created` | `start()` | nothing | no log exists yet |
|
|
360
|
+
* | `run_started` | replay loop, first write of a delivery | `eventCount` when a log is loaded; no cursor, the `run_started` preload owns the response fields | the preload already returns the full log |
|
|
361
|
+
* | `step_created`, `wait_created`, `hook_disposed`, `attr_set` | suspension handler (`createGuarded`) | `eventCount` | the handler keeps writing from, and resumes replay from, this log |
|
|
362
|
+
* | `step_created` | queue-consumer re-ensure (raw) | nothing | runs from a queue message, no log |
|
|
363
|
+
* | `hook_created` | suspension handler (node), `dispatchPendingOps` (QuickJS) | `eventCount` + `sinceCursor` (only when the suspension creates exactly one hook) | the delta is how an already-received hook resolves without a re-invocation; two creates against one cursor would give two deltas of which only the first could be taken |
|
|
364
|
+
* | `hook_received` | replay loop lazy resume; handler in-suspension resume | `eventCount` (preload owns the cursor fields) | both replay from the log right after |
|
|
365
|
+
* | `hook_received` | webhook / `resumeHook` (raw) | nothing | out-of-band, enqueues a delivery that loads the log |
|
|
366
|
+
* | `wait_completed` | replay loop timer path | `eventCount` | the loop keeps replaying from the log |
|
|
367
|
+
* | `wait_completed` | `runs.*` out-of-band (raw) | nothing | no log |
|
|
368
|
+
* | `step_started`, `step_retrying` | step executor | nothing | no log; the next decision is a replay that reloads or receives the delta below |
|
|
369
|
+
* | `step_completed`, `step_failed` | step executor | `sinceCursor` only, outside turbo, single inline step | this is where the inline execution loop gets its log back; in turbo or from a queued delivery a fresh replay loads it anyway |
|
|
370
|
+
* | `step_failed` | suspension handler, unserializable input | `eventCount` | the handler holds a log; rare, and follows a `step_created` that drew the page |
|
|
371
|
+
* | `attr_set` | `setAttributes()` API (raw) | nothing | out-of-band |
|
|
372
|
+
* | `run_completed`, `run_failed`, `run_cancelled` | replay loop, replay budget, `runs.cancel` | `eventCount` where the node loop's seam stamps it (the QuickJS engine sends nothing); never `sinceCursor` (`deltaRequestCursor` excludes terminal types) | terminal: nothing replays the log afterwards, so a World reads no page for them |
|
|
373
|
+
*
|
|
374
|
+
* Batched writes (`events.createBatch`) are outside all of this: a batch carries
|
|
375
|
+
* no per-event position and gets no page. The user-facing version of this table
|
|
376
|
+
* is in `docs/content/docs/v5/how-it-works/event-sourcing.mdx`; keep the two in
|
|
377
|
+
* step.
|
|
378
|
+
*
|
|
332
379
|
* The maximum rather than the length, for the reason {@link maxEventSlot}
|
|
333
380
|
* gives: a partially-read log holds fewer events than its highest position, and
|
|
334
381
|
* counting those would make the write claim to have seen less than it has, so
|
|
@@ -360,6 +407,18 @@ export type EventCreator = (data: CreateEventRequest, params?: CreateEventParams
|
|
|
360
407
|
* based on the presence of a `__health` query parameter.
|
|
361
408
|
*/
|
|
362
409
|
export declare function withHealthCheck(handler: (req: Request) => Promise<Response>, worldSpecVersion?: number): (req: Request) => Promise<Response>;
|
|
410
|
+
/**
|
|
411
|
+
* The lineage root of a loaded run: its `$rootRunId` attribute, or its own id
|
|
412
|
+
* when it is itself a root.
|
|
413
|
+
*/
|
|
414
|
+
export declare function rootRunIdFrom(attributes: Record<string, string> | undefined, runId: string): string;
|
|
415
|
+
/**
|
|
416
|
+
* The immutable run identity a step-execution message carries so its consumer
|
|
417
|
+
* can start the step without a blocking `runs.get` — see
|
|
418
|
+
* `RunDispatchContextSchema` in @workflow/world. Built at dispatch time from
|
|
419
|
+
* the run row the producer already holds.
|
|
420
|
+
*/
|
|
421
|
+
export declare function runDispatchContext(run: Pick<WorkflowRun, 'runId' | 'deploymentId' | 'specVersion' | 'startedAt' | 'attributes'>): RunDispatchContext;
|
|
363
422
|
/**
|
|
364
423
|
* Idempotency key for a step's background-dispatch queue message, scoped to
|
|
365
424
|
* the step's IDENTITY, correlation id plus (hashed) step name, rather than
|
|
@@ -386,6 +445,21 @@ export declare function stepDispatchIdempotencyKey(correlationId: string, stepNa
|
|
|
386
445
|
* Queues a message to the specified queue with tracing.
|
|
387
446
|
*/
|
|
388
447
|
export declare function queueMessage(world: World, ...args: Parameters<typeof world.queue>): Promise<void>;
|
|
448
|
+
/**
|
|
449
|
+
* Publishes several messages to one logical queue, using the World's batch
|
|
450
|
+
* send when it has one and falling back to concurrent single sends when it
|
|
451
|
+
* does not.
|
|
452
|
+
*
|
|
453
|
+
* Rejects if ANY message failed to publish, because every caller so far wants
|
|
454
|
+
* all-or-nothing: the recovery is to fail the delivery and let redelivery
|
|
455
|
+
* republish the whole set, deduped by the per-message `idempotencyKey`. That
|
|
456
|
+
* means a partial batch can leave some messages already out — which is
|
|
457
|
+
* exactly why the keys are required rather than advisory.
|
|
458
|
+
*/
|
|
459
|
+
export declare function queueMessages(world: World, queueName: Parameters<typeof world.queue>[0], messages: readonly {
|
|
460
|
+
message: Parameters<typeof world.queue>[1];
|
|
461
|
+
opts?: Parameters<typeof world.queue>[2];
|
|
462
|
+
}[]): Promise<void>;
|
|
389
463
|
/**
|
|
390
464
|
* Calculates the queue overhead time in milliseconds for a given message.
|
|
391
465
|
*/
|
|
@@ -38,14 +38,29 @@ export declare function isFirstInvocation(preloadedEvents: readonly Event[] | un
|
|
|
38
38
|
* This replaces the `node:vm` replay path (runWorkflow + EventsConsumer)
|
|
39
39
|
* with a QuickJS VM invocation that performs the same full event replay.
|
|
40
40
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
41
|
+
* Log position on writes. This engine follows the same rule as the node:vm
|
|
42
|
+
* replay loop for which writes tell the World where the writer stood (see the
|
|
43
|
+
* "Who names a position" table above `slotSnapshotParams` in `helpers.ts`):
|
|
44
|
+
*
|
|
45
|
+
* - Writes made from this invocation's view of the log (`step_created`,
|
|
46
|
+
* `wait_created`, `hook_created`, `hook_disposed`, `attr_set`, the abort
|
|
47
|
+
* `hook_received`, `wait_completed`, and the `step_created` + `step_failed`
|
|
48
|
+
* pair for an unserializable input) carry `eventCount`, and the page a
|
|
49
|
+
* World hands back is queued for the live VM through {@link QuickJSLogView}.
|
|
50
|
+
* - A single inline step's terminal write asks for the inline delta
|
|
51
|
+
* (`sinceCursor`) through `executeStep`, and so does a lone `hook_created`
|
|
52
|
+
* (see `dispatchPendingOps.deltaCursor`); the delta is queued the same
|
|
53
|
+
* way. The step executor's other writes carry nothing: it holds no log.
|
|
54
|
+
* - Run-terminal writes (`run_completed`, `run_failed`) and the terminal drain
|
|
55
|
+
* of pending ops carry nothing: nothing reads the log afterwards.
|
|
56
|
+
*
|
|
57
|
+
* What differs from the node engine is what "merge into the log" means. The
|
|
58
|
+
* node engine merges a returned page into the array it replays from. This
|
|
59
|
+
* engine holds a live VM that consumes events exactly once, in position
|
|
60
|
+
* order, so a returned page is queued and delivered ahead of the next
|
|
61
|
+
* `events.list`, which then only runs when the queue cannot account for the
|
|
62
|
+
* next position. Both engines fall back to a list for anything a page did
|
|
63
|
+
* not carry.
|
|
49
64
|
*/
|
|
50
65
|
export declare function runWorkflowWithQuickJS(params: {
|
|
51
66
|
workflowCode: string;
|
|
@@ -67,6 +82,13 @@ export declare function runWorkflowWithQuickJS(params: {
|
|
|
67
82
|
* hook-resume preload would be discarded and refetched.
|
|
68
83
|
*/
|
|
69
84
|
preloadedEventsComplete?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* The `events.list` cursor positioned after the last of `preloadedEvents`,
|
|
87
|
+
* when the caller has one. Lets this invocation read incrementally from
|
|
88
|
+
* where the preload ended and ask for an inline delta against it. Without
|
|
89
|
+
* it the first read after the preload starts from the top of the log.
|
|
90
|
+
*/
|
|
91
|
+
preloadedCursor?: string | null;
|
|
70
92
|
/**
|
|
71
93
|
* Run input carried through the queue message on first delivery. Used
|
|
72
94
|
* as a last-resort fallback for `run_created.eventData.input` when
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { type Event } from '#compiled/@workflow/world/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The QuickJS engine's bookkeeping for the run's event log, giving that engine
|
|
4
|
+
* the same relationship to a World's write responses that the node:vm replay
|
|
5
|
+
* loop has.
|
|
6
|
+
*
|
|
7
|
+
* The node engine holds the log as an array it replays from, so a page a World
|
|
8
|
+
* hands back on a write (a skipped-slot report against `eventCount`, or an
|
|
9
|
+
* inline delta against `sinceCursor`; see `CreateEventParams` in
|
|
10
|
+
* `@workflow/world`) is merged into that array and the next replay reads it
|
|
11
|
+
* there. The QuickJS engine holds a LIVE VM instead: events are delivered to it
|
|
12
|
+
* incrementally through `continueWithEvents`, in log order, exactly once. So
|
|
13
|
+
* for this engine a returned page is not merged into a log; it is queued to be
|
|
14
|
+
* delivered. This class owns that queue and the three numbers around it:
|
|
15
|
+
*
|
|
16
|
+
* - `knownMaxSlot`, the highest position this invocation has seen anywhere
|
|
17
|
+
* (fed, buffered, or its own write). Reported as `eventCount` on every write
|
|
18
|
+
* this invocation makes from its view of the log, so the World can hand
|
|
19
|
+
* back what landed above it.
|
|
20
|
+
* - `fedMaxSlot`, the highest position delivered to the VM. Delivery is
|
|
21
|
+
* strictly in position order with no gaps, because the VM consumes events
|
|
22
|
+
* as they arrive and a later replay will read the log in position order;
|
|
23
|
+
* feeding position 13 before 12 exists would let the two disagree.
|
|
24
|
+
* - `cursor`, the read position for `events.list`, advanced by list pages and
|
|
25
|
+
* by a complete inline delta.
|
|
26
|
+
*
|
|
27
|
+
* Only PAGES are queued for delivery, never the created event a write returns
|
|
28
|
+
* on its own. A World reads a report or a delta the way it reads a listing,
|
|
29
|
+
* with payload refs resolved, so those events are what a listing would have
|
|
30
|
+
* delivered. The created event on a create response is not: a World may hand
|
|
31
|
+
* it back with its payload still a ref descriptor and telemetry fields
|
|
32
|
+
* stripped (the Vercel World does, for every type whose entity the runtime
|
|
33
|
+
* does not read off the response), and a VM given that copy of a `step_failed`
|
|
34
|
+
* sees a step that failed with no error in it. The created event still counts
|
|
35
|
+
* toward the position the next write names; it is delivered by the page that
|
|
36
|
+
* covers it or by the next listing. `deliverEvent` opts a write in when its
|
|
37
|
+
* event carries nothing a VM reads (`wait_completed`).
|
|
38
|
+
*
|
|
39
|
+
* Positions come from slot-numbered event ids. A log whose ids are not slots
|
|
40
|
+
* (a World on the old id scheme, or a mocked World) turns tracking off for the
|
|
41
|
+
* rest of the invocation: no `eventCount` is sent, nothing is buffered, and the
|
|
42
|
+
* engine reads the log back the way it did before any of this existed.
|
|
43
|
+
*/
|
|
44
|
+
export declare class QuickJSLogView {
|
|
45
|
+
private slotTracking;
|
|
46
|
+
private knownMaxSlot;
|
|
47
|
+
private fedMaxSlot;
|
|
48
|
+
/** Events handed back by a World that the VM has not been given yet. */
|
|
49
|
+
private readonly unfed;
|
|
50
|
+
private cursor;
|
|
51
|
+
constructor(fedEvents: readonly Event[], cursor: string | null);
|
|
52
|
+
/** Read position for the next `events.list`, or `null` for the start. */
|
|
53
|
+
get logCursor(): string | null;
|
|
54
|
+
/** How many events are queued for delivery to the VM. */
|
|
55
|
+
get bufferedCount(): number;
|
|
56
|
+
/** Whether positions are being tracked (see class doc). */
|
|
57
|
+
get tracking(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* The `eventCount` to attach to a write made from this view. Empty while no
|
|
60
|
+
* position is known (an empty log) or once tracking has been turned off.
|
|
61
|
+
*/
|
|
62
|
+
snapshotParams(): {
|
|
63
|
+
eventCount?: number;
|
|
64
|
+
};
|
|
65
|
+
/** A page of `events.list` was read to `cursor`. */
|
|
66
|
+
advanceCursor(cursor: string | null): void;
|
|
67
|
+
/**
|
|
68
|
+
* Events delivered to the VM by the caller (the initial load, or an
|
|
69
|
+
* `events.list` page). Removes them from the delivery queue if a write
|
|
70
|
+
* response had already handed them back.
|
|
71
|
+
*/
|
|
72
|
+
markFed(events: readonly Event[]): void;
|
|
73
|
+
/**
|
|
74
|
+
* Absorb a write's response: note the committed event's position, and
|
|
75
|
+
* queue the skipped-slot report a World attached to it.
|
|
76
|
+
*
|
|
77
|
+
* A truncated page (`hasMore`) is dropped whole, the same policy as
|
|
78
|
+
* `absorbSkippedSlotReport` in the node engine: it covers a span of
|
|
79
|
+
* positions but carries only some of them, and queuing part of a span
|
|
80
|
+
* would have this view claim, on its next write, to have seen positions it
|
|
81
|
+
* never received. The committed event is queued only under `deliverEvent`
|
|
82
|
+
* (see the class doc for why not by default); its position always counts.
|
|
83
|
+
*/
|
|
84
|
+
absorb(result: {
|
|
85
|
+
event?: Event;
|
|
86
|
+
events?: readonly Event[];
|
|
87
|
+
hasMore?: boolean;
|
|
88
|
+
}, options?: {
|
|
89
|
+
deliverEvent?: boolean;
|
|
90
|
+
}): {
|
|
91
|
+
queued: number;
|
|
92
|
+
truncated: boolean;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Absorb the inline delta a step-terminal write returned for
|
|
96
|
+
* `sinceCursor`, and advance the read cursor past it when that is safe.
|
|
97
|
+
*
|
|
98
|
+
* The delta is everything after `sentCursor`, so it may be taken only if
|
|
99
|
+
* the view still stands at that cursor (a list in between would have moved
|
|
100
|
+
* it, and appending a delta computed from an older position could deliver
|
|
101
|
+
* events behind ones already fed). The cursor advances only when the queue
|
|
102
|
+
* then holds every position between what the VM has and the delta's end:
|
|
103
|
+
* with a hole in between, a later `events.list` from the advanced cursor
|
|
104
|
+
* would never return the missing event and the VM would stall on it.
|
|
105
|
+
*
|
|
106
|
+
* @returns whether the cursor was advanced.
|
|
107
|
+
*/
|
|
108
|
+
absorbDelta(sentCursor: string, delta: {
|
|
109
|
+
events: readonly Event[];
|
|
110
|
+
cursor: string | null;
|
|
111
|
+
hasMore: boolean;
|
|
112
|
+
}): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Drain the events that can be delivered to the VM now: the queued run of
|
|
115
|
+
* consecutive positions directly above the highest one already fed. A queued
|
|
116
|
+
* event above a position nothing has filled yet stays queued until a list
|
|
117
|
+
* fills the gap.
|
|
118
|
+
*/
|
|
119
|
+
takeContiguous(): Event[];
|
|
120
|
+
private queueIsDense;
|
|
121
|
+
/** Queue one event for delivery unless the VM already has it. */
|
|
122
|
+
private queue;
|
|
123
|
+
/**
|
|
124
|
+
* The event's position, bumping `knownMaxSlot`. `undefined` once an id
|
|
125
|
+
* turns out not to be a slot, which turns tracking off for good.
|
|
126
|
+
*/
|
|
127
|
+
private slotOf;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=quickjs-log-view.d.ts.map
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Event, SerializedData, StartedStep, World } from '#compiled/@workflow/world/index.js';
|
|
2
2
|
import type { PayloadKey } from '../serialization/encryption.js';
|
|
3
|
-
import { type SlotSnapshotParams } from './helpers.js';
|
|
4
3
|
import { ReplayRecoveryReporter } from './replay-recovery-reporter.js';
|
|
5
4
|
import { type ResumeTtrTracking } from './resume-latency.js';
|
|
6
5
|
import { type StepLatencyTracking } from './step-latency.js';
|
|
7
6
|
export declare const DEFAULT_STEP_MAX_RETRIES = 3;
|
|
7
|
+
export declare const STEP_STREAM_DRAIN_TIMEOUT_MS = 30000;
|
|
8
|
+
export declare function getStepStreamDrainTimeoutMs(): number;
|
|
8
9
|
export interface StepExecutorParams {
|
|
9
10
|
world: World;
|
|
10
11
|
workflowRunId: string;
|
|
@@ -72,26 +73,6 @@ export interface StepExecutorParams {
|
|
|
72
73
|
* handler is the sole inline writer for the run on this iteration.
|
|
73
74
|
*/
|
|
74
75
|
inlineDeltaSinceCursor?: string;
|
|
75
|
-
/**
|
|
76
|
-
* How much of the run's log the caller's replay had loaded when it scheduled
|
|
77
|
-
* this step, as the highest slot that log occupies. Seeds the snapshot every
|
|
78
|
-
* write this executor makes carries; each committed event advances it to its
|
|
79
|
-
* own slot, so a later write never names a position that predates an earlier
|
|
80
|
-
* one from the same step.
|
|
81
|
-
*
|
|
82
|
-
* It matters most on the lazy inline path, where the `step_started` claim is
|
|
83
|
-
* the step's FIRST durable write (its `step_created` is deferred): without a
|
|
84
|
-
* seed the claim would name no position at all, and a replay working from a
|
|
85
|
-
* stale view could claim (and then commit) a step scheduled without
|
|
86
|
-
* observing an event it never loaded.
|
|
87
|
-
*
|
|
88
|
-
* A World that fences rejects a stale claim with `PreconditionFailedError`
|
|
89
|
-
* (412); executeStep does NOT translate that rejection (re-claiming in place
|
|
90
|
-
* would still commit the stale schedule), so it propagates for the caller to
|
|
91
|
-
* abandon the batch and restart its replay. Undefined for a caller with
|
|
92
|
-
* nothing loaded.
|
|
93
|
-
*/
|
|
94
|
-
slotSnapshot?: SlotSnapshotParams;
|
|
95
76
|
/**
|
|
96
77
|
* Suppress optimistic inline start for this step regardless of
|
|
97
78
|
* `WORKFLOW_OPTIMISTIC_INLINE_START` / `forceOptimisticStart`: take the
|
|
@@ -168,28 +168,6 @@ export interface SuspensionHandlerResult {
|
|
|
168
168
|
* path, the exact machinery the lazy claim's crash window already uses.
|
|
169
169
|
*/
|
|
170
170
|
inlineClaims: Map<string, PreclaimedInlineStart>;
|
|
171
|
-
/**
|
|
172
|
-
* The highest slot the batched fan-out committed, when it ran. The batch's
|
|
173
|
-
* own events are not in the caller's loaded log (the next reload picks
|
|
174
|
-
* them up), so the caller folds this ceiling into the slot snapshot it
|
|
175
|
-
* hands the inline executions; otherwise every inline terminal write
|
|
176
|
-
* would name a pre-batch position and be answered with a skipped-slot
|
|
177
|
-
* report echoing the events this suspension just wrote. Under
|
|
178
|
-
* {@link SuspensionHandlerParams.allowDeferredBatchWork} this covers the
|
|
179
|
-
* chunks that had committed by the handler's return (always the pair
|
|
180
|
-
* chunk); a trailing chunk that commits later is echoed back on the
|
|
181
|
-
* terminal writes like any foreign event: reports the executor reads for
|
|
182
|
-
* position and discards.
|
|
183
|
-
*
|
|
184
|
-
* So the echo is only fully suppressed for a SINGLE-chunk fold. On a
|
|
185
|
-
* multi-chunk fan-out the bodies start off the pair chunk while trailing
|
|
186
|
-
* chunks are still in flight, and an inline terminal write issued in that
|
|
187
|
-
* window still names a position below them and still draws a report for
|
|
188
|
-
* their events. Bounded (trailing chunks only, large fan-outs only) and
|
|
189
|
-
* self-correcting on the next reload, and recorded so a report seen there
|
|
190
|
-
* reads as expected rather than as a bug.
|
|
191
|
-
*/
|
|
192
|
-
batchCommittedSlotCeiling?: number;
|
|
193
171
|
/**
|
|
194
172
|
* The batched fan-out's deferred work, present only when the caller opted
|
|
195
173
|
* in via {@link SuspensionHandlerParams.allowDeferredBatchWork} and
|