mirror of
https://github.com/jambonz/verb-specifications.git
synced 2026-04-04 14:36:05 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87b58b45fe | ||
|
|
3369517364 | ||
|
|
aedbbb028f | ||
|
|
9d426de535 | ||
|
|
49bce96c82 | ||
|
|
0bb1313b5b | ||
|
|
f92c3429d2 | ||
|
|
bb21d7d71f | ||
|
|
d0f77421fe | ||
|
|
161695ed43 | ||
|
|
b46cfe0c55 | ||
|
|
6f39ad2e2e | ||
|
|
66b63d8912 | ||
|
|
de5a2fdd1c | ||
|
|
8cb79d47cc | ||
|
|
11a0dce5ba | ||
|
|
ecf59041c5 | ||
|
|
abcb3ffa5d | ||
|
|
f5e7adcf66 | ||
|
|
f29b214208 | ||
|
|
2bf7561980 | ||
|
|
96db93fcdc | ||
|
|
142718104a | ||
|
|
9ac144ef71 | ||
|
|
337114035d | ||
|
|
253bd8a49c | ||
|
|
7a5c094bfc | ||
|
|
228f8773d3 | ||
|
|
c9cd50c559 | ||
|
|
fe095be5c8 | ||
|
|
71caf6bb53 |
@@ -4,6 +4,27 @@ const _specData = require('./specs');
|
||||
const specs = new Map();
|
||||
for (const key in _specData) { specs.set(key, _specData[key]); }
|
||||
|
||||
/* verb synonyms and shortcuts: maps alias verb names to their canonical form,
|
||||
optionally injecting properties (e.g. vendor) into the verb data */
|
||||
const verbTransforms = new Map([
|
||||
['stream', {verb: 'listen'}],
|
||||
['s2s', {verb: 'llm'}],
|
||||
['openai_s2s', {verb: 'llm', properties: {vendor: 'openai'}}],
|
||||
['microsoft_s2s', {verb: 'llm', properties: {vendor: 'microsoft'}}],
|
||||
['google_s2s', {verb: 'llm', properties: {vendor: 'google'}}],
|
||||
['elevenlabs_s2s', {verb: 'llm', properties: {vendor: 'elevenlabs'}}],
|
||||
['deepgram_s2s', {verb: 'llm', properties: {vendor: 'deepgram'}}],
|
||||
['voiceagent_s2s', {verb: 'llm', properties: {vendor: 'voiceagent'}}],
|
||||
['ultravox_s2s', {verb: 'llm', properties: {vendor: 'ultravox'}}],
|
||||
]);
|
||||
|
||||
function applyVerbTransform(name, data) {
|
||||
const transform = verbTransforms.get(name);
|
||||
if (!transform) return {name, data};
|
||||
const newData = transform.properties ? {...transform.properties, ...data} : data;
|
||||
return {name: transform.verb, data: newData};
|
||||
}
|
||||
|
||||
function normalizeJambones(logger, obj) {
|
||||
if (!Array.isArray(obj)) {
|
||||
throw new Error('malformed jambonz payload: must be array');
|
||||
@@ -13,18 +34,22 @@ function normalizeJambones(logger, obj) {
|
||||
if (typeof tdata !== 'object') throw new Error('malformed jambonz payload: must be array of objects');
|
||||
if ('verb' in tdata) {
|
||||
// {verb: 'say', text: 'foo..bar'..}
|
||||
const name = tdata.verb;
|
||||
const o = {};
|
||||
Object.keys(tdata)
|
||||
.filter((k) => k !== 'verb')
|
||||
.forEach((k) => o[k] = tdata[k]);
|
||||
const {name, data} = applyVerbTransform(tdata.verb, o);
|
||||
const o2 = {};
|
||||
o2[name] = o;
|
||||
o2[name] = data;
|
||||
document.push(o2);
|
||||
}
|
||||
else if (Object.keys(tdata).length === 1) {
|
||||
// {'say': {..}}
|
||||
document.push(tdata);
|
||||
const key = Object.keys(tdata)[0];
|
||||
const {name, data} = applyVerbTransform(key, tdata[key]);
|
||||
const o2 = {};
|
||||
o2[name] = data;
|
||||
document.push(o2);
|
||||
}
|
||||
else {
|
||||
logger.info(tdata, 'malformed jambonz payload: missing verb property');
|
||||
|
||||
132
package-lock.json
generated
132
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@jambonz/verb-specifications",
|
||||
"version": "0.0.125",
|
||||
"version": "0.1.10",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@jambonz/verb-specifications",
|
||||
"version": "0.0.125",
|
||||
"version": "0.1.10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
@@ -219,10 +219,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -399,10 +400,11 @@
|
||||
]
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -528,10 +530,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
@@ -1154,6 +1157,23 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@@ -1180,10 +1200,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.4",
|
||||
@@ -1964,10 +1985,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
@@ -2035,10 +2057,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -2844,15 +2867,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/table/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
"require-from-string": "^2.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -3327,9 +3351,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
@@ -3444,9 +3468,9 @@
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
@@ -3532,9 +3556,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
@@ -4004,6 +4028,12 @@
|
||||
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz",
|
||||
"integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw=="
|
||||
},
|
||||
"fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||
"dev": true
|
||||
},
|
||||
"file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@@ -4024,9 +4054,9 @@
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-each": {
|
||||
@@ -4536,9 +4566,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
@@ -4595,9 +4625,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
@@ -5173,15 +5203,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
"require-from-string": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jambonz/verb-specifications",
|
||||
"version": "0.0.125",
|
||||
"version": "0.1.10",
|
||||
"description": "Jambonz Verb Specification Utilities",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
113
specs.json
113
specs.json
@@ -76,7 +76,10 @@
|
||||
"referHook": "object|string",
|
||||
"earlyMedia": "boolean",
|
||||
"autoStreamTts": "boolean",
|
||||
"disableTtsCache": "boolean"
|
||||
"disableTtsCache": "boolean",
|
||||
"trackTtsPlayout": "boolean",
|
||||
"noiseIsolation": "#noiseIsolation",
|
||||
"turnTaking": "#turnTaking"
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
@@ -280,6 +283,7 @@
|
||||
"statusHook": "object|string",
|
||||
"enterHook": "object|string",
|
||||
"record": "#record",
|
||||
"listen": "#listen",
|
||||
"distributeDtmf": "boolean"
|
||||
},
|
||||
"required": [
|
||||
@@ -329,7 +333,7 @@
|
||||
"region": "string",
|
||||
"model": {
|
||||
"type": "string",
|
||||
"enum": ["es", "cx"]
|
||||
"enum": ["es", "cx", "ces"]
|
||||
},
|
||||
"lang": "string",
|
||||
"actionHook": "object|string",
|
||||
@@ -424,33 +428,6 @@
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"stream": {
|
||||
"properties": {
|
||||
"id": "string",
|
||||
"actionHook": "object|string",
|
||||
"auth": "#auth",
|
||||
"finishOnKey": "string",
|
||||
"maxLength": "number",
|
||||
"metadata": "object",
|
||||
"mixType": {
|
||||
"type": "string",
|
||||
"enum": ["mono", "stereo", "mixed"]
|
||||
},
|
||||
"passDtmf": "boolean",
|
||||
"playBeep": "boolean",
|
||||
"disableBidirectionalAudio": "boolean",
|
||||
"bidirectionalAudio": "#bidirectionalAudio",
|
||||
"sampleRate": "number",
|
||||
"timeout": "number",
|
||||
"transcribe": "#transcribe",
|
||||
"url": "string",
|
||||
"wsAuth": "#auth",
|
||||
"earlyMedia": "boolean"
|
||||
},
|
||||
"required": [
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"llm": {
|
||||
"properties": {
|
||||
"id": "string",
|
||||
@@ -687,6 +664,7 @@
|
||||
"fallbackLabel": "string",
|
||||
"fallbackLanguage": "string",
|
||||
"vad": "#vad",
|
||||
"autogeneratePrompt": "boolean",
|
||||
"hints": "array",
|
||||
"hintsBoost": "number",
|
||||
"altLanguages": "array",
|
||||
@@ -880,7 +858,8 @@
|
||||
"sessionTimeout": "number",
|
||||
"connectionTimeout": "number",
|
||||
"customVocabulary": "array",
|
||||
"languageModel": "string"
|
||||
"languageModel": "string",
|
||||
"audioQueryAbsoluteTimeout": "number"
|
||||
}
|
||||
},
|
||||
"elevenlabsOptions": {
|
||||
@@ -1071,6 +1050,16 @@
|
||||
},
|
||||
"speechmaticsOptions": {
|
||||
"properties": {
|
||||
"host": "string",
|
||||
"profile": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"adaptive",
|
||||
"agile",
|
||||
"smart",
|
||||
"external"
|
||||
]
|
||||
},
|
||||
"transcription_config": "#sm_transcriptionConfig",
|
||||
"translation_config": "#sm_translationConfig",
|
||||
"audio_events_config_config": "#sm_audioEventsConfig"
|
||||
@@ -1234,10 +1223,17 @@
|
||||
"v3"
|
||||
]
|
||||
},
|
||||
"speechModel": "string",
|
||||
"formatTurns": "boolean",
|
||||
"endOfTurnConfidenceThreshold": "number",
|
||||
"minEndOfTurnSilenceWhenConfident": "number",
|
||||
"maxTurnSilence": "number"
|
||||
"maxTurnSilence": "number",
|
||||
"minTurnSilence": "number",
|
||||
"keyterms": "array",
|
||||
"prompt": "string",
|
||||
"languageDetection": "boolean",
|
||||
"vadThreshold": "number",
|
||||
"inactivityTimeout": "number"
|
||||
}
|
||||
},
|
||||
"resource": {
|
||||
@@ -1374,30 +1370,53 @@
|
||||
"id": "string",
|
||||
"stt": "#recognizer",
|
||||
"tts": "#synthesizer",
|
||||
"vad": "#vad",
|
||||
"turnDetection": "#turnDetectionPipeline",
|
||||
"llm": "#llm",
|
||||
"preflightLlm": "boolean",
|
||||
"turnDetection": "string|object",
|
||||
"bargeIn": "#bargeInPipeline",
|
||||
"actionHook": "object|string",
|
||||
"eventHook": "object|string"
|
||||
"eventHook": "object|string",
|
||||
"toolHook": "object|string",
|
||||
"greeting": "boolean",
|
||||
"earlyGeneration": "boolean",
|
||||
"noiseIsolation": "string|#noiseIsolationPipeline",
|
||||
"mcpServers": ["#mcpServer"],
|
||||
"noResponseTimeout": "number"
|
||||
},
|
||||
"required": [
|
||||
"stt",
|
||||
"llm",
|
||||
"tts"
|
||||
"llm"
|
||||
]
|
||||
},
|
||||
"turnDetectionPipeline": {
|
||||
"bargeInPipeline": {
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"enum": ["krisp"]
|
||||
"enable": "boolean",
|
||||
"minSpeechDuration": "number",
|
||||
"sticky": "boolean"
|
||||
}
|
||||
},
|
||||
"noiseIsolationPipeline": {
|
||||
"properties": {
|
||||
"mode": "string",
|
||||
"level": "number",
|
||||
"direction": {
|
||||
"enum": ["read", "write"]
|
||||
},
|
||||
"model": "string"
|
||||
}
|
||||
},
|
||||
"noiseIsolation" : {
|
||||
"properties": {
|
||||
"enable": "boolean",
|
||||
"vendor": "string",
|
||||
"level": "number",
|
||||
"model": "string"
|
||||
}
|
||||
},
|
||||
"turnTaking": {
|
||||
"properties": {
|
||||
"enable": "boolean",
|
||||
"vendor": "string",
|
||||
"threshold": "number",
|
||||
"eagerEotThreshold": "number"
|
||||
},
|
||||
"required": [
|
||||
"vendor"
|
||||
]
|
||||
"model": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const test = require('tape');
|
||||
const logger = require('pino')({level: process.env.JAMBONES_LOGLEVEL || 'error'});
|
||||
const { validate } = require('..');
|
||||
const { validate, normalizeJambones } = require('..');
|
||||
|
||||
test("validate correct verbs", async (t) => {
|
||||
|
||||
@@ -329,7 +329,8 @@ test("validate correct verbs", async (t) => {
|
||||
"sessionTimeout": 30000,
|
||||
"connectionTimeout": 5000,
|
||||
"customVocabulary": ["jambonz", "telephony", "voip"],
|
||||
"languageModel": "enhanced"
|
||||
"languageModel": "enhanced",
|
||||
"audioQueryAbsoluteTimeout": 5
|
||||
},
|
||||
"gladiaOptions": {
|
||||
"post_processing": {
|
||||
@@ -468,6 +469,24 @@ test("validate correct verbs", async (t) => {
|
||||
"speechPadMs": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "config",
|
||||
"noiseIsolation": {
|
||||
"enable": true,
|
||||
"vendor": "krisp",
|
||||
"level": 3,
|
||||
"model": "custom-model"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "config",
|
||||
"turnTaking": {
|
||||
"enable": true,
|
||||
"vendor": "krisp",
|
||||
"threshold": 0.5,
|
||||
"model": "turn-taking-model"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "message",
|
||||
"to": "15083084809",
|
||||
@@ -645,6 +664,56 @@ test("validate correct verbs", async (t) => {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"verb": "s2s",
|
||||
"vendor": "openai",
|
||||
"llmOptions": {
|
||||
"model": "gpt-4o-realtime"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "openai_s2s",
|
||||
"llmOptions": {
|
||||
"model": "gpt-4o-realtime"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "google_s2s",
|
||||
"llmOptions": {
|
||||
"model": "gemini-2.0-flash"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "elevenlabs_s2s",
|
||||
"llmOptions": {
|
||||
"agentId": "agent-123"
|
||||
}
|
||||
},
|
||||
{
|
||||
"verb": "stream",
|
||||
"url": "wss://myrecorder.example.com/calls",
|
||||
"mixType": "stereo"
|
||||
},
|
||||
{
|
||||
"verb": "pipeline",
|
||||
"stt": {
|
||||
"vendor": "google",
|
||||
"language": "en-US"
|
||||
},
|
||||
"tts": {
|
||||
"vendor": "google",
|
||||
"language": "en-US"
|
||||
},
|
||||
"llm": {
|
||||
"vendor": "openai",
|
||||
"llmOptions": {
|
||||
"model": "gpt-4o"
|
||||
}
|
||||
},
|
||||
"actionHook": "/pipeline/action",
|
||||
"eventHook": "/pipeline/event",
|
||||
"toolHook": "/pipeline/tool"
|
||||
},
|
||||
{
|
||||
"verb": "transcribe",
|
||||
"transcriptionHook": "http://example.com/transcribe",
|
||||
@@ -689,6 +758,110 @@ test('invalid test', async (t) => {
|
||||
} catch(err) {
|
||||
t.ok(1 == 1,'successfully validate verbs');
|
||||
}
|
||||
|
||||
|
||||
t.end();
|
||||
})
|
||||
});
|
||||
|
||||
test('verb synonyms: stream is synonym for listen', async (t) => {
|
||||
// "verb" format
|
||||
const result1 = normalizeJambones(logger, [
|
||||
{"verb": "stream", "url": "wss://example.com/calls", "mixType": "stereo"}
|
||||
]);
|
||||
t.equal(Object.keys(result1[0])[0], 'listen', 'stream verb is rewritten to listen');
|
||||
t.equal(result1[0].listen.url, 'wss://example.com/calls', 'data is preserved');
|
||||
|
||||
// object-key format
|
||||
const result2 = normalizeJambones(logger, [
|
||||
{"stream": {"url": "wss://example.com/calls"}}
|
||||
]);
|
||||
t.equal(Object.keys(result2[0])[0], 'listen', 'stream key is rewritten to listen');
|
||||
|
||||
// validate passes
|
||||
try {
|
||||
validate(logger, [{"verb": "stream", "url": "wss://example.com/calls"}]);
|
||||
t.pass('stream verb validates successfully');
|
||||
} catch (err) {
|
||||
t.fail('stream verb should validate: ' + err);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('verb synonyms: s2s is synonym for llm', async (t) => {
|
||||
const result = normalizeJambones(logger, [
|
||||
{"verb": "s2s", "vendor": "openai", "llmOptions": {"model": "gpt-4o"}}
|
||||
]);
|
||||
t.equal(Object.keys(result[0])[0], 'llm', 's2s verb is rewritten to llm');
|
||||
t.equal(result[0].llm.vendor, 'openai', 'vendor is preserved');
|
||||
t.equal(result[0].llm.llmOptions.model, 'gpt-4o', 'llmOptions preserved');
|
||||
|
||||
try {
|
||||
validate(logger, [{"verb": "s2s", "vendor": "openai", "llmOptions": {"model": "gpt-4o"}}]);
|
||||
t.pass('s2s verb validates successfully');
|
||||
} catch (err) {
|
||||
t.fail('s2s verb should validate: ' + err);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('vendor shortcuts: openai_s2s injects vendor', async (t) => {
|
||||
const result = normalizeJambones(logger, [
|
||||
{"verb": "openai_s2s", "llmOptions": {"model": "gpt-4o-realtime"}}
|
||||
]);
|
||||
t.equal(Object.keys(result[0])[0], 'llm', 'openai_s2s is rewritten to llm');
|
||||
t.equal(result[0].llm.vendor, 'openai', 'vendor is injected');
|
||||
t.equal(result[0].llm.llmOptions.model, 'gpt-4o-realtime', 'llmOptions preserved');
|
||||
|
||||
try {
|
||||
validate(logger, [{"verb": "openai_s2s", "llmOptions": {"model": "gpt-4o-realtime"}}]);
|
||||
t.pass('openai_s2s validates successfully');
|
||||
} catch (err) {
|
||||
t.fail('openai_s2s should validate: ' + err);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('vendor shortcuts: all vendors work', async (t) => {
|
||||
const vendors = [
|
||||
'openai', 'microsoft', 'google', 'elevenlabs', 'deepgram', 'voiceagent', 'ultravox'
|
||||
];
|
||||
for (const vendor of vendors) {
|
||||
const verbName = `${vendor}_s2s`;
|
||||
const result = normalizeJambones(logger, [
|
||||
{"verb": verbName, "llmOptions": {}}
|
||||
]);
|
||||
t.equal(Object.keys(result[0])[0], 'llm', `${verbName} rewrites to llm`);
|
||||
t.equal(result[0].llm.vendor, vendor, `${verbName} injects vendor=${vendor}`);
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('vendor shortcuts: object-key format works', async (t) => {
|
||||
const result = normalizeJambones(logger, [
|
||||
{"google_s2s": {"llmOptions": {"model": "gemini-2.0-flash"}}}
|
||||
]);
|
||||
t.equal(Object.keys(result[0])[0], 'llm', 'google_s2s key is rewritten to llm');
|
||||
t.equal(result[0].llm.vendor, 'google', 'vendor is injected');
|
||||
t.equal(result[0].llm.llmOptions.model, 'gemini-2.0-flash', 'llmOptions preserved');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('vendor shortcuts: explicit vendor in data overrides injected vendor', async (t) => {
|
||||
const result = normalizeJambones(logger, [
|
||||
{"verb": "openai_s2s", "vendor": "custom", "llmOptions": {}}
|
||||
]);
|
||||
t.equal(result[0].llm.vendor, 'custom', 'explicit vendor takes precedence');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('non-synonym verbs are unchanged', async (t) => {
|
||||
const result = normalizeJambones(logger, [
|
||||
{"verb": "say", "text": "hello"}
|
||||
]);
|
||||
t.equal(Object.keys(result[0])[0], 'say', 'say verb is not transformed');
|
||||
|
||||
const result2 = normalizeJambones(logger, [
|
||||
{"llm": {"vendor": "openai", "llmOptions": {}}}
|
||||
]);
|
||||
t.equal(Object.keys(result2[0])[0], 'llm', 'llm verb is not transformed');
|
||||
t.end();
|
||||
});
|
||||
Reference in New Issue
Block a user