@pouchy_ai/admin-sdk 0.26.1 → 0.27.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 +38 -0
- package/README.md +56 -0
- package/dist/index.d.ts +54 -2
- package/dist/index.js +12 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@pouchy_ai/admin-sdk` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.27.1 — 2026-08-28
|
|
6
|
+
|
|
7
|
+
- **Docs-only, but read it if you use `encodingFormat: 'base64'`.** The 0.27.0
|
|
8
|
+
README's decode snippet was `new Float32Array(Buffer.from(s,'base64').buffer)`
|
|
9
|
+
— on Node runtimes that pool small buffers (every 768-dim vector qualifies),
|
|
10
|
+
`.buffer` is the whole shared pool and that form silently decodes ~2048
|
|
11
|
+
garbage-tailed elements. Our own live acceptance probe caught it on first
|
|
12
|
+
field run. Correct, everywhere:
|
|
13
|
+
`const buf = Buffer.from(s, 'base64'); new Float32Array(buf.buffer, buf.byteOffset, buf.length / 4)`.
|
|
14
|
+
No client code changed.
|
|
15
|
+
|
|
16
|
+
## 0.27.0 — 2026-08-28
|
|
17
|
+
|
|
18
|
+
- **New: `embedTexts` — text → embedding vectors** (`POST
|
|
19
|
+
/v1/admin/utility/embeddings`), the vector sibling of `extractJson`:
|
|
20
|
+
stateless, no companion side effects, typed failures (`invalid_request` /
|
|
21
|
+
`unavailable` / `provider_error`). For a backend that ranks its own
|
|
22
|
+
inventory by cosine (album/asset pick, intent-gate exemplars) and wants one
|
|
23
|
+
billing/key channel instead of a second embedding vendor. Batch up to 64
|
|
24
|
+
texts per call; the response `model` is a **stable id** to persist next to
|
|
25
|
+
every stored vector and PIN in later requests — an id the deployment cannot
|
|
26
|
+
serve exactly answers 400, never a silent substitute, so a platform model
|
|
27
|
+
swap surfaces as an explicit reindex signal. `encodingFormat: 'base64'`
|
|
28
|
+
returns little-endian float32 base64 (~3.5× smaller) for bulk reindex.
|
|
29
|
+
Motivating ask: LuckyDramas' album selfie pick + L2 memory intent gate,
|
|
30
|
+
previously on a second vendor key at their BFF.
|
|
31
|
+
|
|
32
|
+
## 0.26.2 — 2026-08-21
|
|
33
|
+
|
|
34
|
+
- **`createAgent` / `updateAgent` responses now type the additive
|
|
35
|
+
`droppedSkills?: string[]` field.** The platform filters `skills` slugs to
|
|
36
|
+
its registered allowlist; it now names anything it filtered instead of
|
|
37
|
+
returning a 200 whose `agent.skills` is silently missing what you sent.
|
|
38
|
+
Motivating field report: a manifest said `client_action`, the platform had
|
|
39
|
+
registered `client-action`, and the diff between request and response was
|
|
40
|
+
the only clue. Additive server field (older servers simply never set it) —
|
|
41
|
+
no behavioural change in this client.
|
|
42
|
+
|
|
5
43
|
## 0.26.1 — 2026-08-09
|
|
6
44
|
|
|
7
45
|
- **Docs-only.** No type, method or signature moves. `extractJson`'s failure
|
package/README.md
CHANGED
|
@@ -158,6 +158,62 @@ completion arrived but did not parse or satisfy the schema; the error carries
|
|
|
158
158
|
`raw`, the text actually returned). Tokens roll into the project's month usage
|
|
159
159
|
like any other model call.
|
|
160
160
|
|
|
161
|
+
### Embedding vectors — use `embedTexts`, not a second vendor key
|
|
162
|
+
|
|
163
|
+
The vector sibling of `extractJson`: text → embedding vectors, stateless, no
|
|
164
|
+
companion side effects. For a backend that ranks its **own** inventory by cosine
|
|
165
|
+
(album/asset pick, memory intent-gate exemplars) and wants one billing/key
|
|
166
|
+
channel instead of holding a separate embedding vendor's key beside its Pouchy
|
|
167
|
+
keys — retrieval stays yours; Pouchy only turns text into vectors.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const res = await admin.embedTexts({
|
|
171
|
+
input: ['Send me a casual home coffee selfie', '来张咖啡店自拍'] // ≤ 64 per call
|
|
172
|
+
});
|
|
173
|
+
// res.model → 'openai-text-embedding-3-small-768' (STABLE id — persist it)
|
|
174
|
+
// res.dimensions → 768 (== every vector's length)
|
|
175
|
+
// res.data[i] → { index: i, embedding: number[] } (index-aligned)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Two rules keep a stored index honest:
|
|
179
|
+
|
|
180
|
+
1. **Persist `res.model` next to every stored vector and refuse mixed-model
|
|
181
|
+
cosine.** Then **pin** it in later requests (`model:
|
|
182
|
+
'openai-text-embedding-3-small-768'`): an id the deployment cannot serve
|
|
183
|
+
exactly answers `400` — never a silent substitute — so a platform model swap
|
|
184
|
+
surfaces on your side as an explicit reindex signal.
|
|
185
|
+
2. **Texts are never silently truncated.** An over-cap text (> 8000 chars) is a
|
|
186
|
+
`400` naming its index; split or summarize it yourself, so what you embedded
|
|
187
|
+
is always exactly what you stored.
|
|
188
|
+
|
|
189
|
+
For bulk reindex, `encodingFormat: 'base64'` returns each vector as
|
|
190
|
+
little-endian float32 base64 (~3.5× smaller at 768 dims). Decode with the
|
|
191
|
+
**offset-safe** form:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const res = await admin.embedTexts({
|
|
195
|
+
input: ['来张咖啡店自拍'],
|
|
196
|
+
encodingFormat: 'base64'
|
|
197
|
+
});
|
|
198
|
+
for (const { embedding } of res.data) {
|
|
199
|
+
const buf = Buffer.from(embedding as string, 'base64');
|
|
200
|
+
const vec = new Float32Array(buf.buffer, buf.byteOffset, buf.length / 4);
|
|
201
|
+
// vec.length === res.dimensions, always
|
|
202
|
+
void vec;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Not `new Float32Array(buf.buffer)` — on Node runtimes that pool small buffers
|
|
207
|
+
(every 768-dim vector qualifies), `.buffer` is the whole shared pool and the
|
|
208
|
+
naive form silently decodes ~2048 garbage-tailed elements. Caught live by our
|
|
209
|
+
own acceptance probe; the three-arg form is correct everywhere.
|
|
210
|
+
|
|
211
|
+
Failures are typed: `invalid_request` (400 — fix and resend), `unavailable`
|
|
212
|
+
(503 — transient, back off and retry), `provider_error` (502 — the upstream
|
|
213
|
+
embedder rejected a request the platform believed valid; short provider message
|
|
214
|
+
included). Prompt tokens roll into the project's month usage (tagged
|
|
215
|
+
`utility_embed`); there is no separate platform credit rate.
|
|
216
|
+
|
|
161
217
|
### Spoken audio — use `synthesizeSpeech`, not `/call`
|
|
162
218
|
|
|
163
219
|
The audio sibling of `extractJson`: text → a downloadable **mp3 file**, OUTSIDE
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const ADMIN_SDK_VERSION = "0.
|
|
1
|
+
export declare const ADMIN_SDK_VERSION = "0.27.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
|
|
@@ -59,7 +59,7 @@ export interface AdminClientOptions {
|
|
|
59
59
|
* published: on this plane the status line never disambiguates, so two of the
|
|
60
60
|
* durable-run routes answer 409 for two entirely different reasons each, with
|
|
61
61
|
* different recoveries. `code` is the only thing that tells them apart. */
|
|
62
|
-
export declare const ADMIN_ERROR_CODES: readonly ["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"];
|
|
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
63
|
/** `AdminApiError.code` values. The `(string & {})` arm keeps the type open for
|
|
64
64
|
* codes newer than this SDK build while preserving autocomplete — same
|
|
65
65
|
* doctrine as the companion SDK's `CompanionErrorCodeValue`. */
|
|
@@ -444,18 +444,24 @@ export interface AdminClient {
|
|
|
444
444
|
listAgents(): Promise<{
|
|
445
445
|
agents: Agent[];
|
|
446
446
|
}>;
|
|
447
|
+
/** `droppedSkills` (when present) names any `skills` slugs the platform's
|
|
448
|
+
* registered-skill allowlist filtered out — a slug typo (e.g. `client_action`
|
|
449
|
+
* vs the registered `client-action`) is named, never silently absent. */
|
|
447
450
|
createAgent(input: {
|
|
448
451
|
name: string;
|
|
449
452
|
archetype: string;
|
|
450
453
|
systemPrompt?: string;
|
|
451
454
|
} & Record<string, unknown>): Promise<{
|
|
452
455
|
agent: Agent;
|
|
456
|
+
droppedSkills?: string[];
|
|
453
457
|
}>;
|
|
454
458
|
getAgent(agentId: string): Promise<{
|
|
455
459
|
agent: Agent;
|
|
456
460
|
}>;
|
|
461
|
+
/** See createAgent — `droppedSkills` echoes allowlist-filtered slugs. */
|
|
457
462
|
updateAgent(agentId: string, patch: Partial<Agent> & Record<string, unknown>): Promise<{
|
|
458
463
|
agent: Agent;
|
|
464
|
+
droppedSkills?: string[];
|
|
459
465
|
}>;
|
|
460
466
|
deleteAgent(agentId: string): Promise<{
|
|
461
467
|
deleted: boolean;
|
|
@@ -717,6 +723,52 @@ export interface AdminClient {
|
|
|
717
723
|
completionTokens: number;
|
|
718
724
|
};
|
|
719
725
|
}>;
|
|
726
|
+
/** Text → embedding vectors, OUTSIDE the companion — the vector sibling of
|
|
727
|
+
* `extractJson`: stateless (no session, no persona, no memory), one provider
|
|
728
|
+
* call, typed failures. For a backend that ranks its OWN inventory by cosine
|
|
729
|
+
* (album/asset pick, intent-gate exemplars) and wants one billing/key channel
|
|
730
|
+
* instead of a second embedding vendor beside its Pouchy keys.
|
|
731
|
+
*
|
|
732
|
+
* `input` is one text or a batch (≤ 64 per request, each ≤ 8000 chars — an
|
|
733
|
+
* over-cap text is a 400 naming its index; texts are NEVER silently
|
|
734
|
+
* truncated, because a clipped vector poisons a stored index invisibly).
|
|
735
|
+
*
|
|
736
|
+
* The response `model` is a STABLE id (e.g.
|
|
737
|
+
* `openai-text-embedding-3-small-768`): persist it next to every stored
|
|
738
|
+
* vector, refuse mixed-model cosine, and PIN it in later requests — an id
|
|
739
|
+
* the deployment cannot serve exactly answers 400 rather than silently
|
|
740
|
+
* substituting, so a platform model swap surfaces as an explicit reindex
|
|
741
|
+
* signal. `dimensions` always equals every vector's length.
|
|
742
|
+
*
|
|
743
|
+
* `encodingFormat: 'base64'` returns each vector as little-endian float32
|
|
744
|
+
* base64 (~3.5× smaller at 768 dims — use for bulk reindex); default
|
|
745
|
+
* `'float'` returns `number[]`.
|
|
746
|
+
*
|
|
747
|
+
* Failures: `invalid_request` (400 — fix and resend), `unavailable` (503 —
|
|
748
|
+
* transient, back off and retry), `provider_error` (502 — upstream rejected
|
|
749
|
+
* a request the platform believed valid, short provider message included).
|
|
750
|
+
*
|
|
751
|
+
* Prompt tokens roll into the project's month usage (tagged
|
|
752
|
+
* `utility_embed`); no separate platform credit rate. */
|
|
753
|
+
embedTexts(input: {
|
|
754
|
+
input: string | string[];
|
|
755
|
+
model?: string;
|
|
756
|
+
dimensions?: number;
|
|
757
|
+
encodingFormat?: 'float' | 'base64';
|
|
758
|
+
}): Promise<{
|
|
759
|
+
object: 'list';
|
|
760
|
+
model: string;
|
|
761
|
+
dimensions: number;
|
|
762
|
+
data: Array<{
|
|
763
|
+
object: 'embedding';
|
|
764
|
+
index: number;
|
|
765
|
+
embedding: number[] | string;
|
|
766
|
+
}>;
|
|
767
|
+
usage?: {
|
|
768
|
+
promptTokens: number;
|
|
769
|
+
totalTokens: number;
|
|
770
|
+
};
|
|
771
|
+
}>;
|
|
720
772
|
/** Text → a spoken-audio FILE, OUTSIDE the companion and OUTSIDE a realtime
|
|
721
773
|
* call. The audio sibling of `extractJson`: stateless (no session, no
|
|
722
774
|
* persona, no memory), one synthesis call, a downloadable clip back. Use it
|
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.
|
|
11
|
+
export const ADMIN_SDK_VERSION = '0.27.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;
|
|
@@ -70,6 +70,16 @@ export function requestDeadlineMs(method, path) {
|
|
|
70
70
|
* durable-run routes answer 409 for two entirely different reasons each, with
|
|
71
71
|
* different recoveries. `code` is the only thing that tells them apart. */
|
|
72
72
|
export const ADMIN_ERROR_CODES = [
|
|
73
|
+
'story_contract_v2_write_disabled',
|
|
74
|
+
'story_contract_v3_write_disabled',
|
|
75
|
+
'episode_history_incomplete',
|
|
76
|
+
'episode_ended',
|
|
77
|
+
'idempotency_key_reused',
|
|
78
|
+
'stale_deliberation',
|
|
79
|
+
'deliberation_disabled',
|
|
80
|
+
'deliberation_uncalibrated',
|
|
81
|
+
'deliberation_not_enabled',
|
|
82
|
+
'deliberation_candidates_exceeded',
|
|
73
83
|
'schedule_limit_reached',
|
|
74
84
|
'one_shot_spent',
|
|
75
85
|
'ghost_row',
|
|
@@ -250,6 +260,7 @@ export function createAdminClient(opts) {
|
|
|
250
260
|
ingestKnowledgeUrl: (input) => request('POST', '/knowledge/url', input),
|
|
251
261
|
searchKnowledge: (query) => request('POST', '/knowledge/search', { query }),
|
|
252
262
|
extractJson: (input) => request('POST', '/utility/json', input),
|
|
263
|
+
embedTexts: (input) => request('POST', '/utility/embeddings', input),
|
|
253
264
|
synthesizeSpeech: (input) => request('POST', '/utility/tts', input),
|
|
254
265
|
deleteKnowledge: (id) => request('DELETE', `/knowledge/${encodeURIComponent(id)}`),
|
|
255
266
|
listSkills: () => request('GET', '/skills'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/admin-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.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",
|