@ziggs-ai/api-client 0.39.5 → 0.40.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.40.0
6
+
7
+ - Every message carries one flag, `intent: "fyi" | "request"`, in place of `effect`. A request wakes the agents it is delivered to; an fyi is delivered and filed, never woken on. Nothing records whether a request was answered, so `message_answers` and `message_answer_cancel` are gone and message records carry `intent` instead of `requestedAnswers`. Inbox envelopes no longer list `answersAwaitingMe`. Requires contracts 0.46.0.
8
+
5
9
  ## 0.39.5
6
10
 
7
11
  - `message_send` explains its "Nothing authorizes giving … access to this message" refusal: the reader has no contact basis, so ask its owner with `access_request` `scopeKind: "contact"`, then send once they approve.
@@ -270,7 +270,7 @@ const OPEN_REF_PARAMS = {
270
270
  function resumeResource(kind, id, env) {
271
271
  // After a send grant is approved there is nothing to read: send to the destination.
272
272
  if (kind === 'contact')
273
- return { tool: env.surface === 'mcp' ? 'ziggs_message_send' : 'message_send', args: { command: { audience: { kind: 'explicit', principalIds: [id] }, deliveries: { kind: 'explicit', principalIds: [id] }, effect: { kind: 'none' } } } };
273
+ return { tool: env.surface === 'mcp' ? 'ziggs_message_send' : 'message_send', args: { command: { audience: { kind: 'explicit', principalIds: [id] }, deliveries: { kind: 'explicit', principalIds: [id] }, intent: 'fyi' } } };
274
274
  const tool = kind === 'message' ? 'message_read' : 'open';
275
275
  return {
276
276
  tool: env.surface === 'mcp' ? `ziggs_${tool}` : tool,
@@ -65,7 +65,7 @@ export const listLinksCapability = {
65
65
  // this side, because the addressable id is not in the payload to find. It
66
66
  // is now, as `peer`, resolved relative to whoever asked.
67
67
  const readPlan = active.length ? [
68
- nextCall(env, 'message_send', undefined, 'Send an explicit message command to a returned peer.id; choose readers, delivery recipients and any requested answer separately. A link grants no history access.'),
68
+ nextCall(env, 'message_send', undefined, 'Send an explicit message command to a returned peer.id; choose readers, delivery recipients and the intent (fyi or request) separately. A link grants no history access.'),
69
69
  nextCall(env, 'artifact_share', undefined, 'Share only the selected artifact under its grant and consent policy.'),
70
70
  ] : [];
71
71
  return {
@@ -169,13 +169,11 @@ const BRIEFS = {
169
169
  does: 'Shares one artifact you authored with another agent.',
170
170
  changes: 'grants it at once to a connected agent; otherwise asks your owner to approve (pending_approval)',
171
171
  },
172
- ziggs_message_send: { does: 'Sends a canonical command with independent readers, recipients, answer effect and optional mandate.', changes: 'delivers a message and grants its readers access' },
172
+ ziggs_message_send: { does: 'Sends a canonical command with independent readers, recipients, an intent (fyi or request) and optional mandate.', changes: 'delivers a message and grants its readers access; a request wakes the agents it reaches' },
173
173
  ziggs_message_replies: { does: 'Reads authorized causal replies by messageId; a reference grants no access and receipt expiry does not erase history.' },
174
174
  ziggs_message_read: { does: 'Reads an exact message by messageId under current access and execution policy. Does not acknowledge its receipt.' },
175
175
  ziggs_message_list: { does: 'Queries authorized messages by participants, agreement or task. Filters select history, not authority.' },
176
176
  ziggs_message_controls: { does: 'Inspects recipients and authority for an explicit agreement or task without reading history.' },
177
- ziggs_message_answers: { does: 'Reads durable answer requests and their outcomes independently of inbox acknowledgment.' },
178
- ziggs_message_answer_cancel: { does: 'Cancels one exact pending answer request as its author.', changes: 'closes the request without deleting history or cancelling tasks' },
179
177
  ziggs_task_delegate: {
180
178
  does: 'Delegates work, returns a child output, or rechecks readiness.',
181
179
  changes: 'creates or returns isolated work',
@@ -4,6 +4,4 @@ export declare const sendMessageCapability: CapabilityDefinition;
4
4
  export declare const readRepliesCapability: CapabilityDefinition;
5
5
  export declare const queryMessagesCapability: CapabilityDefinition;
6
6
  export declare const messageControlsCapability: CapabilityDefinition;
7
- export declare const messageAnswersCapability: CapabilityDefinition;
8
- export declare const cancelAnswerCapability: CapabilityDefinition;
9
7
  export declare const MESSAGING_CAPABILITIES: CapabilityDefinition[];
@@ -1,11 +1,9 @@
1
1
  import { MessageRecordsClient } from '../http/MessageRecordsClient.js';
2
2
  import { fullCreds } from './types.js';
3
3
  const client = (env) => { const creds = fullCreds(env); return new MessageRecordsClient(creds.operatorKey, creds.agentId, env.baseUrl); };
4
- export const readMessageCapability = { key: 'message_read', names: { sdk: 'message_read', mcp: 'ziggs_message_read' }, title: 'Read exact message', descriptions: { sdk: 'Read one authorized message. Returns content, independent readers/recipients, requested-answer action slots and authorized relationships. Does not acknowledge delivery.' }, annotation: 'read-only', needsAgentId: true, params: { messageId: { type: 'string', required: true } }, handler: (args, env) => client(env).get(String(args.messageId)) };
5
- export const sendMessageCapability = { key: 'message_send', names: { sdk: 'message_send', mcp: 'ziggs_message_send' }, title: 'Send message', descriptions: { sdk: 'Send the canonical command: operationId; content:{text}; audience:{kind:"explicit",principalIds:[...]}; deliveries:{kind:"explicit",principalIds:[...]}; effect:{kind:"none"} or request-answers:{requests:[{requestId,responsiblePrincipalId}]} or answer:{action:{kind:"message",id,slot:"answer",requestId},artifacts:[]} or provide-input:{action}. Optional mandate:{agreementId,taskId}, relationships:{replyToMessageId,taskIds,artifacts}, exact sources. Reuse operationId unchanged on retry. A causal reply alone never resolves an answer. No room required. Refused with "Nothing authorizes giving … access to this message" means you have no contact basis for that reader (membership, a link, an agreement or a listing): ask its owner with access_request scopeKind=contact and scopeId=that reader, then send once they approve.' }, annotation: 'destructive', needsAgentId: true, params: { command: { type: 'object', required: true, description: 'MessageCommand with explicit independent audience, deliveries, action effect and optional mandate.' } }, handler: (args, env) => client(env).send(args.command) };
4
+ export const readMessageCapability = { key: 'message_read', names: { sdk: 'message_read', mcp: 'ziggs_message_read' }, title: 'Read exact message', descriptions: { sdk: 'Read one authorized message. Returns content, intent (fyi or request), independent readers/recipients and authorized relationships. Does not acknowledge delivery.' }, annotation: 'read-only', needsAgentId: true, params: { messageId: { type: 'string', required: true } }, handler: (args, env) => client(env).get(String(args.messageId)) };
5
+ export const sendMessageCapability = { key: 'message_send', names: { sdk: 'message_send', mcp: 'ziggs_message_send' }, title: 'Send message', descriptions: { sdk: 'Send the canonical command: operationId; content:{text}; audience:{kind:"explicit",principalIds:[...]}; deliveries:{kind:"explicit",principalIds:[...]}; intent:"fyi" or "request". A request wakes the agents it is delivered to; an fyi is delivered and filed, never woken on. Nothing records whether a request was answered: a reply is a message with relationships.replyToMessageId. Optional mandate:{agreementId,taskId}, relationships:{replyToMessageId,taskIds,artifacts}, exact sources. Reuse operationId unchanged on retry. No room required. Refused with "Nothing authorizes giving … access to this message" means you have no contact basis for that reader (membership, a link, an agreement or a listing): ask its owner with access_request scopeKind=contact and scopeId=that reader, then send once they approve.' }, annotation: 'destructive', needsAgentId: true, params: { command: { type: 'object', required: true, description: 'MessageCommand with explicit independent audience, deliveries, intent and optional mandate.' } }, handler: (args, env) => client(env).send(args.command) };
6
6
  export const readRepliesCapability = { key: 'message_replies', names: { sdk: 'message_replies', mcp: 'ziggs_message_replies' }, title: 'Read replies', descriptions: { sdk: 'Read currently authorized causal replies; links never grant access. Continue using nextCursor as before.' }, annotation: 'read-only', needsAgentId: true, params: { messageId: { type: 'string', required: true }, before: { type: 'string' }, limit: { type: 'number' } }, handler: (args, env) => client(env).replies(String(args.messageId), { before: args.before, limit: args.limit }) };
7
7
  export const queryMessagesCapability = { key: 'message_list', names: { sdk: 'message_list', mcp: 'ziggs_message_list' }, title: 'Query messages', descriptions: { sdk: 'Query authorized messages. Use conversationOf with an exact message id to browse messages connected by readable reply relationships; use nextCursor as before for earlier turns. Select conversationOf independently of agreementId, taskId or participantIds. History never selects authority.' }, annotation: 'read-only', needsAgentId: true, params: { conversationOf: { type: 'string', description: 'Authorized anchor message; follows readable causal links, never a reader roster. Each result still requires read access and any execution input authorization.' }, q: { type: 'string' }, senderId: { type: 'string' }, recipientIds: { type: 'array', items: { type: 'string' } }, agreementId: { type: 'string' }, taskId: { type: 'string' }, participantIds: { type: 'array', items: { type: 'string' } }, before: { type: 'string' }, limit: { type: 'number' } }, handler: (args, env) => client(env).list(args) };
8
8
  export const messageControlsCapability = { key: 'message_controls', names: { sdk: 'message_controls', mcp: 'ziggs_message_controls' }, title: 'Inspect message mandate', descriptions: { sdk: 'Discover recipients and current authority under an explicitly selected agreement/task without reading message history.' }, annotation: 'read-only', needsAgentId: true, params: { q: { type: 'string' }, senderId: { type: 'string' }, recipientIds: { type: 'array', items: { type: 'string' } }, agreementId: { type: 'string', required: true }, taskId: { type: 'string' } }, handler: (args, env) => client(env).controls(String(args.agreementId), args.taskId) };
9
- export const messageAnswersCapability = { key: 'message_answers', names: { sdk: 'message_answers', mcp: 'ziggs_message_answers' }, title: 'Read answer requests', descriptions: { sdk: 'Read durable requested-answer outcomes independently of inbox ACK state.' }, annotation: 'read-only', needsAgentId: true, params: { messageId: { type: 'string', required: true } }, handler: (args, env) => client(env).answers(String(args.messageId)) };
10
- export const cancelAnswerCapability = { key: 'message_answer_cancel', names: { sdk: 'message_answer_cancel', mcp: 'ziggs_message_answer_cancel' }, title: 'Cancel answer request', descriptions: { sdk: 'As the request author, cancel one exact pending answer slot. Does not delete history or cancel tasks.' }, annotation: 'destructive', needsAgentId: true, params: { messageId: { type: 'string', required: true }, requestId: { type: 'string', required: true } }, handler: (args, env) => client(env).cancelAnswer(String(args.messageId), String(args.requestId)) };
11
- export const MESSAGING_CAPABILITIES = [readMessageCapability, sendMessageCapability, readRepliesCapability, queryMessagesCapability, messageControlsCapability, messageAnswersCapability, cancelAnswerCapability];
9
+ export const MESSAGING_CAPABILITIES = [readMessageCapability, sendMessageCapability, readRepliesCapability, queryMessagesCapability, messageControlsCapability];
@@ -227,7 +227,7 @@ export function contactPath(env, input) {
227
227
  summary: sameOrg && !linked
228
228
  ? 'Same-org person: reach them under this scoped identity.'
229
229
  : 'Linked person: choose an explicit message audience and delivery. A link does not reveal their org roster.',
230
- next: nextCall(env, 'message_send', undefined, `send an explicit message command to ${partyId}; choose readers, delivery and answer responsibility separately`),
230
+ next: nextCall(env, 'message_send', undefined, `send an explicit message command to ${partyId}; choose readers, delivery and intent (fyi or request) separately`),
231
231
  };
232
232
  }
233
233
  if (partyKind === 'person' && !linked) {
@@ -29,9 +29,5 @@ export declare class MessageRecordsClient {
29
29
  limit?: number;
30
30
  }): Promise<MessagePage>;
31
31
  controls(agreementId: string, taskId?: string): Promise<MessagingControls>;
32
- answers(id: string): Promise<unknown>;
33
- cancelAnswer(id: string, requestId: string): Promise<{
34
- state: 'cancelled';
35
- }>;
36
32
  }
37
33
  export type { MessageCommand, MessageCommandResult, MessageRecord } from '@ziggs-ai/contracts';
@@ -2,6 +2,7 @@ import { parseMessageCommand } from '@ziggs-ai/contracts';
2
2
  import { buildOperatorHeaders } from './operatorHeaders.js';
3
3
  import { getBackendUrl } from '../utils/urlUtils.js';
4
4
  import { throwApiError } from '../shared/apiError.js';
5
+ const isIntent = (value) => value === 'fyi' || value === 'request';
5
6
  /** One command and one representation, independent of navigation. */
6
7
  export class MessageRecordsClient {
7
8
  operatorKey;
@@ -14,9 +15,9 @@ export class MessageRecordsClient {
14
15
  }
15
16
  async request(path, init = {}) { const res = await fetch(`${this.baseUrl ?? getBackendUrl()}/messaging/${path}`, { ...init, headers: { 'content-type': 'application/json', ...buildOperatorHeaders(this.operatorKey, this.agentId) } }); if (!res.ok)
16
17
  throwApiError(res, await res.text().catch(() => ''), `Messaging failed: ${res.status}`); return await res.json(); }
17
- async get(id) { const row = await this.request(`messages/${encodeURIComponent(id)}`); if (row.messageId !== id || !row.content || !Array.isArray(row.requestedAnswers))
18
+ async get(id) { const row = await this.request(`messages/${encodeURIComponent(id)}`); if (row.messageId !== id || !row.content || !isIntent(row.intent))
18
19
  throw new Error('Invalid exact message response'); return row; }
19
- async send(command) { const result = await this.request('messages', { method: 'POST', body: JSON.stringify(parseMessageCommand(command)) }); if (!['created', 'existing'].includes(result.outcome) || !result.message?.messageId || !result.message.content || !Array.isArray(result.message.recipients) || !Array.isArray(result.message.requestedAnswers))
20
+ async send(command) { const result = await this.request('messages', { method: 'POST', body: JSON.stringify(parseMessageCommand(command)) }); if (!['created', 'existing'].includes(result.outcome) || !result.message?.messageId || !result.message.content || !Array.isArray(result.message.recipients) || !isIntent(result.message.intent))
20
21
  throw new Error('Invalid message command response'); return result; }
21
22
  list(input = {}) { const query = new URLSearchParams(); for (const [key, value] of Object.entries(input))
22
23
  if (value !== undefined)
@@ -25,6 +26,4 @@ export class MessageRecordsClient {
25
26
  if (value !== undefined)
26
27
  query.set(key, String(value)); return this.request(`messages/${encodeURIComponent(id)}/replies?${query}`); }
27
28
  controls(agreementId, taskId) { const query = new URLSearchParams({ agreementId, ...(taskId ? { taskId } : {}) }); return this.request(`controls?${query}`); }
28
- answers(id) { return this.request(`messages/${encodeURIComponent(id)}/answers`); }
29
- cancelAnswer(id, requestId) { return this.request(`messages/${encodeURIComponent(id)}/answers/${encodeURIComponent(requestId)}/cancel`, { method: 'POST' }); }
30
29
  }
package/dist/types.d.ts CHANGED
@@ -457,7 +457,6 @@ export interface InboxEnvelope extends InboxRequestChannel, Partial<InboxPlanAck
457
457
  */
458
458
  ackTo: string | null;
459
459
  /** Open tasks assigned to this agent — the work channel. */
460
- answersAwaitingMe?: InboxDeliveryRef[];
461
460
  tasksAwaitingMe: InboxTaskRef[];
462
461
  truncatedTasks: number;
463
462
  proposalsAwaitingMe: InboxProposalRef[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.39.5",
3
+ "version": "0.40.0",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "homepage": "https://ziggsai.com/docs",
6
6
  "bugs": {
@@ -31,7 +31,7 @@
31
31
  "test:watch": "node --import tsx/esm --test --watch test/*.test.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@ziggs-ai/contracts": "0.45.0",
34
+ "@ziggs-ai/contracts": "0.46.0",
35
35
  "socket.io-client": "^4.7.0"
36
36
  },
37
37
  "keywords": [