diff --git a/typescript/package-lock.json b/typescript/package-lock.json index ae21e76..9a3dc34 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -9,7 +9,7 @@ "version": "0.8.3", "license": "MIT", "dependencies": { - "@jambonz/schema": "^0.3.19", + "@jambonz/schema": "^0.4.0", "ajv": "^8.17.1", "ws": "^8.18.0" }, @@ -582,9 +582,9 @@ } }, "node_modules/@jambonz/schema": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jambonz/schema/-/schema-0.3.19.tgz", - "integrity": "sha512-pKhRhAT9xY4ZztHIo/Ras92lmt0oNpeOj3M5QSxMnqUz4Dgzky47ZZMPjJ0xpnt2fL4QOh6vu2iKyyCaaNWuPQ==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@jambonz/schema/-/schema-0.4.0.tgz", + "integrity": "sha512-FtjudIkHFaQgGCS1jVO08u3QcCwpBNIx85Yee74mwOiTfZvl7YTYt+FRT5xrfMUI0Kd4pcYxYZCGdHxLWo5d+w==", "license": "MIT", "dependencies": { "ajv": "^8.17.1", diff --git a/typescript/package.json b/typescript/package.json index 580320b..9e7cf72 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -82,13 +82,10 @@ "examples" ], "scripts": { - "gen:types": "node scripts/gen-llm-vendors.mjs", - "prebuild": "npm run gen:types", "build": "tsup", "dev": "tsup --watch", "test": "vitest run", "test:watch": "vitest", - "pretypecheck": "npm run gen:types", "typecheck": "tsc --noEmit", "lint": "eslint src/", "docs": "typedoc", @@ -98,7 +95,7 @@ "postpublish": "npm run clean-docs" }, "dependencies": { - "@jambonz/schema": "^0.3.19", + "@jambonz/schema": "^0.4.0", "ajv": "^8.17.1", "ws": "^8.18.0" }, diff --git a/typescript/scripts/gen-llm-vendors.mjs b/typescript/scripts/gen-llm-vendors.mjs deleted file mode 100644 index 066df72..0000000 --- a/typescript/scripts/gen-llm-vendors.mjs +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env node -/** - * Code generator: derive the LLM vendor union from the source of truth. - * - * The agent verb's `llm.vendor` is an enum defined once, in - * `@jambonz/schema` (verbs/agent.schema.json). Hand-maintaining a matching - * TypeScript union here drifts every time a vendor is added to the schema. - * Instead we read the enum at build time and emit it as a TS literal union. - * - * Output: src/types/llm-vendors.generated.ts (committed; regenerated on prebuild) - * Run: npm run gen:types - */ -import { createRequire } from 'node:module'; -import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const require = createRequire(import.meta.url); -const __dirname = dirname(fileURLToPath(import.meta.url)); - -// Resolve @jambonz/schema's location via its package.json (no `exports` field, -// so subpath file reads are permitted), then read the agent verb schema. -const schemaPkgJson = require.resolve('@jambonz/schema/package.json'); -const schemaRoot = dirname(schemaPkgJson); -const agentSchemaPath = join(schemaRoot, 'verbs', 'agent.schema.json'); - -const agentSchema = JSON.parse(readFileSync(agentSchemaPath, 'utf8')); -const enumValues = agentSchema?.properties?.llm?.properties?.vendor?.enum; - -if (!Array.isArray(enumValues) || enumValues.length === 0) { - console.error( - `[gen-llm-vendors] Could not find llm.vendor.enum in ${agentSchemaPath}` - ); - process.exit(1); -} - -const schemaVersion = JSON.parse(readFileSync(schemaPkgJson, 'utf8')).version; -const members = enumValues.map((v) => ` '${v}',`).join('\n'); - -const out = `// AUTO-GENERATED — DO NOT EDIT BY HAND. -// Source of truth: @jambonz/schema@${schemaVersion} verbs/agent.schema.json (llm.vendor.enum) -// Regenerate with: npm run gen:types -// -// This file derives the LLM vendor list from the JSON schema so the SDK's -// types never drift from the schema when a new vendor is added. - -/** Supported LLM vendors for the agent verb, derived from the schema enum. */ -export const LLM_VENDORS = [ -${members} -] as const; - -/** Union of LLM vendor ids accepted by the agent verb's \`llm.vendor\`. */ -export type LlmVendor = (typeof LLM_VENDORS)[number]; -`; - -const outPath = resolve(__dirname, '..', 'src', 'types', 'llm-vendors.generated.ts'); -mkdirSync(dirname(outPath), { recursive: true }); -writeFileSync(outPath, out); - -console.log( - `[gen-llm-vendors] Wrote ${enumValues.length} vendors from @jambonz/schema@${schemaVersion} -> src/types/llm-vendors.generated.ts` -); diff --git a/typescript/src/types/components.ts b/typescript/src/types/components.ts index 9e62a06..99a8232 100644 --- a/typescript/src/types/components.ts +++ b/typescript/src/types/components.ts @@ -141,6 +141,7 @@ export interface Recognizer { assemblyAiOptions?: Record; speechmaticsOptions?: Record; openaiOptions?: Record; + xaiOptions?: Record; houndifyOptions?: Record; gladiaOptions?: Record; elevenlabsOptions?: Record; diff --git a/typescript/src/types/index.ts b/typescript/src/types/index.ts index 27f4f5f..c242895 100644 --- a/typescript/src/types/index.ts +++ b/typescript/src/types/index.ts @@ -63,9 +63,8 @@ export type { VerbName, } from './verbs.js'; -// LLM vendors (derived from @jambonz/schema) -export type { LlmVendor } from './llm-vendors.generated.js'; -export { LLM_VENDORS } from './llm-vendors.generated.js'; +// LLM vendor id (free-form string; the schema has no vendor enum by design) +export type { LlmVendor } from './verbs.js'; // Session export type { diff --git a/typescript/src/types/llm-vendors.generated.ts b/typescript/src/types/llm-vendors.generated.ts deleted file mode 100644 index f4080a5..0000000 --- a/typescript/src/types/llm-vendors.generated.ts +++ /dev/null @@ -1,26 +0,0 @@ -// AUTO-GENERATED — DO NOT EDIT BY HAND. -// Source of truth: @jambonz/schema@0.3.18 verbs/agent.schema.json (llm.vendor.enum) -// Regenerate with: npm run gen:types -// -// This file derives the LLM vendor list from the JSON schema so the SDK's -// types never drift from the schema when a new vendor is added. - -/** Supported LLM vendors for the agent verb, derived from the schema enum. */ -export const LLM_VENDORS = [ - 'openai', - 'anthropic', - 'google', - 'vertex-gemini', - 'vertex-openai', - 'bedrock', - 'deepseek', - 'baseten', - 'azure-openai', - 'groq', - 'huggingface', - 'moonshot', - 'zai', -] as const; - -/** Union of LLM vendor ids accepted by the agent verb's `llm.vendor`. */ -export type LlmVendor = (typeof LLM_VENDORS)[number]; diff --git a/typescript/src/types/verbs.ts b/typescript/src/types/verbs.ts index ddbc634..f9733ed 100644 --- a/typescript/src/types/verbs.ts +++ b/typescript/src/types/verbs.ts @@ -16,7 +16,14 @@ import type { Target, Vad, } from './components.js'; -import type { LlmVendor } from './llm-vendors.generated.js'; + +/** + * LLM vendor id for the agent verb's `llm.vendor`. Free-form by design: the + * schema deliberately has no vendor enum so new LLMs can be added without a + * schema release; the server validates the vendor against its registered + * `@jambonz/llm` adapters at runtime. + */ +export type LlmVendor = string; // --------------------------------------------------------------------------- // Audio & Speech @@ -162,9 +169,10 @@ export interface AgentLlmOptions { /** `llm` block on the agent verb. */ export interface AgentLlm { - /** LLM vendor. Derived from the @jambonz/schema agent verb enum — see llm-vendors.generated.ts. */ - vendor: LlmVendor; - model: string; + /** LLM vendor. Optional: falls back to the application's default LLM vendor when omitted. */ + vendor?: LlmVendor; + /** Model id. Optional: falls back to the application's default LLM model when omitted. */ + model?: string; label?: string; auth?: { apiKey?: string; [key: string]: unknown }; connectOptions?: { @@ -314,8 +322,8 @@ export interface AgentVerb { minSpeechDuration?: number; sticky?: boolean; }; - /** LLM configuration. */ - llm: AgentLlm; + /** LLM configuration. Optional: when omitted, the agent uses the application's default LLM (like stt/tts). */ + llm?: AgentLlm; /** Webhook when agent ends. */ actionHook?: ActionHook; /** Webhook for agent events. */ @@ -476,6 +484,8 @@ export interface DialVerb { referHook?: ActionHook; /** Audio URL for ringback tone replacement. */ dialMusic?: string; + /** Request SRTP (encrypted media) on the outbound call. 'sdes' negotiates keys via SDES crypto attributes (used with sips:/TLS targets); 'dtls' via DTLS-SRTP. Applies to SIP URI targets. */ + srtpEncryption?: 'sdes' | 'dtls'; /** DTMF capture patterns during bridged call. */ dtmfCapture?: Record; /** Webhook for captured DTMF patterns. */ diff --git a/typescript/test/schema-drift.test.ts b/typescript/test/schema-drift.test.ts index f2fa2e6..7487d1f 100644 --- a/typescript/test/schema-drift.test.ts +++ b/typescript/test/schema-drift.test.ts @@ -182,22 +182,7 @@ describe('Schema drift detection', () => { } }); - // The agent verb's llm.vendor union is code-generated from the schema enum - // (src/types/llm-vendors.generated.ts, via scripts/gen-llm-vendors.mjs). The - // generated file is committed, so it can go stale if the @jambonz/schema dep is - // bumped without re-running `npm run gen:types`. This guards the committed artifact. - describe('generated LLM vendor list matches schema enum', () => { - it('LLM_VENDORS equals agent.schema.json llm.vendor.enum', async () => { - const agentSchema = JSON.parse( - readFileSync(resolve(verbsDir, 'agent.schema.json'), 'utf-8') - ); - const schemaEnum: string[] = agentSchema.properties.llm.properties.vendor.enum; - const { LLM_VENDORS } = await import('../src/types/llm-vendors.generated.js'); - - expect( - [...LLM_VENDORS], - 'generated LLM_VENDORS is stale — run `npm run gen:types`' - ).toEqual(schemaEnum); - }); - }); + // Note: the agent verb's llm.vendor is intentionally free-form (no enum) in + // @jambonz/schema, so there is no vendor union to drift-check here — vendor + // is validated at runtime against the server's registered adapters. });