@pyai/sdk 0.6.0 → 0.6.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/AGENT_GUIDE.md CHANGED
@@ -10,8 +10,8 @@ Markdown and does not require the marketing website renderer.
10
10
 
11
11
  ## Availability and sources of truth
12
12
 
13
- The CLI is included in `@pyai/sdk` 0.6.0. Install it with
14
- `npm install -g @pyai/sdk@0.6.0`. Browser login supports existing PyAI accounts;
13
+ The CLI is included in `@pyai/sdk` 0.6.1. Install it with
14
+ `npm install -g @pyai/sdk@0.6.1`. Browser login supports existing PyAI accounts;
15
15
  unattended agents should use an authorized environment key. Inspect the
16
16
  installed command schema before acting.
17
17
 
@@ -35,7 +35,7 @@ do not invent an endpoint or present the feature as deployed.
35
35
  Install the published CLI with Node.js 22 or newer recommended:
36
36
 
37
37
  ```bash
38
- npm install -g @pyai/sdk@0.6.0
38
+ npm install -g @pyai/sdk@0.6.1
39
39
  pyai --version
40
40
  pyai schema --json
41
41
  ```
@@ -51,7 +51,7 @@ npm install -g .
51
51
  ```
52
52
 
53
53
  Alternatively install a supplied build with
54
- `npm install -g /path/to/pyai-sdk-0.6.0.tgz`. The compiled executable supports
54
+ `npm install -g /path/to/pyai-sdk-0.6.1.tgz`. The compiled executable supports
55
55
  Node.js 18 or newer. Use `node dist/cli.js` explicitly when another package's
56
56
  `pyai` shadows this executable.
57
57
 
package/CLI.md CHANGED
@@ -6,8 +6,8 @@ scripts and in coding agents with shell access, including Cursor, Claude Code,
6
6
  and Codex. `--json` provides structured results; `--help` and `schema` describe
7
7
  the installed command surface.
8
8
 
9
- **Version:** the expanded CLI is included in `@pyai/sdk` 0.6.0. Install it from
10
- npm with `npm install -g @pyai/sdk@0.6.0`, then run `pyai login` for browser
9
+ **Version:** the expanded CLI is included in `@pyai/sdk` 0.6.1. Install it from
10
+ npm with `npm install -g @pyai/sdk@0.6.1`, then run `pyai login` for browser
11
11
  sign-in or provide `PYAI_API_KEY` for unattended automation.
12
12
 
13
13
  ## Contents
@@ -31,7 +31,7 @@ sign-in or provide `PYAI_API_KEY` for unattended automation.
31
31
  Install the published package (Node.js 22 or newer recommended):
32
32
 
33
33
  ```bash
34
- npm install -g @pyai/sdk@0.6.0
34
+ npm install -g @pyai/sdk@0.6.1
35
35
  pyai --version
36
36
  pyai login
37
37
  pyai speak "Hello from PyAI." -o hello.wav
@@ -56,7 +56,7 @@ also be packaged and installed on another machine:
56
56
  # In sdk/typescript after building
57
57
  npm pack --ignore-scripts
58
58
  # On the destination machine, using the actual tarball path
59
- npm install -g /path/to/pyai-sdk-0.6.0.tgz
59
+ npm install -g /path/to/pyai-sdk-0.6.1.tgz
60
60
  pyai schema --json
61
61
  ```
62
62
 
package/README.md CHANGED
@@ -78,9 +78,17 @@ the instant the socket opens and routes server frames to typed callbacks, so you
78
78
  **can't** trip the #1 Omni integration bug (a hand-rolled `{"event":"configure"}`
79
79
  is acked but silently dropped, giving you a connected session with zero turns):
80
80
 
81
- ```ts
81
+ For a Node 20 server, install `npm install ws` and inject its WebSocket constructor
82
+ as shown below. Use ESM imports. Node 22+ can omit the `ws` import and `webSocket`
83
+ option to use its global WebSocket. This SDK transport option does not change the
84
+ MCP server's Node 22+ requirement.
85
+
86
+ ```js
87
+ import WebSocket from "ws";
88
+
82
89
  // Omni is zero-state: the key's org authorizes the session, nothing to create.
83
90
  const omni = pyai.omni.connect({
91
+ webSocket: WebSocket, // Supplies the transport on Node 20.
84
92
  rate: 16000, // 24000 browser · 16000 wideband telephony · 8000 G.711/Twilio
85
93
  configure: { voice_id: "stock_emma_en_gb", persona: "You are a receptionist." },
86
94
  onAudio: (chunk) => speaker.write(chunk), // binary agent audio, play it out
@@ -109,6 +117,25 @@ Caller transcripts continue to require the `0x02` carrier.
109
117
  agent audio; `rate: 8000` receives 8 kHz. Read `hello.audio_out` before playback.
110
118
  Omni has no commit frame—keep streaming silence during caller pauses.
111
119
 
120
+ For a client-executed lookup, declare `side_effect: "read"` in its tool definition:
121
+
122
+ ```js
123
+ const officeHoursTool = {
124
+ name: "lookup_office_hours",
125
+ description: "Read the office opening time.",
126
+ side_effect: "read",
127
+ parameters: { type: "object", properties: {} },
128
+ };
129
+ // Include officeHoursTool in configure.tools. In onToolCall, return the
130
+ // actual lookup result using session.toolResult(frame.call_id, { result }).
131
+ ```
132
+
133
+ An omitted `side_effect` is treated as an action. Action results need a positive
134
+ completion acknowledgement, for example `{ ok: true, receipt_id: actualReceiptId }`,
135
+ returned inside `toolResult`'s `result`. Send that only after the operation has
136
+ completed; a queued request or transport acknowledgement is insufficient.
137
+ On failure, return `{ error: "Operation failed" }` instead of claiming success.
138
+
112
139
  From the browser, mint an ephemeral token server-side with
113
140
  `pyai.omni.createSession({ allowedOrigins })` and pass it as `token` so the page
114
141
  never holds a secret key:
package/dist/cli-dx.js CHANGED
@@ -34,5 +34,5 @@ export const recipes = [
34
34
  notes: ["Local schema and recipes work without credentials. Live OpenAPI needs a network connection but no API key.", "The CLI manages Agent profiles; use the SDK or WebSocket API for a live Omni audio session."] },
35
35
  { name: "ci", title: "Use PyAI in a build", description: "Check access and produce an audio artifact with machine-readable output.",
36
36
  commands: ["pyai whoami --json", 'pyai speak "Your build is ready" -o build.wav --json', "pyai doctor --json"],
37
- notes: ["Set PYAI_API_KEY through the CI secret store; do not put it in source or shell arguments.", "doctor synthesizes and transcribes a sample, which consumes usage. Use whoami for an authentication-only check.", "Install the CLI with npm install -g @pyai/sdk@0.6.0 and pin that version in repeatable builds."] },
37
+ notes: ["Set PYAI_API_KEY through the CI secret store; do not put it in source or shell arguments.", "doctor synthesizes and transcribes a sample, which consumes usage. Use whoami for an authentication-only check.", "Install the CLI with npm install -g @pyai/sdk@0.6.1 and pin that version in repeatable builds."] },
38
38
  ].map(recipe => ({ ...recipe, docs_url: "https://pyai.com/agents/speech-calling.md" }));
package/dist/cli-init.js CHANGED
@@ -127,7 +127,7 @@ const install = `## Install the CLI
127
127
  Install the published CLI with Node.js 22 or newer recommended:
128
128
 
129
129
  \`\`\`bash
130
- npm install -g @pyai/sdk@0.6.0
130
+ npm install -g @pyai/sdk@0.6.1
131
131
  pyai --version
132
132
  \`\`\`
133
133
 
@@ -220,7 +220,7 @@ and product calls below are separate explicit steps. Read \`PYAI.md\` first.
220
220
  Install the official SDK:
221
221
 
222
222
  \`\`\`bash
223
- npm install @pyai/sdk@0.6.0
223
+ npm install @pyai/sdk@0.6.1
224
224
  cp .env.example .env
225
225
  \`\`\`
226
226
 
package/dist/cli.js CHANGED
@@ -405,7 +405,7 @@ async function main() {
405
405
  if (flags.json)
406
406
  output({ name: "pyai", globals, aliases, short_flags: shortFlags, commands: visible }, flags, undefined, false);
407
407
  else if (!spec && !group)
408
- process.stdout.write(`PyAI CLI — speech, agents, and automation\n\nStart here\n pyai login Sign in through your browser\n pyai speak "Hello from PyAI" -o hello.wav Turn text into audio\n pyai hear call.wav --text-only Print a transcript\n pyai dub call.wav --from en --to hi -o hi.wav\n Submit, wait, and save dubbed audio\n pyai init voice-demo --template typescript Create a starter project offline\n\nDiscover\n pyai recipes [name] Copyable workflows\n pyai help <command> Command options and examples\n pyai help all Every command\n pyai schema [command] -j Machine-readable command definitions\n\nGroups\n auth profiles models voices agents jobs clones design\n cast dub recap trace tools vocabulary amd numbers calls omni\n\nShortcuts: login, logout, whoami, use, say (speak), hear (transcribe)\nOptions: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nGlobal: --base-url URL --api-key KEY --timeout SECONDS --retries N --dry-run\nCredentials: pyai login or PYAI_API_KEY. Run pyai doctor for a usage-consuming diagnostic.\n`);
408
+ process.stdout.write(`PyAI CLI — speech, agents, and automation\n\nStart here\n pyai login Sign in through your browser\n pyai speak "Hello from PyAI" -o hello.wav Turn text into audio\n pyai hear call.wav --text-only Print a transcript\n pyai dub call.wav --from en --to hi -o hi.wav\n Submit, wait, and save dubbed audio\n pyai init voice-demo --template typescript Create a starter project offline\n\nCalling\n pyai numbers list List owned phone numbers\n pyai numbers search --country US Find available numbers\n pyai calls list Inspect outbound calls\n pyai recipes calling --json Setup and preview examples\n pyai calls create --data @call.json --idempotency-key REQUEST_KEY --dry-run\n Preview a call without submitting it\n --dry-run previews a change without sending the request.\n Number purchases and outbound calls require --confirm and --idempotency-key.\n Use --confirm only after that purchase or call is authorized.\n\nDiscover\n pyai recipes [name] Copyable workflows\n pyai help <command> Command options and examples\n pyai help all Every command\n pyai schema [command] -j Machine-readable command definitions\n\nGroups\n auth profiles models voices agents jobs clones design\n cast dub recap trace tools vocabulary amd numbers calls omni\n\nShortcuts: login, logout, whoami, use, say (speak), hear (transcribe)\nOptions: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nGlobal: --base-url URL --api-key KEY --timeout SECONDS --retries N --dry-run\nCredentials: pyai login or PYAI_API_KEY. Run pyai doctor for a usage-consuming diagnostic.\n`);
409
409
  else
410
410
  process.stdout.write(`PyAI CLI — speech, agents, and automation\n\n${visible.map(c => ` pyai ${c.command}${(c.args ?? []).map(a => c.optionalArgs ? ` [${a}${c.variadic ? "..." : ""}]` : ` <${a}>`).join("")}\n ${c.description}${c.flags ? `\n Options: ${Object.keys(c.flags).map(k => `--${k}${c.flags[k] === "boolean" ? "" : " VALUE"}`).join(" ")}` : ""}${c.example ? `\n ${c.example}` : ""}`).join("\n")}\n\nGlobal: --profile NAME --json --timeout SECONDS --retries N --dry-run\n --base-url URL --api-key KEY --help --version\nShort flags: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nAuth: pyai login or PYAI_API_KEY. Discover: pyai schema --json\n`);
411
411
  return;
package/dist/index.d.ts CHANGED
@@ -594,6 +594,9 @@ export interface OmniToolDef {
594
594
  name: string;
595
595
  description?: string;
596
596
  parameters?: Record<string, unknown>;
597
+ /** Declare lookups as read-only. Omitted tools are treated as actions and
598
+ * require a positive completion acknowledgement in their result. */
599
+ side_effect?: "read" | "action";
597
600
  }
598
601
  export interface OmniToolCallFrame {
599
602
  event: "tool_call";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyai/sdk",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Official TypeScript/JavaScript SDK for PyAI, speech-to-text (Hear), text-to-speech (Speak), realtime voice agents (Omni), and call compliance (Trace).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/cli-dx.ts CHANGED
@@ -35,5 +35,5 @@ export const recipes: Recipe[] = [
35
35
  notes: ["Local schema and recipes work without credentials. Live OpenAPI needs a network connection but no API key.", "The CLI manages Agent profiles; use the SDK or WebSocket API for a live Omni audio session."] },
36
36
  { name: "ci", title: "Use PyAI in a build", description: "Check access and produce an audio artifact with machine-readable output.",
37
37
  commands: ["pyai whoami --json", 'pyai speak "Your build is ready" -o build.wav --json', "pyai doctor --json"],
38
- notes: ["Set PYAI_API_KEY through the CI secret store; do not put it in source or shell arguments.", "doctor synthesizes and transcribes a sample, which consumes usage. Use whoami for an authentication-only check.", "Install the CLI with npm install -g @pyai/sdk@0.6.0 and pin that version in repeatable builds."] },
38
+ notes: ["Set PYAI_API_KEY through the CI secret store; do not put it in source or shell arguments.", "doctor synthesizes and transcribes a sample, which consumes usage. Use whoami for an authentication-only check.", "Install the CLI with npm install -g @pyai/sdk@0.6.1 and pin that version in repeatable builds."] },
39
39
  ].map(recipe => ({ ...recipe, docs_url: "https://pyai.com/agents/speech-calling.md" }));
package/src/cli-init.ts CHANGED
@@ -149,7 +149,7 @@ const install = `## Install the CLI
149
149
  Install the published CLI with Node.js 22 or newer recommended:
150
150
 
151
151
  \`\`\`bash
152
- npm install -g @pyai/sdk@0.6.0
152
+ npm install -g @pyai/sdk@0.6.1
153
153
  pyai --version
154
154
  \`\`\`
155
155
 
@@ -242,7 +242,7 @@ and product calls below are separate explicit steps. Read \`PYAI.md\` first.
242
242
  Install the official SDK:
243
243
 
244
244
  \`\`\`bash
245
- npm install @pyai/sdk@0.6.0
245
+ npm install @pyai/sdk@0.6.1
246
246
  cp .env.example .env
247
247
  \`\`\`
248
248
 
package/src/cli.ts CHANGED
@@ -270,7 +270,7 @@ async function main(): Promise<void> {
270
270
  const grouped = group ? commands.filter(c => c.command.startsWith(`${group} `)) : commands;
271
271
  const visible = spec ? [spec, ...commands.filter(c => c.command.startsWith(`${spec.command} `))] : grouped.length ? grouped : commands;
272
272
  if (flags.json) output({ name: "pyai", globals, aliases, short_flags: shortFlags, commands: visible }, flags, undefined, false);
273
- else if (!spec && !group) process.stdout.write(`PyAI CLI — speech, agents, and automation\n\nStart here\n pyai login Sign in through your browser\n pyai speak "Hello from PyAI" -o hello.wav Turn text into audio\n pyai hear call.wav --text-only Print a transcript\n pyai dub call.wav --from en --to hi -o hi.wav\n Submit, wait, and save dubbed audio\n pyai init voice-demo --template typescript Create a starter project offline\n\nDiscover\n pyai recipes [name] Copyable workflows\n pyai help <command> Command options and examples\n pyai help all Every command\n pyai schema [command] -j Machine-readable command definitions\n\nGroups\n auth profiles models voices agents jobs clones design\n cast dub recap trace tools vocabulary amd numbers calls omni\n\nShortcuts: login, logout, whoami, use, say (speak), hear (transcribe)\nOptions: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nGlobal: --base-url URL --api-key KEY --timeout SECONDS --retries N --dry-run\nCredentials: pyai login or PYAI_API_KEY. Run pyai doctor for a usage-consuming diagnostic.\n`);
273
+ else if (!spec && !group) process.stdout.write(`PyAI CLI — speech, agents, and automation\n\nStart here\n pyai login Sign in through your browser\n pyai speak "Hello from PyAI" -o hello.wav Turn text into audio\n pyai hear call.wav --text-only Print a transcript\n pyai dub call.wav --from en --to hi -o hi.wav\n Submit, wait, and save dubbed audio\n pyai init voice-demo --template typescript Create a starter project offline\n\nCalling\n pyai numbers list List owned phone numbers\n pyai numbers search --country US Find available numbers\n pyai calls list Inspect outbound calls\n pyai recipes calling --json Setup and preview examples\n pyai calls create --data @call.json --idempotency-key REQUEST_KEY --dry-run\n Preview a call without submitting it\n --dry-run previews a change without sending the request.\n Number purchases and outbound calls require --confirm and --idempotency-key.\n Use --confirm only after that purchase or call is authorized.\n\nDiscover\n pyai recipes [name] Copyable workflows\n pyai help <command> Command options and examples\n pyai help all Every command\n pyai schema [command] -j Machine-readable command definitions\n\nGroups\n auth profiles models voices agents jobs clones design\n cast dub recap trace tools vocabulary amd numbers calls omni\n\nShortcuts: login, logout, whoami, use, say (speak), hear (transcribe)\nOptions: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nGlobal: --base-url URL --api-key KEY --timeout SECONDS --retries N --dry-run\nCredentials: pyai login or PYAI_API_KEY. Run pyai doctor for a usage-consuming diagnostic.\n`);
274
274
  else process.stdout.write(`PyAI CLI — speech, agents, and automation\n\n${visible.map(c => ` pyai ${c.command}${(c.args ?? []).map(a => c.optionalArgs ? ` [${a}${c.variadic ? "..." : ""}]` : ` <${a}>`).join("")}\n ${c.description}${c.flags ? `\n Options: ${Object.keys(c.flags).map(k => `--${k}${c.flags![k] === "boolean" ? "" : " VALUE"}`).join(" ")}` : ""}${c.example ? `\n ${c.example}` : ""}`).join("\n")}\n\nGlobal: --profile NAME --json --timeout SECONDS --retries N --dry-run\n --base-url URL --api-key KEY --help --version\nShort flags: -o FILE -f FILE -t TEXT -p PROFILE -j (JSON)\nAuth: pyai login or PYAI_API_KEY. Discover: pyai schema --json\n`);
275
275
  return;
276
276
  }
package/src/index.ts CHANGED
@@ -887,6 +887,9 @@ export interface OmniToolDef {
887
887
  name: string;
888
888
  description?: string;
889
889
  parameters?: Record<string, unknown>;
890
+ /** Declare lookups as read-only. Omitted tools are treated as actions and
891
+ * require a positive completion acknowledgement in their result. */
892
+ side_effect?: "read" | "action";
890
893
  }
891
894
 
892
895
  export interface OmniToolCallFrame {