@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,188 @@
1
+ /**
2
+ * Handoff client for SW4RM.
3
+ *
4
+ * This module provides the HandoffClient for managing agent-to-agent task
5
+ * handoffs. The handoff pattern enables:
6
+ * - Graceful transfer of work between agents
7
+ * - Context preservation during handoff
8
+ * - Capability-based routing to appropriate agents
9
+ *
10
+ * Based on handoff.proto definitions.
11
+ */
12
+ /**
13
+ * Status of a handoff request.
14
+ */
15
+ export declare enum HandoffStatus {
16
+ HANDOFF_STATUS_UNSPECIFIED = 0,
17
+ PENDING = 1,
18
+ ACCEPTED = 2,
19
+ REJECTED = 3,
20
+ COMPLETED = 4,
21
+ EXPIRED = 5
22
+ }
23
+ /**
24
+ * A request to hand off work from one agent to another.
25
+ *
26
+ * Contains the context needed for the receiving agent to continue
27
+ * the work, including capability requirements and priority information.
28
+ */
29
+ export interface HandoffRequest {
30
+ /** Unique identifier for this handoff request */
31
+ requestId: string;
32
+ /** Agent ID of the agent initiating the handoff */
33
+ fromAgent: string;
34
+ /** Agent ID of the target agent (or empty for capability-based routing) */
35
+ toAgent: string;
36
+ /** Human-readable reason for the handoff */
37
+ reason: string;
38
+ /** Serialized context snapshot for the receiving agent */
39
+ contextSnapshot: Uint8Array;
40
+ /** List of capabilities required by the receiving agent */
41
+ capabilitiesRequired: string[];
42
+ /** Priority level of the handoff (lower is higher priority) */
43
+ priority: number;
44
+ /** Timeout in milliseconds for the handoff to be accepted */
45
+ timeoutMs?: number;
46
+ /** Timestamp when the request was created (ISO-8601 string) */
47
+ createdAt?: string;
48
+ }
49
+ /**
50
+ * Response to a handoff request.
51
+ *
52
+ * Indicates whether the handoff was accepted and by whom, or provides
53
+ * a rejection reason.
54
+ */
55
+ export interface HandoffResponse {
56
+ /** Identifier of the handoff request being responded to */
57
+ requestId: string;
58
+ /** Whether the handoff was accepted */
59
+ accepted: boolean;
60
+ /** Agent ID of the agent that accepted the handoff (if accepted) */
61
+ acceptingAgent?: string;
62
+ /** Reason for rejection (if not accepted) */
63
+ rejectionReason?: string;
64
+ }
65
+ /**
66
+ * Error thrown when a handoff operation fails validation.
67
+ */
68
+ export declare class HandoffValidationError extends Error {
69
+ constructor(message: string);
70
+ }
71
+ /**
72
+ * Error thrown when a handoff operation times out.
73
+ */
74
+ export declare class HandoffTimeoutError extends Error {
75
+ constructor(message: string);
76
+ }
77
+ /**
78
+ * Client for managing agent-to-agent handoffs.
79
+ *
80
+ * Enables agents to transfer work to other agents while preserving
81
+ * context and ensuring proper capability matching. This is an in-memory
82
+ * implementation for Phase 2; future phases will integrate with gRPC services.
83
+ */
84
+ export declare class HandoffClient {
85
+ private requests;
86
+ private responses;
87
+ private pendingByAgent;
88
+ /**
89
+ * Request a handoff to another agent.
90
+ *
91
+ * Initiates a handoff request that the target agent can accept or reject.
92
+ * The request is stored and made available to the target agent via
93
+ * getPendingHandoffs().
94
+ *
95
+ * @param request - The handoff request containing context and requirements
96
+ * @returns The response once the handoff is accepted, rejected, or times out
97
+ * @throws HandoffValidationError if a request with the same ID already exists
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const client = new HandoffClient();
102
+ * const request: HandoffRequest = {
103
+ * requestId: "handoff-123",
104
+ * fromAgent: "agent-a",
105
+ * toAgent: "agent-b",
106
+ * reason: "Capability mismatch",
107
+ * contextSnapshot: new TextEncoder().encode('{"state": "in_progress"}'),
108
+ * capabilitiesRequired: ["code_review"],
109
+ * priority: 5
110
+ * };
111
+ * const response = await client.requestHandoff(request);
112
+ * ```
113
+ */
114
+ requestHandoff(request: HandoffRequest): Promise<HandoffResponse>;
115
+ /**
116
+ * Accept a pending handoff request.
117
+ *
118
+ * Called by the target agent to accept a handoff. After acceptance,
119
+ * the agent should process the context snapshot and continue the work.
120
+ *
121
+ * @param handoffId - The ID of the handoff request to accept
122
+ * @throws HandoffValidationError if no request exists with the given ID
123
+ * @throws HandoffValidationError if the request has already been responded to
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * // Get pending handoffs for this agent
128
+ * const pending = await client.getPendingHandoffs("agent-b");
129
+ * if (pending.length > 0) {
130
+ * await client.acceptHandoff(pending[0].requestId);
131
+ * }
132
+ * ```
133
+ */
134
+ acceptHandoff(handoffId: string): Promise<void>;
135
+ /**
136
+ * Reject a pending handoff request.
137
+ *
138
+ * Called by the target agent to reject a handoff. A reason should be
139
+ * provided to help the originating agent determine next steps.
140
+ *
141
+ * @param handoffId - The ID of the handoff request to reject
142
+ * @param reason - Human-readable reason for the rejection
143
+ * @throws HandoffValidationError if no request exists with the given ID
144
+ * @throws HandoffValidationError if the request has already been responded to
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * await client.rejectHandoff("handoff-123", "Agent at capacity");
149
+ * ```
150
+ */
151
+ rejectHandoff(handoffId: string, reason: string): Promise<void>;
152
+ /**
153
+ * Get all pending handoff requests for an agent.
154
+ *
155
+ * Returns handoff requests that have been addressed to the specified
156
+ * agent and have not yet been accepted or rejected.
157
+ *
158
+ * @param agentId - The ID of the agent to get pending handoffs for
159
+ * @returns List of pending handoff requests for the agent
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * const pending = await client.getPendingHandoffs("agent-b");
164
+ * console.log(`${pending.length} pending handoffs`);
165
+ * for (const request of pending) {
166
+ * console.log(`From ${request.fromAgent}: ${request.reason}`);
167
+ * }
168
+ * ```
169
+ */
170
+ getPendingHandoffs(agentId: string): Promise<HandoffRequest[]>;
171
+ /**
172
+ * Get the response for a handoff request.
173
+ *
174
+ * Returns the response if the handoff has been accepted, rejected, or
175
+ * timed out. Returns null if the handoff is still pending.
176
+ *
177
+ * @param handoffId - The ID of the handoff request
178
+ * @returns The handoff response if available, null otherwise
179
+ */
180
+ getHandoffResponse(handoffId: string): Promise<HandoffResponse | null>;
181
+ /**
182
+ * Get the original handoff request.
183
+ *
184
+ * @param handoffId - The ID of the handoff request
185
+ * @returns The handoff request if it exists, null otherwise
186
+ */
187
+ getHandoffRequest(handoffId: string): Promise<HandoffRequest | null>;
188
+ }
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Negotiation Room client for SW4RM.
3
+ *
4
+ * This module provides the NegotiationRoomClient for managing multi-agent
5
+ * artifact approval workflows using the Negotiation Room pattern. The client
6
+ * supports:
7
+ * - Submitting artifacts for review
8
+ * - Collecting votes from critics
9
+ * - Retrieving and waiting for decisions
10
+ * - Coordinating the review process
11
+ *
12
+ * Based on SPEC_REQUESTS.md section 6.1.
13
+ */
14
+ /**
15
+ * Type of artifact being negotiated.
16
+ *
17
+ * Maps to the artifact_type field in negotiation proposals to categorize
18
+ * what stage of the workflow the artifact belongs to.
19
+ */
20
+ export declare enum ArtifactType {
21
+ ARTIFACT_TYPE_UNSPECIFIED = 0,
22
+ REQUIREMENTS = 1,
23
+ PLAN = 2,
24
+ CODE = 3,
25
+ DEPLOYMENT = 4
26
+ }
27
+ /**
28
+ * Outcome of a negotiation decision.
29
+ *
30
+ * Represents the final decision made by the coordinator after aggregating
31
+ * critic votes and applying policy.
32
+ */
33
+ export declare enum DecisionOutcome {
34
+ DECISION_OUTCOME_UNSPECIFIED = 0,
35
+ APPROVED = 1,
36
+ REVISION_REQUESTED = 2,
37
+ ESCALATED_TO_HITL = 3
38
+ }
39
+ /**
40
+ * A proposal for artifact evaluation in a negotiation room.
41
+ *
42
+ * Submitted by a producer agent to request multi-agent review of an artifact.
43
+ * The proposal specifies which critics should evaluate the artifact and
44
+ * includes the artifact content for review.
45
+ */
46
+ export interface NegotiationProposal {
47
+ /** Category of artifact (requirements, plan, code, deployment) */
48
+ artifactType: ArtifactType;
49
+ /** Unique identifier for this artifact */
50
+ artifactId: string;
51
+ /** Agent ID of the producer submitting the artifact */
52
+ producerId: string;
53
+ /** Binary artifact content (e.g., serialized JSON, code files) */
54
+ artifact: Uint8Array;
55
+ /** MIME type or content type identifier */
56
+ artifactContentType: string;
57
+ /** List of critic agent IDs requested for evaluation */
58
+ requestedCritics: string[];
59
+ /** Identifier for the negotiation room session */
60
+ negotiationRoomId: string;
61
+ /** Timestamp when proposal was created (ISO-8601 string) */
62
+ createdAt?: string;
63
+ }
64
+ /**
65
+ * A critic's evaluation of an artifact.
66
+ *
67
+ * Represents a single critic's assessment including numerical scoring,
68
+ * qualitative feedback, and confidence level based on POMDP uncertainty.
69
+ */
70
+ export interface NegotiationVote {
71
+ /** Identifier of the artifact being evaluated */
72
+ artifactId: string;
73
+ /** Agent ID of the critic providing this vote */
74
+ criticId: string;
75
+ /** Numerical score from 0-10 (10 = excellent) */
76
+ score: number;
77
+ /** Confidence level from 0-1 (based on POMDP research) */
78
+ confidence: number;
79
+ /** Boolean indicating if artifact meets minimum criteria */
80
+ passed: boolean;
81
+ /** List of identified strengths in the artifact */
82
+ strengths: string[];
83
+ /** List of identified weaknesses or concerns */
84
+ weaknesses: string[];
85
+ /** List of suggestions for improvement */
86
+ recommendations: string[];
87
+ /** Identifier for the negotiation room session */
88
+ negotiationRoomId: string;
89
+ /** Timestamp when vote was cast (ISO-8601 string) */
90
+ votedAt?: string;
91
+ }
92
+ /**
93
+ * Statistical aggregation of multiple critic votes.
94
+ *
95
+ * Provides multiple views of the voting results including basic statistics
96
+ * and confidence-weighted metrics for decision making.
97
+ */
98
+ export interface AggregatedScore {
99
+ /** Arithmetic mean of all scores */
100
+ mean: number;
101
+ /** Minimum score from any critic */
102
+ minScore: number;
103
+ /** Maximum score from any critic */
104
+ maxScore: number;
105
+ /** Standard deviation of scores (measures consensus) */
106
+ stdDev: number;
107
+ /** Confidence-weighted mean (higher confidence votes weighted more) */
108
+ weightedMean: number;
109
+ /** Number of votes included in aggregation */
110
+ voteCount: number;
111
+ }
112
+ /**
113
+ * Final decision on an artifact after critic evaluation.
114
+ *
115
+ * Represents the coordinator's decision after aggregating all critic votes
116
+ * and applying policy thresholds. Includes full audit trail of votes and
117
+ * reasoning.
118
+ */
119
+ export interface NegotiationDecision {
120
+ /** Identifier of the artifact that was evaluated */
121
+ artifactId: string;
122
+ /** Final decision (approved, revision requested, escalated to HITL) */
123
+ outcome: DecisionOutcome;
124
+ /** Complete list of all critic votes considered */
125
+ votes: NegotiationVote[];
126
+ /** Statistical summary of the votes */
127
+ aggregatedScore: AggregatedScore;
128
+ /** Version identifier of the policy used for decision */
129
+ policyVersion: string;
130
+ /** Human-readable explanation of the decision */
131
+ reason: string;
132
+ /** Identifier for the negotiation room session */
133
+ negotiationRoomId: string;
134
+ /** Timestamp when decision was made (ISO-8601 string) */
135
+ decidedAt?: string;
136
+ }
137
+ /**
138
+ * Error thrown when a negotiation room operation times out.
139
+ */
140
+ export declare class NegotiationTimeoutError extends Error {
141
+ constructor(message: string);
142
+ }
143
+ /**
144
+ * Error thrown when a negotiation room operation fails validation.
145
+ */
146
+ export declare class NegotiationValidationError extends Error {
147
+ constructor(message: string);
148
+ }
149
+ /**
150
+ * Client for interacting with negotiation rooms.
151
+ *
152
+ * Manages the lifecycle of artifact proposals through the multi-agent
153
+ * review process. Producers submit proposals, critics submit votes,
154
+ * and coordinators retrieve votes to make decisions.
155
+ *
156
+ * This is an in-memory implementation for Phase 2. Future phases
157
+ * will integrate with persistent storage and gRPC services.
158
+ */
159
+ export declare class NegotiationRoomClient {
160
+ private proposals;
161
+ private votes;
162
+ private decisions;
163
+ /**
164
+ * Submit an artifact proposal for multi-agent review.
165
+ *
166
+ * Stores the proposal and initializes empty vote tracking for the artifact.
167
+ * This method is typically called by producer agents.
168
+ *
169
+ * @param proposal - The negotiation proposal containing artifact details
170
+ * @returns The artifact_id of the submitted proposal
171
+ * @throws NegotiationValidationError if a proposal with the same artifact_id already exists
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const client = new NegotiationRoomClient();
176
+ * const proposal: NegotiationProposal = {
177
+ * artifactType: ArtifactType.CODE,
178
+ * artifactId: "code-123",
179
+ * producerId: "agent-producer",
180
+ * artifact: new TextEncoder().encode("def hello(): pass"),
181
+ * artifactContentType: "text/x-python",
182
+ * requestedCritics: ["critic-1", "critic-2"],
183
+ * negotiationRoomId: "room-1"
184
+ * };
185
+ * const artifactId = await client.submitProposal(proposal);
186
+ * console.log(artifactId); // "code-123"
187
+ * ```
188
+ */
189
+ submitProposal(proposal: NegotiationProposal): Promise<string>;
190
+ /**
191
+ * Submit a critic's vote for an artifact.
192
+ *
193
+ * Adds the vote to the collection for the specified artifact.
194
+ * This method is typically called by critic agents after evaluating
195
+ * an artifact.
196
+ *
197
+ * @param vote - The negotiation vote containing the critic's evaluation
198
+ * @throws NegotiationValidationError if no proposal exists for the vote's artifact_id
199
+ * @throws NegotiationValidationError if the critic has already voted for this artifact
200
+ * @throws NegotiationValidationError if score or confidence are out of range
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * const vote: NegotiationVote = {
205
+ * artifactId: "code-123",
206
+ * criticId: "critic-1",
207
+ * score: 8.5,
208
+ * confidence: 0.9,
209
+ * passed: true,
210
+ * strengths: ["Good structure"],
211
+ * weaknesses: ["Needs tests"],
212
+ * recommendations: ["Add unit tests"],
213
+ * negotiationRoomId: "room-1"
214
+ * };
215
+ * await client.submitVote(vote);
216
+ * ```
217
+ */
218
+ submitVote(vote: NegotiationVote): Promise<void>;
219
+ /**
220
+ * Retrieve all votes for a specific artifact.
221
+ *
222
+ * Returns all critic votes that have been submitted for the artifact.
223
+ * This method is typically called by coordinator agents to aggregate
224
+ * votes and make decisions.
225
+ *
226
+ * @param artifactId - The identifier of the artifact
227
+ * @returns List of all votes for the artifact (empty array if no votes yet)
228
+ * @throws NegotiationValidationError if no proposal exists for the artifact_id
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * const votes = await client.getVotes("code-123");
233
+ * console.log(votes.length); // 1
234
+ * ```
235
+ */
236
+ getVotes(artifactId: string): Promise<NegotiationVote[]>;
237
+ /**
238
+ * Retrieve the decision for a specific artifact if available.
239
+ *
240
+ * Returns the final decision if one has been made, or null if the
241
+ * artifact is still under review.
242
+ *
243
+ * @param artifactId - The identifier of the artifact
244
+ * @returns The negotiation decision if available, null otherwise
245
+ * @throws NegotiationValidationError if no proposal exists for the artifact_id
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * const decision = await client.getDecision("code-123");
250
+ * if (decision === null) {
251
+ * console.log("Decision pending");
252
+ * }
253
+ * ```
254
+ */
255
+ getDecision(artifactId: string): Promise<NegotiationDecision | null>;
256
+ /**
257
+ * Store a decision for an artifact.
258
+ *
259
+ * This is an internal method used by coordinators to record the
260
+ * final decision after evaluating votes. Once a decision is stored,
261
+ * it becomes available via getDecision() and waitForDecision().
262
+ *
263
+ * @param decision - The negotiation decision to store
264
+ * @throws NegotiationValidationError if no proposal exists for the decision's artifact_id
265
+ * @throws NegotiationValidationError if a decision already exists for this artifact
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * const votes = await client.getVotes("code-123");
270
+ * const aggregated = aggregateVotes(votes);
271
+ * const decision: NegotiationDecision = {
272
+ * artifactId: "code-123",
273
+ * outcome: DecisionOutcome.APPROVED,
274
+ * votes: votes,
275
+ * aggregatedScore: aggregated,
276
+ * policyVersion: "1.0",
277
+ * reason: "Met all criteria",
278
+ * negotiationRoomId: "room-1"
279
+ * };
280
+ * await client.storeDecision(decision);
281
+ * ```
282
+ */
283
+ storeDecision(decision: NegotiationDecision): Promise<void>;
284
+ /**
285
+ * Wait for a decision to be made on an artifact.
286
+ *
287
+ * Polls for a decision until one is available or the timeout is reached.
288
+ * This method is useful for producer agents waiting for the outcome
289
+ * of their artifact review.
290
+ *
291
+ * @param artifactId - The identifier of the artifact
292
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 30000)
293
+ * @param pollIntervalMs - Time between polling attempts in milliseconds (default: 100)
294
+ * @returns The negotiation decision once available
295
+ * @throws NegotiationValidationError if no proposal exists for the artifact_id
296
+ * @throws NegotiationTimeoutError if no decision is made within the timeout period
297
+ *
298
+ * @example
299
+ * ```typescript
300
+ * // In a separate thread/process, a coordinator makes a decision
301
+ * const decision = await client.waitForDecision("code-123", 10000);
302
+ * console.log(decision.outcome); // DecisionOutcome.APPROVED
303
+ * ```
304
+ */
305
+ waitForDecision(artifactId: string, timeoutMs?: number, pollIntervalMs?: number): Promise<NegotiationDecision>;
306
+ /**
307
+ * Retrieve the original proposal for an artifact.
308
+ *
309
+ * Useful for critics that need to review the original artifact
310
+ * before submitting a vote.
311
+ *
312
+ * @param artifactId - The identifier of the artifact
313
+ * @returns The negotiation proposal if it exists, null otherwise
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * const proposal = await client.getProposal("code-123");
318
+ * console.log(proposal?.artifactType); // ArtifactType.CODE
319
+ * ```
320
+ */
321
+ getProposal(artifactId: string): Promise<NegotiationProposal | null>;
322
+ /**
323
+ * List all proposals, optionally filtered by negotiation room.
324
+ *
325
+ * @param negotiationRoomId - If provided, only return proposals for this room
326
+ * @returns List of proposals matching the filter criteria
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * const proposals = await client.listProposals("room-1");
331
+ * console.log(proposals.length); // 1
332
+ * ```
333
+ */
334
+ listProposals(negotiationRoomId?: string): Promise<NegotiationProposal[]>;
335
+ }
336
+ /**
337
+ * Aggregate multiple critic votes into statistical summary.
338
+ *
339
+ * Computes both basic statistics (mean, min, max, std dev) and a
340
+ * confidence-weighted mean that gives more weight to votes from critics
341
+ * with higher confidence levels.
342
+ *
343
+ * @param votes - List of critic votes to aggregate
344
+ * @returns AggregatedScore with statistical summary of votes
345
+ * @throws NegotiationValidationError if votes list is empty
346
+ */
347
+ export declare function aggregateVotes(votes: NegotiationVote[]): AggregatedScore;