@pouchy_ai/admin-sdk 0.31.1 → 0.32.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 CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.32.1 — 2026-09-06
6
+
7
+ - **A transport failure now names the request.** `AdminApiError.message` on a
8
+ timeout or a network error is `GET /agents — request timed out after 30000ms`
9
+ / `POST /knowledge — network error: fetch failed`, where it used to be the
10
+ bare tail. Status 0 failures carry no `code` and no `errorId`, and ~70
11
+ methods share one request funnel, so the message was the only place the call
12
+ could have been named and it was the one place that did not name it — the
13
+ README's own `console.error(e.status, e.message)` read identically for every
14
+ route. The sibling `@pouchy_ai/world-sdk` has always spelled `${method}
15
+ ${path}` here. The non-2xx path is UNCHANGED: the server's own `error` string
16
+ is still passed through verbatim, because that is the message this SDK
17
+ documents and integrators match on. Only its no-body fallback gained the
18
+ prefix (`GET /agents → HTTP 502`, previously `HTTP 502`), where there was no
19
+ server text to displace. If you assert on exact message text for a timeout or
20
+ network error, match on a substring.
21
+
22
+ ## 0.32.0 — 2026-09-06
23
+
24
+ - **Diff entries are `{ field, before, after }`** — `diffAgentVersions` and
25
+ `getAgentPromotion` were typed `{ field, from, to }` since they were added,
26
+ and the server has always sent `before` / `after` (`diffAgentTemplates`).
27
+ Reading `d.from` / `d.to` gave `undefined` for every changed field. The
28
+ types (and the published OpenAPI spec) now say what the wire says; no
29
+ runtime change. If you read the keys by name, rename them.
30
+ - **`getAgentPromotion().pinnedSnapshotMissing?`** — true when the production
31
+ pin names an archived snapshot that no longer exists, in which case live
32
+ instances run the staging head until a re-promote re-pins. Additive;
33
+ older servers omit it. The diff is empty in that state, so read this before
34
+ reading an empty diff as "in sync".
35
+
5
36
  ## 0.31.1 — 2026-09-06
6
37
 
7
38
  - **`AdminApiError.errorId`** — the server's lookup reference (`err_…`) for a
package/README.md CHANGED
@@ -351,6 +351,20 @@ occurred.") and `AdminApiError.errorId` carries the server's `err_…` lookup
351
351
  reference (0.31.1) — quote it in a support request; it is what resolves to the
352
352
  real cause.
353
353
 
354
+ A **transport** failure has no status, no `code` and no `errorId`, so since
355
+ 0.32.1 its message names the request that failed:
356
+
357
+ ```text
358
+ GET /agents — request timed out after 30000ms
359
+ POST /knowledge/url — network error: fetch failed
360
+ ```
361
+
362
+ Every method shares one request funnel, so without that prefix a timeout on a
363
+ five-minute knowledge ingest and a timeout on `listAgents` printed the same
364
+ line. HTTP errors are unchanged: the message is the server's own `error` string
365
+ (`"unknown agent"`), and only its no-body fallback names the request
366
+ (`GET /agents → HTTP 502`).
367
+
354
368
  ### Failure codes (409)
355
369
 
356
370
  **Every machine-readable failure on this API is a 409**, so `status` separates
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ADMIN_SDK_VERSION = "0.31.1";
1
+ export declare const ADMIN_SDK_VERSION = "0.32.1";
2
2
  export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1/admin";
3
3
  /** Deadline for the routes whose server handler declares `maxDuration: 300` —
4
4
  * the server's own ceiling plus headroom, so a client abort can only ever mean
@@ -65,10 +65,21 @@ export declare const ADMIN_ERROR_CODES: readonly ["story_contract_v2_write_disab
65
65
  * codes newer than this SDK build while preserving autocomplete — same
66
66
  * doctrine as the companion SDK's `CompanionErrorCodeValue`. */
67
67
  export type AdminErrorCode = (typeof ADMIN_ERROR_CODES)[number] | (string & {});
68
- /** Thrown on any non-2xx response. `status` is the HTTP status; `message` is the
69
- * server's `error` string when present; `retryAfter` is the throttle's own
70
- * backoff in SECONDS on a 429 (undefined on every other failure); `code` is the
71
- * server's machine tag when it named one (undefined otherwise).
68
+ /** Thrown on any non-2xx response AND on a transport failure that never reached
69
+ * the server (network / DNS / timeout), which carries `status: 0`. `status` is
70
+ * the HTTP status; `retryAfter` is the throttle's own backoff in SECONDS on a
71
+ * 429 (undefined on every other failure); `code` is the server's machine tag
72
+ * when it named one (undefined otherwise).
73
+ *
74
+ * `message` has two shapes, and which one you get follows `status`. On a
75
+ * non-2xx it is the server's own `error` string, verbatim — that is what this
76
+ * package documents and what integrators read. On a status-0 transport failure
77
+ * there IS no server string, and no `code` or `errorId` either, so the message
78
+ * names the request instead (`GET /agents — request timed out after 30000ms`);
79
+ * ~70 methods share one funnel, and without it a hung five-minute knowledge
80
+ * ingest printed the same line as a hung `listAgents` (0.32.1). The non-2xx
81
+ * fallback for a body with no `error` at all is named the same way
82
+ * (`GET /agents → HTTP 502`). Prose either way: switch on `code`, not on this.
72
83
  *
73
84
  * Why `code` exists: the Admin API's machine-readable failures are ALL on
74
85
  * 409, so `status` cannot separate them and this package used to discard the
@@ -517,8 +528,8 @@ export interface AdminClient {
517
528
  to: string;
518
529
  diff: Array<{
519
530
  field: string;
520
- from: unknown;
521
- to: unknown;
531
+ before: unknown;
532
+ after: unknown;
522
533
  }>;
523
534
  }>;
524
535
  /** Roll an agent back to an archived revision. git-revert semantics: the
@@ -529,16 +540,21 @@ export interface AdminClient {
529
540
  }>;
530
541
  /** Promotion status: the head (staging) vs the pinned production version, plus
531
542
  * the diff a promotion would ship (empty when in sync). `pending` is false
532
- * when the agent was never promoted (live follows the head). */
543
+ * when the agent was never promoted (live follows the head).
544
+ * `pinnedSnapshotMissing` (0.32.0) is true when the pin names a snapshot
545
+ * that no longer exists — live instances are then running the staging head
546
+ * and a re-promote re-pins; the diff is empty in that state for the OTHER
547
+ * reason, so read this field before reading an empty diff as "in sync". */
533
548
  getAgentPromotion(agentId: string): Promise<{
534
549
  stagingRev: number;
535
550
  prodRev: number | null;
536
551
  pending: boolean;
537
552
  diff: Array<{
538
553
  field: string;
539
- from: unknown;
540
- to: unknown;
554
+ before: unknown;
555
+ after: unknown;
541
556
  }>;
557
+ pinnedSnapshotMissing?: boolean;
542
558
  }>;
543
559
  /** Promote the head to production: freezes the head as an archived version and
544
560
  * pins prodRev WITHOUT bumping the rev. Live instances re-resolve on their
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // import { createAdminClient } from '@pouchy_ai/admin-sdk';
9
9
  // const admin = createAdminClient({ adminKey: process.env.POUCHY_ADMIN_KEY! });
10
10
  // const { agents } = await admin.listAgents();
11
- export const ADMIN_SDK_VERSION = '0.31.1';
11
+ export const ADMIN_SDK_VERSION = '0.32.1';
12
12
  export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1/admin';
13
13
  /** Default per-request timeout (ms). A hung upstream otherwise never rejects. */
14
14
  const DEFAULT_TIMEOUT_MS = 30_000;
@@ -94,10 +94,21 @@ export const ADMIN_ERROR_CODES = [
94
94
  'run_not_waiting',
95
95
  'event_mismatch'
96
96
  ];
97
- /** Thrown on any non-2xx response. `status` is the HTTP status; `message` is the
98
- * server's `error` string when present; `retryAfter` is the throttle's own
99
- * backoff in SECONDS on a 429 (undefined on every other failure); `code` is the
100
- * server's machine tag when it named one (undefined otherwise).
97
+ /** Thrown on any non-2xx response AND on a transport failure that never reached
98
+ * the server (network / DNS / timeout), which carries `status: 0`. `status` is
99
+ * the HTTP status; `retryAfter` is the throttle's own backoff in SECONDS on a
100
+ * 429 (undefined on every other failure); `code` is the server's machine tag
101
+ * when it named one (undefined otherwise).
102
+ *
103
+ * `message` has two shapes, and which one you get follows `status`. On a
104
+ * non-2xx it is the server's own `error` string, verbatim — that is what this
105
+ * package documents and what integrators read. On a status-0 transport failure
106
+ * there IS no server string, and no `code` or `errorId` either, so the message
107
+ * names the request instead (`GET /agents — request timed out after 30000ms`);
108
+ * ~70 methods share one funnel, and without it a hung five-minute knowledge
109
+ * ingest printed the same line as a hung `listAgents` (0.32.1). The non-2xx
110
+ * fallback for a body with no `error` at all is named the same way
111
+ * (`GET /agents → HTTP 502`). Prose either way: switch on `code`, not on this.
101
112
  *
102
113
  * Why `code` exists: the Admin API's machine-readable failures are ALL on
103
114
  * 409, so `status` cannot separate them and this package used to discard the
@@ -239,11 +250,29 @@ export function createAdminClient(opts) {
239
250
  }
240
251
  catch (e) {
241
252
  const isTimeout = e instanceof Error && (e.name === 'TimeoutError' || e.name === 'AbortError');
242
- throw new AdminApiError(isTimeout ? `request timed out after ${timeoutMs}ms` : `network error: ${e instanceof Error ? e.message : String(e)}`, 0);
253
+ // The REQUEST is named, because nothing else in the envelope can name it.
254
+ // ~70 methods share this one funnel and a transport failure has status 0,
255
+ // no `code` and no `errorId` — so the README's own
256
+ // `console.error(e.status, e.message)` read `0 "request timed out after
257
+ // 30000ms"` for every route alike, and an operator could not tell a hung
258
+ // knowledge ingest from a hung `listAgents`. The sibling world-sdk has
259
+ // spelled `${method} ${path}` on both of its transport throws since it
260
+ // shipped; this is the same prefix, for the same reason.
261
+ throw new AdminApiError(isTimeout
262
+ ? `${method} ${path} — request timed out after ${timeoutMs}ms`
263
+ : `${method} ${path} — network error: ${e instanceof Error ? e.message : String(e)}`, 0);
243
264
  }
244
265
  const data = (await res.json().catch(() => ({})));
245
266
  if (!res.ok)
246
- throw new AdminApiError(data?.error ?? `HTTP ${res.status}`, res.status, retryAfterFrom(res, data), codeFrom(data), errorIdFrom(data));
267
+ throw new AdminApiError(
268
+ // The server's own `error` string is passed through UNCHANGED — it is
269
+ // the message this SDK documents (`404 "unknown agent"`), integrators
270
+ // match on it, and `status` / `code` / `errorId` already disambiguate a
271
+ // coded failure. Only the FALLBACK is prefixed, and only because there
272
+ // is no server text there to displace: an edge 502 whose body is HTML
273
+ // (`res.json()` rejects → `{}`) used to read `HTTP 502` with nothing
274
+ // saying which of ~70 calls produced it.
275
+ data?.error ?? `${method} ${path} → HTTP ${res.status}`, res.status, retryAfterFrom(res, data), codeFrom(data), errorIdFrom(data));
247
276
  return data;
248
277
  }
249
278
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/admin-sdk",
3
- "version": "0.31.1",
3
+ "version": "0.32.1",
4
4
  "description": "Typed TypeScript client for the Pouchy Admin API \u2014 manage agents, keys, end users, knowledge, skills, channels, schedules, webhooks and credentials headlessly, with a project Admin key.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",