@cana-ai/sdk 0.2.0 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +165 -0
  2. package/package.json +19 -3
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @cana-ai/sdk
2
+
3
+ OpenAI-compatible client for Cana **Apps** — programmatic access to your agent
4
+ with **HMAC auth**, **server-hosted MCP** federation, **streaming**, and
5
+ **typed structured output**.
6
+
7
+ Point any OpenAI SDK at a Cana App and it just works. Or use this client to get
8
+ auto MCP dispatch, Web-Crypto signing, and Zod typing for free.
9
+
10
+ ```bash
11
+ npm install @cana-ai/sdk
12
+ # or just drop a script tag — see below
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Quick start (Node / Bun / Deno / Workers)
18
+
19
+ ```ts
20
+ import { CanaClient } from "@cana-ai/sdk/openai";
21
+
22
+ const client = new CanaClient({
23
+ appId: "app_…",
24
+ signingKey: process.env.CANA_APP_KEY!, // csk_live_…
25
+ apiBase: "https://cana.build", // optional
26
+ });
27
+
28
+ const c = await client.chat.completions.create({
29
+ model: "openai/gpt-4o",
30
+ messages: [{ role: "user", content: "Hello" }],
31
+ });
32
+ console.log(c.choices[0].message.content);
33
+ ```
34
+
35
+ Model strings are `<provider>/<model-id>` — `openai/gpt-4o`,
36
+ `anthropic/claude-haiku-4-5-20251001`, `moonshot/moonshot-v1-32k`,
37
+ `google/gemini-2.5-pro`, etc. The proxy resolves the right credentials from the
38
+ App owner's provider configs.
39
+
40
+ ## Streaming
41
+
42
+ ```ts
43
+ const stream = await client.chat.completions.create({
44
+ model: "openai/gpt-4o",
45
+ messages: [{ role: "user", content: "Write a haiku about TCP." }],
46
+ stream: true,
47
+ });
48
+
49
+ for await (const chunk of stream) {
50
+ process.stdout.write(chunk.choices[0]?.delta.content ?? "");
51
+ }
52
+ ```
53
+
54
+ Chunks are verbatim OpenAI Server-Sent-Events shapes, with `[DONE]`
55
+ auto-terminated.
56
+
57
+ ## Typed structured output (Zod)
58
+
59
+ ```ts
60
+ import { z } from "zod";
61
+
62
+ const Person = z.object({ name: z.string(), age: z.number() });
63
+
64
+ const { result } = await client.chat.completions.generate({
65
+ model: "openai/gpt-4o",
66
+ messages: [{ role: "user", content: "Pick a friendly person" }],
67
+ schema: Person,
68
+ });
69
+
70
+ result.name; // string
71
+ result.age; // number
72
+ ```
73
+
74
+ Uses OpenAI's strict `response_format: { type: "json_schema" }` under the hood.
75
+ Optional peer dep: `zod-to-json-schema` (auto-converts your schema).
76
+
77
+ ## MCP federation — discover + auto-dispatch
78
+
79
+ Server-hosted MCP connectors are exposed via two helper endpoints; the SDK
80
+ drives the loop for you:
81
+
82
+ ```ts
83
+ const r = await client.runWithMcp({
84
+ model: "anthropic/claude-haiku-4-5-20251001",
85
+ messages: [{ role: "user", content: "Find last week's PRs in cana-web" }],
86
+ mcp: ["github", "search"], // connector names attached to your App
87
+ maxRounds: 5,
88
+ });
89
+
90
+ console.log(r.message.content);
91
+ ```
92
+
93
+ Or do it by hand:
94
+
95
+ ```ts
96
+ const { tools } = await client.mcp.tools(["github"]);
97
+ // `tools` is in OpenAI tool format → pass to chat.completions.create
98
+ // When you get a tool_call back named `mcp__github__<tool>`, dispatch:
99
+ const out = await client.mcp.execute({ name: "mcp__github__list_prs", arguments: { repo: "…" } });
100
+ ```
101
+
102
+ Tool names follow the `mcp__<connector>__<tool>` convention; everything else
103
+ is treated as a client-side tool you handle yourself.
104
+
105
+ ## Browser — `<script>` tag
106
+
107
+ A pre-built IIFE bundle is hosted at the App owner's Cana URL:
108
+
109
+ ```html
110
+ <script src="https://cana.build/sdk/openai.js"></script>
111
+ <script>
112
+ const client = new CanaOpenAI.CanaClient({
113
+ appId: "app_…",
114
+ signingKey: "csk_live_…", // server-issued, scoped to one App
115
+ });
116
+ client.chat.completions.create({
117
+ model: "openai/gpt-4o",
118
+ messages: [{ role: "user", content: "Hello" }],
119
+ }).then(c => console.log(c.choices[0].message.content));
120
+ </script>
121
+ ```
122
+
123
+ > Browser-direct mode leaks the signing key to anyone who views source. Use it
124
+ > for prototypes; in prod, proxy through your own server.
125
+
126
+ ## Plain OpenAI SDK
127
+
128
+ Any OpenAI client can hit the proxy directly if it can sign requests. The
129
+ URL shape is `https://<base>/api/v1/apps/<appId>/openai`. You'll need a fetch
130
+ hook that adds:
131
+
132
+ ```
133
+ X-Cana-App-Signature: t=<unix-ms>,v1=<hmac-sha256-hex>
134
+ ```
135
+
136
+ over the canonical string `${unixMs}.${rawBody}`. The Node/browser examples
137
+ above do this for you.
138
+
139
+ ## Errors
140
+
141
+ All non-2xx responses throw `CanaApiError` with a typed `.code` and `.status`.
142
+ Common codes: `signature_invalid`, `signature_expired`, `app_paused`,
143
+ `rate_limited`, `billing_exceeded`, `unknown_provider`, `model_not_found`,
144
+ `mcp_connector_unknown`, `upstream_error`.
145
+
146
+ ```ts
147
+ import { CanaApiError } from "@cana-ai/sdk/openai";
148
+
149
+ try {
150
+ await client.chat.completions.create({ … });
151
+ } catch (e) {
152
+ if (e instanceof CanaApiError && e.code === "rate_limited") {
153
+ // back off, check `Retry-After`
154
+ } else throw e;
155
+ }
156
+ ```
157
+
158
+ ## Web Crypto only
159
+
160
+ Zero `node:crypto` import — works on Node 18+, Bun, Deno, Cloudflare Workers,
161
+ and modern browsers out of the box.
162
+
163
+ ## License
164
+
165
+ MIT
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cana-ai/sdk",
3
- "version": "0.2.0",
4
- "description": "Cana Apps SDK programmatic access for embedders who drive their own UI.",
3
+ "version": "0.2.1",
4
+ "description": "OpenAI-compatible client for Cana Apps — HMAC auth, server-hosted MCP federation, streaming, typed structured output. Web Crypto only (Node 18+, Bun, Deno, Workers, browsers).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -16,7 +16,23 @@
16
16
  "import": "./dist/openai/index.js"
17
17
  }
18
18
  },
19
- "files": ["dist"],
19
+ "files": ["dist", "README.md"],
20
+ "keywords": [
21
+ "cana",
22
+ "openai",
23
+ "openai-compatible",
24
+ "llm",
25
+ "agent",
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "structured-output",
29
+ "hmac",
30
+ "ai-sdk",
31
+ "anthropic",
32
+ "moonshot"
33
+ ],
34
+ "license": "MIT",
35
+ "homepage": "https://cana.build",
20
36
  "scripts": {
21
37
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
22
38
  "dev": "tsc -p tsconfig.json --watch",