@ziggs-ai/api-client 0.1.22 → 0.1.24
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/dist/http/AgreementClient.js +55 -40
- package/dist/http/ChatClient.js +13 -9
- package/package.json +1 -1
|
@@ -126,8 +126,15 @@ export async function respondToAgreement(agreementId, action, creds, opts = {})
|
|
|
126
126
|
}
|
|
127
127
|
const proposedTo = agreement.parties?.proposedTo;
|
|
128
128
|
if (isBroadcastTarget(proposedTo)) {
|
|
129
|
-
if (action === 'reject')
|
|
130
|
-
|
|
129
|
+
if (action === 'reject') {
|
|
130
|
+
// ZIG-719: an open/broadcast proposal is offered to many via a sentinel
|
|
131
|
+
// `proposedTo` ('everyone' | 'org'), so there is no per-recipient party
|
|
132
|
+
// slot for one recipient to reject and nothing a single reject could
|
|
133
|
+
// change server-side. Returning the agreement here reported a fake
|
|
134
|
+
// success while the item stayed claimable. Fail honestly instead — the
|
|
135
|
+
// caller either claims it (action=approve → POST /claim) or ignores it.
|
|
136
|
+
throw new Error(`Agreement ${agreementId} is an open/broadcast proposal (proposedTo="${String(proposedTo)}") and cannot be rejected by a single recipient — it has no personal approval slot. Ignore it to pass on it, or use action=approve to claim it.`);
|
|
137
|
+
}
|
|
131
138
|
const { agreement: updated } = await claimAgreement(agreementId, creds);
|
|
132
139
|
return updated;
|
|
133
140
|
}
|
|
@@ -233,57 +240,65 @@ export async function getAgreementStatus(agreementId, creds) {
|
|
|
233
240
|
}
|
|
234
241
|
export async function listAgreements(filters = {}, creds) {
|
|
235
242
|
assertCreds(creds, 'list agreements');
|
|
243
|
+
// ZIG-699 — return an empty array only for a genuine empty 200 result. Any
|
|
244
|
+
// failure (non-2xx / network) throws so the MCP tool reports a real error
|
|
245
|
+
// instead of "you have no agreements". The status stays whitespace-delimited
|
|
246
|
+
// so the tool's toolError/classifyToolError maps it to a stable code.
|
|
247
|
+
// Canonical query path: GET /agreements?scope=&status=&engagementKind=&...
|
|
248
|
+
const url = new URL(getAgreementBaseUrl());
|
|
249
|
+
if (filters.status)
|
|
250
|
+
url.searchParams.set('status', filters.status);
|
|
251
|
+
if (filters.engagementKind)
|
|
252
|
+
url.searchParams.set('engagementKind', filters.engagementKind);
|
|
253
|
+
if (filters.proposalStatus)
|
|
254
|
+
url.searchParams.set('proposalStatus', filters.proposalStatus);
|
|
255
|
+
if (filters.hasTask != null)
|
|
256
|
+
url.searchParams.set('hasTask', String(filters.hasTask));
|
|
257
|
+
let res;
|
|
236
258
|
try {
|
|
237
|
-
|
|
238
|
-
const url = new URL(getAgreementBaseUrl());
|
|
239
|
-
if (filters.status)
|
|
240
|
-
url.searchParams.set('status', filters.status);
|
|
241
|
-
if (filters.engagementKind)
|
|
242
|
-
url.searchParams.set('engagementKind', filters.engagementKind);
|
|
243
|
-
if (filters.proposalStatus)
|
|
244
|
-
url.searchParams.set('proposalStatus', filters.proposalStatus);
|
|
245
|
-
if (filters.hasTask != null)
|
|
246
|
-
url.searchParams.set('hasTask', String(filters.hasTask));
|
|
247
|
-
const res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
|
|
248
|
-
if (!res.ok) {
|
|
249
|
-
const body = await res.text().catch(() => '');
|
|
250
|
-
runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
251
|
-
return [];
|
|
252
|
-
}
|
|
253
|
-
const data = await res.json().catch(() => null);
|
|
254
|
-
return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
|
|
259
|
+
res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
|
|
255
260
|
}
|
|
256
261
|
catch (e) {
|
|
257
262
|
runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${e.message}`);
|
|
258
|
-
|
|
263
|
+
throw new Error(`GET /agreements network error: ${e.message}`);
|
|
264
|
+
}
|
|
265
|
+
if (!res.ok) {
|
|
266
|
+
const body = await res.text().catch(() => '');
|
|
267
|
+
runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
268
|
+
throw new Error(`GET /agreements ${res.status} ${body?.slice(0, 200)}`);
|
|
259
269
|
}
|
|
270
|
+
const data = await res.json().catch(() => null);
|
|
271
|
+
return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
|
|
260
272
|
}
|
|
261
273
|
export async function getMyAgreements(filters = {}, creds) {
|
|
262
274
|
assertCreds(creds, 'get my agreements');
|
|
275
|
+
// ZIG-699 — empty array only for a genuine empty 200; any failure throws so
|
|
276
|
+
// the tool surfaces a real error rather than "no agreements" (see listAgreements).
|
|
277
|
+
// Canonical query path: GET /agreements?scope=mine returns the enriched
|
|
278
|
+
// shape (tasks + originChatId + isYou flags).
|
|
279
|
+
const url = new URL(getAgreementBaseUrl());
|
|
280
|
+
url.searchParams.set('scope', 'mine');
|
|
281
|
+
if (filters.engagementKind)
|
|
282
|
+
url.searchParams.set('engagementKind', filters.engagementKind);
|
|
283
|
+
if (filters.proposalStatus)
|
|
284
|
+
url.searchParams.set('proposalStatus', filters.proposalStatus);
|
|
285
|
+
if (filters.hasTask != null)
|
|
286
|
+
url.searchParams.set('hasTask', String(filters.hasTask));
|
|
287
|
+
let res;
|
|
263
288
|
try {
|
|
264
|
-
|
|
265
|
-
// shape (tasks + originChatId + isYou flags).
|
|
266
|
-
const url = new URL(getAgreementBaseUrl());
|
|
267
|
-
url.searchParams.set('scope', 'mine');
|
|
268
|
-
if (filters.engagementKind)
|
|
269
|
-
url.searchParams.set('engagementKind', filters.engagementKind);
|
|
270
|
-
if (filters.proposalStatus)
|
|
271
|
-
url.searchParams.set('proposalStatus', filters.proposalStatus);
|
|
272
|
-
if (filters.hasTask != null)
|
|
273
|
-
url.searchParams.set('hasTask', String(filters.hasTask));
|
|
274
|
-
const res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
|
|
275
|
-
if (!res.ok) {
|
|
276
|
-
const body = await res.text().catch(() => '');
|
|
277
|
-
runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
278
|
-
return [];
|
|
279
|
-
}
|
|
280
|
-
const data = await res.json().catch(() => null);
|
|
281
|
-
return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
|
|
289
|
+
res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
|
|
282
290
|
}
|
|
283
291
|
catch (e) {
|
|
284
292
|
runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${e.message}`);
|
|
285
|
-
|
|
293
|
+
throw new Error(`GET /agreements?scope=mine network error: ${e.message}`);
|
|
286
294
|
}
|
|
295
|
+
if (!res.ok) {
|
|
296
|
+
const body = await res.text().catch(() => '');
|
|
297
|
+
runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
298
|
+
throw new Error(`GET /agreements?scope=mine ${res.status} ${body?.slice(0, 200)}`);
|
|
299
|
+
}
|
|
300
|
+
const data = await res.json().catch(() => null);
|
|
301
|
+
return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
|
|
287
302
|
}
|
|
288
303
|
export async function getAgreement(agreementId, creds) {
|
|
289
304
|
if (!agreementId)
|
package/dist/http/ChatClient.js
CHANGED
|
@@ -112,23 +112,27 @@ export async function sendChatMessage(input, creds) {
|
|
|
112
112
|
}
|
|
113
113
|
export async function listMyChats(creds) {
|
|
114
114
|
assertCreds(creds, 'list my chats');
|
|
115
|
+
// ZIG-699 — empty array only for a genuine empty 200; any failure (non-2xx /
|
|
116
|
+
// network) throws so ziggs_list_chats reports a real error instead of "you
|
|
117
|
+
// have no chats". Status stays whitespace-delimited for toolError classification.
|
|
118
|
+
let res;
|
|
115
119
|
try {
|
|
116
|
-
|
|
120
|
+
res = await fetch(`${getBackendUrl()}/chats/mine`, {
|
|
117
121
|
method: 'GET',
|
|
118
122
|
headers: buildHeaders(creds),
|
|
119
123
|
});
|
|
120
|
-
if (!res.ok) {
|
|
121
|
-
const body = await res.text().catch(() => '');
|
|
122
|
-
runtimeLog.warn('ChatClient', `⚠️ listMyChats failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
123
|
-
return [];
|
|
124
|
-
}
|
|
125
|
-
const data = await res.json().catch(() => null);
|
|
126
|
-
return Array.isArray(data?.['chats']) ? data['chats'] : [];
|
|
127
124
|
}
|
|
128
125
|
catch (e) {
|
|
129
126
|
runtimeLog.warn('ChatClient', `⚠️ listMyChats failed: ${e.message}`);
|
|
130
|
-
|
|
127
|
+
throw new Error(`GET /chats/mine network error: ${e.message}`);
|
|
131
128
|
}
|
|
129
|
+
if (!res.ok) {
|
|
130
|
+
const body = await res.text().catch(() => '');
|
|
131
|
+
runtimeLog.warn('ChatClient', `⚠️ listMyChats failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
132
|
+
throw new Error(`GET /chats/mine ${res.status} ${body?.slice(0, 200)}`);
|
|
133
|
+
}
|
|
134
|
+
const data = await res.json().catch(() => null);
|
|
135
|
+
return Array.isArray(data?.['chats']) ? data['chats'] : [];
|
|
132
136
|
}
|
|
133
137
|
export class ChatClient {
|
|
134
138
|
creds;
|