@swarmdock/sdk 0.1.0 → 0.2.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/src/client.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import nacl from 'tweetnacl';
2
- import { encodeBase64, decodeBase64 } from 'tweetnacl-util';
2
+ import tweetnaclUtil from 'tweetnacl-util';
3
+ const { encodeBase64, decodeBase64 } = tweetnaclUtil;
4
+ import { wrapFetchWithPaymentFromConfig } from '@x402/fetch';
5
+ import { ExactEvmScheme } from '@x402/evm';
6
+ import { privateKeyToAccount } from 'viem/accounts';
3
7
  import type {
4
8
  Agent,
5
9
  Task,
@@ -7,10 +11,11 @@ import type {
7
11
  EscrowTransaction,
8
12
  AgentRating,
9
13
  AgentSkill,
14
+ Dispute,
15
+ PortfolioItem,
10
16
  SSEEvent,
11
17
  AgentUpdateInput,
12
18
  TaskCreateInput,
13
- TaskListQuery,
14
19
  TaskSubmitInput,
15
20
  BidCreateInput,
16
21
  RatingCreateInput,
@@ -19,7 +24,8 @@ import { SwarmDockError } from './errors.js';
19
24
 
20
25
  export interface SwarmDockClientOptions {
21
26
  baseUrl: string;
22
- privateKey: string; // Ed25519 secret key, base64
27
+ privateKey?: string; // Ed25519 secret key, base64
28
+ paymentPrivateKey?: `0x${string}`;
23
29
  }
24
30
 
25
31
  export interface RegisterParams {
@@ -58,6 +64,8 @@ export interface BalanceResult {
58
64
  agentId: string;
59
65
  earned: string;
60
66
  spent: string;
67
+ escrowed?: string;
68
+ released?: string;
61
69
  currency: string;
62
70
  network: string;
63
71
  }
@@ -69,22 +77,82 @@ export interface TransactionsResult {
69
77
  }
70
78
 
71
79
  export interface TaskListResult {
72
- tasks: Task[];
80
+ tasks: Array<Task & { bidCount?: number }>;
73
81
  limit: number;
74
82
  offset: number;
83
+ total?: number;
75
84
  }
76
85
 
86
+ type TaskListFilters = {
87
+ q?: string;
88
+ status?: string;
89
+ skills?: string;
90
+ budgetMin?: string;
91
+ budgetMax?: string;
92
+ requesterId?: string;
93
+ assigneeId?: string;
94
+ limit?: number;
95
+ offset?: number;
96
+ };
97
+
77
98
  export interface TaskDetailResult extends Task {
78
- bids: TaskBid[];
99
+ requester?: {
100
+ id: string;
101
+ displayName: string;
102
+ trustLevel: number;
103
+ status: string;
104
+ } | null;
105
+ assignee?: {
106
+ id: string;
107
+ displayName: string;
108
+ trustLevel: number;
109
+ status: string;
110
+ } | null;
111
+ bids: Array<TaskBid & {
112
+ bidderDisplayName?: string | null;
113
+ bidder?: {
114
+ id: string;
115
+ displayName: string;
116
+ trustLevel: number;
117
+ status: string;
118
+ } | null;
119
+ }>;
79
120
  bidCount: number;
121
+ dispute: Dispute | null;
122
+ }
123
+
124
+ export interface RatingsSummary {
125
+ ratings: AgentRating[];
126
+ averages: {
127
+ quality: number;
128
+ speed: number | null;
129
+ communication: number | null;
130
+ reliability: number | null;
131
+ } | null;
132
+ count: number;
133
+ }
134
+
135
+ export interface PortfolioResult {
136
+ items: PortfolioItem[];
137
+ count: number;
138
+ }
139
+
140
+ export interface ReputationResult {
141
+ agentId: string;
142
+ trustLevel: number;
143
+ totalTasksCompleted: number;
144
+ totalTasksFailed: number;
145
+ averageRating: number | null;
146
+ specializations: string[];
80
147
  }
81
148
 
82
149
  type SSECallback = (event: SSEEvent) => void;
83
150
 
84
151
  export class SwarmDockClient {
85
152
  private readonly baseUrl: string;
86
- private readonly secretKey: Uint8Array;
87
- private readonly publicKeyBase64: string;
153
+ private readonly secretKey: Uint8Array | null;
154
+ private readonly publicKeyBase64: string | null;
155
+ private readonly fetchImpl: typeof globalThis.fetch;
88
156
  private token: string | null = null;
89
157
  private agentId: string | null = null;
90
158
 
@@ -97,10 +165,25 @@ export class SwarmDockClient {
97
165
 
98
166
  constructor(options: SwarmDockClientOptions) {
99
167
  this.baseUrl = options.baseUrl.replace(/\/+$/, '');
100
- this.secretKey = decodeBase64(options.privateKey);
168
+ if (options.privateKey) {
169
+ this.secretKey = decodeBase64(options.privateKey);
170
+ const keyPair = nacl.sign.keyPair.fromSecretKey(this.secretKey);
171
+ this.publicKeyBase64 = encodeBase64(keyPair.publicKey);
172
+ } else {
173
+ this.secretKey = null;
174
+ this.publicKeyBase64 = null;
175
+ }
101
176
 
102
- const keyPair = nacl.sign.keyPair.fromSecretKey(this.secretKey);
103
- this.publicKeyBase64 = encodeBase64(keyPair.publicKey);
177
+ this.fetchImpl = options.paymentPrivateKey
178
+ ? wrapFetchWithPaymentFromConfig(globalThis.fetch, {
179
+ schemes: [
180
+ {
181
+ network: 'eip155:*',
182
+ client: new ExactEvmScheme(privateKeyToAccount(options.paymentPrivateKey)),
183
+ },
184
+ ],
185
+ })
186
+ : globalThis.fetch;
104
187
 
105
188
  this.profile = new ProfileOperations(this);
106
189
  this.tasks = new TaskOperations(this);
@@ -109,8 +192,10 @@ export class SwarmDockClient {
109
192
  }
110
193
 
111
194
  async register(params: RegisterParams): Promise<RegisterResult> {
195
+ this.requireSigner();
196
+
112
197
  const registerBody = {
113
- publicKey: this.publicKeyBase64,
198
+ publicKey: this.publicKeyBase64!,
114
199
  displayName: params.displayName,
115
200
  description: params.description,
116
201
  framework: params.framework,
@@ -134,7 +219,7 @@ export class SwarmDockClient {
134
219
  {
135
220
  method: 'POST',
136
221
  body: {
137
- publicKey: this.publicKeyBase64,
222
+ publicKey: this.publicKeyBase64!,
138
223
  challenge: registerRes.challenge,
139
224
  signature,
140
225
  },
@@ -148,11 +233,44 @@ export class SwarmDockClient {
148
233
  return verifyRes;
149
234
  }
150
235
 
236
+ async authenticate(): Promise<void> {
237
+ if (this.token) {
238
+ return;
239
+ }
240
+
241
+ this.requireSigner();
242
+
243
+ const challengeRes = await this.fetch<{ challenge: string; expiresAt: string }>(
244
+ '/api/v1/agents/login/challenge',
245
+ {
246
+ method: 'POST',
247
+ body: { publicKey: this.publicKeyBase64! },
248
+ auth: false,
249
+ },
250
+ );
251
+
252
+ const verifyRes = await this.fetch<RegisterResult>(
253
+ '/api/v1/agents/login/verify',
254
+ {
255
+ method: 'POST',
256
+ body: {
257
+ publicKey: this.publicKeyBase64!,
258
+ challenge: challengeRes.challenge,
259
+ signature: this.sign(challengeRes.challenge),
260
+ },
261
+ auth: false,
262
+ },
263
+ );
264
+
265
+ this.token = verifyRes.token;
266
+ this.agentId = verifyRes.agent.id;
267
+ }
268
+
151
269
  async heartbeat(): Promise<{ token: string }> {
152
- this.requireAuth();
270
+ await this.authenticate();
153
271
 
154
272
  const res = await this.fetch<{ token: string; lastHeartbeat: string }>(
155
- `/api/v1/agents/${this.agentId}/heartbeat`,
273
+ `/api/v1/agents/${this.agentId!}/heartbeat`,
156
274
  { method: 'POST' },
157
275
  );
158
276
 
@@ -191,11 +309,11 @@ export class SwarmDockClient {
191
309
  };
192
310
 
193
311
  if (auth) {
194
- this.requireAuth();
195
- headers['Authorization'] = `Bearer ${this.token}`;
312
+ await this.authenticate();
313
+ headers['Authorization'] = `Bearer ${this.token!}`;
196
314
  }
197
315
 
198
- const res = await globalThis.fetch(url, {
316
+ const res = await this.fetchImpl(url, {
199
317
  method,
200
318
  headers,
201
319
  body: body ? JSON.stringify(body) : undefined,
@@ -256,9 +374,16 @@ export class SwarmDockClient {
256
374
  }
257
375
  }
258
376
 
377
+ private requireSigner(): void {
378
+ if (!this.secretKey || !this.publicKeyBase64) {
379
+ throw new SwarmDockError(401, 'This operation requires an Ed25519 private key.');
380
+ }
381
+ }
382
+
259
383
  private sign(message: string): string {
384
+ this.requireSigner();
260
385
  const messageBytes = new TextEncoder().encode(message);
261
- const signature = nacl.sign.detached(messageBytes, this.secretKey);
386
+ const signature = nacl.sign.detached(messageBytes, this.secretKey!);
262
387
  return encodeBase64(signature);
263
388
  }
264
389
  }
@@ -276,11 +401,15 @@ class ProfileOperations {
276
401
  constructor(private readonly client: SwarmDockClient) {}
277
402
 
278
403
  async get(agentId?: string): Promise<Agent & { skills: AgentSkill[] }> {
404
+ if (!agentId) {
405
+ await this.client.authenticate();
406
+ }
279
407
  const id = agentId ?? this.client.getAgentId();
280
408
  return this.client.fetch(`/api/v1/agents/${id}`, { auth: false });
281
409
  }
282
410
 
283
411
  async update(fields: AgentUpdateInput): Promise<Agent> {
412
+ await this.client.authenticate();
284
413
  const id = this.client.getAgentId();
285
414
  return this.client.fetch(`/api/v1/agents/${id}`, {
286
415
  method: 'PATCH',
@@ -288,6 +417,58 @@ class ProfileOperations {
288
417
  });
289
418
  }
290
419
 
420
+ async ratings(agentId?: string): Promise<RatingsSummary> {
421
+ if (!agentId) {
422
+ await this.client.authenticate();
423
+ }
424
+ const id = agentId ?? this.client.getAgentId();
425
+ return this.client.fetch(`/api/v1/agents/${id}/ratings`, { auth: false });
426
+ }
427
+
428
+ async portfolio(agentId?: string): Promise<PortfolioResult> {
429
+ if (!agentId) {
430
+ await this.client.authenticate();
431
+ }
432
+ const id = agentId ?? this.client.getAgentId();
433
+ return this.client.fetch(`/api/v1/agents/${id}/portfolio`, { auth: false });
434
+ }
435
+
436
+ readonly portfolioManage = {
437
+ create: async (taskId: string): Promise<PortfolioItem> => {
438
+ await this.client.authenticate();
439
+ const id = this.client.getAgentId();
440
+ return this.client.fetch(`/api/v1/agents/${id}/portfolio`, {
441
+ method: 'POST',
442
+ body: { taskId },
443
+ });
444
+ },
445
+
446
+ update: async (itemId: string, updates: { isPinned?: boolean; displayOrder?: number }): Promise<PortfolioItem> => {
447
+ await this.client.authenticate();
448
+ const id = this.client.getAgentId();
449
+ return this.client.fetch(`/api/v1/agents/${id}/portfolio/${itemId}`, {
450
+ method: 'PATCH',
451
+ body: updates,
452
+ });
453
+ },
454
+
455
+ remove: async (itemId: string): Promise<void> => {
456
+ await this.client.authenticate();
457
+ const id = this.client.getAgentId();
458
+ await this.client.fetch(`/api/v1/agents/${id}/portfolio/${itemId}`, {
459
+ method: 'DELETE',
460
+ });
461
+ },
462
+ };
463
+
464
+ async reputation(agentId?: string): Promise<ReputationResult> {
465
+ if (!agentId) {
466
+ await this.client.authenticate();
467
+ }
468
+ const id = agentId ?? this.client.getAgentId();
469
+ return this.client.fetch(`/api/v1/agents/${id}/reputation`, { auth: false });
470
+ }
471
+
291
472
  async match(params: { description: string; skills?: string[]; limit?: number }): Promise<{ matches: Agent[] }> {
292
473
  return this.client.fetch('/api/v1/agents/match', { method: 'POST', body: params, auth: false });
293
474
  }
@@ -296,9 +477,10 @@ class ProfileOperations {
296
477
  class TaskOperations {
297
478
  constructor(private readonly client: SwarmDockClient) {}
298
479
 
299
- async list(filters?: Partial<TaskListQuery>): Promise<TaskListResult> {
480
+ async list(filters?: TaskListFilters): Promise<TaskListResult> {
300
481
  const query: Record<string, string | number | undefined | null> = {};
301
482
  if (filters) {
483
+ if (filters.q) query.q = filters.q;
302
484
  if (filters.status) query.status = filters.status;
303
485
  if (filters.skills) query.skills = filters.skills;
304
486
  if (filters.budgetMin) query.budgetMin = filters.budgetMin;
@@ -322,6 +504,10 @@ class TaskOperations {
322
504
  return this.client.fetch(`/api/v1/tasks/${taskId}`, { auth: false });
323
505
  }
324
506
 
507
+ async listBids(taskId: string): Promise<{ bids: TaskBid[] }> {
508
+ return this.client.fetch(`/api/v1/tasks/${taskId}/bids`, { auth: false });
509
+ }
510
+
325
511
  async bid(taskId: string, input: BidCreateInput): Promise<TaskBid> {
326
512
  return this.client.fetch(`/api/v1/tasks/${taskId}/bids`, {
327
513
  method: 'POST',
@@ -329,6 +515,12 @@ class TaskOperations {
329
515
  });
330
516
  }
331
517
 
518
+ async acceptBid(taskId: string, bidId: string): Promise<{ task: Task; acceptedBid: TaskBid; escrow?: EscrowTransaction }> {
519
+ return this.client.fetch(`/api/v1/tasks/${taskId}/bids/${bidId}/accept`, {
520
+ method: 'POST',
521
+ });
522
+ }
523
+
332
524
  async start(taskId: string): Promise<Task> {
333
525
  return this.client.fetch(`/api/v1/tasks/${taskId}/start`, {
334
526
  method: 'POST',
@@ -354,6 +546,13 @@ class TaskOperations {
354
546
  body: reason ? { reason } : undefined,
355
547
  });
356
548
  }
549
+
550
+ async dispute(taskId: string, reason: string): Promise<Dispute> {
551
+ return this.client.fetch(`/api/v1/tasks/${taskId}/dispute`, {
552
+ method: 'POST',
553
+ body: { reason },
554
+ });
555
+ }
357
556
  }
358
557
 
359
558
  class EventOperations {
@@ -451,14 +650,277 @@ class PaymentOperations {
451
650
  constructor(private readonly client: SwarmDockClient) {}
452
651
 
453
652
  async balance(): Promise<BalanceResult> {
653
+ await this.client.authenticate();
454
654
  const id = this.client.getAgentId();
455
655
  return this.client.fetch(`/api/v1/payments/agents/${id}/balance`);
456
656
  }
457
657
 
458
658
  async transactions(limit?: number, offset?: number): Promise<TransactionsResult> {
659
+ await this.client.authenticate();
459
660
  const id = this.client.getAgentId();
460
661
  return this.client.fetch(`/api/v1/payments/agents/${id}/transactions`, {
461
662
  query: { limit: limit ?? undefined, offset: offset ?? undefined },
462
663
  });
463
664
  }
464
665
  }
666
+
667
+ // -- Agent mode types --
668
+
669
+ export interface TaskContext {
670
+ id: string;
671
+ title: string;
672
+ description: string;
673
+ inputData: unknown;
674
+ inputFiles: string[];
675
+ skillRequirements: string[];
676
+ budgetMax: string;
677
+
678
+ /** Mark the task as in-progress */
679
+ start(): Promise<void>;
680
+ /** Submit the completed result */
681
+ complete(result: TaskResult): Promise<void>;
682
+ }
683
+
684
+ export interface TaskResult {
685
+ artifacts: Array<{ type: string; content: unknown }>;
686
+ files?: string[];
687
+ notes?: string;
688
+ }
689
+
690
+ export interface TaskListing {
691
+ id: string;
692
+ title: string;
693
+ description: string;
694
+ skillRequirements: string[];
695
+ budgetMin: string | null;
696
+ budgetMax: string;
697
+ matchingMode: string;
698
+ }
699
+
700
+ export interface SwarmDockAgentOptions {
701
+ baseUrl?: string;
702
+ name: string;
703
+ skills: Array<{
704
+ id: string;
705
+ name: string;
706
+ description: string;
707
+ category: string;
708
+ pricing?: { model?: string; basePrice: number };
709
+ examples?: string[];
710
+ inputModes?: string[];
711
+ outputModes?: string[];
712
+ }>;
713
+ framework?: string;
714
+ modelProvider?: string;
715
+ modelName?: string;
716
+ walletAddress: string;
717
+ privateKey?: string;
718
+ paymentPrivateKey?: `0x${string}`;
719
+ }
720
+
721
+ type TaskHandler = (task: TaskContext) => Promise<TaskResult>;
722
+ type TaskAvailableHandler = (listing: TaskListing) => Promise<void>;
723
+
724
+ const HEARTBEAT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
725
+
726
+ export class SwarmDockAgent {
727
+ private client: SwarmDockClient;
728
+ private readonly options: SwarmDockAgentOptions;
729
+ private taskHandlers: Map<string, TaskHandler> = new Map();
730
+ private taskAvailableHandler?: TaskAvailableHandler;
731
+ private heartbeatInterval?: ReturnType<typeof setInterval>;
732
+ private eventUnsubscribe?: () => void;
733
+ private running = false;
734
+
735
+ constructor(options: SwarmDockAgentOptions) {
736
+ this.options = options;
737
+ this.client = new SwarmDockClient({
738
+ baseUrl: options.baseUrl ?? 'https://api.swarmdock.ai',
739
+ privateKey: options.privateKey,
740
+ paymentPrivateKey: options.paymentPrivateKey,
741
+ });
742
+ }
743
+
744
+ /**
745
+ * Register a handler for tasks that match a specific skill.
746
+ * When this agent is assigned a task whose skillRequirements include
747
+ * the given skillId, the handler will be invoked.
748
+ */
749
+ onTask(skillId: string, handler: TaskHandler): void {
750
+ this.taskHandlers.set(skillId, handler);
751
+ }
752
+
753
+ /**
754
+ * Register a handler that fires when a new task is created on the
755
+ * marketplace that matches this agent's skills. Useful for auto-bidding.
756
+ */
757
+ onTaskAvailable(handler: TaskAvailableHandler): void {
758
+ this.taskAvailableHandler = handler;
759
+ }
760
+
761
+ /**
762
+ * Start the agent: register (or authenticate), begin heartbeat,
763
+ * and subscribe to the SSE event stream.
764
+ */
765
+ async start(): Promise<void> {
766
+ if (this.running) return;
767
+
768
+ // Register or authenticate
769
+ try {
770
+ await this.client.register({
771
+ displayName: this.options.name,
772
+ framework: this.options.framework,
773
+ modelProvider: this.options.modelProvider,
774
+ modelName: this.options.modelName,
775
+ walletAddress: this.options.walletAddress,
776
+ skills: this.options.skills.map((s) => ({
777
+ skillId: s.id,
778
+ skillName: s.name,
779
+ description: s.description,
780
+ category: s.category,
781
+ tags: [],
782
+ pricingModel: s.pricing?.model ?? 'fixed',
783
+ basePrice: String(s.pricing?.basePrice ?? 0),
784
+ examplePrompts: s.examples ?? [],
785
+ })),
786
+ });
787
+ } catch (err) {
788
+ // If already registered, authenticate instead
789
+ if (err instanceof SwarmDockError && (err.status === 409 || err.message.includes('already registered'))) {
790
+ await this.client.authenticate();
791
+ } else {
792
+ throw err;
793
+ }
794
+ }
795
+
796
+ this.running = true;
797
+
798
+ // Start heartbeat
799
+ this.heartbeatInterval = setInterval(async () => {
800
+ try {
801
+ await this.client.heartbeat();
802
+ } catch {
803
+ // Heartbeat failures are non-fatal; the next one will retry
804
+ }
805
+ }, HEARTBEAT_INTERVAL_MS);
806
+
807
+ // Subscribe to SSE events
808
+ const agentId = this.client.getAgentId();
809
+
810
+ this.client.events.subscribe((event) => {
811
+ this.handleEvent(event, agentId).catch(() => {
812
+ // Event handling errors are non-fatal
813
+ });
814
+ });
815
+
816
+ this.eventUnsubscribe = () => this.client.events.unsubscribe();
817
+ }
818
+
819
+ /**
820
+ * Stop the agent: unsubscribe from events, clear heartbeat,
821
+ * and mark as not running.
822
+ */
823
+ async stop(): Promise<void> {
824
+ if (!this.running) return;
825
+ this.running = false;
826
+
827
+ if (this.heartbeatInterval) {
828
+ clearInterval(this.heartbeatInterval);
829
+ this.heartbeatInterval = undefined;
830
+ }
831
+
832
+ if (this.eventUnsubscribe) {
833
+ this.eventUnsubscribe();
834
+ this.eventUnsubscribe = undefined;
835
+ }
836
+ }
837
+
838
+ /**
839
+ * Submit a bid on a task.
840
+ */
841
+ async bid(taskId: string, options: { price: number; confidence?: number; proposal?: string }): Promise<TaskBid> {
842
+ return this.client.tasks.bid(taskId, {
843
+ proposedPrice: String(options.price),
844
+ confidenceScore: options.confidence,
845
+ proposal: options.proposal,
846
+ portfolioRefs: [],
847
+ });
848
+ }
849
+
850
+ /** Expose the underlying client for advanced use cases */
851
+ getClient(): SwarmDockClient {
852
+ return this.client;
853
+ }
854
+
855
+ // -- Private helpers --
856
+
857
+ private async handleEvent(event: SSEEvent, agentId: string): Promise<void> {
858
+ if (!this.running) return;
859
+
860
+ const data = event.data as Record<string, unknown>;
861
+
862
+ if (event.type === 'task.assigned' && data.assigneeId === agentId) {
863
+ await this.handleTaskAssigned(data.taskId as string);
864
+ } else if (event.type === 'task.created' && this.taskAvailableHandler) {
865
+ await this.handleTaskCreated(data);
866
+ }
867
+ }
868
+
869
+ private async handleTaskAssigned(taskId: string): Promise<void> {
870
+ const detail = await this.client.tasks.get(taskId);
871
+
872
+ // Find the first matching handler based on skill requirements
873
+ let matchedHandler: TaskHandler | undefined;
874
+ for (const skillReq of detail.skillRequirements ?? []) {
875
+ matchedHandler = this.taskHandlers.get(skillReq);
876
+ if (matchedHandler) break;
877
+ }
878
+
879
+ if (!matchedHandler) return;
880
+
881
+ const ctx: TaskContext = {
882
+ id: detail.id,
883
+ title: detail.title,
884
+ description: detail.description ?? '',
885
+ inputData: detail.inputData ?? null,
886
+ inputFiles: detail.inputFiles ?? [],
887
+ skillRequirements: detail.skillRequirements ?? [],
888
+ budgetMax: detail.budgetMax ?? '0',
889
+
890
+ start: async () => {
891
+ await this.client.tasks.start(taskId);
892
+ },
893
+
894
+ complete: async (result: TaskResult) => {
895
+ await this.client.tasks.submit(taskId, {
896
+ artifacts: result.artifacts,
897
+ files: result.files ?? [],
898
+ notes: result.notes,
899
+ });
900
+ },
901
+ };
902
+
903
+ const result = await matchedHandler(ctx);
904
+
905
+ // If the handler returns a result directly, auto-submit it
906
+ if (result && result.artifacts) {
907
+ await ctx.complete(result);
908
+ }
909
+ }
910
+
911
+ private async handleTaskCreated(data: Record<string, unknown>): Promise<void> {
912
+ if (!this.taskAvailableHandler) return;
913
+
914
+ const listing: TaskListing = {
915
+ id: data.taskId as string,
916
+ title: (data.title as string) ?? '',
917
+ description: (data.description as string) ?? '',
918
+ skillRequirements: (data.skillRequirements as string[]) ?? [],
919
+ budgetMin: (data.budgetMin as string) ?? null,
920
+ budgetMax: (data.budgetMax as string) ?? '0',
921
+ matchingMode: (data.matchingMode as string) ?? 'manual',
922
+ };
923
+
924
+ await this.taskAvailableHandler(listing);
925
+ }
926
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { SwarmDockClient } from './client.js';
1
+ export { SwarmDockClient, SwarmDockAgent } from './client.js';
2
2
  export type {
3
3
  SwarmDockClientOptions,
4
4
  RegisterParams,
@@ -7,6 +7,13 @@ export type {
7
7
  TransactionsResult,
8
8
  TaskListResult,
9
9
  TaskDetailResult,
10
+ RatingsSummary,
11
+ PortfolioResult,
12
+ ReputationResult,
13
+ TaskContext,
14
+ TaskResult,
15
+ TaskListing,
16
+ SwarmDockAgentOptions,
10
17
  } from './client.js';
11
18
  export { SwarmDockError } from './errors.js';
12
19
 
@@ -17,9 +24,12 @@ export type {
17
24
  TaskBid,
18
25
  EscrowTransaction,
19
26
  AgentRating,
27
+ Dispute,
20
28
  AATPayload,
21
29
  AgentCard,
22
30
  AgentCardSkill,
31
+ PortfolioItem,
32
+ StoredArtifactRef,
23
33
  SSEEvent,
24
34
  AgentUpdateInput,
25
35
  TaskCreateInput,