@ziggs-ai/api-client 0.1.25 → 0.1.26

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.
@@ -17,7 +17,12 @@ export interface ProposeTerms {
17
17
  agreementDescription?: string;
18
18
  parentAgreementId?: string;
19
19
  parentTaskId?: string;
20
- payerId?: string;
20
+ /**
21
+ * Who does the work. Required on direct proposals (your own id = you offer;
22
+ * the proposedTo id = you commission the recipient); forbidden on
23
+ * broadcasts. The payer is always derived server-side as the non-providing
24
+ * side — there is no payer input.
25
+ */
21
26
  providerId?: string;
22
27
  plan?: unknown;
23
28
  planReviewTiming?: PlanReviewTiming;
@@ -146,6 +151,12 @@ export declare function revokeAgreement(agreementId: string, creds: Creds): Prom
146
151
  ok: boolean;
147
152
  agreement: Agreement;
148
153
  }>;
154
+ /** ZIG-832: mark an agreement fulfilled (complete). A provider closing its own
155
+ * delivered work — party-gated server-side. */
156
+ export declare function fulfillAgreement(agreementId: string, creds: Creds): Promise<{
157
+ ok: boolean;
158
+ agreement: Agreement;
159
+ }>;
149
160
  /**
150
161
  * Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
151
162
  * - open link invite (`engagementKind: link`, proposedTo everyone)
@@ -200,6 +211,10 @@ export declare class AgreementClient {
200
211
  ok: boolean;
201
212
  agreement: Agreement;
202
213
  }>;
214
+ fulfill(id: string): Promise<{
215
+ ok: boolean;
216
+ agreement: Agreement;
217
+ }>;
203
218
  claimAgreement(id: string): Promise<{
204
219
  ok: boolean;
205
220
  agreement: Agreement;
@@ -370,6 +370,26 @@ export async function revokeAgreement(agreementId, creds) {
370
370
  }
371
371
  return data;
372
372
  }
373
+ /** ZIG-832: mark an agreement fulfilled (complete). A provider closing its own
374
+ * delivered work — party-gated server-side. */
375
+ export async function fulfillAgreement(agreementId, creds) {
376
+ if (!agreementId)
377
+ throw new Error('agreementId is required to fulfill');
378
+ assertCreds(creds, 'agreement fulfillment');
379
+ const res = await fetch(`${getAgreementBaseUrl()}/${encodeURIComponent(agreementId)}/fulfill`, {
380
+ method: 'POST',
381
+ headers: buildHeaders(creds),
382
+ });
383
+ if (!res.ok) {
384
+ const body = await res.text().catch(() => '');
385
+ throwApiError(res, body, `Agreement fulfillment failed: ${res.status} ${res.statusText}`);
386
+ }
387
+ const data = await res.json().catch(() => null);
388
+ if (!data?.['agreement']) {
389
+ throw new Error('Invalid response: expected { ok, agreement } from POST /agreements/:id/fulfill');
390
+ }
391
+ return data;
392
+ }
373
393
  /**
374
394
  * Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
375
395
  * - open link invite (`engagementKind: link`, proposedTo everyone)
@@ -596,6 +616,7 @@ export class AgreementClient {
596
616
  get(id) { return getAgreement(id, this.creds); }
597
617
  create(data) { return createAgreement(data, this.creds); }
598
618
  revoke(id) { return revokeAgreement(id, this.creds); }
619
+ fulfill(id) { return fulfillAgreement(id, this.creds); }
599
620
  claimAgreement(id) { return claimAgreement(id, this.creds); }
600
621
  listByChat(chatId) { return getAgreementsByChat(chatId, this.creds); }
601
622
  linkToChat(id, chatId, linkType) { return linkAgreementToChat(id, chatId, linkType ?? 'mention', this.creds); }
@@ -1,23 +1,20 @@
1
1
  import 'dotenv/config';
2
+ import type { GrantView } from './grants.js';
2
3
  export type ContextGrantScopeKind = 'chat' | 'agreement' | 'org';
3
4
  export type ContextTemporal = 'from-now' | 'from-start';
4
5
  export interface ContextGrantScope {
5
6
  kind: ContextGrantScopeKind;
6
7
  id: string;
7
8
  }
8
- export interface ContextGrantRecord {
9
- grantId: string;
10
- issuerId: string;
11
- holderId: string;
12
- scopeKind: ContextGrantScopeKind;
13
- scopeId: string;
14
- temporal: ContextTemporal;
15
- watermarkAt: string;
16
- parentGrantId: string | null;
17
- expiresAt: string | null;
18
- revoked: boolean;
19
- createdAt: string;
20
- }
9
+ /**
10
+ * @deprecated ZIG-646 — context grants now serialise to the canonical
11
+ * {@link GrantView} like every other rail. This alias previously declared a
12
+ * flat `scopeKind`/`scopeId` + `revoked` shape that the backend never actually
13
+ * emitted (it sends nested `scope: { kind, id }` and folds temporal/watermark
14
+ * into `caveats`), so reads like `record.scopeKind` were always `undefined`.
15
+ * Use `GrantView`; this remains only so existing name-imports keep resolving.
16
+ */
17
+ export type ContextGrantRecord = GrantView;
21
18
  export interface IssueContextGrantInput {
22
19
  holderId: string;
23
20
  scope: ContextGrantScope;
@@ -36,7 +33,7 @@ export interface DelegateContextGrantInput {
36
33
  * approves — no grant is minted until then. */
37
34
  export type DelegateContextGrantResult = {
38
35
  status: 'granted';
39
- grant: ContextGrantRecord;
36
+ grant: GrantView;
40
37
  } | {
41
38
  status: 'pending_approval';
42
39
  agreementId: string;
@@ -54,7 +51,7 @@ export declare class ContextGrantsClient {
54
51
  * @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
55
52
  */
56
53
  constructor(operatorKey: string, agentId?: string, baseUrl?: string);
57
- issueGrant(input: IssueContextGrantInput): Promise<ContextGrantRecord>;
54
+ issueGrant(input: IssueContextGrantInput): Promise<GrantView>;
58
55
  delegateGrant(parentGrantId: string, input: DelegateContextGrantInput): Promise<DelegateContextGrantResult>;
59
56
  revokeGrant(grantId: string): Promise<{
60
57
  status: string;
@@ -35,7 +35,11 @@ export class MessagesClient {
35
35
  const res = await fetch(url.toString(), { headers: this._headers() });
36
36
  if (!res.ok) {
37
37
  const body = await res.text().catch(() => '');
38
- throw new Error(`MessagesClient.list ${res.status} ${res.statusText} ${body.slice(0, 200)}`);
38
+ const err = new Error(`MessagesClient.list ${res.status} ${res.statusText} ${body.slice(0, 200)}`);
39
+ // Callers branch on the HTTP status (404 = chat deleted/not visible)
40
+ // without parsing the message string.
41
+ err.status = res.status;
42
+ throw err;
39
43
  }
40
44
  return (await res.json());
41
45
  }
@@ -117,7 +117,38 @@ export async function getActiveTasksForAgent(agentId, creds) {
117
117
  throwApiError(res, body, `Get active tasks for agent failed: ${res.status} ${res.statusText}`);
118
118
  }
119
119
  const data = await res.json().catch(() => null);
120
- return Array.isArray(data?.['tasks']) ? data['tasks'] : [];
120
+ const fromAgent = Array.isArray(data?.['tasks']) ? data['tasks'] : [];
121
+ if (fromAgent.length > 0)
122
+ return fromAgent;
123
+ // Fallback when /agents/:id/tasks is empty but party-agreement tasks exist (ZIG-802).
124
+ return getActiveTasksForAgentViaPartyAgreements(agentId, creds);
125
+ }
126
+ async function getActiveTasksForAgentViaPartyAgreements(agentId, creds) {
127
+ const { listAgreements } = await import('./AgreementClient.js');
128
+ const agreements = await listAgreements({ status: 'active' }, creds);
129
+ const partyIds = agreements
130
+ .filter((a) => {
131
+ const p = a.parties ?? {};
132
+ return (p.provider === agentId ||
133
+ p.providerAgent === agentId ||
134
+ p.creator === agentId ||
135
+ p.payer === agentId);
136
+ })
137
+ .map((a) => a.agreementId)
138
+ .filter(Boolean);
139
+ if (partyIds.length === 0)
140
+ return [];
141
+ const lists = await Promise.all(partyIds.map(async (aid) => {
142
+ const url = new URL(`${getBackendUrl()}/agreements/${encodeURIComponent(aid)}/tasks`);
143
+ url.searchParams.set('state', 'active');
144
+ const res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
145
+ if (!res.ok)
146
+ return [];
147
+ const data = await res.json().catch(() => null);
148
+ return Array.isArray(data?.['tasks']) ? data['tasks'] : [];
149
+ }));
150
+ const merged = lists.flat();
151
+ return merged.filter((t) => !t.assigneeId || t.assigneeId === agentId);
121
152
  }
122
153
  // Backend deliberately has no `/chats/:id/tasks` route — it's composable
123
154
  // from links → per-agreement tasks. We do the composition here so callers
@@ -0,0 +1,39 @@
1
+ /**
2
+ * ZIG-646: the one grant shape the backend presents on the wire, mirrored for
3
+ * SDK consumers. Context, connection, and payment grants all serialise to this
4
+ * exact object (see backend `src/grants/grant-view.ts`), so a caller reads one
5
+ * shape to answer "what grants exist, and are they live?" regardless of rail.
6
+ *
7
+ * `scope.kind` names the rail's resource: context grants keep chat/agreement/org;
8
+ * a connection grant is `connection` + connectionId; a payment grant is
9
+ * `wallet` + the root wallet id. A grant's bounds are its `caveats` — for
10
+ * context grants (which have no caveat column) the temporal mode and read
11
+ * watermark are presented as `temporal` / `watermark_at` caveats.
12
+ */
13
+ export type GrantHealth = 'active' | 'expired' | 'revoked';
14
+ export type GrantScopeKind = 'chat' | 'agreement' | 'org' | 'connection' | 'wallet';
15
+ export interface GrantScopeView {
16
+ kind: GrantScopeKind;
17
+ id: string;
18
+ }
19
+ export interface GrantCaveatView {
20
+ type: string;
21
+ value: unknown;
22
+ }
23
+ export interface GrantView {
24
+ grantId: string;
25
+ issuerId: string;
26
+ holderId: string;
27
+ parentGrantId: string | null;
28
+ agreementId: string | null;
29
+ scope: GrantScopeView;
30
+ caveats: GrantCaveatView[];
31
+ revoked: boolean;
32
+ /** ISO-8601, or null for no expiry. */
33
+ expiresAt: string | null;
34
+ /** ISO-8601. */
35
+ createdAt: string;
36
+ health: GrantHealth;
37
+ }
38
+ /** Value of the first caveat of `type` on a grant, or undefined. */
39
+ export declare function grantCaveat(grant: GrantView, type: string): unknown | undefined;
@@ -0,0 +1,4 @@
1
+ /** Value of the first caveat of `type` on a grant, or undefined. */
2
+ export function grantCaveat(grant, type) {
3
+ return grant.caveats.find((c) => c.type === type)?.value;
4
+ }
@@ -14,6 +14,8 @@ export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
14
14
  export type { ContextReachDescriptor } from './ContextDiscoveryClient.js';
15
15
  export { ContextGrantsClient } from './ContextGrantsClient.js';
16
16
  export type { ContextGrantRecord, ContextGrantScope, ContextGrantScopeKind, ContextTemporal, IssueContextGrantInput, DelegateContextGrantInput, } from './ContextGrantsClient.js';
17
+ export { grantCaveat } from './grants.js';
18
+ export type { GrantView, GrantScopeKind, GrantScopeView, GrantCaveatView, GrantHealth, } from './grants.js';
17
19
  export { AgentSearchClient } from './AgentSearchClient.js';
18
20
  export { TelemetryClient } from './TelemetryClient.js';
19
21
  export { InboxClient } from './InboxClient.js';
@@ -8,6 +8,7 @@ export { ScopeClient } from './ScopeClient.js';
8
8
  export { ContextReadClient } from './ContextReadClient.js';
9
9
  export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
10
10
  export { ContextGrantsClient } from './ContextGrantsClient.js';
11
+ export { grantCaveat } from './grants.js';
11
12
  export { AgentSearchClient } from './AgentSearchClient.js';
12
13
  export { TelemetryClient } from './TelemetryClient.js';
13
14
  export { InboxClient } from './InboxClient.js';
@@ -27,6 +27,12 @@ export interface ResourceEvent {
27
27
  taskId?: string;
28
28
  change?: 'created' | 'updated' | 'state-changed';
29
29
  reason?: string;
30
+ /**
31
+ * Principal whose action produced the event, when the backend knows it.
32
+ * Hosts drop events the receiving agent itself caused — its own writes
33
+ * aren't news to it.
34
+ */
35
+ actorId?: string;
30
36
  }
31
37
  export type ResourceEventHandler = (event: ResourceEvent) => void | Promise<void>;
32
38
  export interface SendOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",