@pouchy_ai/admin-sdk 0.10.0 → 0.12.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,40 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.12.0 — 2026-08-01
6
+
7
+ - **Typed capability declarations.** `publishCapability` now takes a
8
+ `CapabilityDeclaration` (`ViewDeclaration | ActionDeclaration |
9
+ EventDeclaration`, all exported) — compile-time help for the one call with
10
+ 14+ fields and four closed vocabularies (`sensitivity`, `idempotency`,
11
+ `automation`, `signing`). The server stays the one validator; an index
12
+ signature keeps newer server fields publishable from an older SDK.
13
+ - **Typed agent Data flags.** `Agent` gains `data?: AgentData` — the live
14
+ levers (`enabled`, `actions.enabled` / `autoRun` / `autoRunDailyCap`,
15
+ `events.enabled` / `subscriptions`), usable through
16
+ `updateAgent(id, { data: { … } })`.
17
+ - **Observability readers.** `listActionExecutions({ limit? })` and
18
+ `listEventReceipts({ limit? })` over the new `/v1/admin/actions` +
19
+ `/v1/admin/events` mirrors (Admin API 1.5.0) — the durable Action journal
20
+ (typed rows incl. `authorizedBy: 'automation'`) and Event receipts + wake
21
+ trail, closing the headless loop: publish → test → read back what ran.
22
+
23
+ ## 0.11.0 — 2026-08-01
24
+
25
+ - **Data capabilities, headless.** Six new methods over the `/v1/admin/capabilities`
26
+ mirror: `listCapabilities` (heads + masked signing status — the `pcsk_`
27
+ plaintext is issued once on the owner plane and is never readable through any
28
+ API), `publishCapability` (immutable next version; idempotent on content),
29
+ `setCapabilityDisabled` (per-capability live revoke — live both directions,
30
+ pinned reconciliations unaffected), `listCapabilityVersions` (append-only
31
+ history; rollback = republishing an old declaration as the next version),
32
+ `testReadCapability`, and `testActionCapability` (the four-phase Action
33
+ protocol verifier; the server refuses without `confirmDuplicates: true`
34
+ because phases B/C intentionally re-deliver the same `actionId`).
35
+ - `POST /capabilities/{name}/test-action` joins `LONG_WORK_REQUESTS`: the
36
+ verifier makes real round-trips to YOUR endpoint, and aborting mid-test
37
+ cannot undo phase A's side effect — so the default deadline is the long one.
38
+
5
39
  ## 0.10.0 — 2026-07-29
6
40
 
7
41
  - **`AdminApiError.code` — the Admin API's machine-readable failure tag.** The
package/README.md CHANGED
@@ -198,14 +198,20 @@ Reads (`GET`) are not covered by that bucket. `retryAfter` is available from
198
198
  | Channels | `listChannels` · `createChannel` · `getChannel` · `updateChannel` · `deleteChannel` |
199
199
  | Schedules | `listSchedules` · `createSchedule` · `getSchedule` · `updateSchedule` · `deleteSchedule` |
200
200
  | Durable runs | `listRuns` · `createRun` · `getRun` · `cancelRun` · `resumeRun` · `signalRun` |
201
+ | Data capabilities | `listCapabilities` (heads + MASKED signing status) · `publishCapability` (TYPED `CapabilityDeclaration`; immutable next version, idempotent on content) · `setCapabilityDisabled` (per-capability live revoke) · `listCapabilityVersions` (history; rollback = republish an old declaration) · `testReadCapability` · `testActionCapability({ confirmDuplicates: true, … })` (REAL deliveries incl. intentional duplicates — 428 without consent) · `listActionExecutions` (the durable Action journal, incl. `authorizedBy: 'automation'`) · `listEventReceipts` (receipts + wake trail) |
202
+ | Webhooks | `listWebhooks` · `createWebhook` · `updateWebhook` · `rotateWebhookSecret` · `deleteWebhook` · `testWebhook` · `redeliverWebhook` |
203
+ | Reporting | `getUsage` · `getBilling` · `getTracesSummary` · `getRecentTraces` · `getLogs` · `getProject` · `updateProject` |
204
+ | Escape hatch | `request(method, path, body?)` — any endpoint not yet typed |
201
205
 
202
206
  Channel types are checked at compile time: `createChannel` takes a
203
207
  `CreatableChannelType` (the platform's 31-transport union minus the adapterless
204
208
  `internal-a2a`), and `secret` is a named `ChannelSecretInput`. Per-transport
205
209
  `secret.extra` fields are listed in <https://pouchy.ai/docs/channel-setup>.
206
- | Webhooks | `listWebhooks` · `createWebhook` · `updateWebhook` · `rotateWebhookSecret` · `deleteWebhook` · `testWebhook` · `redeliverWebhook` |
207
- | Reporting | `getUsage` · `getBilling` · `getTracesSummary` · `getRecentTraces` · `getLogs` · `getProject` · `updateProject` |
208
- | Escape hatch | `request(method, path, body?)` any endpoint not yet typed |
210
+
211
+ Capability **signing-key management is deliberately not mirrored** here: the
212
+ one-time `pcsk_`/`pesk_` plaintext reveal stays a human act on the owner
213
+ plane (dashboard / owner API). `listCapabilities` returns masked key status
214
+ only.
209
215
 
210
216
  ### Durable runs
211
217
 
@@ -231,6 +237,11 @@ const { run } = await admin.createRun({
231
237
  console.log(run.id, run.status); // → 'queued'
232
238
  ```
233
239
 
240
+ A `subtask_fanout` step runs at most **4** subtasks (`input.subtasks`).
241
+ Declaring more is a **400** naming the cap rather than a silent trim — split
242
+ the remainder into a second fan-out step. Entries without a non-empty `goal`
243
+ are ignored and do not count against the cap.
244
+
234
245
  When a run reaches a `human_approval` step it **parks**: it holds no lease and
235
246
  leaves the platform's due window, so nothing will move it until you answer.
236
247
  You learn about it either way — the `agent.run_awaiting` webhook pushes the
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ADMIN_SDK_VERSION = "0.10.0";
1
+ export declare const ADMIN_SDK_VERSION = "0.12.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
@@ -99,6 +99,30 @@ export declare class AdminApiError extends Error {
99
99
  export type Env = 'live' | 'test';
100
100
  export type AgentStatus = 'draft' | 'published';
101
101
  export type ModelTier = 'standard' | 'pro';
102
+ /** The agent template's Data plane flags — the LIVE half of every Data
103
+ * authorization (the pinned half is the published declaration). All fields
104
+ * are live levers: flipping one off stops that plane on the next turn of
105
+ * sessions already running. */
106
+ export interface AgentData {
107
+ /** Parent gate: instances get `read_data` + the pinned capability menu. */
108
+ enabled?: boolean;
109
+ actions?: {
110
+ /** Exposes the confirm-gated `run_action` gateway (needs `enabled`). */
111
+ enabled?: boolean;
112
+ /** Operator half of event-to-action automation (≤5 action names; the
113
+ * declaration must also say `automation: 'allowed'`). */
114
+ autoRun?: string[];
115
+ /** Automated runs per user per UTC day, 1..50 (default 10). */
116
+ autoRunDailyCap?: number;
117
+ };
118
+ events?: {
119
+ /** Lets your backend POST published events at this agent's instances. */
120
+ enabled?: boolean;
121
+ /** Subscription routing: an event POSTed WITHOUT agentId fans out to
122
+ * every subscribed, events-enabled agent (≤10 capability names). */
123
+ subscriptions?: string[];
124
+ };
125
+ }
102
126
  export interface Agent {
103
127
  agentId: string;
104
128
  name: string;
@@ -106,10 +130,67 @@ export interface Agent {
106
130
  systemPrompt: string;
107
131
  status?: AgentStatus;
108
132
  modelTier?: ModelTier;
133
+ /** Agent Data plane flags (see AgentData). */
134
+ data?: AgentData;
109
135
  templateRev: number;
110
136
  createdAt: string;
111
137
  [k: string]: unknown;
112
138
  }
139
+ export type CapabilitySensitivity = 'public' | 'personal' | 'intimate';
140
+ export interface ViewDeclaration {
141
+ kind: 'view';
142
+ /** The agent's business vocabulary (e.g. `Order`), not a table name. */
143
+ name: string;
144
+ description: string;
145
+ sensitivity?: CapabilitySensitivity;
146
+ /** ONE exact lowercase hostname; every endpoint must live on it. */
147
+ audience: string;
148
+ /** HTTPS GET endpoint — declared `filters` arrive as query parameters. */
149
+ endpoint: string;
150
+ /** Output allowlist — extra fields your endpoint returns never reach the agent. */
151
+ fields: string[];
152
+ filters?: string[];
153
+ [k: string]: unknown;
154
+ }
155
+ export interface ActionDeclaration {
156
+ kind: 'action';
157
+ name: string;
158
+ description: string;
159
+ sensitivity?: CapabilitySensitivity;
160
+ audience: string;
161
+ /** HTTPS POST endpoint — receives `{"actionId","action","args"}` signed. */
162
+ endpoint: string;
163
+ args?: string[];
164
+ /** The contract's only Phase-1 mode. */
165
+ idempotency: 'action_id';
166
+ /** Signed read-only `GET ?actionId=` resolver for `unknown` outcomes. */
167
+ reconcile?: {
168
+ endpoint: string;
169
+ };
170
+ /** Declared + validated today, NOT yet dispatched (forward-compat). */
171
+ compensate?: {
172
+ endpoint: string;
173
+ };
174
+ /** Author's pinned safety claim: eligible for event-driven automation
175
+ * (still needs the agent's live `autoRun` grant). */
176
+ automation?: 'allowed';
177
+ [k: string]: unknown;
178
+ }
179
+ export interface EventDeclaration {
180
+ kind: 'event';
181
+ name: string;
182
+ description: string;
183
+ sensitivity?: CapabilitySensitivity;
184
+ /** The declared emitter id — bound at ingress, never payload-decided. */
185
+ source: string;
186
+ schemaVersion: number;
187
+ /** Payload field mined as the subject reference (an EXISTING instance). */
188
+ subjectField: string;
189
+ /** Demand POUCHY-SOURCE-V1 per-source signatures on ingress. */
190
+ signing?: 'required';
191
+ [k: string]: unknown;
192
+ }
193
+ export type CapabilityDeclaration = ViewDeclaration | ActionDeclaration | EventDeclaration;
113
194
  export interface SecretKey {
114
195
  keyId: string;
115
196
  label: string;
@@ -623,7 +704,12 @@ export interface AdminClient {
623
704
  * turn carrying `goal`. Step ids must be unique and match
624
705
  * `[A-Za-z0-9_-]{1,64}`; `kind` is one of `agent_turn`, `subtask_fanout`,
625
706
  * `human_approval`, `await_event`. Answers **202**, not 201: the run is
626
- * accepted and has not run yet. */
707
+ * accepted and has not run yet.
708
+ *
709
+ * A `subtask_fanout` step runs at most **4** subtasks (`input.subtasks`).
710
+ * Declaring more is a **400** naming the cap, not a silent trim — split the
711
+ * remainder into a second fan-out step. Entries without a non-empty `goal`
712
+ * are ignored and do not count against the cap. */
627
713
  createRun(input: {
628
714
  agentId: string;
629
715
  externalUserId: string;
@@ -686,6 +772,114 @@ export interface AdminClient {
686
772
  event: string;
687
773
  status: string;
688
774
  }>;
775
+ /** Capability heads + MASKED signing status (key IDs and rotation state
776
+ * only — the `pcsk_` plaintext is issued ONCE on the owner plane and is
777
+ * never readable through any API). */
778
+ listCapabilities(): Promise<{
779
+ capabilities: Array<{
780
+ capabilityId: string;
781
+ name: string;
782
+ kind: string;
783
+ latestVersion: number;
784
+ disabled?: boolean;
785
+ }>;
786
+ signing: {
787
+ activeKeyId: string;
788
+ previousKeyId: string | null;
789
+ } | null;
790
+ }>;
791
+ /** Publish the next IMMUTABLE revision. Idempotent on content: an unchanged
792
+ * manifest returns the existing version with `created: false`; different
793
+ * bytes mint version+1 and never rewrite an old one. Publishing is NOT
794
+ * revocation — the per-agent data flags and `setCapabilityDisabled` are
795
+ * the live levers. */
796
+ publishCapability(declaration: CapabilityDeclaration): Promise<{
797
+ revision: {
798
+ capabilityId: string;
799
+ version: number;
800
+ revisionHash: string;
801
+ };
802
+ created: boolean;
803
+ }>;
804
+ /** Per-capability live revoke: flips the head's `disabled` bit. Live in
805
+ * BOTH directions on the next resolution — existing sessions lose it from
806
+ * their next turn, new plans/ingress see honest absence; a reconciliation
807
+ * pinned to a revision keeps reconciling. */
808
+ setCapabilityDisabled(name: string, disabled: boolean): Promise<{
809
+ name: string;
810
+ disabled: boolean;
811
+ }>;
812
+ /** Full version history, newest first, WITH declaration bodies. There is no
813
+ * rollback verb: restoring vN = `publishCapability(versions[i].declaration)`,
814
+ * which mints it as the NEXT version (history stays append-only). */
815
+ listCapabilityVersions(name: string): Promise<{
816
+ versions: Array<{
817
+ version: number;
818
+ revisionHash: string;
819
+ publishedAt: string;
820
+ declaration: Record<string, unknown>;
821
+ }>;
822
+ }>;
823
+ /** View integration test: real pinned revision + production signer; returns
824
+ * the curated rows exactly as an agent would see them, the menu/model
825
+ * bytes, and DECODED (never signed, never replayable) claims. */
826
+ testReadCapability(name: string, input?: {
827
+ externalUserId?: string;
828
+ filters?: Record<string, unknown>;
829
+ }): Promise<Record<string, unknown>>;
830
+ /** Action protocol verifier — four phases (connectivity, duplicate
831
+ * same-intent, mismatch, reconcile) against your REAL endpoint, including
832
+ * intentional duplicate deliveries of one actionId; the server refuses
833
+ * (428) without `confirmDuplicates: true`. Phase outcomes use production
834
+ * vocabulary (committed/rejected/unknown) SEPARATELY from protocol
835
+ * verdicts — "Protocol: PASS, outcome: unknown" is a valid result. */
836
+ testActionCapability(name: string, input: {
837
+ confirmDuplicates: true;
838
+ args?: Record<string, unknown>;
839
+ externalUserId?: string;
840
+ }): Promise<Record<string, unknown>>;
841
+ /** The durable Action journal, newest first (limit clamped to 1..100,
842
+ * default 50) — every run_action ever dispatched, with pinned revision,
843
+ * canonical intent, outcome status and reconcile trail. `unknown` is
844
+ * shown as unknown, never dressed up; `authorizedBy: 'automation'` marks
845
+ * event-driven runs (absent = a user approved). Same rows as the
846
+ * owner-plane viewer (one server-side shaper, two doors). */
847
+ listActionExecutions(params?: {
848
+ limit?: number;
849
+ }): Promise<{
850
+ executions: Array<{
851
+ actionId: string;
852
+ capabilityId: string;
853
+ version: number;
854
+ revisionHash: string;
855
+ status: 'dispatching' | 'committed' | 'rejected' | 'unknown';
856
+ intent: Record<string, string>;
857
+ intentHash: string;
858
+ subject: {
859
+ kind: string;
860
+ externalUserId?: string;
861
+ } | null;
862
+ confirmId: string;
863
+ authorizedBy?: 'user' | 'automation';
864
+ createdAt: number;
865
+ settledAt?: number;
866
+ remoteStatus?: number;
867
+ receipt?: string;
868
+ reconcileAttempts?: number;
869
+ reconcileLastAt?: number | null;
870
+ reconcileLastResult?: string | null;
871
+ [k: string]: unknown;
872
+ }>;
873
+ }>;
874
+ /** Event receipts + wake trail, newest first (limit clamped to 1..100,
875
+ * default 50). Pure metadata — the payload was mined for the subject and
876
+ * discarded at ingress. The wake trail records acceptance, turn and
877
+ * delivery milestones SEPARATELY: accepted never implies a turn ran. */
878
+ listEventReceipts(params?: {
879
+ limit?: number;
880
+ }): Promise<{
881
+ receipts: Array<Record<string, unknown>>;
882
+ }>;
689
883
  listWebhooks(): Promise<{
690
884
  webhooks: unknown[];
691
885
  }>;
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.10.0';
11
+ export const ADMIN_SDK_VERSION = '0.12.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;
@@ -44,7 +44,12 @@ export const LONG_WORK_REQUESTS = [
44
44
  // GDPR erasure: recursive delete of the instance's whole users/** subtree
45
45
  // plus the top-level social graph. A client abort here is the worst of the
46
46
  // four — the operator is left not knowing whether the wipe completed.
47
- { method: 'DELETE', path: /^\/users\/[^/]+$/ }
47
+ { method: 'DELETE', path: /^\/users\/[^/]+$/ },
48
+ // The Action protocol verifier makes REAL deliveries to the developer's
49
+ // endpoint (four phases incl. reconcile) — network round-trips we don't
50
+ // control the latency of. An abort mid-test also cannot undo phase A's
51
+ // side effect, so waiting is strictly better than cutting.
52
+ { method: 'POST', path: /^\/capabilities\/[^/]+\/test-action$/ }
48
53
  ];
49
54
  /** The deadline a given request runs under when the host set no `timeoutMs`.
50
55
  * Exported so the contract is assertable without timing anything. */
@@ -281,6 +286,14 @@ export function createAdminClient(opts) {
281
286
  cancelRun: (id) => request('DELETE', `/runs/${encodeURIComponent(id)}`),
282
287
  resumeRun: (id, input) => request('POST', `/runs/${encodeURIComponent(id)}/resume`, input),
283
288
  signalRun: (id, input) => request('POST', `/runs/${encodeURIComponent(id)}/signal`, input),
289
+ listCapabilities: () => request('GET', '/capabilities'),
290
+ publishCapability: (declaration) => request('POST', '/capabilities', declaration),
291
+ setCapabilityDisabled: (name, disabled) => request('PATCH', `/capabilities/${encodeURIComponent(name)}`, { disabled }),
292
+ listCapabilityVersions: (name) => request('GET', `/capabilities/${encodeURIComponent(name)}/versions`),
293
+ testReadCapability: (name, input = {}) => request('POST', `/capabilities/${encodeURIComponent(name)}/test-read`, input),
294
+ listActionExecutions: (params = {}) => request('GET', `/actions${qs(params)}`),
295
+ listEventReceipts: (params = {}) => request('GET', `/events${qs(params)}`),
296
+ testActionCapability: (name, input) => request('POST', `/capabilities/${encodeURIComponent(name)}/test-action`, input),
284
297
  listWebhooks: () => request('GET', '/webhooks'),
285
298
  createWebhook: (input) => request('POST', '/webhooks', input),
286
299
  deleteWebhook: (id) => request('DELETE', `/webhooks/${encodeURIComponent(id)}`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/admin-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.12.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",