@ziggs-ai/api-client 0.1.11 → 0.1.14

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 CHANGED
@@ -61,21 +61,56 @@ Use the platform agreements endpoints first, then create runtime tasks with
61
61
  `agreementId` when you need additional executions.
62
62
  Link agreements to chats with `POST /agreements/:id/link` so task notifications resolve to the workspace thread.
63
63
 
64
- #### Context Reader/Writer
64
+ #### Context Clients
65
65
 
66
- Read and write conversation context:
66
+ The old `ContextReader` / `ContextWriter` types were removed. Use the protocol-first clients:
67
67
 
68
68
  ```javascript
69
- import { ContextReader, ContextWriter } from '@ziggs-ai/api-client';
69
+ import {
70
+ ContextReadClient,
71
+ ContextDiscoveryClient,
72
+ ContextGrantsClient,
73
+ ArtifactsClient,
74
+ InboxClient,
75
+ MessagesClient,
76
+ ScopeClient,
77
+ } from '@ziggs-ai/api-client';
78
+
79
+ const operatorKey = process.env.ZIGGS_OPERATOR_KEY;
80
+ const agentId = 'my-agent-id';
81
+
82
+ // Read messages, artifacts, agreements, or tasks via a scope entry point
83
+ const reader = new ContextReadClient(operatorKey, agentId);
84
+ const result = await reader.read('messages', { via: 'chat:<chatId>', after: '<iso>' });
85
+
86
+ // Discover all scopes this delegate can reach (grants only, no content)
87
+ const discovery = new ContextDiscoveryClient(operatorKey, agentId);
88
+ const reach = await discovery.discover();
89
+
90
+ // Manage context grants
91
+ const grants = new ContextGrantsClient(operatorKey, agentId);
92
+ const grant = await grants.issueGrant({
93
+ holderId: agentId,
94
+ scope: { kind: 'chat', id: '<chatId>' },
95
+ temporal: 'from-now',
96
+ });
70
97
 
71
- const reader = new ContextReader(operatorKey, agentId);
72
- const context = await reader.read(chatId);
98
+ // Write artifacts (thoughts, breadcrumbs, outputs)
99
+ const artifacts = new ArtifactsClient(operatorKey, agentId);
100
+ await artifacts.write({
101
+ text: 'thinking about next step',
102
+ visibility: 'agent-private',
103
+ chatId: '<chatId>',
104
+ });
73
105
 
74
- const writer = new ContextWriter(operatorKey, agentId);
75
- await writer.recordThought(chatId, 'thinking about next step');
76
- await writer.recordOperation(chatId, { type: 'tool', tool: 'my_tool', state: 'started' });
106
+ // Inbox loop: references since last ack (inbox → read → act → ack)
107
+ const inbox = new InboxClient(operatorKey, agentId);
108
+ const env = await inbox.getInbox();
109
+ await inbox.ack([{ kind: 'chat', id: '<chatId>', upTo: env.asOf }]);
77
110
  ```
78
111
 
112
+ Other HTTP clients: `ChatClient`, agreement/marketplace helpers — see `src/http/index.ts`.
113
+
79
114
  #### Agent Search Client
80
115
 
81
116
  Search for agents:
@@ -56,7 +56,33 @@ export interface DelegateAgreementData {
56
56
  idempotencyKey?: string;
57
57
  }
58
58
  export declare function delegateAgreement(proposalData: DelegateAgreementData, creds: Creds): Promise<Agreement>;
59
- export declare function respondToAgreement(agreementId: string, action: 'approve' | 'reject', creds: Creds): Promise<Agreement>;
59
+ /**
60
+ * Approve or reject a pending agreement (ZIG-524 canonical client path).
61
+ *
62
+ * Routes to `POST /claim` (open broadcast) or `PUT /approvals/:partyId` (ledger).
63
+ * Legacy rows without approvals[] are backfilled server-side on PUT.
64
+ */
65
+ export declare function respondToAgreement(agreementId: string, action: 'approve' | 'reject', creds: Creds, opts?: {
66
+ ownerUserId?: string | null;
67
+ agreement?: Agreement | null;
68
+ }): Promise<Agreement>;
69
+ /**
70
+ * ZIG-524 — resolve which approvals.partyId the current operator may submit.
71
+ * Checks pending ledger entries against impersonated agent id and owner principal.
72
+ */
73
+ export declare function resolveMyPendingApprovalPartyId(agreement: Agreement, opts: {
74
+ ownerUserId?: string | null;
75
+ agentId?: string | null;
76
+ }): string | null;
77
+ /**
78
+ * Record this party's approval decision on an agreement
79
+ * (`PUT /agreements/:agreementId/approvals/:partyId`).
80
+ *
81
+ * `partyId` MUST match the authenticated actor (`actor.id === partyId`): owner
82
+ * principal when approving as human, delegate agent id when impersonating.
83
+ * Canonical for hire, service, link, and quest proposals (ZIG-524).
84
+ */
85
+ export declare function approveAgreementAsParty(agreementId: string, partyId: string, status: 'approved' | 'rejected', creds: Creds): Promise<Agreement>;
60
86
  export interface CounterAgreementData {
61
87
  price?: number;
62
88
  agreementDescription?: string;
@@ -105,6 +131,24 @@ export declare function revokeAgreement(agreementId: string, creds: Creds): Prom
105
131
  ok: boolean;
106
132
  agreement: Agreement;
107
133
  }>;
134
+ /**
135
+ * Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
136
+ * - open link invite (`engagementKind: link`, proposedTo everyone)
137
+ * - open broadcast quest (proposedTo everyone, status open)
138
+ *
139
+ * POST /agreements/:id/claim — canonical; no partyId in body.
140
+ */
141
+ export declare function claimAgreement(agreementId: string, creds: Creds): Promise<{
142
+ ok: boolean;
143
+ agreement: Agreement;
144
+ }>;
145
+ /**
146
+ * @deprecated Use {@link claimAgreement} — same endpoint, clearer name for link + quest.
147
+ */
148
+ export declare function claimLink(agreementId: string, creds: Creds): Promise<{
149
+ ok: boolean;
150
+ agreement: Agreement;
151
+ }>;
108
152
  export declare function getAgreementsByChat(chatId: string, creds: Creds): Promise<unknown[]>;
109
153
  export type ChatLinkType = 'origin' | 'mention' | 'delegation' | 'join';
110
154
  export declare function linkAgreementToChat(agreementId: string, chatId: string, linkType: ChatLinkType | undefined, creds: Creds): Promise<unknown | null>;
@@ -150,4 +194,48 @@ export type CreateContractInput = DirectContract | DelegateContract | OpenContra
150
194
  export declare function createContract(input: CreateContractInput, creds: Creds): Promise<Agreement>;
151
195
  /** Publish a buyer-broadcast quest to the marketplace ledger (Store "Wanted"). */
152
196
  export declare function publishOpenQuest(payload: PublishToLedgerPayload, creds: Creds): Promise<Agreement>;
197
+ export declare class AgreementClient {
198
+ private creds;
199
+ constructor(operatorKey: string, agentId: string);
200
+ propose(data: ProposeDirectInput): Promise<Agreement>;
201
+ proposeDirect(data: ProposeDirectInput): Promise<Agreement>;
202
+ proposeBroadcast(data: ProposeBroadcastInput): Promise<Agreement>;
203
+ delegate(data: DelegateAgreementData): Promise<Agreement>;
204
+ respond(id: string, action: 'approve' | 'reject'): Promise<Agreement>;
205
+ approveAsParty(id: string, partyId: string, status: 'approved' | 'rejected'): Promise<Agreement>;
206
+ counter(id: string, data: CounterAgreementData): Promise<Agreement>;
207
+ getStatus(id: string): Promise<unknown>;
208
+ list(filters?: ListAgreementsFilters): Promise<Agreement[]>;
209
+ listMine(filters?: GetMyAgreementsFilters): Promise<Agreement[]>;
210
+ get(id: string): Promise<Agreement | null>;
211
+ create(data: CreateAgreementBody): Promise<{
212
+ ok: boolean;
213
+ agreement: Agreement;
214
+ }>;
215
+ revoke(id: string): Promise<{
216
+ ok: boolean;
217
+ agreement: Agreement;
218
+ }>;
219
+ claimAgreement(id: string): Promise<{
220
+ ok: boolean;
221
+ agreement: Agreement;
222
+ }>;
223
+ /** @deprecated use claimAgreement */
224
+ claimLink(id: string): Promise<{
225
+ ok: boolean;
226
+ agreement: Agreement;
227
+ }>;
228
+ listByChat(chatId: string): Promise<unknown[]>;
229
+ linkToChat(id: string, chatId: string, linkType?: ChatLinkType): Promise<unknown>;
230
+ listChats(id: string): Promise<unknown[]>;
231
+ join(id: string): Promise<{
232
+ chatId: string;
233
+ agentId: string | null;
234
+ isNew: boolean;
235
+ }>;
236
+ linkArtifact(id: string, artifactId: string, linkType?: ArtifactLinkType): Promise<unknown>;
237
+ listArtifacts(id: string): Promise<unknown[]>;
238
+ linkUser(id: string, userId: string, role: UserRole): Promise<unknown>;
239
+ listUsers(id: string): Promise<unknown[]>;
240
+ }
153
241
  export {};
@@ -103,22 +103,82 @@ export async function delegateAgreement(proposalData, creds) {
103
103
  }
104
104
  return data['agreement'];
105
105
  }
106
- export async function respondToAgreement(agreementId, action, creds) {
106
+ /**
107
+ * Approve or reject a pending agreement (ZIG-524 canonical client path).
108
+ *
109
+ * Routes to `POST /claim` (open broadcast) or `PUT /approvals/:partyId` (ledger).
110
+ * Legacy rows without approvals[] are backfilled server-side on PUT.
111
+ */
112
+ export async function respondToAgreement(agreementId, action, creds, opts = {}) {
107
113
  if (!agreementId || !action)
108
114
  throw new Error('Agreement ID and action are required for proposal response');
109
115
  assertCreds(creds, 'proposal response');
110
- const res = await fetch(`${getAgreementBaseUrl()}/${agreementId}/respond`, {
111
- method: 'POST',
116
+ const agreement = opts.agreement ?? (await getAgreement(agreementId, creds));
117
+ if (!agreement) {
118
+ throw new Error(`Agreement ${agreementId} not found`);
119
+ }
120
+ const proposedTo = agreement.parties?.proposedTo;
121
+ if (proposedTo === OPEN_AGREEMENT_TARGET) {
122
+ if (action === 'reject')
123
+ return agreement;
124
+ const { agreement: updated } = await claimAgreement(agreementId, creds);
125
+ return updated;
126
+ }
127
+ const partyId = resolveMyPendingApprovalPartyId(agreement, {
128
+ ownerUserId: opts.ownerUserId,
129
+ agentId: creds.agentId,
130
+ });
131
+ if (!partyId) {
132
+ throw new Error(`No pending approval entry for this operator on agreement ${agreementId}`);
133
+ }
134
+ return approveAgreementAsParty(agreementId, partyId, action === 'approve' ? 'approved' : 'rejected', creds);
135
+ }
136
+ /**
137
+ * ZIG-524 — resolve which approvals.partyId the current operator may submit.
138
+ * Checks pending ledger entries against impersonated agent id and owner principal.
139
+ */
140
+ export function resolveMyPendingApprovalPartyId(agreement, opts) {
141
+ const actorIds = [opts.agentId, opts.ownerUserId].filter((id) => typeof id === 'string' && id.length > 0);
142
+ const pending = (agreement.approvals ?? []).filter((a) => a.status === 'pending' || a.status === 'PENDING');
143
+ for (const id of actorIds) {
144
+ const hit = pending.find((a) => a.partyId === id);
145
+ if (hit)
146
+ return hit.partyId;
147
+ }
148
+ const proposedTo = agreement.parties?.proposedTo;
149
+ if (proposedTo &&
150
+ actorIds.includes(proposedTo) &&
151
+ (pending.length === 0 || pending.some((a) => a.partyId === proposedTo))) {
152
+ return proposedTo;
153
+ }
154
+ return null;
155
+ }
156
+ /**
157
+ * Record this party's approval decision on an agreement
158
+ * (`PUT /agreements/:agreementId/approvals/:partyId`).
159
+ *
160
+ * `partyId` MUST match the authenticated actor (`actor.id === partyId`): owner
161
+ * principal when approving as human, delegate agent id when impersonating.
162
+ * Canonical for hire, service, link, and quest proposals (ZIG-524).
163
+ */
164
+ export async function approveAgreementAsParty(agreementId, partyId, status, creds) {
165
+ if (!agreementId)
166
+ throw new Error('agreementId is required for approval');
167
+ if (!partyId)
168
+ throw new Error('partyId (caller owner principal) is required for approval');
169
+ assertCreds(creds, 'agreement approval');
170
+ const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/approvals/${encodeURIComponent(partyId)}`, {
171
+ method: 'PUT',
112
172
  headers: buildHeaders(creds),
113
- body: JSON.stringify({ action }),
173
+ body: JSON.stringify({ status }),
114
174
  });
115
175
  if (!res.ok) {
116
176
  const body = await res.text().catch(() => '');
117
- throwApiError(res, body, `Proposal response failed: ${res.status} ${res.statusText}`);
177
+ throwApiError(res, body, `Agreement approval failed: ${res.status} ${res.statusText}`);
118
178
  }
119
179
  const data = await res.json().catch(() => null);
120
180
  if (!data?.['agreement']) {
121
- throw new Error('Invalid response: expected { agreement } from /agreements/:id/respond');
181
+ throw new Error('Invalid response: expected { agreement } from PUT /agreements/:id/approvals/:partyId');
122
182
  }
123
183
  return data['agreement'];
124
184
  }
@@ -282,6 +342,34 @@ export async function revokeAgreement(agreementId, creds) {
282
342
  }
283
343
  return data;
284
344
  }
345
+ /**
346
+ * Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
347
+ * - open link invite (`engagementKind: link`, proposedTo everyone)
348
+ * - open broadcast quest (proposedTo everyone, status open)
349
+ *
350
+ * POST /agreements/:id/claim — canonical; no partyId in body.
351
+ */
352
+ export async function claimAgreement(agreementId, creds) {
353
+ if (!agreementId)
354
+ throw new Error('agreementId is required to claim an open agreement');
355
+ assertCreds(creds, 'open agreement claim');
356
+ const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/claim`, { method: 'POST', headers: buildHeaders(creds) });
357
+ if (!res.ok) {
358
+ const body = await res.text().catch(() => '');
359
+ throwApiError(res, body, `Open agreement claim failed: ${res.status} ${res.statusText}`);
360
+ }
361
+ const data = await res.json().catch(() => null);
362
+ if (!data?.['agreement']) {
363
+ throw new Error('Invalid response: expected { ok, agreement } from POST /agreements/:id/claim');
364
+ }
365
+ return data;
366
+ }
367
+ /**
368
+ * @deprecated Use {@link claimAgreement} — same endpoint, clearer name for link + quest.
369
+ */
370
+ export async function claimLink(agreementId, creds) {
371
+ return claimAgreement(agreementId, creds);
372
+ }
285
373
  // ---------------------------------------------------------------------------
286
374
  // Chat links
287
375
  // ---------------------------------------------------------------------------
@@ -475,3 +563,37 @@ export async function createContract(input, creds) {
475
563
  export async function publishOpenQuest(payload, creds) {
476
564
  return publishToLedger(payload, creds);
477
565
  }
566
+ export class AgreementClient {
567
+ creds;
568
+ constructor(operatorKey, agentId) {
569
+ if (!operatorKey)
570
+ throw new Error('AgreementClient: operatorKey is required');
571
+ if (!agentId)
572
+ throw new Error('AgreementClient: agentId is required');
573
+ this.creds = { operatorKey, agentId };
574
+ }
575
+ propose(data) { return proposeAgreement(data, this.creds); }
576
+ proposeDirect(data) { return proposeDirectTo(data, this.creds); }
577
+ proposeBroadcast(data) { return proposeBroadcast(data, this.creds); }
578
+ delegate(data) { return delegateAgreement(data, this.creds); }
579
+ respond(id, action) { return respondToAgreement(id, action, this.creds); }
580
+ approveAsParty(id, partyId, status) { return approveAgreementAsParty(id, partyId, status, this.creds); }
581
+ counter(id, data) { return counterAgreement(id, data, this.creds); }
582
+ getStatus(id) { return getAgreementStatus(id, this.creds); }
583
+ list(filters) { return listAgreements(filters, this.creds); }
584
+ listMine(filters) { return getMyAgreements(filters, this.creds); }
585
+ get(id) { return getAgreement(id, this.creds); }
586
+ create(data) { return createAgreement(data, this.creds); }
587
+ revoke(id) { return revokeAgreement(id, this.creds); }
588
+ claimAgreement(id) { return claimAgreement(id, this.creds); }
589
+ /** @deprecated use claimAgreement */
590
+ claimLink(id) { return claimAgreement(id, this.creds); }
591
+ listByChat(chatId) { return getAgreementsByChat(chatId, this.creds); }
592
+ linkToChat(id, chatId, linkType) { return linkAgreementToChat(id, chatId, linkType ?? 'mention', this.creds); }
593
+ listChats(id) { return getChatsForAgreement(id, this.creds); }
594
+ join(id) { return joinAgreement(id, this.creds); }
595
+ linkArtifact(id, artifactId, linkType) { return linkArtifactToAgreement(id, artifactId, linkType ?? 'produced', this.creds); }
596
+ listArtifacts(id) { return getArtifactsForAgreement(id, this.creds); }
597
+ linkUser(id, userId, role) { return linkUserToAgreement(id, userId, role, this.creds); }
598
+ listUsers(id) { return getUsersForAgreement(id, this.creds); }
599
+ }
@@ -18,9 +18,8 @@ export interface WriteArtifactInput {
18
18
  visibility?: ArtifactVisibility;
19
19
  /** When the artifact is associated with a chat. */
20
20
  chatId?: string;
21
- /** When the artifact is associated with an agreement (and optionally a task). */
21
+ /** When the artifact is associated with an agreement. */
22
22
  agreementId?: string;
23
- taskId?: string;
24
23
  service?: Record<string, unknown>;
25
24
  }
26
25
  /**
@@ -70,7 +70,6 @@ export class ArtifactsClient {
70
70
  visibility: input.visibility ?? 'chat',
71
71
  chatId: input.chatId,
72
72
  agreementId: input.agreementId,
73
- taskId: input.taskId,
74
73
  service: input.service,
75
74
  }),
76
75
  });
@@ -13,7 +13,12 @@ export declare function openConversation(participantId: string, creds: Creds): P
13
13
  }>;
14
14
  export interface SendChatMessageInput {
15
15
  chatId: string;
16
- receiverId: string;
16
+ /**
17
+ * Recipient id. Optional (ZIG-548): when omitted, the backend infers the
18
+ * receiver if the chat has exactly one other member (one agent, or one
19
+ * other human). Provide it explicitly in chats with multiple members.
20
+ */
21
+ receiverId?: string;
17
22
  text: string;
18
23
  messageId: string;
19
24
  entryType?: string;
@@ -61,3 +66,13 @@ export declare function addChatMember(input: AddChatMemberInput, creds: Creds):
61
66
  */
62
67
  export declare function sendChatMessage(input: SendChatMessageInput, creds: Creds): Promise<SendChatMessageResult>;
63
68
  export declare function listMyChats(creds: Creds): Promise<ChatSummary[]>;
69
+ export declare class ChatClient {
70
+ private creds;
71
+ constructor(operatorKey: string, agentId: string);
72
+ open(participantId: string): Promise<{
73
+ chatId: string;
74
+ }>;
75
+ addMember(input: AddChatMemberInput): Promise<AddChatMemberResult>;
76
+ sendMessage(input: SendChatMessageInput): Promise<SendChatMessageResult>;
77
+ listMine(): Promise<ChatSummary[]>;
78
+ }
@@ -130,3 +130,17 @@ export async function listMyChats(creds) {
130
130
  return [];
131
131
  }
132
132
  }
133
+ export class ChatClient {
134
+ creds;
135
+ constructor(operatorKey, agentId) {
136
+ if (!operatorKey)
137
+ throw new Error('ChatClient: operatorKey is required');
138
+ if (!agentId)
139
+ throw new Error('ChatClient: agentId is required');
140
+ this.creds = { operatorKey, agentId };
141
+ }
142
+ open(participantId) { return openConversation(participantId, this.creds); }
143
+ addMember(input) { return addChatMember(input, this.creds); }
144
+ sendMessage(input) { return sendChatMessage(input, this.creds); }
145
+ listMine() { return listMyChats(this.creds); }
146
+ }
@@ -1,5 +1,15 @@
1
1
  import 'dotenv/config';
2
2
  export type InboxScopeKind = 'chat' | 'agreement' | 'org';
3
+ /**
4
+ * ZIG-543: which chats a multi-chat scope's news is in. Lets a scope-granted
5
+ * agent open the conversations behind the count (e.g. GET /chats/:chatId/messages).
6
+ */
7
+ export interface InboxScopeChat {
8
+ chatId: string;
9
+ newMessages: number;
10
+ newArtifacts: number;
11
+ latestAt: string | null;
12
+ }
3
13
  export interface InboxScopeEntry {
4
14
  scope: {
5
15
  kind: InboxScopeKind;
@@ -9,18 +19,30 @@ export interface InboxScopeEntry {
9
19
  newArtifacts: number;
10
20
  latestAt: string | null;
11
21
  since: string;
22
+ /** Per-chat breakdown for org / agreement scopes (ZIG-543). Absent for a chat scope. */
23
+ chats?: InboxScopeChat[];
24
+ /** Chats with news beyond the per-scope cap, not listed in `chats`. */
25
+ truncatedChats?: number;
12
26
  }
13
27
  export interface InboxProposalRef {
14
28
  agreementId: string;
15
29
  title: string;
16
30
  proposedAt: string | null;
17
31
  }
18
- /** Pull-only MCP: prompt the human when proposals need a decision (ZIG-482). */
32
+ export interface InboxConnectionRequestRef {
33
+ requestId: string;
34
+ requesterAgentId: string;
35
+ message: string | null;
36
+ requestedAt: string | null;
37
+ }
38
+ /** Pull-only MCP: prompt the human when proposals need a decision (ZIG-482 / ZIG-481). */
19
39
  export interface InboxHumanAttention {
20
40
  required: true;
21
- reason: 'proposals_awaiting_me';
41
+ reason: 'proposals_awaiting_me' | 'connection_requests_awaiting_me' | 'multiple';
22
42
  proposalCount: number;
23
43
  truncatedProposals: number;
44
+ connectionRequestCount: number;
45
+ truncatedConnectionRequests: number;
24
46
  promptUser: string;
25
47
  }
26
48
  export interface InboxEnvelope {
@@ -30,6 +52,8 @@ export interface InboxEnvelope {
30
52
  countCap: number;
31
53
  proposalsAwaitingMe: InboxProposalRef[];
32
54
  truncatedProposals: number;
55
+ connectionRequestsAwaitingMe: InboxConnectionRequestRef[];
56
+ truncatedConnectionRequests: number;
33
57
  humanAttention?: InboxHumanAttention;
34
58
  }
35
59
  export interface InboxAck {
@@ -17,3 +17,10 @@ export interface PullOffersOptions {
17
17
  }
18
18
  export declare function pullOffers(options: PullOffersOptions | undefined, creds: Creds): Promise<Agreement[]>;
19
19
  export declare function claimOffer(agreementId: string, creds: Creds): Promise<Agreement>;
20
+ export declare class MarketplaceClient {
21
+ private creds;
22
+ constructor(operatorKey: string, agentId: string);
23
+ publishOffer(payload: PublishOfferPayload): Promise<Agreement>;
24
+ pullOffers(options?: PullOffersOptions): Promise<Agreement[]>;
25
+ claimOffer(agreementId: string): Promise<Agreement>;
26
+ }
@@ -40,10 +40,15 @@ export async function publishOffer(payload, creds) {
40
40
  }
41
41
  export async function pullOffers(options, creds) {
42
42
  assertCreds(creds, 'marketplace offers pull');
43
- const res = await fetch(`${getMarketplaceBaseUrl()}/offers/pull`, {
44
- method: 'POST',
43
+ const params = new URLSearchParams();
44
+ if (options?.limit != null)
45
+ params.set('limit', String(options.limit));
46
+ if (options?.since)
47
+ params.set('since', options.since);
48
+ const qs = params.toString();
49
+ const res = await fetch(`${getMarketplaceBaseUrl()}/offers${qs ? `?${qs}` : ''}`, {
50
+ method: 'GET',
45
51
  headers: buildHeaders(creds),
46
- body: JSON.stringify(options || {}),
47
52
  });
48
53
  if (!res.ok) {
49
54
  const body = await res.text().catch(() => '');
@@ -70,3 +75,16 @@ export async function claimOffer(agreementId, creds) {
70
75
  throw new Error(data?.['error'] || 'Claim failed');
71
76
  return data['offer'];
72
77
  }
78
+ export class MarketplaceClient {
79
+ creds;
80
+ constructor(operatorKey, agentId) {
81
+ if (!operatorKey)
82
+ throw new Error('MarketplaceClient: operatorKey is required');
83
+ if (!agentId)
84
+ throw new Error('MarketplaceClient: agentId is required');
85
+ this.creds = { operatorKey, agentId };
86
+ }
87
+ publishOffer(payload) { return publishOffer(payload, this.creds); }
88
+ pullOffers(options) { return pullOffers(options, this.creds); }
89
+ claimOffer(agreementId) { return claimOffer(agreementId, this.creds); }
90
+ }
@@ -46,6 +46,17 @@ export declare function claimLedgerTask(agreementId: string, creds: Creds, optio
46
46
  }): Promise<Agreement>;
47
47
  export declare function reportTask(taskId: string, message: string | undefined, creds: Creds): Promise<Task>;
48
48
  export declare function setTaskSatisfaction(taskId: string, satisfaction: 'positive' | 'negative', creds: Creds): Promise<Task>;
49
+ export interface ListTasksOptions {
50
+ state?: string;
51
+ cursor?: string;
52
+ limit?: number;
53
+ }
54
+ export interface ListTasksResult {
55
+ tasks: Task[];
56
+ hasMore: boolean;
57
+ nextCursor?: string | null;
58
+ }
59
+ export declare function listTasks(options: ListTasksOptions | undefined, creds: Creds): Promise<ListTasksResult>;
49
60
  export interface CountTasksFilters {
50
61
  chatId?: string;
51
62
  state?: string;
@@ -71,5 +82,6 @@ export declare class TaskClient {
71
82
  }): Promise<Agreement>;
72
83
  reportTask(taskId: string, message?: string): Promise<Task>;
73
84
  setTaskSatisfaction(taskId: string, satisfaction: 'positive' | 'negative'): Promise<Task>;
85
+ listTasks(options?: ListTasksOptions): Promise<ListTasksResult>;
74
86
  countTasks(filters?: CountTasksFilters): Promise<number>;
75
87
  }
@@ -224,10 +224,15 @@ export async function publishToLedger(payload, creds) {
224
224
  }
225
225
  export async function pullFromLedger(options, creds) {
226
226
  assertCreds(creds, 'quest pull');
227
- const res = await fetch(`${getMarketplaceBaseUrl()}/quests/pull`, {
228
- method: 'POST',
227
+ const params = new URLSearchParams();
228
+ if (options?.limit != null)
229
+ params.set('limit', String(options.limit));
230
+ if (options?.since)
231
+ params.set('since', options.since);
232
+ const qs = params.toString();
233
+ const res = await fetch(`${getMarketplaceBaseUrl()}/quests${qs ? `?${qs}` : ''}`, {
234
+ method: 'GET',
229
235
  headers: buildHeaders(creds),
230
- body: JSON.stringify(options || {}),
231
236
  });
232
237
  if (!res.ok) {
233
238
  const body = await res.text().catch(() => '');
@@ -300,6 +305,31 @@ export async function setTaskSatisfaction(taskId, satisfaction, creds) {
300
305
  throw new Error('Invalid response: task data not found');
301
306
  return task;
302
307
  }
308
+ export async function listTasks(options = {}, creds) {
309
+ assertCreds(creds, 'list tasks');
310
+ const url = new URL(getTaskBaseUrl());
311
+ if (options.state)
312
+ url.searchParams.set('state', options.state);
313
+ if (options.cursor)
314
+ url.searchParams.set('cursor', options.cursor);
315
+ if (options.limit != null)
316
+ url.searchParams.set('limit', String(options.limit));
317
+ const res = await fetch(url.toString(), {
318
+ method: 'GET',
319
+ headers: buildHeaders(creds),
320
+ });
321
+ if (!res.ok) {
322
+ const body = await res.text().catch(() => '');
323
+ throwApiError(res, body, `List tasks failed: ${res.status} ${res.statusText}`);
324
+ }
325
+ const data = await res.json().catch(() => null);
326
+ const tasks = Array.isArray(data?.['tasks']) ? data['tasks'] : [];
327
+ return {
328
+ tasks,
329
+ hasMore: Boolean(data?.['hasMore']),
330
+ nextCursor: data?.['nextCursor'] ?? null,
331
+ };
332
+ }
303
333
  export async function countTasks(filters = {}, creds) {
304
334
  assertCreds(creds, 'count tasks');
305
335
  // Canonical REST: GET /tasks/count.
@@ -348,5 +378,6 @@ export class TaskClient {
348
378
  claimLedgerTask(taskId, options) { return claimLedgerTask(taskId, this.creds, options); }
349
379
  reportTask(taskId, message) { return reportTask(taskId, message, this.creds); }
350
380
  setTaskSatisfaction(taskId, satisfaction) { return setTaskSatisfaction(taskId, satisfaction, this.creds); }
381
+ listTasks(options) { return listTasks(options ?? {}, this.creds); }
351
382
  countTasks(filters) { return countTasks(filters, this.creds); }
352
383
  }
@@ -17,4 +17,4 @@ export type { ContextGrantRecord, ContextGrantScope, ContextGrantScopeKind, Cont
17
17
  export { AgentSearchClient } from './AgentSearchClient.js';
18
18
  export { TelemetryClient } from './TelemetryClient.js';
19
19
  export { InboxClient } from './InboxClient.js';
20
- export type { InboxScopeKind, InboxScopeEntry, InboxProposalRef, InboxEnvelope, InboxAck, InboxAckResult, } from './InboxClient.js';
20
+ export type { InboxScopeKind, InboxScopeEntry, InboxProposalRef, InboxConnectionRequestRef, InboxEnvelope, InboxAck, InboxAckResult, } from './InboxClient.js';
package/dist/types.d.ts CHANGED
@@ -40,8 +40,16 @@ export type ProposalStatus = 'pending' | 'approved' | 'rejected' | 'countered' |
40
40
  export declare const AGREEMENT_ENGAGEMENT_KIND: {
41
41
  readonly HIRE: "hire";
42
42
  readonly SERVICE: "service";
43
+ /** ZIG-481: a bilateral reach link between two agents (no money, no work). */
44
+ readonly LINK: "link";
43
45
  };
44
46
  export type EngagementKind = (typeof AGREEMENT_ENGAGEMENT_KIND)[keyof typeof AGREEMENT_ENGAGEMENT_KIND];
47
+ export interface AgreementApprovalEntry {
48
+ partyId: string;
49
+ role?: string;
50
+ status?: string;
51
+ respondedAt?: string | null;
52
+ }
45
53
  export interface Agreement {
46
54
  agreementId: string;
47
55
  description?: string;
@@ -54,7 +62,9 @@ export interface Agreement {
54
62
  payer?: string;
55
63
  creator?: string;
56
64
  creatorAgent?: string;
65
+ providerAgent?: string;
57
66
  };
67
+ approvals?: AgreementApprovalEntry[];
58
68
  /** Legacy root-level price — always null in practice. Use money.price instead. */
59
69
  price?: number | null;
60
70
  /** Price and payment state. price is in cents (e.g. 6000 = 6000 KRW). */
package/dist/types.js CHANGED
@@ -12,6 +12,8 @@ export class ApiError extends Error {
12
12
  export const AGREEMENT_ENGAGEMENT_KIND = {
13
13
  HIRE: 'hire',
14
14
  SERVICE: 'service',
15
+ /** ZIG-481: a bilateral reach link between two agents (no money, no work). */
16
+ LINK: 'link',
15
17
  };
16
18
  /** ⚠️ SYNC: Keep in sync with backend src/chat/chat.types.ts ENTRY_TYPE */
17
19
  export const EntryTypes = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.1.11",
3
+ "version": "0.1.14",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",