@pouchy_ai/admin-sdk 0.32.0 → 0.33.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,42 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.33.0 — 2026-09-08
6
+
7
+ ### Added
8
+
9
+ - `Agent.instructions?: boolean` — the template flag that grants
10
+ `chat.instructions` on an agent's session mints, so a turn may carry an
11
+ `instructions` field (developer-authored rules for THAT turn, joined to the
12
+ prompt and never scored as user speech by inbound moderation; issue #3379).
13
+
14
+ Typed here because it is the **only** way to obtain that scope, and an
15
+ integrator's first instinct is to request it at mint time — which silently
16
+ does nothing: the scope sits outside the mintable default set on purpose
17
+ (the field it unlocks skips moderation, and a session token is routinely
18
+ held by the end user's own client), and `validateSessionRequest` narrows a
19
+ requested scope to that set. Flip the template flag instead, from the
20
+ Dashboard or `PATCH /v1/projects/{id}/agents/{agentId}` with
21
+ `{"instructions": true}`. Settings-class: no `templateRev` bump; existing
22
+ session tokens gain the scope on re-mint.
23
+
24
+ ## 0.32.1 — 2026-09-06
25
+
26
+ - **A transport failure now names the request.** `AdminApiError.message` on a
27
+ timeout or a network error is `GET /agents — request timed out after 30000ms`
28
+ / `POST /knowledge — network error: fetch failed`, where it used to be the
29
+ bare tail. Status 0 failures carry no `code` and no `errorId`, and ~70
30
+ methods share one request funnel, so the message was the only place the call
31
+ could have been named and it was the one place that did not name it — the
32
+ README's own `console.error(e.status, e.message)` read identically for every
33
+ route. The sibling `@pouchy_ai/world-sdk` has always spelled `${method}
34
+ ${path}` here. The non-2xx path is UNCHANGED: the server's own `error` string
35
+ is still passed through verbatim, because that is the message this SDK
36
+ documents and integrators match on. Only its no-body fallback gained the
37
+ prefix (`GET /agents → HTTP 502`, previously `HTTP 502`), where there was no
38
+ server text to displace. If you assert on exact message text for a timeout or
39
+ network error, match on a substring.
40
+
5
41
  ## 0.32.0 — 2026-09-06
6
42
 
7
43
  - **Diff entries are `{ field, before, after }`** — `diffAgentVersions` and
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.32.0";
1
+ export declare const ADMIN_SDK_VERSION = "0.33.0";
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
@@ -154,6 +165,14 @@ export interface Agent {
154
165
  * (concurrent headless workers under one persona). Default false since
155
166
  * owner decision D-10 (2026-09-05). */
156
167
  spawnSubtasks?: boolean;
168
+ /** Grant `chat.instructions` on this agent's session mints, so a turn may
169
+ * carry an `instructions` field — developer-authored rules for THAT turn,
170
+ * joined to the prompt and never scored as user speech by inbound
171
+ * moderation (issue #3379). Default false, and this template flag is the
172
+ * ONLY way to obtain the scope: it sits outside the mintable default set
173
+ * on purpose, so asking for it in the session-mint body is narrowed away.
174
+ * Leave it off unless your backend assembles per-turn rules itself. */
175
+ instructions?: boolean;
157
176
  /** Reply-cue opt-in (see ReplyCues). */
158
177
  replyCues?: ReplyCues;
159
178
  templateRev: number;
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.32.0';
11
+ export const ADMIN_SDK_VERSION = '0.33.0';
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.32.0",
3
+ "version": "0.33.0",
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",