@pouchy_ai/admin-sdk 0.28.0 → 0.30.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,46 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.30.0 — 2026-09-04
6
+
7
+ - **`internal-a2a` leaves `ChannelTransportType`.** It was a placeholder the
8
+ platform's union and store knew and no adapter served — `createChannel`
9
+ answered 400 on it, which is why `CreatableChannelType` excluded it. The
10
+ platform retired the id (design #24 / F-04: the friend auto-reply is a
11
+ companion session SURFACE, not a transport), so the union no longer names it
12
+ and `CreatableChannelType` is now the whole union. A caller that referenced
13
+ the literal type gets a compile error, which is the point; nothing that ever
14
+ worked changes.
15
+
16
+ ## 0.29.1 — 2026-09-04
17
+
18
+ - **`story_contract_v4_write_disabled`** joins `ADMIN_ERROR_CODES` — a Story
19
+ Package publish that declares a `public: true` flag (Story Contract v4,
20
+ design #23) answers 409 with this code in an environment that has not
21
+ enabled v4 writes, the field intact. Vocabulary only; no method changed.
22
+
23
+ ## 0.29.0 — 2026-08-31
24
+
25
+ - **`setSkillAutoRunTools(slug, toolNames)` — the per-tool confirm exemptions
26
+ (免确认工具) the Admin API could not reach.** Admin API 1.12.0. The knob
27
+ existed on the owner plane and in the dashboard since 2026-08 and was never
28
+ added here, so a headless provisioning flow could install a skill, rate-limit
29
+ it, grant its domains and attach it to an agent — and then answer nothing.
30
+ For MCP skills that is not an edge case: `mcpRecord` hard-codes
31
+ `platformSafe: false`, so every `run_skill` raises a confirm, and a platform
32
+ instance has no human who could ever approve one. This was the only route out.
33
+
34
+ A full REPLACE, not a merge — pass the complete list each call. Names the
35
+ skill does not declare are dropped and echoed in `dropped`, so a typo is
36
+ visible rather than silently ungranted. Grant the READ tools (a storefront's
37
+ `search_catalog` / `get_product`); leave cart mutations and order placement
38
+ gated.
39
+
40
+ Opening this to a long-lived admin key was an explicit decision, not a
41
+ symmetry fix: the confirm being waived is not a human in the loop (on an
42
+ instance nobody can approve it), and the same key already grants the strictly
43
+ wider `freeHttp` + `grantedDomains`.
44
+
5
45
  ## 0.28.0 — 2026-08-29
6
46
 
7
47
  - **`installSkill` / `importAgentPlugin` now type the re-push outcome.** Both
package/README.md CHANGED
@@ -243,7 +243,8 @@ that voice, or the voice catalog is temporarily unreachable; retry),
243
243
  like the other voice planes — there is no separate platform credit rate; it is
244
244
  bounded by an input cap and the shared per-IP utility rate limit.
245
245
 
246
- Every skill knob (`setSkillRate`, `setSkillDailyCap`, `grantSkill`) returns
246
+ Every skill knob (`setSkillRate`, `setSkillDailyCap`, `grantSkill`,
247
+ `setSkillAutoRunTools`) returns
247
248
  `SkillKnobResult<T>` — the knob you set plus `reprovisioned` (instances the new
248
249
  def reached) and `truncated`. A knob only binds a running agent once the def
249
250
  reaches its instance, so `truncated: true` means the sweep hit its cap (100
@@ -307,15 +308,19 @@ createAdminClient({
307
308
  });
308
309
  ```
309
310
 
310
- `timeoutMs` defaults to **30s**, except for the four requests whose server
311
- handler declares `maxDuration: 300` and therefore answers only when the work is
311
+ `timeoutMs` defaults to **30s**, except for the requests whose server handler
312
+ declares `maxDuration: 300` and therefore answers only when the work is
312
313
  finished — `POST /knowledge`, `POST /knowledge/file`, `POST /knowledge/url`
313
- (chunk + summarize + embed, after OCR / Whisper / vision or a page fetch) and
314
- `DELETE /users/{instanceId}` (recursive GDPR erasure). Those default to **310s**
315
- (`LONG_WORK_TIMEOUT_MS`), so a client abort can only ever mean "the server really
316
- is hung", never "the server is still working" a shorter deadline there reports
317
- a failure for an ingest that is succeeding, and the retry it invites races the
318
- still-running first one.
314
+ (chunk + summarize + embed, after OCR / Whisper / vision or a page fetch),
315
+ `DELETE /users/{instanceId}` (recursive GDPR erasure) and
316
+ `POST /capabilities/{name}/test-action` (the Action protocol verifier makes
317
+ REAL deliveries to your endpoint, and an abort mid-test cannot undo the ones
318
+ already made). Those default to **310s** (`LONG_WORK_TIMEOUT_MS`), so a client
319
+ abort can only ever mean "the server really is hung", never "the server is
320
+ still working" — a shorter deadline there reports a failure for an ingest that
321
+ is succeeding, and the retry it invites races the still-running first one (or
322
+ re-runs a side-effecting test whose first verdict is never read). The list is
323
+ `LONG_WORK_REQUESTS`, exported, and a drift test binds it to the routes.
319
324
 
320
325
  Setting `timeoutMs` explicitly always wins and applies to **every** request, long
321
326
  or short. `requestDeadlineMs(method, path)` returns the default a given request
@@ -436,7 +441,7 @@ Reads (`GET`) are not covered by that bucket. `retryAfter` is available from
436
441
  | Secret keys | `listKeys` · `createKey` · `revokeKey` · `rotateKey` (24 h grace) |
437
442
  | End users | `listUsers({ limit?, cursor? })` (cursor-paginated — the response's `nextCursor` feeds the next page; filter variants: `external_user_id` / `external_user_prefix`) · `setUserSuspended` · `deleteUser` · `getUserWallet` · `getUserTraces` · `importUsers` · `exportUser` · `getUserSessions` · `getUserTurns` |
438
443
  | Knowledge | `listKnowledge` · `ingestKnowledge` · `ingestKnowledgeFile` (PDF/audio/video/image) · `ingestKnowledgeUrl` (web page) · `searchKnowledge` (recall probe) · `deleteKnowledge` |
439
- | Skills | `listSkills` · `installSkill` · `updateSkill` · `setSkillRate` · `setSkillDailyCap` · `grantSkill` (free-HTTP) · `compileSkill` (prose→tools) · `uninstallSkill` · `importAgentPlugin` / `exportAgentPlugin` (Agent Plugins 1.0.0 interop) |
444
+ | Skills | `listSkills` · `installSkill` · `updateSkill` · `setSkillRate` · `setSkillDailyCap` · `grantSkill` (free-HTTP) · `setSkillAutoRunTools` (免确认工具 — required to arm an MCP skill on an instance) · `compileSkill` (prose→tools) · `uninstallSkill` · `importAgentPlugin` / `exportAgentPlugin` (Agent Plugins 1.0.0 interop) |
440
445
  | Credentials | `listCredentials` · `putCredentials` · `deleteCredentials` |
441
446
  | Channels | `listChannels` · `createChannel` · `getChannel` · `updateChannel` · `deleteChannel` |
442
447
  | Schedules | `listSchedules` · `createSchedule` · `getSchedule` · `updateSchedule` · `deleteSchedule` |
@@ -448,8 +453,8 @@ Reads (`GET`) are not covered by that bucket. `retryAfter` is available from
448
453
  | Escape hatch | `request(method, path, body?)` — any endpoint not yet typed |
449
454
 
450
455
  Channel types are checked at compile time: `createChannel` takes a
451
- `CreatableChannelType` (the platform's 82-transport union minus the adapterless
452
- `internal-a2a`), and `secret` is a named `ChannelSecretInput`. Per-transport
456
+ `CreatableChannelType` (the platform's 81-transport union every member has an
457
+ adapter since 0.30.0), and `secret` is a named `ChannelSecretInput`. Per-transport
453
458
  `secret.extra` fields are listed in <https://pouchy.ai/docs/channel-setup>.
454
459
 
455
460
  **Telegram and Discord register themselves.** On create — and again on a
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ADMIN_SDK_VERSION = "0.28.0";
1
+ export declare const ADMIN_SDK_VERSION = "0.30.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
@@ -38,7 +38,8 @@ export interface AdminClientOptions {
38
38
  fetch?: typeof fetch;
39
39
  /** Per-request timeout in ms. Default 30s, EXCEPT the requests whose server
40
40
  * handler declares `maxDuration: 300` (knowledge ingest by text/file/url,
41
- * and the GDPR user delete), which default to
41
+ * the GDPR user delete, and the capability test-action verifier — the
42
+ * list is {@link LONG_WORK_REQUESTS}), which default to
42
43
  * {@link LONG_WORK_TIMEOUT_MS}. Setting this explicitly always wins and
43
44
  * applies to every request, long or short. A request that outlives its
44
45
  * deadline rejects with an AdminApiError(status 0).
@@ -59,7 +60,7 @@ export interface AdminClientOptions {
59
60
  * published: on this plane the status line never disambiguates, so two of the
60
61
  * durable-run routes answer 409 for two entirely different reasons each, with
61
62
  * different recoveries. `code` is the only thing that tells them apart. */
62
- export declare const ADMIN_ERROR_CODES: readonly ["story_contract_v2_write_disabled", "story_contract_v3_write_disabled", "episode_history_incomplete", "episode_ended", "idempotency_key_reused", "stale_deliberation", "deliberation_disabled", "deliberation_uncalibrated", "deliberation_not_enabled", "deliberation_candidates_exceeded", "schedule_limit_reached", "one_shot_spent", "ghost_row", "channel_limit_reached", "webhook_limit_reached", "run_limit_reached", "reembed_required", "run_terminal", "run_not_parked", "stale_token", "run_not_waiting", "event_mismatch"];
63
+ export declare const ADMIN_ERROR_CODES: readonly ["story_contract_v2_write_disabled", "story_contract_v3_write_disabled", "story_contract_v4_write_disabled", "episode_history_incomplete", "episode_ended", "idempotency_key_reused", "stale_deliberation", "deliberation_disabled", "deliberation_uncalibrated", "deliberation_not_enabled", "deliberation_candidates_exceeded", "schedule_limit_reached", "one_shot_spent", "ghost_row", "channel_limit_reached", "webhook_limit_reached", "run_limit_reached", "reembed_required", "run_terminal", "run_not_parked", "stale_token", "run_not_waiting", "event_mismatch"];
63
64
  /** `AdminApiError.code` values. The `(string & {})` arm keeps the type open for
64
65
  * codes newer than this SDK build while preserving autocomplete — same
65
66
  * doctrine as the companion SDK's `CompanionErrorCodeValue`. */
@@ -332,11 +333,12 @@ export interface DeliveryOutcome {
332
333
  * (`channels/types.ts`) — this package is standalone and cannot import it, so
333
334
  * `admin-sdk-channel-types.drift.test.ts` binds the two and fails CI if either
334
335
  * side gains a transport the other lacks. */
335
- export type ChannelTransportType = 'echo' | 'matrix' | 'telegram' | 'web' | 'activitypub' | 'internal-a2a' | 'discord' | 'slack' | 'nostr' | 'atproto' | 'sms' | 'email' | 'whatsapp' | 'messenger' | 'instagram' | 'line' | 'teams' | 'wechat' | 'wecom' | 'feishu' | 'dingtalk' | 'twitter' | 'xmpp' | 'qq' | 'kakao' | 'viber' | 'signal' | 'weibo' | 'alexa' | 'google-assistant' | 'voice' | 'onlyfans' | 'fansly' | 'fanvue' | 'imessage' | 'rcs' | 'intercom' | 'twitch' | 'zalo' | 'douyin' | 'kick' | 'reddit' | 'xmtp' | 'guilded' | 'youtube-live' | 'bilibili-live' | 'minecraft' | 'steam' | 'vk' | 'ok' | 'threads' | 'groupme' | 'threema' | 'mattermost' | 'rocketchat' | 'zulip' | 'farcaster' | 'tiktok' | 'crisp' | 'freshchat' | 'front' | 'gorgias' | 'kustomer' | 'helpscout' | 'livechat' | 'zohodesk' | 'hubspot' | 'zendesk' | 'salesforce' | 'webex' | 'chatwork' | 'google-chat' | 'zohocliq' | 'zoom' | 'line-works' | 'ringcentral' | 'vonage' | 'github' | 'gitlab' | 'bitbucket' | 'jira' | 'linear' | 'discourse';
336
- /** Transports `createChannel` accepts. `internal-a2a` is in the union but has
337
- * no adapter, so the server answers 400 excluding it here turns a runtime
338
- * rejection into a compile error. */
339
- export type CreatableChannelType = Exclude<ChannelTransportType, 'internal-a2a'>;
336
+ export type ChannelTransportType = 'echo' | 'matrix' | 'telegram' | 'web' | 'activitypub' | 'discord' | 'slack' | 'nostr' | 'atproto' | 'sms' | 'email' | 'whatsapp' | 'messenger' | 'instagram' | 'line' | 'teams' | 'wechat' | 'wecom' | 'feishu' | 'dingtalk' | 'twitter' | 'xmpp' | 'qq' | 'kakao' | 'viber' | 'signal' | 'weibo' | 'alexa' | 'google-assistant' | 'voice' | 'onlyfans' | 'fansly' | 'fanvue' | 'imessage' | 'rcs' | 'intercom' | 'twitch' | 'zalo' | 'douyin' | 'kick' | 'reddit' | 'xmtp' | 'guilded' | 'youtube-live' | 'bilibili-live' | 'minecraft' | 'steam' | 'vk' | 'ok' | 'threads' | 'groupme' | 'threema' | 'mattermost' | 'rocketchat' | 'zulip' | 'farcaster' | 'tiktok' | 'crisp' | 'freshchat' | 'front' | 'gorgias' | 'kustomer' | 'helpscout' | 'livechat' | 'zohodesk' | 'hubspot' | 'zendesk' | 'salesforce' | 'webex' | 'chatwork' | 'google-chat' | 'zohocliq' | 'zoom' | 'line-works' | 'ringcentral' | 'vonage' | 'github' | 'gitlab' | 'bitbucket' | 'jira' | 'linear' | 'discourse';
337
+ /** Transports `createChannel` accepts the whole union, since 0.30.0: the
338
+ * adapterless `internal-a2a` placeholder this type used to exclude was
339
+ * retired from the platform's union (design #24 / F-04). Kept as a named
340
+ * alias so existing imports compile unchanged. */
341
+ export type CreatableChannelType = ChannelTransportType;
340
342
  /** Credentials for a connector, sealed server-side as one AES-GCM blob.
341
343
  *
342
344
  * `extra` is where the transports needing more than a token live — Twitter
@@ -888,6 +890,25 @@ export interface AdminClient {
888
890
  freeHttp: boolean;
889
891
  grantedDomains: string[];
890
892
  }>>;
893
+ /** Per-tool confirm exemptions (免确认工具) — the tools an INSTANCE may call
894
+ * without a confirm card.
895
+ *
896
+ * The one knob a headless flow could not reach before 0.29.0, and for MCP
897
+ * skills it is not optional: `mcpRecord` hard-codes `platformSafe: false`,
898
+ * so every `run_skill` raises a confirm — and a platform instance has no
899
+ * human who could ever approve one (a synthetic uid has no Firebase user).
900
+ * Without this the skill installs, rate-limits and attaches cleanly and then
901
+ * answers nothing. Grant the READ tools (a storefront's `search_catalog` /
902
+ * `get_product`) and leave anything that mutates a cart or places an order
903
+ * gated.
904
+ *
905
+ * A full REPLACE, not a merge — pass the complete list every call. Names the
906
+ * skill does not declare are dropped and echoed back in `dropped`, so a typo
907
+ * is visible rather than silently ungranted. */
908
+ setSkillAutoRunTools(slug: string, toolNames: string[]): Promise<SkillKnobResult<{
909
+ autoRunTools: string[];
910
+ dropped: string[];
911
+ }>>;
891
912
  uninstallSkill(slug: string): Promise<{
892
913
  deleted: boolean;
893
914
  }>;
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.28.0';
11
+ export const ADMIN_SDK_VERSION = '0.30.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;
@@ -72,6 +72,7 @@ export function requestDeadlineMs(method, path) {
72
72
  export const ADMIN_ERROR_CODES = [
73
73
  'story_contract_v2_write_disabled',
74
74
  'story_contract_v3_write_disabled',
75
+ 'story_contract_v4_write_disabled',
75
76
  'episode_history_incomplete',
76
77
  'episode_ended',
77
78
  'idempotency_key_reused',
@@ -194,8 +195,9 @@ export function createAdminClient(opts) {
194
195
  throw new AdminApiError('no fetch available — pass opts.fetch on Node <18', 0);
195
196
  async function request(method, path, body) {
196
197
  // An explicit host `timeoutMs` always wins (JS SDK contract); otherwise
197
- // the deadline is sized to the ROUTE, so the four handlers that declare
198
- // `maxDuration: 300` are not cut at 30s while they are still working.
198
+ // the deadline is sized to the ROUTE, so the handlers that declare
199
+ // `maxDuration: 300` (LONG_WORK_REQUESTS) are not cut at 30s while they
200
+ // are still working.
199
201
  // `??` (not `||`) is deliberate: 0 is a SET value meaning "no deadline",
200
202
  // and it must not fall through to the route default.
201
203
  const timeoutMs = opts.timeoutMs ?? requestDeadlineMs(method, path);
@@ -266,6 +268,7 @@ export function createAdminClient(opts) {
266
268
  listSkills: () => request('GET', '/skills'),
267
269
  installSkill: (input) => request('POST', '/skills', input),
268
270
  updateSkill: (slug, patch) => request('PATCH', `/skills/${encodeURIComponent(slug)}`, patch),
271
+ setSkillAutoRunTools: (slug, toolNames) => request('PATCH', `/skills/${encodeURIComponent(slug)}`, { autoRunTools: toolNames }),
269
272
  setSkillRate: (slug, ratePerMin) => request('PATCH', `/skills/${encodeURIComponent(slug)}`, { ratePerMin }),
270
273
  setSkillDailyCap: (slug, maxCallsPerDay) => request('PATCH', `/skills/${encodeURIComponent(slug)}`, { maxCallsPerDay }),
271
274
  compileSkill: (slug) => request('POST', `/skills/${encodeURIComponent(slug)}/compile`, {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/admin-sdk",
3
- "version": "0.28.0",
3
+ "version": "0.30.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",