@sw4rm/js-sdk 0.3.0 → 0.4.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.
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Workflow client for SW4RM.
3
+ *
4
+ * This module provides the WorkflowClient for managing DAG-based workflow
5
+ * orchestration. Workflows enable:
6
+ * - Multi-step task coordination
7
+ * - Dependency-based execution ordering
8
+ * - Node-level state tracking
9
+ * - Context passing between nodes
10
+ *
11
+ * Based on workflow.proto definitions.
12
+ */
13
+ /**
14
+ * Status of a workflow node.
15
+ */
16
+ export declare enum NodeStatus {
17
+ NODE_STATUS_UNSPECIFIED = 0,
18
+ /** Node waiting for dependencies */
19
+ PENDING = 1,
20
+ /** Node ready to execute */
21
+ READY = 2,
22
+ /** Node currently executing */
23
+ RUNNING = 3,
24
+ /** Node finished successfully */
25
+ COMPLETED = 4,
26
+ /** Node encountered an error */
27
+ FAILED = 5,
28
+ /** Node skipped due to conditional logic */
29
+ SKIPPED = 6
30
+ }
31
+ /**
32
+ * Type of trigger for a workflow node.
33
+ */
34
+ export declare enum TriggerType {
35
+ TRIGGER_TYPE_UNSPECIFIED = 0,
36
+ /** Triggered by specific events */
37
+ EVENT = 1,
38
+ /** Triggered on a schedule (cron-like) */
39
+ SCHEDULE = 2,
40
+ /** Triggered by explicit user action */
41
+ MANUAL = 3,
42
+ /** Triggered by dependency completion */
43
+ DEPENDENCY = 4
44
+ }
45
+ /**
46
+ * Status of a workflow instance.
47
+ */
48
+ export declare enum WorkflowStatus {
49
+ WORKFLOW_STATUS_UNSPECIFIED = 0,
50
+ /** Workflow has been created but not started */
51
+ CREATED = 1,
52
+ /** Workflow is currently running */
53
+ RUNNING = 2,
54
+ /** Workflow completed successfully */
55
+ COMPLETED = 3,
56
+ /** Workflow failed with error */
57
+ FAILED = 4,
58
+ /** Workflow was cancelled */
59
+ CANCELLED = 5,
60
+ /** Workflow is paused */
61
+ PAUSED = 6
62
+ }
63
+ /**
64
+ * A node in a workflow definition.
65
+ *
66
+ * Represents a single step in the workflow DAG with its dependencies,
67
+ * trigger conditions, and input/output mappings.
68
+ */
69
+ export interface WorkflowNode {
70
+ /** Unique identifier for this node */
71
+ nodeId: string;
72
+ /** Identifier of the agent executing this node */
73
+ agentId: string;
74
+ /** Set of node_ids that must complete before this node runs */
75
+ dependencies: string[];
76
+ /** How this node is triggered */
77
+ triggerType: TriggerType;
78
+ /** Maps workflow state keys to node input parameters */
79
+ inputMapping: Record<string, string>;
80
+ /** Maps node output keys to workflow state keys */
81
+ outputMapping: Record<string, string>;
82
+ /** Additional node configuration and context */
83
+ metadata: Record<string, string>;
84
+ }
85
+ /**
86
+ * A workflow definition.
87
+ *
88
+ * Describes a complete workflow as a DAG of nodes with their
89
+ * dependencies and configuration.
90
+ */
91
+ export interface WorkflowDefinition {
92
+ /** Unique identifier for this workflow */
93
+ workflowId: string;
94
+ /** Map of node_id to WorkflowNode */
95
+ nodes: Record<string, WorkflowNode>;
96
+ /** When the workflow was created (ISO-8601 string) */
97
+ createdAt?: string;
98
+ /** Additional workflow-level configuration */
99
+ metadata: Record<string, string>;
100
+ }
101
+ /**
102
+ * State of a single node during execution.
103
+ */
104
+ export interface NodeState {
105
+ /** The node this state belongs to */
106
+ nodeId: string;
107
+ /** Current execution status */
108
+ status: NodeStatus;
109
+ /** When node execution started (ISO-8601 string) */
110
+ startedAt?: string;
111
+ /** When node execution completed (ISO-8601 string) */
112
+ completedAt?: string;
113
+ /** Output data from node execution (JSON string) */
114
+ output?: string;
115
+ /** Error information if node failed */
116
+ error?: string;
117
+ }
118
+ /**
119
+ * A running instance of a workflow.
120
+ *
121
+ * Tracks the execution state of all nodes and the shared workflow data.
122
+ */
123
+ export interface WorkflowInstance {
124
+ /** Identifier of this workflow instance */
125
+ instanceId: string;
126
+ /** Identifier of the workflow definition */
127
+ workflowId: string;
128
+ /** Current status of the workflow */
129
+ status: WorkflowStatus;
130
+ /** Map of node_id to NodeState for tracking execution */
131
+ nodeStates: Record<string, NodeState>;
132
+ /** Shared workflow data (JSON string) */
133
+ workflowData: string;
134
+ /** When the workflow execution started (ISO-8601 string) */
135
+ startedAt?: string;
136
+ /** When the workflow execution completed (ISO-8601 string) */
137
+ completedAt?: string;
138
+ /** Additional runtime metadata */
139
+ metadata: Record<string, string>;
140
+ }
141
+ /**
142
+ * Error thrown when a workflow operation fails validation.
143
+ */
144
+ export declare class WorkflowValidationError extends Error {
145
+ constructor(message: string);
146
+ }
147
+ /**
148
+ * Error thrown when a workflow contains a cycle.
149
+ */
150
+ export declare class WorkflowCycleError extends Error {
151
+ constructor(message: string);
152
+ }
153
+ /**
154
+ * Client for managing workflow orchestration.
155
+ *
156
+ * Enables creation and execution of DAG-based workflows that coordinate
157
+ * multiple agents. This is an in-memory implementation for Phase 2;
158
+ * future phases will integrate with gRPC services.
159
+ */
160
+ export declare class WorkflowClient {
161
+ private definitions;
162
+ private instances;
163
+ private instancesByWorkflow;
164
+ /**
165
+ * Create a new workflow from a definition.
166
+ *
167
+ * Validates the workflow definition and stores it for later execution.
168
+ *
169
+ * @param definition - The workflow definition to create
170
+ * @returns The workflow_id of the created workflow
171
+ * @throws WorkflowValidationError if the definition is invalid
172
+ * @throws WorkflowCycleError if the workflow contains a cycle
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const client = new WorkflowClient();
177
+ * const definition: WorkflowDefinition = {
178
+ * workflowId: "review-workflow",
179
+ * nodes: {
180
+ * "produce": {
181
+ * nodeId: "produce",
182
+ * agentId: "producer-agent",
183
+ * dependencies: [],
184
+ * triggerType: TriggerType.MANUAL,
185
+ * inputMapping: {},
186
+ * outputMapping: { "artifact": "produced_artifact" },
187
+ * metadata: {}
188
+ * },
189
+ * "review": {
190
+ * nodeId: "review",
191
+ * agentId: "critic-agent",
192
+ * dependencies: ["produce"],
193
+ * triggerType: TriggerType.DEPENDENCY,
194
+ * inputMapping: { "artifact": "produced_artifact" },
195
+ * outputMapping: { "result": "review_result" },
196
+ * metadata: {}
197
+ * }
198
+ * },
199
+ * metadata: {}
200
+ * };
201
+ * const workflowId = await client.createWorkflow(definition);
202
+ * ```
203
+ */
204
+ createWorkflow(definition: WorkflowDefinition): Promise<string>;
205
+ /**
206
+ * Start a new instance of a workflow.
207
+ *
208
+ * Creates a new workflow instance and initializes all nodes to their
209
+ * starting states based on dependencies.
210
+ *
211
+ * @param workflowId - The ID of the workflow to start
212
+ * @param initialData - Optional initial workflow data (JSON string)
213
+ * @param metadata - Optional runtime metadata
214
+ * @returns The created workflow instance
215
+ * @throws WorkflowValidationError if the workflow does not exist
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * const instance = await client.startWorkflow("review-workflow");
220
+ * console.log(instance.status); // WorkflowStatus.RUNNING
221
+ * ```
222
+ */
223
+ startWorkflow(workflowId: string, initialData?: string, metadata?: Record<string, string>): Promise<WorkflowInstance>;
224
+ /**
225
+ * Get the current status of a workflow instance.
226
+ *
227
+ * @param instanceId - The ID of the workflow instance
228
+ * @returns The workflow instance with current state
229
+ * @throws WorkflowValidationError if the instance does not exist
230
+ *
231
+ * @example
232
+ * ```typescript
233
+ * const instance = await client.getWorkflowStatus("wf-123-abc");
234
+ * console.log(instance.status);
235
+ * for (const [nodeId, state] of Object.entries(instance.nodeStates)) {
236
+ * console.log(`${nodeId}: ${NodeStatus[state.status]}`);
237
+ * }
238
+ * ```
239
+ */
240
+ getWorkflowStatus(instanceId: string): Promise<WorkflowInstance>;
241
+ /**
242
+ * Cancel a running workflow instance.
243
+ *
244
+ * Marks the workflow as cancelled and stops any pending nodes.
245
+ *
246
+ * @param instanceId - The ID of the workflow instance to cancel
247
+ * @throws WorkflowValidationError if the instance does not exist
248
+ * @throws WorkflowValidationError if the workflow is not in a cancellable state
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * await client.cancelWorkflow("wf-123-abc");
253
+ * const instance = await client.getWorkflowStatus("wf-123-abc");
254
+ * console.log(instance.status); // WorkflowStatus.CANCELLED
255
+ * ```
256
+ */
257
+ cancelWorkflow(instanceId: string): Promise<void>;
258
+ /**
259
+ * Get the workflow definition.
260
+ *
261
+ * @param workflowId - The ID of the workflow
262
+ * @returns The workflow definition if it exists, null otherwise
263
+ */
264
+ getWorkflowDefinition(workflowId: string): Promise<WorkflowDefinition | null>;
265
+ /**
266
+ * List all instances of a workflow.
267
+ *
268
+ * @param workflowId - The ID of the workflow
269
+ * @returns List of all instances for the workflow
270
+ */
271
+ listWorkflowInstances(workflowId: string): Promise<WorkflowInstance[]>;
272
+ /**
273
+ * Update the state of a node in a workflow instance.
274
+ *
275
+ * This is an internal method used by node executors to report progress.
276
+ *
277
+ * @param instanceId - The ID of the workflow instance
278
+ * @param nodeId - The ID of the node to update
279
+ * @param status - The new status of the node
280
+ * @param output - Optional output data from the node
281
+ * @param error - Optional error message if the node failed
282
+ * @throws WorkflowValidationError if the instance or node does not exist
283
+ */
284
+ updateNodeState(instanceId: string, nodeId: string, status: NodeStatus, output?: string, error?: string): Promise<void>;
285
+ /**
286
+ * Update the status of nodes that depend on a completed node.
287
+ */
288
+ private updateDependentNodes;
289
+ /**
290
+ * Check if a workflow instance is complete and update its status.
291
+ */
292
+ private checkWorkflowCompletion;
293
+ /**
294
+ * Update the shared workflow data.
295
+ *
296
+ * @param instanceId - The ID of the workflow instance
297
+ * @param workflowData - The new workflow data (JSON string)
298
+ * @throws WorkflowValidationError if the instance does not exist
299
+ */
300
+ updateWorkflowData(instanceId: string, workflowData: string): Promise<void>;
301
+ }
@@ -1,4 +1,4 @@
1
- export declare const version = "0.3.0";
1
+ export declare const version = "0.4.0";
2
2
  export * from './clients/router.js';
3
3
  export * from './clients/scheduler.js';
4
4
  export * from './clients/schedulerPolicy.js';
@@ -11,6 +11,9 @@ export * from './clients/negotiation.js';
11
11
  export * from './clients/reasoning.js';
12
12
  export * from './clients/connector.js';
13
13
  export * from './clients/registry.js';
14
+ export * from './clients/negotiationRoom.js';
15
+ export * from './clients/handoff.js';
16
+ export * from './clients/workflow.js';
14
17
  export { buildEnvelope, type EnvelopeBuilt, type EnvelopeInput, nowTimestamp, type Timestamp, } from './internal/envelope.js';
15
18
  export * from './internal/errorMapping.js';
16
19
  export * from './internal/baseClient.js';
@@ -26,6 +29,9 @@ export * from './runtime/activitySync.js';
26
29
  export * from './runtime/streams.js';
27
30
  export * from './runtime/negotiationEvents.js';
28
31
  export * from './persistence/persistence.js';
32
+ export * from './runtime/voting.js';
33
+ export * from './runtime/policyStore.js';
34
+ export * from './runtime/agentState.js';
29
35
  export * from './internal/ids.js';
30
36
  export * from './internal/idempotency.js';
31
37
  export * from './runtime/persistenceAdapter.js';
@@ -29,5 +29,5 @@ export declare class BaseClient {
29
29
  protected metadata(base?: grpc.Metadata): grpc.Metadata;
30
30
  protected deadlineFromNow(): Date;
31
31
  protected getServiceClient<T = any>(fqn: string): T;
32
- protected withRetryUnary<Req, Res>(fn: () => Promise<Res>, methodName?: string, mdForCtx?: grpc.Metadata): Promise<Res>;
32
+ protected withRetryUnary<Res>(fn: () => Promise<Res>, methodName?: string, mdForCtx?: grpc.Metadata): Promise<Res>;
33
33
  }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Agent runtime state machine for SW4RM.
3
+ *
4
+ * This module provides the AgentState enum and state transition validation
5
+ * for implementing the agent lifecycle as specified in spec section 8.
6
+ *
7
+ * The agent lifecycle states are:
8
+ * - INITIALIZING: Agent starting up and registering
9
+ * - RUNNABLE: Agent ready to accept tasks
10
+ * - SCHEDULED: Agent has task assigned but not yet running
11
+ * - RUNNING: Agent actively executing task
12
+ * - WAITING: Agent waiting for external input
13
+ * - WAITING_RESOURCES: Agent waiting for resources
14
+ * - SUSPENDED: Agent paused by scheduler
15
+ * - RESUMED: Agent transitioning from suspended to running
16
+ * - COMPLETED: Agent finished current task
17
+ * - FAILED: Agent encountered error
18
+ * - SHUTTING_DOWN: Agent gracefully terminating
19
+ * - RECOVERING: Agent recovering from failure
20
+ */
21
+ /**
22
+ * Agent lifecycle states as defined in spec section 8.
23
+ */
24
+ export declare enum AgentState {
25
+ /** Agent state not set */
26
+ AGENT_STATE_UNSPECIFIED = 0,
27
+ /** Agent starting up and registering */
28
+ INITIALIZING = 1,
29
+ /** Agent ready to accept tasks */
30
+ RUNNABLE = 2,
31
+ /** Agent has task assigned but not yet running */
32
+ SCHEDULED = 3,
33
+ /** Agent actively executing task */
34
+ RUNNING = 4,
35
+ /** Agent waiting for external input */
36
+ WAITING = 5,
37
+ /** Agent waiting for resources */
38
+ WAITING_RESOURCES = 6,
39
+ /** Agent paused by scheduler */
40
+ SUSPENDED = 7,
41
+ /** Agent transitioning from suspended to running */
42
+ RESUMED = 8,
43
+ /** Agent finished current task */
44
+ COMPLETED = 9,
45
+ /** Agent encountered error */
46
+ FAILED = 10,
47
+ /** Agent gracefully terminating */
48
+ SHUTTING_DOWN = 11,
49
+ /** Agent recovering from failure */
50
+ RECOVERING = 12
51
+ }
52
+ /**
53
+ * Error thrown when an invalid state transition is attempted.
54
+ */
55
+ export declare class StateTransitionError extends Error {
56
+ readonly fromState: AgentState;
57
+ readonly toState: AgentState;
58
+ constructor(fromState: AgentState, toState: AgentState);
59
+ }
60
+ /**
61
+ * Check if a state transition is valid.
62
+ *
63
+ * @param fromState - The current state
64
+ * @param toState - The target state
65
+ * @returns True if the transition is valid, false otherwise
66
+ */
67
+ export declare function isValidTransition(fromState: AgentState, toState: AgentState): boolean;
68
+ /**
69
+ * Get all valid target states from a given state.
70
+ *
71
+ * @param fromState - The current state
72
+ * @returns Array of valid target states
73
+ */
74
+ export declare function getValidTransitions(fromState: AgentState): AgentState[];
75
+ /**
76
+ * Lifecycle hook types for agent state changes.
77
+ */
78
+ export interface AgentLifecycleHooks {
79
+ /** Called on any state change */
80
+ onStateChange?: (fromState: AgentState, toState: AgentState, context?: Record<string, unknown>) => void | Promise<void>;
81
+ /** Called when agent becomes SCHEDULED */
82
+ onScheduled?: (taskId: string, context?: Record<string, unknown>) => void | Promise<void>;
83
+ /** Called when agent is preempted (RUNNING -> SUSPENDED) */
84
+ onPreempt?: (reason: string, context?: Record<string, unknown>) => void | Promise<void>;
85
+ /** Called when agent resumes (RESUMED -> RUNNING) */
86
+ onResume?: (context?: Record<string, unknown>) => void | Promise<void>;
87
+ /** Called when agent starts waiting (RUNNING -> WAITING) */
88
+ onWait?: (reason: string, context?: Record<string, unknown>) => void | Promise<void>;
89
+ /** Called when agent waits for resources (RUNNING -> WAITING_RESOURCES) */
90
+ onWaitResources?: (resources: string[], context?: Record<string, unknown>) => void | Promise<void>;
91
+ /** Called when task completes (RUNNING -> COMPLETED) */
92
+ onComplete?: (result?: unknown, context?: Record<string, unknown>) => void | Promise<void>;
93
+ /** Called when agent fails (any -> FAILED) */
94
+ onFail?: (error: Error, context?: Record<string, unknown>) => void | Promise<void>;
95
+ /** Called when shutdown starts (RUNNING -> SHUTTING_DOWN) */
96
+ onShutdown?: (gracePeriodMs: number, context?: Record<string, unknown>) => void | Promise<void>;
97
+ /** Called when recovery starts (FAILED -> RECOVERING) */
98
+ onRecover?: (context?: Record<string, unknown>) => void | Promise<void>;
99
+ }
100
+ /**
101
+ * Agent state machine implementation.
102
+ *
103
+ * Manages agent lifecycle state transitions with validation and lifecycle hooks.
104
+ */
105
+ export declare class AgentStateMachine {
106
+ private state;
107
+ private hooks;
108
+ private stateHistory;
109
+ /**
110
+ * Create a new agent state machine.
111
+ *
112
+ * @param hooks - Optional lifecycle hooks
113
+ */
114
+ constructor(hooks?: AgentLifecycleHooks);
115
+ /**
116
+ * Get the current state.
117
+ *
118
+ * @returns The current agent state
119
+ */
120
+ getState(): AgentState;
121
+ /**
122
+ * Get the state history.
123
+ *
124
+ * @returns Array of state transitions with timestamps
125
+ */
126
+ getStateHistory(): Array<{
127
+ state: AgentState;
128
+ timestamp: string;
129
+ context?: Record<string, unknown>;
130
+ }>;
131
+ /**
132
+ * Initialize the agent (transition to INITIALIZING).
133
+ *
134
+ * @throws StateTransitionError if already initialized
135
+ */
136
+ initialize(): Promise<void>;
137
+ /**
138
+ * Transition to a new state.
139
+ *
140
+ * @param toState - The target state
141
+ * @param context - Optional context for the transition
142
+ * @throws StateTransitionError if the transition is invalid
143
+ */
144
+ transitionTo(toState: AgentState, context?: Record<string, unknown>): Promise<void>;
145
+ /**
146
+ * Perform the state transition and call hooks.
147
+ */
148
+ private doTransition;
149
+ /**
150
+ * Call specific lifecycle hooks based on the transition.
151
+ */
152
+ private callSpecificHooks;
153
+ /**
154
+ * Check if the agent can transition to a given state.
155
+ *
156
+ * @param toState - The target state
157
+ * @returns True if the transition is valid
158
+ */
159
+ canTransitionTo(toState: AgentState): boolean;
160
+ /**
161
+ * Get all states the agent can currently transition to.
162
+ *
163
+ * @returns Array of valid target states
164
+ */
165
+ getAvailableTransitions(): AgentState[];
166
+ /**
167
+ * Check if the agent is in a terminal state.
168
+ *
169
+ * Terminal states are states where the agent cannot make further
170
+ * progress without external intervention.
171
+ *
172
+ * @returns True if in a terminal state
173
+ */
174
+ isTerminal(): boolean;
175
+ /**
176
+ * Check if the agent is in an active state (executing work).
177
+ *
178
+ * @returns True if the agent is actively working
179
+ */
180
+ isActive(): boolean;
181
+ /**
182
+ * Check if the agent is in a waiting state.
183
+ *
184
+ * @returns True if the agent is waiting
185
+ */
186
+ isWaiting(): boolean;
187
+ /**
188
+ * Check if the agent is in a suspended or shutdown state.
189
+ *
190
+ * @returns True if the agent is suspended or shutting down
191
+ */
192
+ isSuspendedOrShuttingDown(): boolean;
193
+ /**
194
+ * Update lifecycle hooks.
195
+ *
196
+ * @param hooks - New hooks to merge with existing hooks
197
+ */
198
+ setHooks(hooks: Partial<AgentLifecycleHooks>): void;
199
+ /**
200
+ * Reset the state machine to uninitialized state.
201
+ *
202
+ * This is primarily for testing purposes.
203
+ */
204
+ reset(): void;
205
+ }