@ziggs-ai/api-client 0.30.0 → 0.30.2

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.
@@ -424,6 +424,9 @@ export const agreementHandoffCapability = {
424
424
  // would have had to look it up to pass it, and a lookup whose answer is
425
425
  // unique is not a decision worth handing to the caller.
426
426
  const parent = await getAgreement(parentAgreementId, creds);
427
+ if (typeof parent?.publishedService !== 'boolean') {
428
+ throw new Error('Service publishing requires an updated server. No proposal was sent.');
429
+ }
427
430
  const providerId = parent?.parties?.provider?.actor;
428
431
  if (!providerId) {
429
432
  throw new Error(`Cannot hand off ${parentAgreementId}: it names no provider, so there is no hire to share. Check the id with agreement_get.`);
@@ -435,8 +438,8 @@ export const agreementHandoffCapability = {
435
438
  };
436
439
  const to = args['to'];
437
440
  const agreement = to
438
- ? await proposeDirectTo({ ...terms, proposedTo: to, chatId: '', providerId, engagementKind: 'hire' }, creds)
439
- : await proposeBroadcast({ ...terms, chatId: '', audience: 'everyone', providerId, engagementKind: 'hire' }, creds);
441
+ ? await proposeDirectTo({ ...terms, proposedTo: to, chatId: '', useParentProvider: true, engagementKind: 'hire' }, creds)
442
+ : await proposeBroadcast({ ...terms, chatId: '', audience: 'everyone', useParentProvider: true, engagementKind: 'hire' }, creds);
440
443
  return { agreement, ...(to ? {} : { readPlan: publishedNext(env) }) };
441
444
  },
442
445
  sdkOptions: { isAgreementCreation: true },
@@ -3,13 +3,13 @@ import { claimOpenAgreement } from '../http/agreementFlows.js';
3
3
  import { linkIsReachOnly, webAppOrigin } from './links.js';
4
4
  import { workContextFromEnv } from './nextCall.js';
5
5
  import { fullCreds } from './types.js';
6
- /** Which side the claimer just took, for a claim that has not activated yet. */
7
- function claimedWhat(kind) {
6
+ /** Plain outcome once the hire is active. `kind` stays on the result, not in this sentence. */
7
+ function activeHireMessage(kind) {
8
8
  if (kind === 'offer')
9
- return 'Standing offer claimed — the publisher provides, your side pays.';
9
+ return 'The hire is active. They do the work.';
10
10
  if (kind === 'hand-off')
11
- return 'Hand-off claimed — the pinned agent works FOR you.';
12
- return 'Request claimed — you provide the work.';
11
+ return 'The hire is active. Their agent works for you.';
12
+ return 'The hire is active. You do the work.';
13
13
  }
14
14
  /**
15
15
  * One claim result shape for both surfaces. The SDK protocol runner used to
@@ -52,16 +52,14 @@ function presentClaim(agreement, kind, env) {
52
52
  if (agreement?.status !== 'active') {
53
53
  const held = (agreement?.approvals ?? []).find((a) => a.status === 'pending');
54
54
  const approveUrl = agreementAppUrl(webAppOrigin(env), agreement.agreementId);
55
- const remedy = held?.heldReason === 'contact-basis'
56
- ? 'This is a first engagement with that counterparty — your human approves once; a standing link covers it after that.'
57
- : 'Claiming for a job your human already approved activates at once — name the job with mandateAgreementId.';
55
+ const stranger = held?.heldReason === 'contact-basis'
56
+ ? ' This is a first engagement with that counterparty — your human approves once; a standing link covers it after that.'
57
+ : '';
58
58
  return {
59
59
  status: 'pending_approval',
60
60
  outcome: 'pending',
61
61
  kind,
62
- message: `${claimedWhat(kind)} It is not active yet: the formation is waiting on ` +
63
- 'human approval, so nothing can be created under it until that lands. ' +
64
- `Your human can approve it here: ${approveUrl} — ${remedy}`,
62
+ message: `Hire requested. Waiting for your yes: ${approveUrl}.${stranger}`,
65
63
  agreement,
66
64
  ...(workContext ? { workContext } : {}),
67
65
  };
@@ -70,11 +68,7 @@ function presentClaim(agreement, kind, env) {
70
68
  status: 'claimed',
71
69
  outcome: 'ok',
72
70
  kind,
73
- message: kind === 'offer'
74
- ? 'Standing offer claimed — the publisher provides, your side pays. Spawn work under it with the task-create tool.'
75
- : kind === 'hand-off'
76
- ? 'Hand-off claimed — the pinned agent works FOR you: you are the customer (and the payer when priced), never the worker. Spawn work under it with the task-create tool.'
77
- : 'Request claimed — you provide the work. Read the terms, then post progress and set the task result under this agreement.',
71
+ message: activeHireMessage(kind),
78
72
  agreement,
79
73
  ...(workContext ? { workContext } : {}),
80
74
  };
@@ -1,5 +1,7 @@
1
1
  import { openConversation } from '../http/ChatClient.js';
2
+ import { chatAppUrl } from '../utils/appUrls.js';
2
3
  import { fullCreds } from './types.js';
4
+ import { webAppOrigin } from './links.js';
3
5
  import { workContextFromEnv } from './nextCall.js';
4
6
  /**
5
7
  * Present a send as what it is: a message that now exists, addressed to
@@ -113,6 +115,8 @@ export const openConversationCapability = {
113
115
  ...(typeof args.agreementId === 'string' && args.agreementId ? { agreementId: args.agreementId } : {}),
114
116
  ...(typeof args.name === 'string' && args.name.trim() ? { name: args.name.trim() } : {}),
115
117
  }, fullCreds(env));
118
+ const agentId = fullCreds(env).agentId;
119
+ const { people, pending } = roomRoster(args, invited, agentId);
116
120
  const lister = env.surface === 'mcp' ? 'ziggs_grant_list' : 'grant_list';
117
121
  const grantNote = `Use ${lister} with scopeKind ["chat"] to inspect your room grants. Opening a conversation does not send a message or confirm that anyone has read it.`;
118
122
  // word the note from the outcome instead of covering both cases.
@@ -133,7 +137,10 @@ export const openConversationCapability = {
133
137
  : 'Conversation is open (or reused).';
134
138
  return {
135
139
  chatId,
136
- actingAgentId: fullCreds(env).agentId,
140
+ appUrl: chatAppUrl(webAppOrigin(env), chatId),
141
+ actingAgentId: agentId,
142
+ people,
143
+ pending,
137
144
  ...(typeof reused === 'boolean' ? { reused } : {}),
138
145
  ...(name ? { name } : {}),
139
146
  ...(invited ? { invited } : {}),
@@ -141,6 +148,19 @@ export const openConversationCapability = {
141
148
  };
142
149
  },
143
150
  };
151
+ /** Ids this open knows are in the room, and ids still waiting for approval. */
152
+ function roomRoster(args, invited, agentId) {
153
+ const named = Array.isArray(args.participantIds)
154
+ ? args.participantIds.filter((id) => typeof id === 'string' && id.trim().length > 0).map((id) => id.trim())
155
+ : typeof args.participantId === 'string' && args.participantId.trim()
156
+ ? [args.participantId.trim()]
157
+ : [];
158
+ const pending = (invited ?? []).filter((row) => row.status === 'pending').map((row) => row.id);
159
+ const waiting = new Set(pending);
160
+ const here = (invited ?? []).filter((row) => row.status !== 'pending').map((row) => row.id);
161
+ const people = [...new Set([...named.filter((id) => !waiting.has(id)), ...here, agentId])];
162
+ return { people, pending };
163
+ }
144
164
  /** Say what happened to each invited id, so the agent reports it truthfully. */
145
165
  function inviteNote(invited) {
146
166
  if (!invited?.length) {
@@ -408,7 +408,7 @@ export const accessRequestCapability = {
408
408
  title: 'Request access for yourself',
409
409
  descriptions: {
410
410
  sdk: 'Create a pending approval agreement for the calling agent to access one artifact, chat, agreement context, or task branch for 1–168 hours. This only requests permission: it never grants access, signs, or approves. After the authorized person approves, open the original resource. Artifact requests need a writable conversation with the named owner; other requests go to your accountable person, who must have authority over the scope. Read-only by default; permission=reply requests read and reply to one chat. No spending or work commitment. Reuse idempotencyKey for a retry.',
411
- mcp: 'Ask for missing access through a pending approval agreement. Use this when open/access_explain reports an unreadable resource, or discovery/inbox names a scope you need. It requests access ONLY for this MCP agent; never grants access or approves anything. Scope is one artifact, chat, agreement context, or task branch (including subtasks), for 1–168 hours (default 24). Read-only by default; permission=reply requests read and reply in one chat. For earlier chat messages explicitly set temporal=from-start. Artifact requests require chatId of your existing writable conversation with the owner and that ownerId; other requests route to your accountable person, who must be allowed to share the resource. Surface appUrl, wait for the decision when asked, then open the original resource and resume. Pending grants no access. Never use issue_grant, change identity, create another room, or form a generic work agreement to recover missing access.',
411
+ mcp: 'Ask for missing access through a pending approval agreement. Use this when open/access_explain reports an unreadable resource, or discovery/inbox names a scope you need. It requests access ONLY for this MCP agent; never grants access or approves anything. Scope is one artifact, chat, agreement context, or task branch (including subtasks), for 1–168 hours (default 24). Read-only by default; permission=reply requests read and reply in one chat. For earlier chat messages explicitly set temporal=from-start. Artifact requests require chatId of your existing writable conversation with the owner and that ownerId; other requests route to your accountable person, who must be allowed to share the resource. Surface appUrl, wait for the decision when asked, then open the original resource and resume. Pending grants no access. Never use issue_grant, change identity, or form a generic work agreement to recover missing access.',
412
412
  },
413
413
  annotation: 'write', needsAgentId: true,
414
414
  params: {
@@ -31,6 +31,8 @@ export interface ProposeTerms {
31
31
  * side — there is no payer input.
32
32
  */
33
33
  providerId?: string;
34
+ /** Resolve the authorized active parent hire's provider on the server. */
35
+ useParentProvider?: boolean;
34
36
  /** Defaults to `service` on the server when omitted. Set `hire` for representation contracts. */
35
37
  engagementKind?: EngagementKind;
36
38
  idempotencyKey?: string;
package/dist/types.d.ts CHANGED
@@ -176,6 +176,7 @@ export interface AgreementApprovalEntry {
176
176
  heldReason?: string | null;
177
177
  }
178
178
  export interface Agreement {
179
+ publishedService?: boolean;
179
180
  approvalAction?: {
180
181
  state: 'available' | 'needs_decision' | 'unavailable';
181
182
  partyId?: string;
@@ -1,6 +1,7 @@
1
1
  /** Resolve the app origin once for SDK, MCP, and capability links. */
2
2
  export declare function resolveWebAppOrigin(webUrl?: string | null, backendUrl?: string): string;
3
3
  export declare function agreementAppUrl(origin: string, id: string): string;
4
+ export declare function chatAppUrl(origin: string, id: string): string;
4
5
  export declare function agreementsListAppUrl(origin: string): string;
5
6
  export declare function connectInviteAppUrl(origin: string, id: string): string;
6
7
  export declare function connectionsSettingsAppUrl(origin: string, requestId?: string | null): string;
@@ -21,6 +21,9 @@ function appUrl(origin, path) {
21
21
  export function agreementAppUrl(origin, id) {
22
22
  return appUrl(origin, `/app/agreements/${encodeURIComponent(id)}`);
23
23
  }
24
+ export function chatAppUrl(origin, id) {
25
+ return appUrl(origin, `/app/chat/${encodeURIComponent(id)}`);
26
+ }
24
27
  export function agreementsListAppUrl(origin) {
25
28
  return appUrl(origin, '/app/agreements');
26
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.30.0",
3
+ "version": "0.30.2",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",