@ziggs-ai/api-client 0.1.22 → 0.1.23

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.
@@ -233,57 +233,65 @@ export async function getAgreementStatus(agreementId, creds) {
233
233
  }
234
234
  export async function listAgreements(filters = {}, creds) {
235
235
  assertCreds(creds, 'list agreements');
236
+ // ZIG-699 — return an empty array only for a genuine empty 200 result. Any
237
+ // failure (non-2xx / network) throws so the MCP tool reports a real error
238
+ // instead of "you have no agreements". The status stays whitespace-delimited
239
+ // so the tool's toolError/classifyToolError maps it to a stable code.
240
+ // Canonical query path: GET /agreements?scope=&status=&engagementKind=&...
241
+ const url = new URL(getAgreementBaseUrl());
242
+ if (filters.status)
243
+ url.searchParams.set('status', filters.status);
244
+ if (filters.engagementKind)
245
+ url.searchParams.set('engagementKind', filters.engagementKind);
246
+ if (filters.proposalStatus)
247
+ url.searchParams.set('proposalStatus', filters.proposalStatus);
248
+ if (filters.hasTask != null)
249
+ url.searchParams.set('hasTask', String(filters.hasTask));
250
+ let res;
236
251
  try {
237
- // Canonical query path: GET /agreements?scope=&status=&engagementKind=&...
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'] : [];
252
+ res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
255
253
  }
256
254
  catch (e) {
257
255
  runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${e.message}`);
258
- return [];
256
+ throw new Error(`GET /agreements network error: ${e.message}`);
259
257
  }
258
+ if (!res.ok) {
259
+ const body = await res.text().catch(() => '');
260
+ runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
261
+ throw new Error(`GET /agreements ${res.status} ${body?.slice(0, 200)}`);
262
+ }
263
+ const data = await res.json().catch(() => null);
264
+ return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
260
265
  }
261
266
  export async function getMyAgreements(filters = {}, creds) {
262
267
  assertCreds(creds, 'get my agreements');
268
+ // ZIG-699 — empty array only for a genuine empty 200; any failure throws so
269
+ // the tool surfaces a real error rather than "no agreements" (see listAgreements).
270
+ // Canonical query path: GET /agreements?scope=mine returns the enriched
271
+ // shape (tasks + originChatId + isYou flags).
272
+ const url = new URL(getAgreementBaseUrl());
273
+ url.searchParams.set('scope', 'mine');
274
+ if (filters.engagementKind)
275
+ url.searchParams.set('engagementKind', filters.engagementKind);
276
+ if (filters.proposalStatus)
277
+ url.searchParams.set('proposalStatus', filters.proposalStatus);
278
+ if (filters.hasTask != null)
279
+ url.searchParams.set('hasTask', String(filters.hasTask));
280
+ let res;
263
281
  try {
264
- // Canonical query path: GET /agreements?scope=mine returns the enriched
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'] : [];
282
+ res = await fetch(url.toString(), { method: 'GET', headers: buildHeaders(creds) });
282
283
  }
283
284
  catch (e) {
284
285
  runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${e.message}`);
285
- return [];
286
+ throw new Error(`GET /agreements?scope=mine network error: ${e.message}`);
286
287
  }
288
+ if (!res.ok) {
289
+ const body = await res.text().catch(() => '');
290
+ runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
291
+ throw new Error(`GET /agreements?scope=mine ${res.status} ${body?.slice(0, 200)}`);
292
+ }
293
+ const data = await res.json().catch(() => null);
294
+ return Array.isArray(data?.['agreements']) ? data['agreements'] : [];
287
295
  }
288
296
  export async function getAgreement(agreementId, creds) {
289
297
  if (!agreementId)
@@ -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
- const res = await fetch(`${getBackendUrl()}/chats/mine`, {
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
- return [];
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",