@pouchy_ai/admin-sdk 0.4.0 → 0.4.2

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,64 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.4.2 — 2026-07-16
6
+
7
+ The rest of the 0.4.1 drift class — four more response/input shapes that lied
8
+ about the live routes, caught by comparing every method against its
9
+ `/v1/admin` handler. Type + doc fixes only (the client is a generic proxy).
10
+
11
+ - **`listCredentials`** returns `{ enabled, skills }` (vault status + which
12
+ skill slugs hold credentials) — the old `{ credentials }` key never existed,
13
+ so `res.credentials` was always `undefined`. `putCredentials` returns
14
+ `{ ok, skill, entries }`.
15
+ - **`updateProject`** returns what changed — `{ renamed?, name?, archived? }` —
16
+ not `{ project: { projectId } }` (that key never existed on PATCH).
17
+ - **`createSchedule.runAt`** is **epoch milliseconds** (number), not an ISO
18
+ string — the server type-checks `typeof runAt === 'number'` and silently
19
+ drops a string (your "one-shot" 400s, or becomes recurring if
20
+ `intervalMinutes` was also set). Input also gains the server's `env?`.
21
+ - **`SecretKey.displayPrefix`** — the stored-key metadata field is
22
+ `displayPrefix`, not `prefix` (affects `listKeys`/`createKey`/`rotateKey`
23
+ consumers); `lastUsedAt`/`revokedAt` marked optional as stored.
24
+ - **`getTracesSummary`** now requires `agentId` — the server 400s without it,
25
+ so the old all-optional signature compiled calls that always fail.
26
+ - **`createChannel`** input gains `env?` + `secret?` (connector credentials) —
27
+ the closed object literal blocked fields the server accepts, so test-env /
28
+ secret-bearing connectors were unreachable through the typed method.
29
+ - **`getBilling().billing.periodEnd`** is `string | null` (always present).
30
+
31
+ Also in this release: `GET /v1/admin/openapi` (the machine-readable spec this
32
+ SDK mirrors) was rewritten against the live routes — it still described the
33
+ pre-0.4.1 contract, so generated clients inherited every bug above.
34
+
35
+ ## 0.4.1 — 2026-07-16
36
+
37
+ Type-shape corrections — several method signatures had drifted from the live
38
+ `/v1/admin` routes, so a caller trusting the types built request bodies the
39
+ server rejects or read response fields that don't exist. No runtime code
40
+ changed (the client is a generic proxy); these are type + doc fixes.
41
+
42
+ - **`createSchedule`** now requires `externalUserId` + `prompt` alongside
43
+ `agentId` and schedules by `intervalMinutes`/`runAt` — the old `{ agentId,
44
+ cron, prompt? }` was unusable (there is no `cron` field; the server 400s
45
+ without `externalUserId`). Return is `{ schedule: { id } }` (was
46
+ `scheduleId`).
47
+ - **`ingestKnowledge`** input is `{ text, name?, kind?, locale? }` — the old
48
+ `title`/`url` fields were silently ignored by the server.
49
+ - **`getUserWallet`** returns `{ hasWallet, balance: string | null }` (a prose
50
+ balance string), not `{ balance: number, address }`.
51
+ - **`createKey`** returns `{ key: string, record }` (plaintext token in `key`);
52
+ the README example logged the nonexistent `key.token`.
53
+ - **`getUsage`** returns `{ usage }` and **`getBilling`** returns `{ billing,
54
+ ledger }` (both were typed flat); the README `usage.mau` example is fixed.
55
+ - **Channels** methods return `connector`/`connectors` (was `channel`), and
56
+ `deleteChannel`/`deleteSchedule` return `{ ok }` (was `{ deleted }`).
57
+ - **`listUsers`** params are `{ external_user_id?, external_user_prefix? }`
58
+ (the old `{ q, limit }` were no-ops; the server hard-caps at 100).
59
+ - **`updateSkill`** generic return is `Record<string, unknown>` (it echoes only
60
+ the changed knob) — prefer the typed `setSkillRate`/`setSkillDailyCap`/
61
+ `grantSkill` conveniences, which were already correct.
62
+
5
63
  ## 0.4.0 — 2026-07-13
6
64
 
7
65
  Full skill-lifecycle parity — the two knobs the dashboard grew (a runaway
package/README.md CHANGED
@@ -35,10 +35,10 @@ await admin.updateAgent(agent.agentId, { status: 'published' });
35
35
 
36
36
  // Mint a secret key for your backend to open end-user sessions with
37
37
  const { key } = await admin.createKey({ label: 'prod-backend', env: 'live' });
38
- console.log(key.token); // shown ONCE
38
+ console.log(key); // the plaintext token — shown ONCE
39
39
 
40
40
  // Read this month's usage
41
- const usage = await admin.getUsage();
41
+ const { usage } = await admin.getUsage();
42
42
  console.log(usage.mau, '/', usage.mauLimit, 'MAU');
43
43
 
44
44
  // Equip an agent with ANY skill — including a docs-only skill.md that has no
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ADMIN_SDK_VERSION = "0.4.0";
1
+ export declare const ADMIN_SDK_VERSION = "0.4.2";
2
2
  export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1/admin";
3
3
  export interface AdminClientOptions {
4
4
  /** A project Admin key (`pchy_admin_…`) from the dashboard Admin Keys page. */
@@ -32,10 +32,13 @@ export interface SecretKey {
32
32
  keyId: string;
33
33
  label: string;
34
34
  env: Env;
35
- prefix: string;
35
+ /** The key's display prefix (e.g. `pchy_live_ab12…`) — the server never
36
+ * returns the plaintext after mint. */
37
+ displayPrefix: string;
36
38
  createdAt: string;
37
- lastUsedAt: string | null;
38
- revokedAt: string | null;
39
+ lastUsedAt?: string | null;
40
+ revokedAt?: string | null;
41
+ [k: string]: unknown;
39
42
  }
40
43
  export interface Instance {
41
44
  instanceId: string;
@@ -75,6 +78,8 @@ export interface CatalogVoice {
75
78
  previewUrl?: string;
76
79
  /** Present on tagged rows; filter with listVoices({ gender }). */
77
80
  gender?: 'female' | 'male' | 'neutral';
81
+ /** Present on tagged rows; filter with listVoices({ age }). */
82
+ age?: 'young' | 'middle_aged' | 'old';
78
83
  /** Locales this voice suits; ABSENT = unrestricted. */
79
84
  locales?: string[];
80
85
  }
@@ -127,15 +132,14 @@ export interface AdminClient {
127
132
  listKeys(): Promise<{
128
133
  keys: SecretKey[];
129
134
  }>;
135
+ /** Mint a secret key. `key` is the plaintext token, returned ONCE; `record`
136
+ * is the stored metadata (no plaintext). */
130
137
  createKey(input: {
131
138
  label?: string;
132
139
  env?: Env;
133
140
  }): Promise<{
134
- key: {
135
- keyId: string;
136
- token: string;
137
- env: Env;
138
- };
141
+ key: string;
142
+ record: SecretKey;
139
143
  }>;
140
144
  revokeKey(keyId: string): Promise<{
141
145
  revoked: boolean;
@@ -152,9 +156,11 @@ export interface AdminClient {
152
156
  graceUntil: string | null;
153
157
  };
154
158
  }>;
159
+ /** List end-user instances. Filter by exact external id or by prefix (the
160
+ * server ignores any other query param and hard-caps the page at 100). */
155
161
  listUsers(params?: {
156
- q?: string;
157
- limit?: number;
162
+ external_user_id?: string;
163
+ external_user_prefix?: string;
158
164
  }): Promise<{
159
165
  users: Instance[];
160
166
  }>;
@@ -164,9 +170,12 @@ export interface AdminClient {
164
170
  deleteUser(instanceId: string): Promise<{
165
171
  deleted: boolean;
166
172
  }>;
173
+ /** The instance companion's wallet. `balance` is a human-readable prose
174
+ * string (e.g. "Wallet balance: … (~$X total)."), or null when the instance
175
+ * has no wallet — NOT a number, and there is no address field. */
167
176
  getUserWallet(instanceId: string): Promise<{
168
- balance: number;
169
- address: string;
177
+ hasWallet: boolean;
178
+ balance: string | null;
170
179
  }>;
171
180
  getUserTraces(instanceId: string): Promise<{
172
181
  traces: unknown[];
@@ -199,10 +208,13 @@ export interface AdminClient {
199
208
  listKnowledge(): Promise<{
200
209
  docs: unknown[];
201
210
  }>;
211
+ /** Ingest a knowledge doc. `text` is required; `name`/`kind`/`locale` are the
212
+ * server's fields (an earlier `title`/`url` shape was silently ignored). */
202
213
  ingestKnowledge(input: {
203
- title?: string;
204
- text?: string;
205
- url?: string;
214
+ text: string;
215
+ name?: string;
216
+ kind?: string;
217
+ locale?: string;
206
218
  }): Promise<{
207
219
  doc: {
208
220
  docId: string;
@@ -228,11 +240,12 @@ export interface AdminClient {
228
240
  version: number;
229
241
  };
230
242
  }>;
231
- updateSkill(slug: string, patch: Record<string, unknown>): Promise<{
232
- skill: {
233
- slug: string;
234
- };
235
- }>;
243
+ /** Generic PATCH of a skill's knobs. The response echoes only the knob(s)
244
+ * you changed (e.g. `{ ratePerMin }`, `{ maxCallsPerDay, reprovisioned }`,
245
+ * `{ freeHttp, grantedDomains, reprovisioned }`) — prefer the typed
246
+ * conveniences (setSkillRate / setSkillDailyCap / grantSkill) for a precise
247
+ * return type. */
248
+ updateSkill(slug: string, patch: Record<string, unknown>): Promise<Record<string, unknown>>;
236
249
  /** Set a skill's per-minute call budget (1..120; null restores the default). */
237
250
  setSkillRate(slug: string, ratePerMin: number | null): Promise<{
238
251
  ratePerMin: number | null;
@@ -273,50 +286,69 @@ export interface AdminClient {
273
286
  uninstallSkill(slug: string): Promise<{
274
287
  deleted: boolean;
275
288
  }>;
289
+ /** Secret-free vault metadata: `enabled` says whether the deployment has a
290
+ * vault at all; `skills` lists which skill slugs hold credentials (values
291
+ * are never returned by any endpoint). */
276
292
  listCredentials(): Promise<{
277
- credentials: unknown[];
293
+ enabled: boolean;
294
+ skills: unknown[];
278
295
  }>;
279
296
  putCredentials(input: {
280
297
  skill: string;
281
298
  credentials: Record<string, unknown>;
282
299
  }): Promise<{
283
300
  ok: boolean;
301
+ skill: string;
302
+ entries: number;
284
303
  }>;
285
304
  deleteCredentials(skill: string): Promise<{
286
305
  deleted: boolean;
287
306
  }>;
288
307
  listChannels(): Promise<{
289
- channels: unknown[];
308
+ connectors: unknown[];
290
309
  }>;
291
310
  createChannel(input: {
292
311
  type: string;
293
312
  agentId: string;
313
+ env?: Env;
294
314
  config?: Record<string, unknown>;
315
+ /** Connector credentials (bot token, signing secret, …) — stored
316
+ * encrypted, never returned. */
317
+ secret?: Record<string, unknown>;
295
318
  }): Promise<{
296
- channel: {
319
+ connector: {
297
320
  id: string;
298
321
  };
299
322
  inboundUrl: string;
300
323
  }>;
301
324
  getChannel(channelId: string): Promise<{
302
- channel: unknown;
325
+ connector: unknown;
303
326
  }>;
304
327
  updateChannel(channelId: string, patch: Record<string, unknown>): Promise<{
305
- channel: unknown;
328
+ connector: unknown;
306
329
  }>;
307
330
  deleteChannel(channelId: string): Promise<{
308
- deleted: boolean;
331
+ ok: boolean;
309
332
  }>;
310
333
  listSchedules(): Promise<{
311
334
  schedules: unknown[];
312
335
  }>;
336
+ /** Create a schedule. `externalUserId` and `prompt` are required alongside
337
+ * `agentId`; the schedule fires by `intervalMinutes` (recurring, >=5) or
338
+ * `runAt` (one-shot **epoch milliseconds** — an ISO string is silently
339
+ * ignored by the server) — there is NO cron field. Returns the stored
340
+ * record, whose id lives on `.id`. */
313
341
  createSchedule(input: {
314
342
  agentId: string;
315
- cron: string;
316
- prompt?: string;
343
+ externalUserId: string;
344
+ prompt: string;
345
+ intervalMinutes?: number;
346
+ runAt?: number;
347
+ env?: Env;
348
+ deliverTo?: unknown;
317
349
  }): Promise<{
318
350
  schedule: {
319
- scheduleId: string;
351
+ id: string;
320
352
  };
321
353
  }>;
322
354
  getSchedule(scheduleId: string): Promise<{
@@ -326,7 +358,7 @@ export interface AdminClient {
326
358
  schedule: unknown;
327
359
  }>;
328
360
  deleteSchedule(scheduleId: string): Promise<{
329
- deleted: boolean;
361
+ ok: boolean;
330
362
  }>;
331
363
  listWebhooks(): Promise<{
332
364
  webhooks: unknown[];
@@ -363,14 +395,22 @@ export interface AdminClient {
363
395
  testWebhook(webhookId: string): Promise<DeliveryOutcome>;
364
396
  /** Manually re-send a recorded delivery's original body, re-signed. */
365
397
  redeliverWebhook(deliveryId: string): Promise<DeliveryOutcome>;
366
- getUsage(): Promise<MonthUsage>;
398
+ getUsage(): Promise<{
399
+ usage: MonthUsage;
400
+ }>;
367
401
  getBilling(): Promise<{
368
- plan: string;
369
- mauLimit: number;
370
- periodEnd?: string;
402
+ billing: {
403
+ plan: string;
404
+ effectivePlan: string;
405
+ mauLimit: number;
406
+ periodEnd: string | null;
407
+ };
408
+ ledger: unknown;
371
409
  }>;
372
- getTracesSummary(params?: {
373
- agentId?: string;
410
+ /** Aggregate trace analytics. `agentId` is REQUIRED — the server 400s
411
+ * without it. */
412
+ getTracesSummary(params: {
413
+ agentId: string;
374
414
  sinceHours?: number;
375
415
  }): Promise<Record<string, unknown>>;
376
416
  /** Recent run rows project-wide (the failed-run browser). */
@@ -382,11 +422,12 @@ export interface AdminClient {
382
422
  }): Promise<{
383
423
  traces: RecentTrace[];
384
424
  }>;
385
- /** Enabled platform voices for programmatic provisioning. Filter by gender
386
- * (explicitly tagged rows only) and/or locale (rows listing it, or with no
387
- * locale list = unrestricted). */
425
+ /** Enabled platform voices for programmatic provisioning. Filter by gender /
426
+ * age (explicitly tagged rows only) and/or locale (rows listing it, or with
427
+ * no locale list = unrestricted). */
388
428
  listVoices(params?: {
389
429
  gender?: 'female' | 'male' | 'neutral';
430
+ age?: 'young' | 'middle_aged' | 'old';
390
431
  locale?: string;
391
432
  }): Promise<{
392
433
  voices: CatalogVoice[];
@@ -403,13 +444,15 @@ export interface AdminClient {
403
444
  archived?: boolean;
404
445
  };
405
446
  }>;
447
+ /** Rename / archive the project. The response echoes only what changed —
448
+ * `{ renamed, name }` and/or `{ archived }` — there is no `project` key. */
406
449
  updateProject(patch: {
407
450
  name?: string;
408
451
  archived?: boolean;
409
452
  }): Promise<{
410
- project: {
411
- projectId: string;
412
- };
453
+ renamed?: boolean;
454
+ name?: string;
455
+ archived?: boolean;
413
456
  }>;
414
457
  /** Escape hatch: call any endpoint the typed methods don't cover yet. */
415
458
  request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
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.4.0';
11
+ export const ADMIN_SDK_VERSION = '0.4.2';
12
12
  export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1/admin';
13
13
  /** Thrown on any non-2xx response. `status` is the HTTP status; `message` is the
14
14
  * server's `error` string when present. */
@@ -104,7 +104,7 @@ export function createAdminClient(opts) {
104
104
  redeliverWebhook: (id) => request('POST', `/webhooks/deliveries/${encodeURIComponent(id)}/redeliver`),
105
105
  getUsage: () => request('GET', '/usage'),
106
106
  getBilling: () => request('GET', '/billing'),
107
- getTracesSummary: (params = {}) => request('GET', `/traces/summary${qs(params)}`),
107
+ getTracesSummary: (params) => request('GET', `/traces/summary${qs(params)}`),
108
108
  getRecentTraces: (params = {}) => request('GET', `/traces/recent${qs({ ...params, errorsOnly: params.errorsOnly ? '1' : undefined })}`),
109
109
  listVoices: (params = {}) => request('GET', `/voice-catalog${qs(params)}`),
110
110
  getLogs: (params = {}) => request('GET', `/logs${qs(params)}`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/admin-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Typed TypeScript client for the Pouchy Admin API — 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",