@ziggs-ai/api-client 0.30.0 → 0.30.1

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) {
@@ -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.1",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",