@baselineos/temporal 1.6.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/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @baselineos/temporal
2
+
3
+ Temporal.io workflow integration for BaselineOS. Provides durable
4
+ workflow execution, activity definitions, and the client/worker pair.
5
+
6
+ Extracted from `baselineos/src/temporal/` in Sprint 4.2a so consumers
7
+ can install Temporal support without pulling the entire BaselineOS
8
+ runtime.
9
+
10
+ ## Usage
11
+
12
+ ```typescript
13
+ import { createTemporalClient, createActivities, BASELINE_TASK_QUEUE } from '@baselineos/temporal';
14
+ ```
15
+
16
+ The `baselineos` package re-exports the same surface for backward
17
+ compatibility — existing consumers don't need to change imports.
18
+
19
+ ## License
20
+
21
+ Apache-2.0
@@ -0,0 +1,189 @@
1
+ import { Task, ExecutionStep, Artifact, VerificationResult, Review } from '@baselineos/protocol-core';
2
+ import * as _temporalio_client from '@temporalio/client';
3
+ import { Client } from '@temporalio/client';
4
+
5
+ /**
6
+ * Minimal type stubs for the host runtime.
7
+ *
8
+ * Carryover #35: temporal can't depend on `baselineos` (cycle), so we
9
+ * define the narrow shape of ExecutionEngine + DecompositionResult that
10
+ * temporal activities actually use. The real implementations live in
11
+ * baselineos/src/core/execution-engine.ts; this file mirrors only the
12
+ * surface the activities call.
13
+ *
14
+ * @license Apache-2.0
15
+ */
16
+
17
+ /** A decomposed task plan returned by ExecutionEngine.decompose(). */
18
+ interface DecompositionResult {
19
+ phases: Array<{
20
+ title: string;
21
+ description: string;
22
+ capabilities: string[];
23
+ }>;
24
+ estimatedComplexity: Task['complexity'];
25
+ rationale: string;
26
+ }
27
+ /** A single compliance violation; mirrors baselineos/src/core/compliance-gate.ts. */
28
+ interface ComplianceViolation {
29
+ principleId: string;
30
+ name: string;
31
+ severity: 'blocking' | 'warning';
32
+ evidence: string;
33
+ line?: number;
34
+ }
35
+ /** Compliance result attached to an ExecutionResult. */
36
+ interface ComplianceResult {
37
+ passed: boolean;
38
+ violations: ComplianceViolation[];
39
+ warnings: ComplianceViolation[];
40
+ score: number;
41
+ }
42
+ /**
43
+ * The shape of an execution-engine `execute()` return. Mirrors the runtime
44
+ * baselineos/src/core/execution-engine.ts definition. Kept local because
45
+ * protocol-core's ExecutionResult is a different concept (lang IR).
46
+ */
47
+ interface ExecutionResult {
48
+ output: string;
49
+ tokensUsed: number;
50
+ duration: number;
51
+ artifacts: Artifact[];
52
+ model: string;
53
+ compliance: ComplianceResult;
54
+ }
55
+ /**
56
+ * Minimal ExecutionEngine surface that temporal activities call.
57
+ *
58
+ * Kept narrow on purpose — the full ExecutionEngine in baselineos has many
59
+ * more methods (selfVerify variants, streaming, cache integration, etc.).
60
+ * Activities only need these four; expand only when a new activity needs
61
+ * something else.
62
+ */
63
+ interface ExecutionEngine {
64
+ execute(task: Task, step?: ExecutionStep): Promise<ExecutionResult>;
65
+ selfVerify(task: Task, output: string): Promise<VerificationResult>;
66
+ conductReview(task: Task, output: string, reviewType: 'supervisor' | 'quality'): Promise<Review>;
67
+ decompose(task: Task): Promise<DecompositionResult>;
68
+ }
69
+
70
+ /**
71
+ * Temporal Activities — SIGNAL-045
72
+ *
73
+ * Activity functions executed by the Temporal worker. Each activity wraps a
74
+ * single operation on the execution engine and is retried independently by
75
+ * Temporal on failure. Activities are the boundary between Temporal's durable
76
+ * orchestration and the existing BaselineOS execution infrastructure.
77
+ *
78
+ * Retry policy (applied by workflow — see workflows.ts):
79
+ * - maximumAttempts: 3
80
+ * - initialInterval: 1s, backoffCoefficient: 2, maximumInterval: 30s
81
+ * - Non-retryable: ApplicationFailure with nonRetryable=true
82
+ *
83
+ * All activities receive their dependencies via context injection through
84
+ * createActivities(). This keeps activities pure functions for testing.
85
+ *
86
+ * @license Apache-2.0
87
+ */
88
+
89
+ interface ActivityDependencies {
90
+ engine: ExecutionEngine;
91
+ }
92
+ interface ExecuteTaskInput {
93
+ task: Task;
94
+ step?: ExecutionStep;
95
+ }
96
+ interface SelfVerifyInput {
97
+ task: Task;
98
+ output: string;
99
+ }
100
+ interface ConductReviewInput {
101
+ task: Task;
102
+ output: string;
103
+ reviewType: 'supervisor' | 'quality';
104
+ }
105
+ interface DecomposeInput {
106
+ task: Task;
107
+ }
108
+ /**
109
+ * Create activity functions bound to the given execution engine.
110
+ * Register the returned object with the Temporal worker:
111
+ * worker.run({ activities: createActivities({ engine }) })
112
+ */
113
+ declare function createActivities(deps: ActivityDependencies): {
114
+ /**
115
+ * Execute a task (or a specific step) using the underlying engine.
116
+ * Returns ExecutionResult on success; throws ApplicationFailure on compliance violations.
117
+ */
118
+ executeTask(input: ExecuteTaskInput): Promise<ExecutionResult>;
119
+ /**
120
+ * Agent self-verifies its output against the task's acceptance criteria.
121
+ */
122
+ selfVerifyTask(input: SelfVerifyInput): Promise<VerificationResult>;
123
+ /**
124
+ * Supervisor or quality review of task output.
125
+ */
126
+ conductTaskReview(input: ConductReviewInput): Promise<Review>;
127
+ /**
128
+ * Decompose a complex task into structured subtasks.
129
+ */
130
+ decomposeTask(input: DecomposeInput): Promise<DecompositionResult>;
131
+ };
132
+ type BaselineActivities = ReturnType<typeof createActivities>;
133
+
134
+ /**
135
+ * Temporal Client Factory — SIGNAL-045
136
+ *
137
+ * Creates a Temporal client configured from environment variables.
138
+ * The client is used by TemporalOrchestrator to submit workflows.
139
+ *
140
+ * Environment variables:
141
+ * TEMPORAL_ADDRESS — Temporal frontend address (default: localhost:7233)
142
+ * TEMPORAL_NAMESPACE — Temporal namespace (default: baseline)
143
+ * TEMPORAL_TLS — 'true' to enable TLS (default: false)
144
+ *
145
+ * @license Apache-2.0
146
+ */
147
+
148
+ interface TemporalClientConfig {
149
+ address?: string;
150
+ namespace?: string;
151
+ tls?: boolean;
152
+ }
153
+ declare const BASELINE_TASK_QUEUE = "baseline-task-queue";
154
+ /**
155
+ * Create and connect a Temporal client.
156
+ * Call client.connection.close() when done.
157
+ */
158
+ declare function createTemporalClient(config?: TemporalClientConfig): Promise<Client>;
159
+
160
+ interface BaselineTaskWorkflowInput {
161
+ task: Task;
162
+ step?: ExecutionStep;
163
+ /** Whether to run supervisor review after self-verify (default: false) */
164
+ runSupervisorReview?: boolean;
165
+ /** Whether to decompose the task before executing (default: false) */
166
+ runDecomposition?: boolean;
167
+ /** Whether to pause for human approval before execution (default: false) */
168
+ requireHumanApproval?: boolean;
169
+ }
170
+ interface WorkflowResult {
171
+ taskId: string;
172
+ output: string;
173
+ tokensUsed: number;
174
+ duration: number;
175
+ model: string;
176
+ verification: VerificationResult;
177
+ review?: Review;
178
+ decomposition?: DecompositionResult;
179
+ phase: WorkflowPhase;
180
+ }
181
+ type WorkflowPhase = 'initialising' | 'awaiting-approval' | 'decomposing' | 'executing' | 'verifying' | 'reviewing' | 'completed' | 'failed';
182
+ declare const humanApprovalSignal: _temporalio_client.SignalDefinition<[{
183
+ approved: boolean;
184
+ reason: string;
185
+ }], string>;
186
+ declare const getStatusQuery: _temporalio_client.QueryDefinition<WorkflowPhase, [], string>;
187
+ declare function baselineTaskWorkflow(input: BaselineTaskWorkflowInput): Promise<WorkflowResult>;
188
+
189
+ export { type ActivityDependencies, BASELINE_TASK_QUEUE, type BaselineActivities, type BaselineTaskWorkflowInput, type TemporalClientConfig, type WorkflowPhase, type WorkflowResult, baselineTaskWorkflow, createActivities, createTemporalClient, getStatusQuery, humanApprovalSignal };
package/dist/index.js ADDED
@@ -0,0 +1,210 @@
1
+ // src/activities.ts
2
+ import { ApplicationFailure } from "@temporalio/activity";
3
+ function createActivities(deps) {
4
+ const { engine } = deps;
5
+ return {
6
+ /**
7
+ * Execute a task (or a specific step) using the underlying engine.
8
+ * Returns ExecutionResult on success; throws ApplicationFailure on compliance violations.
9
+ */
10
+ async executeTask(input) {
11
+ const result = await engine.execute(input.task, input.step);
12
+ if (!result.compliance.passed) {
13
+ const violations = result.compliance.violations.filter((v) => v.severity === "blocking").map((v) => v.name).join(", ");
14
+ throw ApplicationFailure.nonRetryable(
15
+ `Compliance gate failed \u2014 blocking violations: ${violations}`,
16
+ "ComplianceFailure"
17
+ );
18
+ }
19
+ return result;
20
+ },
21
+ /**
22
+ * Agent self-verifies its output against the task's acceptance criteria.
23
+ */
24
+ async selfVerifyTask(input) {
25
+ return engine.selfVerify(input.task, input.output);
26
+ },
27
+ /**
28
+ * Supervisor or quality review of task output.
29
+ */
30
+ async conductTaskReview(input) {
31
+ return engine.conductReview(input.task, input.output, input.reviewType);
32
+ },
33
+ /**
34
+ * Decompose a complex task into structured subtasks.
35
+ */
36
+ async decomposeTask(input) {
37
+ return engine.decompose(input.task);
38
+ }
39
+ };
40
+ }
41
+
42
+ // src/client.ts
43
+ import { Client, Connection } from "@temporalio/client";
44
+ var BASELINE_TASK_QUEUE = "baseline-task-queue";
45
+ async function createTemporalClient(config = {}) {
46
+ const address = config.address ?? process.env.TEMPORAL_ADDRESS ?? "localhost:7233";
47
+ const namespace = config.namespace ?? process.env.TEMPORAL_NAMESPACE ?? "baseline";
48
+ const tls = config.tls ?? process.env.TEMPORAL_TLS === "true";
49
+ const connection = await Connection.connect({
50
+ address,
51
+ tls: tls ? {} : false
52
+ });
53
+ return new Client({ connection, namespace });
54
+ }
55
+
56
+ // src/workflows.ts
57
+ import { proxyActivities, defineSignal, defineQuery, setHandler, condition, sleep, ApplicationFailure as ApplicationFailure2 } from "@temporalio/workflow";
58
+ var humanApprovalSignal = defineSignal("humanApproval");
59
+ var getStatusQuery = defineQuery("getStatus");
60
+ var {
61
+ executeTask,
62
+ selfVerifyTask,
63
+ conductTaskReview,
64
+ decomposeTask
65
+ } = proxyActivities({
66
+ startToCloseTimeout: "5 minutes",
67
+ retry: {
68
+ maximumAttempts: 3,
69
+ initialInterval: "1 second",
70
+ backoffCoefficient: 2,
71
+ maximumInterval: "30 seconds",
72
+ nonRetryableErrorTypes: ["ComplianceFailure"]
73
+ }
74
+ });
75
+ async function baselineTaskWorkflow(input) {
76
+ let phase = "initialising";
77
+ setHandler(getStatusQuery, () => phase);
78
+ if (input.requireHumanApproval) {
79
+ phase = "awaiting-approval";
80
+ let approved = false;
81
+ let approvalReason = "";
82
+ setHandler(humanApprovalSignal, ({ approved: a, reason }) => {
83
+ approved = a;
84
+ approvalReason = reason;
85
+ });
86
+ const signalReceived = await condition(() => approved || approvalReason !== "", "24 hours");
87
+ if (!signalReceived || !approved) {
88
+ throw ApplicationFailure2.nonRetryable(
89
+ `Human approval not received within timeout${approvalReason ? `: ${approvalReason}` : ""}`,
90
+ "ApprovalTimeout"
91
+ );
92
+ }
93
+ }
94
+ let decomposition;
95
+ if (input.runDecomposition) {
96
+ phase = "decomposing";
97
+ decomposition = await decomposeTask({ task: input.task });
98
+ await sleep(100);
99
+ }
100
+ phase = "executing";
101
+ const executionStart = Date.now();
102
+ const execution = await executeTask({
103
+ task: input.task,
104
+ step: input.step
105
+ });
106
+ phase = "verifying";
107
+ const verification = await selfVerifyTask({
108
+ task: input.task,
109
+ output: execution.output
110
+ });
111
+ let review;
112
+ const needsReview = input.runSupervisorReview || !verification.passed;
113
+ if (needsReview) {
114
+ phase = "reviewing";
115
+ review = await conductTaskReview({
116
+ task: input.task,
117
+ output: execution.output,
118
+ reviewType: verification.passed ? "quality" : "supervisor"
119
+ });
120
+ }
121
+ phase = "completed";
122
+ return {
123
+ taskId: input.task.id,
124
+ output: execution.output,
125
+ tokensUsed: execution.tokensUsed,
126
+ duration: Date.now() - executionStart,
127
+ model: execution.model,
128
+ verification,
129
+ review,
130
+ decomposition,
131
+ phase
132
+ };
133
+ }
134
+ export {
135
+ BASELINE_TASK_QUEUE,
136
+ baselineTaskWorkflow,
137
+ createActivities,
138
+ createTemporalClient,
139
+ getStatusQuery,
140
+ humanApprovalSignal
141
+ };
142
+ /**
143
+ * Temporal Activities — SIGNAL-045
144
+ *
145
+ * Activity functions executed by the Temporal worker. Each activity wraps a
146
+ * single operation on the execution engine and is retried independently by
147
+ * Temporal on failure. Activities are the boundary between Temporal's durable
148
+ * orchestration and the existing BaselineOS execution infrastructure.
149
+ *
150
+ * Retry policy (applied by workflow — see workflows.ts):
151
+ * - maximumAttempts: 3
152
+ * - initialInterval: 1s, backoffCoefficient: 2, maximumInterval: 30s
153
+ * - Non-retryable: ApplicationFailure with nonRetryable=true
154
+ *
155
+ * All activities receive their dependencies via context injection through
156
+ * createActivities(). This keeps activities pure functions for testing.
157
+ *
158
+ * @license Apache-2.0
159
+ */
160
+ /**
161
+ * Temporal Client Factory — SIGNAL-045
162
+ *
163
+ * Creates a Temporal client configured from environment variables.
164
+ * The client is used by TemporalOrchestrator to submit workflows.
165
+ *
166
+ * Environment variables:
167
+ * TEMPORAL_ADDRESS — Temporal frontend address (default: localhost:7233)
168
+ * TEMPORAL_NAMESPACE — Temporal namespace (default: baseline)
169
+ * TEMPORAL_TLS — 'true' to enable TLS (default: false)
170
+ *
171
+ * @license Apache-2.0
172
+ */
173
+ /**
174
+ * Temporal Workflows — SIGNAL-045
175
+ *
176
+ * Durable workflow definitions for BaselineOS task execution.
177
+ *
178
+ * Workflows run in Temporal's deterministic sandbox. They orchestrate
179
+ * activity calls and carry the full execution history, enabling:
180
+ * - Automatic retry of failed activities (with backoff)
181
+ * - Pause/resume after process restarts
182
+ * - Full audit trail via Temporal's event history
183
+ * - Human-in-the-loop signals (humanApproval, pause, cancel)
184
+ *
185
+ * Main workflow: baselineTaskWorkflow
186
+ * 1. [Optional] decompose — if task complexity is 'epic' or 'complex'
187
+ * 2. execute — call the LLM via executeTask activity
188
+ * 3. selfVerify — agent verifies its own output
189
+ * 4. [Optional] supervisorReview — for high-priority or failed self-verify
190
+ * 5. Return WorkflowResult
191
+ *
192
+ * Signals:
193
+ * humanApproval(approved: boolean, reason: string) — unblocks paused workflows
194
+ *
195
+ * Queries:
196
+ * getStatus() — returns current workflow phase
197
+ *
198
+ * @license Apache-2.0
199
+ */
200
+ /**
201
+ * @baselineos/temporal — Temporal.io workflow integration for BaselineOS
202
+ *
203
+ * Provides activity definitions, the client wrapper, and the workflow
204
+ * definitions that BaselineOS uses to execute tasks durably on a Temporal
205
+ * cluster. The standalone worker script remains in the baselineos package
206
+ * (it needs a runtime AnthropicEngine instance and would otherwise create
207
+ * a circular runtime dependency).
208
+ *
209
+ * @license Apache-2.0
210
+ */
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@baselineos/temporal",
3
+ "version": "1.6.0",
4
+ "description": "BaselineOS Temporal.io workflow integration — durable workflow execution",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format esm --dts",
17
+ "dev": "tsup src/index.ts --format esm --dts --watch",
18
+ "test": "vitest run",
19
+ "lint": "eslint src/",
20
+ "typecheck": "tsc --noEmit",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "dependencies": {
24
+ "@temporalio/activity": "^1.17.2",
25
+ "@temporalio/client": "^1.17.2",
26
+ "@temporalio/worker": "^1.17.2",
27
+ "@temporalio/workflow": "^1.17.2",
28
+ "@baselineos/protocol-core": "workspace:*"
29
+ },
30
+ "devDependencies": {
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.7.0",
33
+ "vitest": "^2.1.0"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ]
42
+ }