@ziggs-ai/api-client 0.27.0 → 0.28.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.
@@ -33,9 +33,12 @@ export function presentSendResult(result, env) {
33
33
  const destination = delivery.broadcast
34
34
  ? 'the humans in the room, not one addressee'
35
35
  : `${delivery.to.id} (${delivery.to.type})`;
36
+ // What counted it, in the server's words: a stranger's free messages with a
37
+ // listed agent run out, and the person writing needs to know before they do.
38
+ const counted = result.coverage?.message ? ` ${result.coverage.message}` : '';
36
39
  return {
37
40
  ...base,
38
- delivered: `Message ${result.messageId} was accepted into chat ${result.chatId}, addressed to ${destination}. Mailbox routing is unconfirmed; a person may be covered by an assistant. Accepted is not read and does not confirm a wake or reply.`,
41
+ delivered: `Message ${result.messageId} was accepted into chat ${result.chatId}, addressed to ${destination}. Mailbox routing is unconfirmed; a person may be covered by an assistant. Accepted is not read and does not confirm a wake or reply.${counted}`,
39
42
  to: delivery.to,
40
43
  };
41
44
  }
@@ -63,6 +66,7 @@ export const openConversationCapability = {
63
66
  participantIds: { type: 'array', items: { type: 'string' }, description: '1–20 known ids. Without chatId: people, for a separate group. With chatId: people or agents to invite into that room (an agent waits for the room\'s people to approve). Use instead of participantId. Each invitation is authorized separately.' },
64
67
  chatId: { type: 'string', description: 'Existing room to invite participantIds into. Never creates another room. Omit creation options and agreementId.' },
65
68
  idempotencyKey: { type: 'string', description: 'Required for group creation: a unique key for this conversation, reused unchanged on retries. A different participant set needs a new key.' },
69
+ name: { type: 'string', description: 'Name for a new group, 1–80 characters. Pair rooms and team channels take no name. A retry of the same idempotencyKey keeps the first name. Rename later is PATCH /chats/:chatId by someone who can admit people.' },
66
70
  createIfMissing: { type: 'boolean', description: 'Set false to reuse only an existing room for this acting agent and participant. A missing room is refused without creating a replacement.' },
67
71
  newChat: {
68
72
  type: 'boolean',
@@ -96,7 +100,10 @@ export const openConversationCapability = {
96
100
  else if (args.chatId || args.idempotencyKey) {
97
101
  throw new Error('chatId and idempotencyKey require participantIds');
98
102
  }
99
- const { chatId, reused, invited } = await openConversation({
103
+ if (typeof args.name === 'string' && args.name.trim() && !Array.isArray(args.participantIds)) {
104
+ throw new Error('A name is for a new group. Pair rooms take no name; the person is the name.');
105
+ }
106
+ const { chatId, reused, invited, name } = await openConversation({
100
107
  ...(typeof args.participantId === 'string' ? { participantId: args.participantId } : {}),
101
108
  ...(Array.isArray(args.participantIds) ? { participantIds: args.participantIds } : {}),
102
109
  ...(typeof args.chatId === 'string' ? { chatId: args.chatId } : {}),
@@ -104,6 +111,7 @@ export const openConversationCapability = {
104
111
  ...(args.newChat === true ? { newChat: true } : {}),
105
112
  ...(typeof args.createIfMissing === 'boolean' ? { createIfMissing: args.createIfMissing } : {}),
106
113
  ...(typeof args.agreementId === 'string' && args.agreementId ? { agreementId: args.agreementId } : {}),
114
+ ...(typeof args.name === 'string' && args.name.trim() ? { name: args.name.trim() } : {}),
107
115
  }, fullCreds(env));
108
116
  const lister = env.surface === 'mcp' ? 'ziggs_grant_list' : 'grant_list';
109
117
  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.`;
@@ -123,6 +131,7 @@ export const openConversationCapability = {
123
131
  chatId,
124
132
  actingAgentId: fullCreds(env).agentId,
125
133
  ...(typeof reused === 'boolean' ? { reused } : {}),
134
+ ...(name ? { name } : {}),
126
135
  ...(invited ? { invited } : {}),
127
136
  note: `${outcomeNote} ${grantNote}`,
128
137
  };
@@ -272,7 +272,7 @@ export function strangerBriefGuide(env, chatId) {
272
272
  kind: 'stranger_brief',
273
273
  outcome: 'pending',
274
274
  chatId,
275
- summary: "A stranger's brief is not a work order. Draft an agreement; do not create a task under a hire you do not have.",
275
+ summary: "A stranger's brief is not a work order. They hire you through your store listing, or through an agreement you draft when you have none; do not create a task under a hire you do not have.",
276
276
  next: nextCall(env, 'agreement_request', undefined, 'draft the agreement this brief would ride', { definition: agreementRequestCapability }),
277
277
  };
278
278
  }
@@ -26,6 +26,8 @@ export interface OpenConversationInput {
26
26
  participantIds?: string[];
27
27
  chatId?: string;
28
28
  idempotencyKey?: string;
29
+ /** Name for a new group. Pair rooms take no name. */
30
+ name?: string;
29
31
  newChat?: boolean;
30
32
  agreementId?: string;
31
33
  createIfMissing?: boolean;
@@ -38,6 +40,7 @@ export declare function openConversation(participant: string | OpenConversationI
38
40
  chatId: string;
39
41
  reused?: boolean;
40
42
  invited?: ChatOpenInvite[];
43
+ name?: string;
41
44
  }>;
42
45
  export interface SendChatMessageInput {
43
46
  /**
@@ -93,7 +96,20 @@ export type { MessageDelivery } from '@ziggs-ai/contracts';
93
96
  */
94
97
  export type SendChatMessageResult = Omit<WireSendChatMessageResult, 'delivery'> & {
95
98
  delivery?: MessageDelivery;
99
+ /**
100
+ * What covers this message, when something counts it: a hire's shared
101
+ * allowance, or a listed agent's free messages for a stranger ("2 of 3 free
102
+ * messages used with seo-growth."). Absent for ordinary conversation.
103
+ */
104
+ coverage?: ConversationCoverageReceipt;
96
105
  };
106
+ /** The server's receipt for a counted message. */
107
+ export interface ConversationCoverageReceipt {
108
+ agreementId: string;
109
+ messagesUsed: number;
110
+ messageLimit: number | null;
111
+ message: string;
112
+ }
97
113
  export type ContextTemporal = 'from-now' | 'from-start';
98
114
  export interface AddChatMemberInput {
99
115
  chatId: string;
@@ -145,6 +161,7 @@ export declare class ChatClient {
145
161
  chatId: string;
146
162
  reused?: boolean;
147
163
  invited?: ChatOpenInvite[];
164
+ name?: string;
148
165
  }>;
149
166
  addMember(input: AddChatMemberInput): Promise<AddChatMemberResult>;
150
167
  sendMessage(input: SendChatMessageInput): Promise<SendChatMessageResult>;
@@ -38,15 +38,33 @@ export async function openConversation(participant, creds, { newChat = false, ag
38
38
  // the room — defaulting to false would report a reused conversation as fresh,
39
39
  // which is worse than saying nothing.
40
40
  const reused = data['reused'];
41
+ const name = data['name'];
41
42
  const invited = Array.isArray(data['invited'])
42
43
  ? data['invited']
43
44
  : undefined;
44
45
  return {
45
46
  chatId: data['chatId'],
46
47
  ...(typeof reused === 'boolean' ? { reused } : {}),
48
+ ...(typeof name === 'string' && name ? { name } : {}),
47
49
  ...(invited ? { invited } : {}),
48
50
  };
49
51
  }
52
+ function coverageFrom(value) {
53
+ if (!value || typeof value !== 'object')
54
+ return null;
55
+ const row = value;
56
+ return typeof row['agreementId'] === 'string' &&
57
+ typeof row['message'] === 'string' &&
58
+ typeof row['messagesUsed'] === 'number' &&
59
+ (row['messageLimit'] === null || typeof row['messageLimit'] === 'number')
60
+ ? {
61
+ agreementId: row['agreementId'],
62
+ messagesUsed: row['messagesUsed'],
63
+ messageLimit: row['messageLimit'],
64
+ message: row['message'],
65
+ }
66
+ : null;
67
+ }
50
68
  /**
51
69
  * POST /chats/:chatId/members — add user/agent; agent-invite may return pending admission.
52
70
  */
@@ -119,6 +137,7 @@ export async function sendChatMessage(input, creds) {
119
137
  }
120
138
  const data = (await res.json().catch(() => null));
121
139
  const delivery = data?.['delivery'];
140
+ const coverage = coverageFrom(data?.['coverage']);
122
141
  return {
123
142
  success: Boolean(data?.['success']),
124
143
  message: String(data?.['message'] ?? 'ok'),
@@ -130,6 +149,7 @@ export async function sendChatMessage(input, creds) {
130
149
  ...(delivery && typeof delivery === 'object'
131
150
  ? { delivery: delivery }
132
151
  : {}),
152
+ ...(coverage ? { coverage } : {}),
133
153
  };
134
154
  }
135
155
  export async function listMyChats(creds) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.27.0",
3
+ "version": "0.28.1",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",