@pouchy_ai/admin-sdk 0.16.1 → 0.18.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 +85 -0
- package/README.md +95 -0
- package/dist/index.d.ts +60 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@pouchy_ai/admin-sdk` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.18.0 — 2026-08-07
|
|
6
|
+
|
|
7
|
+
- **`extractJson` takes `reasoningEffort`, and its server default moved to
|
|
8
|
+
`'low'`.** 0.17.0 shipped the endpoint running on the shared one-shot floor of
|
|
9
|
+
`'minimal'`, and nothing could change it — the request accepted a `model` but
|
|
10
|
+
not a thinking budget, so an integrator who noticed the quality had no lever
|
|
11
|
+
short of swapping models.
|
|
12
|
+
|
|
13
|
+
It is measured, not theoretical. An A/B over 26 utterances against an
|
|
14
|
+
integrator's own extractor agreed on kind for all 22 inputs carrying a SINGLE
|
|
15
|
+
directive, and diverged on exactly the two carrying more than one:
|
|
16
|
+
「以后别叫我宝贝,叫我老板」 came back labelled by its leading clause (a
|
|
17
|
+
boundary) instead of its operative one (a nickname), and 「叫我阿凯,别剧透,
|
|
18
|
+
我不喜欢虐心结局」 merged three directives into two. In both the summary text
|
|
19
|
+
was correct and complete — only the segmentation collapsed, and in both the
|
|
20
|
+
earlier-appearing kind absorbed the later one. That is the signature of a
|
|
21
|
+
budget that can write one good sentence but cannot deliberate over how many
|
|
22
|
+
items there are, which is exactly what an extraction endpoint is for.
|
|
23
|
+
|
|
24
|
+
`'minimal'` restores 0.17.0's behaviour if you want the cheapest, fastest
|
|
25
|
+
extraction; raise it further when one input can carry several directives at
|
|
26
|
+
once. `AdminReasoningEffort` is exported. Additive — every 0.17.0 call
|
|
27
|
+
compiles unchanged — but note the DEFAULT moved, so extraction calls that pass
|
|
28
|
+
nothing now think one notch harder and cost slightly more.
|
|
29
|
+
|
|
30
|
+
A domain precedence rule ("a nickname wins over a boundary when the user says
|
|
31
|
+
what to call them") still belongs in YOUR schema's `description`, not in this
|
|
32
|
+
endpoint: it forwards your schema verbatim and holds no opinion about your
|
|
33
|
+
vocabulary.
|
|
34
|
+
|
|
35
|
+
## 0.17.0 — 2026-08-07
|
|
36
|
+
|
|
37
|
+
- **New `extractJson()` — structured JSON output, outside the companion.**
|
|
38
|
+
`POST /v1/admin/utility/json`. Additive; nothing else changed.
|
|
39
|
+
|
|
40
|
+
This exists because using a companion agent for extraction does not work, and
|
|
41
|
+
did not fail in a way that explained itself. A companion turn is a
|
|
42
|
+
conversation engine — persona prompt, memory recall, tools — and when the
|
|
43
|
+
model returns an empty completion it answers with a natural-language fallback
|
|
44
|
+
line rather than shipping an empty bubble. Correct for a chat surface, wrong
|
|
45
|
+
for a parser. An extraction prompt reliably *reaches* that fallback, because
|
|
46
|
+
the reasoning-effort bump off the cheapest tier is gated on conversational and
|
|
47
|
+
functional cues (weather, search, wallet, social) that an extraction input
|
|
48
|
+
never matches. The result was a soft chat sentence where JSON was expected.
|
|
49
|
+
|
|
50
|
+
`extractJson()` shares none of that machinery: no persona, no memory, no
|
|
51
|
+
tools, no session, no fallback. One provider call with `response_format` set,
|
|
52
|
+
and a parsed result.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const { data } = await admin.extractJson<{ nickname: string | null }>({
|
|
56
|
+
content: '叫我 Alex',
|
|
57
|
+
schema: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
required: ['nickname'],
|
|
61
|
+
properties: { nickname: { type: ['string', 'null'] } }
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// → { nickname: 'Alex' }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **`strict` defaults to true**, which asks the provider to ENFORCE the schema.
|
|
68
|
+
The schema must then sit inside the provider's structured-output subset: root
|
|
69
|
+
object, `additionalProperties: false`, and every property listed in
|
|
70
|
+
`required` — model an optional field as a union with `null` rather than by
|
|
71
|
+
omitting it from `required`. A schema outside the subset comes back as `400`
|
|
72
|
+
/ `code: 'schema_invalid'` carrying the provider's own reason instead of
|
|
73
|
+
failing at generation time. Pass `strict: false` to fall back to plain JSON
|
|
74
|
+
mode plus server-side validation.
|
|
75
|
+
|
|
76
|
+
- **Failures are typed, not prose.** `schema_invalid` (400 — fix the schema;
|
|
77
|
+
retrying verbatim cannot help), `unavailable` (5xx — transient, back off),
|
|
78
|
+
`invalid_json` (502 — a completion arrived but did not parse or did not
|
|
79
|
+
satisfy the schema). `invalid_json` carries `raw`, the text actually
|
|
80
|
+
returned, so the failure is debuggable rather than opaque.
|
|
81
|
+
|
|
82
|
+
- **Note on schema key names.** The companion reply path strips objects
|
|
83
|
+
matching internal memory-pipeline signatures, among them
|
|
84
|
+
`{domain, key, value, label}` and `{content, kind, importance}`. That
|
|
85
|
+
stripping does not apply to this endpoint — but if you were previously
|
|
86
|
+
extracting through a companion agent with a schema shaped like either of
|
|
87
|
+
those, a *correct* answer could be removed before you saw it. Another reason
|
|
88
|
+
to move extraction here.
|
|
89
|
+
|
|
5
90
|
## 0.16.1 — 2026-08-06
|
|
6
91
|
|
|
7
92
|
Documentation only — no type, signature or runtime change. Two doc comments
|
package/README.md
CHANGED
|
@@ -58,6 +58,101 @@ console.log(`armed — ${armed.reprovisioned} running instance(s) updated`);
|
|
|
58
58
|
// The agent can now drive the API from the skill's prose via http_request.
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
### Structured JSON — use `extractJson`, not a companion agent
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const { data } = await admin.extractJson<{ nickname: string | null }>({
|
|
65
|
+
content: '叫我 Alex',
|
|
66
|
+
schema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
required: ['nickname'], // strict mode: EVERY property, always
|
|
70
|
+
properties: { nickname: { type: ['string', 'null'] } } // optional → union with null
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
console.log(data.nickname); // 'Alex'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A companion turn is a **conversation** engine — persona prompt, memory recall,
|
|
77
|
+
tools — and when the model returns an empty completion it answers with a
|
|
78
|
+
natural-language fallback line rather than an empty bubble. That is right for a
|
|
79
|
+
chat surface and wrong for a parser, and an extraction prompt reliably reaches
|
|
80
|
+
it, because the reasoning-effort bump off the cheapest tier is gated on
|
|
81
|
+
conversational/functional cues an extraction input never matches. So a companion
|
|
82
|
+
agent asked for JSON returns chat filler, fairly consistently.
|
|
83
|
+
|
|
84
|
+
`extractJson` shares none of that: no persona, no memory, no tools, no session,
|
|
85
|
+
no fallback — one provider call with `response_format` set. `strict` defaults to
|
|
86
|
+
true, which makes the provider **enforce** the schema; the schema must then sit
|
|
87
|
+
inside the provider's structured-output subset (root object,
|
|
88
|
+
`additionalProperties: false`, every property listed in `required`). Pass
|
|
89
|
+
`strict: false` for schemas outside it — you still get JSON mode plus
|
|
90
|
+
server-side validation.
|
|
91
|
+
|
|
92
|
+
#### `reasoningEffort` — matters most when one input carries several directives
|
|
93
|
+
|
|
94
|
+
`reasoningEffort` (`'minimal' | 'low' | 'medium' | 'high'`, default `'low'`) is
|
|
95
|
+
the thinking budget. It is worth a moment because extraction fails at the cheap
|
|
96
|
+
tier in a specific, easy-to-miss way: **the summary comes out right and the
|
|
97
|
+
segmentation collapses.**
|
|
98
|
+
|
|
99
|
+
Measured over 26 utterances against an integrator's own extractor, the previous
|
|
100
|
+
floor (`'minimal'`) agreed on kind for all 22 inputs carrying a SINGLE
|
|
101
|
+
directive, then diverged on both inputs carrying more than one — 「以后别叫我宝
|
|
102
|
+
贝,叫我老板」 labelled by its leading clause (a boundary) rather than its
|
|
103
|
+
operative one (a nickname), and 「叫我阿凯,别剧透,我不喜欢虐心结局」 merged
|
|
104
|
+
three directives into two. In each case the item's own text mentioned every
|
|
105
|
+
clause; only the count and the label were wrong, which is exactly the failure a
|
|
106
|
+
schema check cannot catch.
|
|
107
|
+
|
|
108
|
+
Pass `'minimal'` for the cheapest, fastest extraction when each input carries at
|
|
109
|
+
most one directive. Raise it above the default when the split matters more than
|
|
110
|
+
the latency.
|
|
111
|
+
|
|
112
|
+
Precedence between YOUR kinds — "a nickname wins over a boundary when the user
|
|
113
|
+
also says what to call them" — belongs in the schema's `description`, not here:
|
|
114
|
+
this endpoint forwards your schema verbatim and holds no opinion about your
|
|
115
|
+
vocabulary.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const { data } = await admin.extractJson<{ items: { kind: string; summary: string }[] }>({
|
|
119
|
+
content: '以后别叫我宝贝,叫我老板',
|
|
120
|
+
reasoningEffort: 'low',
|
|
121
|
+
schema: {
|
|
122
|
+
type: 'object',
|
|
123
|
+
additionalProperties: false,
|
|
124
|
+
required: ['items'],
|
|
125
|
+
properties: {
|
|
126
|
+
items: {
|
|
127
|
+
type: 'array',
|
|
128
|
+
items: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
additionalProperties: false,
|
|
131
|
+
required: ['kind', 'summary'],
|
|
132
|
+
properties: {
|
|
133
|
+
kind: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
enum: ['nickname', 'boundary', 'preference'],
|
|
136
|
+
// The precedence rule lives HERE, in your vocabulary's own words.
|
|
137
|
+
description:
|
|
138
|
+
'One directive per item — never merge two of different kinds. If the user says what to CALL them (even alongside what not to), the item is `nickname` and the rejected form goes in the summary; `boundary` is only for a prohibition with no replacement.'
|
|
139
|
+
},
|
|
140
|
+
summary: { type: 'string' }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Failures are typed rather than prose, so the recoveries are distinguishable:
|
|
150
|
+
`schema_invalid` (400 — fix the schema; retrying verbatim cannot help),
|
|
151
|
+
`unavailable` (5xx — transient, back off), and `invalid_json` (502 — a
|
|
152
|
+
completion arrived but did not parse or satisfy the schema; the error carries
|
|
153
|
+
`raw`, the text actually returned). Tokens roll into the project's month usage
|
|
154
|
+
like any other model call.
|
|
155
|
+
|
|
61
156
|
Every skill knob (`setSkillRate`, `setSkillDailyCap`, `grantSkill`) returns
|
|
62
157
|
`SkillKnobResult<T>` — the knob you set plus `reprovisioned` (instances the new
|
|
63
158
|
def reached) and `truncated`. A knob only binds a running agent once the def
|
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.18.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
|
|
@@ -436,6 +436,10 @@ export type SkillKnobResult<T> = T & {
|
|
|
436
436
|
reprovisioned: number;
|
|
437
437
|
truncated: boolean;
|
|
438
438
|
};
|
|
439
|
+
/** Thinking budget for `extractJson`, cheapest first. Mirrors the server's
|
|
440
|
+
* vocabulary; an unknown value is refused with a 400 by the endpoint rather
|
|
441
|
+
* than forwarded to the provider. */
|
|
442
|
+
export type AdminReasoningEffort = 'minimal' | 'low' | 'medium' | 'high';
|
|
439
443
|
export interface AdminClient {
|
|
440
444
|
listAgents(): Promise<{
|
|
441
445
|
agents: Agent[];
|
|
@@ -652,6 +656,61 @@ export interface AdminClient {
|
|
|
652
656
|
mode: 'semantic' | 'lexical';
|
|
653
657
|
hits: unknown[];
|
|
654
658
|
}>;
|
|
659
|
+
/** Structured JSON extraction, OUTSIDE the companion.
|
|
660
|
+
*
|
|
661
|
+
* Use this — not a companion agent — whenever you want machine-readable
|
|
662
|
+
* output. A companion turn is a conversation engine: it carries a persona
|
|
663
|
+
* prompt, recalls memory, and when the model returns nothing it answers with
|
|
664
|
+
* a natural-language fallback line rather than dead air. That is right for a
|
|
665
|
+
* chat bubble and wrong for a parser, and an extraction prompt reliably
|
|
666
|
+
* triggers it, because the reasoning-effort bump off the cheapest tier is
|
|
667
|
+
* gated on conversational/functional cues that an extraction input does not
|
|
668
|
+
* match. This endpoint shares none of that: no persona, no memory, no tools,
|
|
669
|
+
* no session, no fallback — one provider call with `response_format` set.
|
|
670
|
+
*
|
|
671
|
+
* `strict` (default true) asks the provider to ENFORCE the schema. It must
|
|
672
|
+
* then sit inside the provider's structured-output subset: a root object,
|
|
673
|
+
* `additionalProperties: false`, and EVERY property listed in `required`
|
|
674
|
+
* (model an optional field as a union with `null`, not by omitting it from
|
|
675
|
+
* `required`). A schema outside the subset is rejected with `400` /
|
|
676
|
+
* `code: 'schema_invalid'` naming the provider's reason — pass
|
|
677
|
+
* `strict: false` to fall back to plain JSON mode plus server-side
|
|
678
|
+
* validation.
|
|
679
|
+
*
|
|
680
|
+
* Failures are typed rather than prose, which is the point:
|
|
681
|
+
* `schema_invalid` (400 — fix the schema, retrying verbatim cannot help),
|
|
682
|
+
* `unavailable` (5xx — transient, back off), `invalid_json` (502 — a
|
|
683
|
+
* completion arrived but did not parse or did not satisfy the schema; the
|
|
684
|
+
* error carries `raw`, the text actually returned).
|
|
685
|
+
*
|
|
686
|
+
* `reasoningEffort` is the thinking budget, default `'low'`. It matters more
|
|
687
|
+
* than it sounds for extraction: the shared one-shot floor is `'minimal'`,
|
|
688
|
+
* and an A/B over 26 utterances found that floor agreed on kind for all 22
|
|
689
|
+
* inputs carrying a SINGLE directive, then diverged on both inputs carrying
|
|
690
|
+
* more than one — labelling "以后别叫我宝贝,叫我老板" by its leading clause
|
|
691
|
+
* (a boundary) rather than its operative one (a nickname), and merging three
|
|
692
|
+
* directives into two. The summary text was correct both times; only the
|
|
693
|
+
* segmentation collapsed. Raise it when one input can carry several
|
|
694
|
+
* directives at once and the split matters more than the latency; pass
|
|
695
|
+
* `'minimal'` for the cheapest, fastest extraction.
|
|
696
|
+
*
|
|
697
|
+
* Tokens roll into the project's month usage like any other model call. */
|
|
698
|
+
extractJson<T = unknown>(input: {
|
|
699
|
+
schema: Record<string, unknown>;
|
|
700
|
+
content: string;
|
|
701
|
+
system?: string;
|
|
702
|
+
strict?: boolean;
|
|
703
|
+
model?: string;
|
|
704
|
+
schemaName?: string;
|
|
705
|
+
reasoningEffort?: AdminReasoningEffort;
|
|
706
|
+
}): Promise<{
|
|
707
|
+
data: T;
|
|
708
|
+
raw: string;
|
|
709
|
+
usage?: {
|
|
710
|
+
promptTokens: number;
|
|
711
|
+
completionTokens: number;
|
|
712
|
+
};
|
|
713
|
+
}>;
|
|
655
714
|
deleteKnowledge(docId: string): Promise<{
|
|
656
715
|
deleted: boolean;
|
|
657
716
|
}>;
|
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.18.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;
|
|
@@ -247,6 +247,7 @@ export function createAdminClient(opts) {
|
|
|
247
247
|
ingestKnowledgeFile: (input) => request('POST', '/knowledge/file', input),
|
|
248
248
|
ingestKnowledgeUrl: (input) => request('POST', '/knowledge/url', input),
|
|
249
249
|
searchKnowledge: (query) => request('POST', '/knowledge/search', { query }),
|
|
250
|
+
extractJson: (input) => request('POST', '/utility/json', input),
|
|
250
251
|
deleteKnowledge: (id) => request('DELETE', `/knowledge/${encodeURIComponent(id)}`),
|
|
251
252
|
listSkills: () => request('GET', '/skills'),
|
|
252
253
|
installSkill: (input) => request('POST', '/skills', input),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/admin-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|