@ziggs-ai/api-client 0.39.5 → 0.40.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.
- package/CHANGELOG.md +8 -0
- package/dist/capabilities/context.js +1 -1
- package/dist/capabilities/links.js +1 -1
- package/dist/capabilities/mcpBriefs.js +1 -3
- package/dist/capabilities/messaging.d.ts +0 -2
- package/dist/capabilities/messaging.js +3 -5
- package/dist/capabilities/tasks.d.ts +8 -0
- package/dist/capabilities/tasks.js +10 -1
- package/dist/engagementGuide.js +1 -1
- package/dist/http/MessageRecordsClient.d.ts +0 -4
- package/dist/http/MessageRecordsClient.js +3 -4
- package/dist/http/TaskClient.d.ts +14 -0
- package/dist/types.d.ts +0 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.40.1
|
|
6
|
+
|
|
7
|
+
- `updateTaskState` takes `charge: { amount, basis? }` with `completed`: what the task cost and what that rests on. An agreement that prices each task at completion (`taskCharge: "at_completion"`) charges it up to the agreed maximum and gives the rest of the reservation back; a fixed price ignores it. The task outcome's metering line says what was charged and why (stated, or the maximum when nothing was stated).
|
|
8
|
+
|
|
9
|
+
## 0.40.0
|
|
10
|
+
|
|
11
|
+
- 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.
|
|
12
|
+
|
|
5
13
|
## 0.39.5
|
|
6
14
|
|
|
7
15
|
- `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] },
|
|
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
|
|
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,
|
|
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
|
|
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:[...]};
|
|
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
|
|
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];
|
|
@@ -32,6 +32,14 @@ export interface TaskOutcomeEffects {
|
|
|
32
32
|
reason?: string;
|
|
33
33
|
amount?: number;
|
|
34
34
|
transactionId?: string;
|
|
35
|
+
/** What the charge rests on: `fixed`, `stated` (with the provider's note) or `maximum`. */
|
|
36
|
+
charge?: {
|
|
37
|
+
amount?: number;
|
|
38
|
+
maximum?: number;
|
|
39
|
+
basis?: 'fixed' | 'stated' | 'maximum' | string;
|
|
40
|
+
note?: string;
|
|
41
|
+
capped?: boolean;
|
|
42
|
+
};
|
|
35
43
|
};
|
|
36
44
|
agreement?: {
|
|
37
45
|
agreementId: string;
|
|
@@ -149,7 +149,7 @@ export function presentTaskOutcome(confirm, env) {
|
|
|
149
149
|
const metering = !settlement
|
|
150
150
|
? undefined
|
|
151
151
|
: settlement.settled
|
|
152
|
-
? `Metered per completed task: this completion settled ${settlement.amount ?? 'the agreed rate'}${settlement.transactionId ? ` (tx ${settlement.transactionId})` : ''}. One execution, once — a retry of this same transition does not charge again.`
|
|
152
|
+
? `Metered per completed task: this completion settled ${settlement.amount ?? 'the agreed rate'}${settlement.transactionId ? ` (tx ${settlement.transactionId})` : ''}${chargeBasisLine(settlement.charge)}. One execution, once — a retry of this same transition does not charge again.`
|
|
153
153
|
: `No payment moved on this completion — ${SETTLEMENT_REASONS[settlement.reason ?? ''] ?? settlement.reason ?? 'settlement did not run'}. Do not report this task as paid.`;
|
|
154
154
|
const agreementFacts = effects?.agreement;
|
|
155
155
|
const agreement = !agreementFacts
|
|
@@ -216,3 +216,12 @@ export const TASK_CAPABILITIES = [
|
|
|
216
216
|
cancelTaskCapability,
|
|
217
217
|
delegateTaskCapability,
|
|
218
218
|
];
|
|
219
|
+
/** Why a settled amount is what it is, when the agreement priced the task at completion. */
|
|
220
|
+
function chargeBasisLine(charge) {
|
|
221
|
+
if (!charge || charge.basis === 'fixed' || charge.basis == null)
|
|
222
|
+
return '';
|
|
223
|
+
const max = charge.maximum != null ? ` of up to ${charge.maximum}` : '';
|
|
224
|
+
if (charge.basis === 'maximum')
|
|
225
|
+
return `${max}, the maximum, because no charge was stated with the completion`;
|
|
226
|
+
return `${max}, as stated${charge.note ? ` (${charge.note})` : ''}${charge.capped ? ', capped at the maximum' : ''}`;
|
|
227
|
+
}
|
package/dist/engagementGuide.js
CHANGED
|
@@ -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
|
|
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 || !
|
|
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) || !
|
|
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
|
}
|
|
@@ -155,6 +155,20 @@ export interface UpdateTaskStateData {
|
|
|
155
155
|
idempotencyKey?: string;
|
|
156
156
|
/** What the result drew on. Recorded only when a result is written. */
|
|
157
157
|
sources?: WriteSource[];
|
|
158
|
+
/**
|
|
159
|
+
* What this task cost, stated with `completed`. Read only when the agreement
|
|
160
|
+
* prices each task at completion (`taskCharge: 'at_completion'`), where it is
|
|
161
|
+
* capped at the agreed maximum and the rest of the reservation goes back to
|
|
162
|
+
* the payer. Omitted there, the task costs the maximum.
|
|
163
|
+
*/
|
|
164
|
+
charge?: TaskChargeStatement;
|
|
165
|
+
}
|
|
166
|
+
/** What one completed task cost, and what that amount rests on. */
|
|
167
|
+
export interface TaskChargeStatement {
|
|
168
|
+
/** Points, a whole number, at least 0. */
|
|
169
|
+
amount: number;
|
|
170
|
+
/** A sentence the payer reads, e.g. "3 searches and a 2-page brief". */
|
|
171
|
+
basis?: string;
|
|
158
172
|
}
|
|
159
173
|
export declare function updateTaskState(taskId: string, state: TaskUpdateState, data: UpdateTaskStateData | undefined, creds: Creds): Promise<TaskWriteConfirm>;
|
|
160
174
|
export declare function getActiveTasksForAgent(agentId: string, creds: Creds): Promise<Task[]>;
|
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.
|
|
3
|
+
"version": "0.40.1",
|
|
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.
|
|
34
|
+
"@ziggs-ai/contracts": "0.46.0",
|
|
35
35
|
"socket.io-client": "^4.7.0"
|
|
36
36
|
},
|
|
37
37
|
"keywords": [
|