@puku-ai/sdk 4.0.5 → 4.0.6

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.
Files changed (2) hide show
  1. package/README.md +151 -19
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -77,7 +77,6 @@ returns a model-not-found error.
77
77
  |---------------|----------|-------|
78
78
  | `puku-ai-2.7` | Puku AI | Cheaper, lower-latency. |
79
79
  | `puku-ai-2.8` | Puku AI | Default for most workloads. |
80
- | `opus-4.8` | Opus | Strongest reasoning; pick this for fallbacks (`fallbacks: [{ model: "opus-4.8" }]`). |
81
80
 
82
81
 
83
82
  ## Usage
@@ -168,25 +167,155 @@ Every feature below was exercised against the live Puku gateway at
168
167
  | `stream.finalMessage()` | ✅ works | `MessageStream` |
169
168
  | `stream.on("text", cb)` listener | ✅ works | `MessageStream` |
170
169
  | `client.beta.messages.toolRunner(...).runUntilDone()` | ✅ works | `client.beta.messages` |
170
+ | `client.messages.countTokens` | ✅ works | `count-tokens.ts` |
171
+ | `client.messages.batches.create / retrieve / results` | ✅ works | `batch-results.ts` (D1-backed storage) |
172
+ | Server-side `web_search` (both streaming + non-streaming variants) | ✅ works | `web-search.ts`, `web-search-stream.ts` (gateway forwards `tool_use` to puku-research-gateway and maps back to `web_search_tool_result`) |
173
+ | Structured outputs (`output_config.format`) — zod / json-schema / raw / standard-schema | ✅ works (non-streaming; raw occasionally flaky) | `structured-outputs-*.ts` |
171
174
  | `ToolError` class (exceptions from the runner) | ✅ works | `helpers/beta` |
172
175
  | MCP helpers (`mcpTool`, `mcpTools`, `mcpMessage`, `mcpMessages`, `mcpResourceToContent`, `mcpResourceToFile`) | ✅ exported | `helpers/beta/mcp` |
173
176
  | Agent toolset (`betaAgentToolset20260401`, `betaBashTool`, `betaReadTool`, `betaWriteTool`, `betaEditTool`, `betaGlobTool`, `betaGrepTool`) | ✅ exported | `tools/agent-toolset` |
174
177
  | Full error hierarchy (`APIError`, `RateLimitError`, `AuthenticationError`, …) | ✅ works | static on `PukuAI` |
175
178
 
176
- ### Known gateway gaps (SDK calls the correct path, gateway returns 404)
179
+ ### Known gateway gaps
177
180
 
178
181
  | Feature | Status | Note |
179
182
  |--------------------------------------|--------|------|
180
- | `client.messages.countTokens` | ⚠ 404 | SDK POSTs to `/v1/messages/count_tokens` exactly like upstream. Puku's gateway does not proxy this endpoint. |
181
- | `client.messages.batches.create` | ⚠ 404 | SDK POSTs to `/v1/messages/batches` exactly like upstream. Puku's gateway does not proxy this endpoint. |
182
- | `client.beta.agents.*` | ⚠ 404 | SDK POSTs to `/v1/agents/*` exactly like upstream. Puku's gateway does not proxy these endpoints yet. |
183
- | `client.beta.environments.*` | ⚠ 404 | SDK POSTs to `/v1/environments/*` exactly like upstream. Puku's gateway does not proxy these endpoints yet. |
184
- | `client.beta.sessions.*` | ⚠ 404 | SDK POSTs to `/v1/sessions/*` exactly like upstream. Puku's gateway does not proxy these endpoints yet. |
185
- | `client.beta.vaults.*` | ⚠ 404 | SDK POSTs to `/v1/vaults/*` exactly like upstream. Puku's gateway does not proxy these endpoints yet. |
186
- | `client.beta.skills.{listVersions, retrieve, delete}` | ⚠ 404 | SDK POSTs/GETs to `/v1/skills/{id}/versions/...` exactly like upstream. Puku's gateway does not proxy these endpoints yet. The pure archive-validation helpers (`assertSafeMemberNames`, `assertNoSpecialMembers`, `runArchiveTool`, `archiveTopDir`, `readHead`) remain usable. |
187
- | `client.messages.batches.results` | ⚠ n/a | Not exercised against the live gateway because `batches.create` already 404s. |
188
- | Structured-outputs JSON parser (`output_format` / `output_config.format`) | ⚠ not wired | The SDK accepts the option but no structured-outputs parser is hooked into the stream finalizer. The `JSONOutputFormat` shape exists in types only. |
189
- | Server-side `web_search` tool result | ⚠ not proxied | The SDK forwards a `web_search_20250305` tool definition; the gateway does not execute the search and returns the placeholder shape. Use the agent toolset + your own search client instead. |
183
+ | Structured-outputs JSON parser (`output_config.format`) — streaming variant | ⚠ flaky | Passes most runs but `puku-ai-2.8` / `puku-ai-2.7` occasionally emit a duplicate JSON key in the payload which the SDK's Zod parser rejects. Re-running usually passes — not a regression, just model-output variance. |
184
+ | Structured-outputs JSON parser (`output_config.format`) — `raw` variant | ⚠ flaky | Same root cause: `puku-ai-2.8` occasionally emits non-JSON prose (e.g. `I computed …`) or a malformed JSON payload (e.g. an unterminated string) inside the synthetic tool call, which the SDK's `JSON.parse` rejects. Re-running usually passes — not a regression, just model-output variance. |
185
+
186
+ ### Beta managed-agents surface (preview)
187
+
188
+ The Puku gateway serves Anthropic-shaped responses for the beta managed-agents
189
+ namespace so SDK code that calls them does not 404. These exist so SDK
190
+ examples round-trip against the live gateway while the full managed-agents
191
+ runtime track is reopened — they are **not a production control plane**.
192
+
193
+ | Surface | Status | What you can do with it |
194
+ |--------------------------------------|--------|-------------------------|
195
+ | `client.beta.sessions.*` | ✅ works | Run a managed-agent loop — create session, post `events.send`, stream `events.stream`. The gateway drives the LLM turn and emits the same Anthropic-shaped SSE events the SDK's `SessionToolRunner` consumes. |
196
+ | `client.beta.agents.*` | ⚠ limited | CRUD round-trip. `agents.create` returns a populated `BetaAgent` shape but no remote agent execution. |
197
+ | `client.beta.environments.*` | ⚠ limited | `POST /environments` returns `{id, status:'ready'}` synchronously — no `creating → ready` polling. |
198
+ | `client.beta.environments.*.work.{poll,ack,heartbeat,stop,retrieve,update}` | ⚠ limited | The work queue round-trips so `WorkPoller`/`EnvironmentWorker` terminate. One synthetic work item per session. |
199
+ | `client.beta.vaults.*` | ⚠ limited | CRUD + `credentials.create`. Secret tokens are dropped — `vault_ids` passed to `sessions.create` are ignored (sessions don't need credentials in puku). |
200
+ | `client.beta.skills.{create,list,retrieve,delete}` | ⚠ limited | Multipart upload + metadata only. Accepts `files` and `files[]` field names. |
201
+ | `client.beta.skills.versions.{create,list,retrieve,delete}` | ⚠ limited | Multipart upload + metadata only. Idempotent on `(skill_id, version)` — 409 on duplicate. |
202
+ | `client.beta.skills.versions.download` | ⚠ limited | Returns a 22-byte empty-zip body so `response.blob()` decodes a real `Blob`. Real archive bytes are not stored. |
203
+ | `client.files.{upload,list,retrieve,download,delete}` (non-beta `/v1/files`) | ⚠ limited | Bytes held in-memory only — not persisted anywhere durable. |
204
+
205
+ #### Working example: managed-agent session with `toolRunner`
206
+
207
+ This is the loop `client.beta.sessions.*` actually drives for you. You create
208
+ a session, post a user message, open the event stream, and the SDK's
209
+ `toolRunner` dispatches any `agent.tool_use` events back through
210
+ `events.send` automatically.
211
+
212
+ ```ts
213
+ import PukuAI from "@puku-ai/sdk";
214
+
215
+ const client = new PukuAI();
216
+
217
+ // 1. Create an environment + an agent + a session.
218
+ const env = await client.beta.environments.create({ name: "demo" });
219
+ const agent = await client.beta.agents.create({
220
+ name: "weather-bot",
221
+ model: "puku-ai-2.8",
222
+ environment: { type: "cloud", id: env.id },
223
+ tools: [
224
+ // Tools the gateway's tool registry will resolve at agent-turn time.
225
+ { type: "agent_toolset_20260401" },
226
+ ],
227
+ });
228
+ const session = await client.beta.sessions.create({
229
+ agent_id: agent.id,
230
+ environment_id: env.id,
231
+ });
232
+
233
+ // 2. Define a runnable tool the gateway will round-trip.
234
+ const getWeather = {
235
+ name: "get_weather",
236
+ description: "Return the current temperature for a city.",
237
+ input_schema: {
238
+ type: "object",
239
+ properties: { city: { type: "string" } },
240
+ required: ["city"],
241
+ },
242
+ run: async (input: { city: string }) =>
243
+ JSON.stringify({ temp_c: 22.4, city: input.city }),
244
+ };
245
+
246
+ // 3. Post a user message and stream the agent turn.
247
+ await client.beta.sessions.events.send(session.id, {
248
+ type: "user.message",
249
+ content: [{ type: "text", text: "What's the weather in Tokyo?" }],
250
+ });
251
+
252
+ for await (const event of client.beta.sessions.events.stream(session.id)) {
253
+ // `agent.message` is the final assistant turn; everything before it
254
+ // is either tool_use / tool_result round-trips or status transitions.
255
+ if (event.type === "agent.message") {
256
+ console.log("agent:", event.content);
257
+ }
258
+ }
259
+
260
+ // 4. Clean up.
261
+ await client.beta.sessions.delete(session.id);
262
+ await client.beta.agents.delete(agent.id);
263
+ await client.beta.environments.delete(env.id);
264
+ ```
265
+
266
+ #### Working example: skill upload + version
267
+
268
+ The skills router accepts multipart upload and round-trips a single version
269
+ per skill. Real archive bytes are not stored — `versions.download` returns a
270
+ 22-byte empty zip so `response.blob()` succeeds.
271
+
272
+ ```ts
273
+ import PukuAI from "@puku-ai/sdk";
274
+
275
+ const client = new PukuAI();
276
+
277
+ // Upload a skill.
278
+ const skill = await client.skills.create({
279
+ display_name: "my-skill",
280
+ files: [new File(["# SKILL"], "SKILL.md", { type: "text/markdown" })],
281
+ });
282
+
283
+ // Add a version (auto-generated timestamp, or pass one explicitly).
284
+ const v1 = await client.beta.skills.versions.create(skill.id, {
285
+ files: [new File(["# v1"], "SKILL.md", { type: "text/markdown" })],
286
+ });
287
+
288
+ // List versions, retrieve one, download (returns an empty zip blob).
289
+ const page = await client.beta.skills.versions.list(skill.id);
290
+ const fetched = await client.beta.skills.versions.retrieve(skill.id, v1.version);
291
+ const blob = await client.beta.skills.versions.download(skill.id, v1.version);
292
+ console.log(page.data.length, fetched.version, blob.size); // 1, "20260101T000000Z", 22
293
+
294
+ // Cleanup — delete cascades to all versions.
295
+ await client.beta.skills.delete(skill.id);
296
+ ```
297
+
298
+ #### Working example: file upload + download (non-beta `/v1/files`)
299
+
300
+ `client.files.*` is the non-beta Anthropic Files API stub. Bytes are held in
301
+ memory and not persisted anywhere durable.
302
+
303
+ ```ts
304
+ import PukuAI from "@puku-ai/sdk";
305
+
306
+ const client = new PukuAI();
307
+
308
+ const file = await client.files.upload({
309
+ file: new File(["hello"], "hello.txt", { type: "text/plain" }),
310
+ });
311
+ console.log(file.id, file.filename, file.size_bytes); // file_xxx, "hello.txt", 5
312
+
313
+ const list = await client.files.list();
314
+ const blob = await client.files.download(file.id);
315
+ console.log(await blob.text()); // "hello"
316
+
317
+ await client.files.delete(file.id);
318
+ ```
190
319
 
191
320
 
192
321
 
@@ -263,7 +392,7 @@ import PukuAI, { mcpTools, mcpMessage, mcpMessages, mcpResourceToFile } from "@p
263
392
  const client = new PukuAI();
264
393
 
265
394
  // `mcpTools` converts an MCP client from @modelcontextprotocol/sdk into
266
- // a list of Anthropic tool definitions. The SDK ships every helper
395
+
267
396
 
268
397
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
269
398
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
@@ -318,12 +447,15 @@ import { betaReadTool, betaBashTool } from "@puku-ai/sdk";
318
447
  const tools = [betaReadTool({ workdir: "/tmp/sandbox" })];
319
448
  ```
320
449
 
321
- > `setupSkills`, `resolveSkillVersion`, and `extractSkillArchive` require
322
- > `/v1/skills/{id}/versions/{version}` (download/retrieve/list) and
323
- > `/v1/sessions/{id}`, which the Puku gateway doesn't proxy.
324
- > archive-validation helpers (`assertSafeMemberNames`,
325
- > `assertNoSpecialMembers`, `runArchiveTool`, `archiveTopDir`, `readHead`)
326
- > stay available — they are pure functions and don't touch the gateway.
450
+ > `setupSkills`, `resolveSkillVersion`, and `extractSkillArchive` round-trip
451
+ > against `/v1/skills/{id}/versions/{version}` + `/v1/sessions/{id}`. The
452
+ > gateway now serves those endpoints (multipart upload + metadata in-memory,
453
+ > download returns a 22-byte empty zip), so the helpers no longer 404 —
454
+ > but `extractSkillArchive` will receive an empty zip body and cannot
455
+ > extract real archive contents. The pure archive-validation helpers
456
+ > (`assertSafeMemberNames`, `assertNoSpecialMembers`, `runArchiveTool`,
457
+ > `archiveTopDir`, `readHead`) stay available — they don't touch the
458
+ > gateway.
327
459
 
328
460
  ## Namespace
329
461
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puku-ai/sdk",
3
- "version": "4.0.5",
3
+ "version": "4.0.6",
4
4
  "description": "PukuAI client SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",