@yak-io/javascript 0.10.0 → 0.10.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/dist/tool-name.d.ts +16 -5
- package/dist/tool-name.d.ts.map +1 -1
- package/dist/tool-name.js +36 -18
- package/dist/voice-session.d.ts +5 -5
- package/dist/voice-session.d.ts.map +1 -1
- package/dist/voice-session.js +10 -8
- package/package.json +1 -1
package/dist/tool-name.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Format: `yt_<8-char-hex-hash>`.
|
|
2
|
+
* Convert a host tool name into a model-facing function name.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* We sanitise to the allowed function-name charset (rather than hashing to an opaque
|
|
5
|
+
* `yt_<hex>`), so the model keeps the semantic signal of a readable name — e.g.
|
|
6
|
+
* `orders.list` → `orders_list`.
|
|
7
|
+
*
|
|
8
|
+
* This is a pure per-name transform; uniqueness across a manifest (and avoiding the
|
|
9
|
+
* reserved `redirect` name / `mcp__` namespace) is handled by the caller via
|
|
10
|
+
* {@link uniqueToolId}. Each runtime (the chat-ui iframe and this SDK's voice session)
|
|
11
|
+
* decorates and reverse-maps with its own manifest, so the ids never need to match
|
|
12
|
+
* across paths — only to be self-consistent within one.
|
|
8
13
|
*/
|
|
9
14
|
export declare function generateToolId(originalName: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a collision-free, model-safe id for a host tool name, given the ids already
|
|
17
|
+
* taken in this manifest (seed `used` with reserved names like `redirect`). Host ids must
|
|
18
|
+
* never start with the `mcp__` namespace, which the dispatcher routes on.
|
|
19
|
+
*/
|
|
20
|
+
export declare function uniqueToolId(originalName: string, used: Set<string>): string;
|
|
10
21
|
//# sourceMappingURL=tool-name.d.ts.map
|
package/dist/tool-name.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-name.d.ts","sourceRoot":"","sources":["../src/tool-name.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool-name.d.ts","sourceRoot":"","sources":["../src/tool-name.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG3D;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAc5E"}
|
package/dist/tool-name.js
CHANGED
|
@@ -1,24 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
/** OpenAI/Realtime function names must match `^[a-zA-Z0-9_-]{1,64}$`. */
|
|
2
|
+
const MAX_TOOL_NAME_LENGTH = 64;
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* Convert a host tool name into a model-facing function name.
|
|
5
|
+
*
|
|
6
|
+
* We sanitise to the allowed function-name charset (rather than hashing to an opaque
|
|
7
|
+
* `yt_<hex>`), so the model keeps the semantic signal of a readable name — e.g.
|
|
8
|
+
* `orders.list` → `orders_list`.
|
|
9
|
+
*
|
|
10
|
+
* This is a pure per-name transform; uniqueness across a manifest (and avoiding the
|
|
11
|
+
* reserved `redirect` name / `mcp__` namespace) is handled by the caller via
|
|
12
|
+
* {@link uniqueToolId}. Each runtime (the chat-ui iframe and this SDK's voice session)
|
|
13
|
+
* decorates and reverse-maps with its own manifest, so the ids never need to match
|
|
14
|
+
* across paths — only to be self-consistent within one.
|
|
5
15
|
*/
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;
|
|
10
|
-
}
|
|
11
|
-
return hash;
|
|
16
|
+
export function generateToolId(originalName) {
|
|
17
|
+
const sanitized = originalName.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, MAX_TOOL_NAME_LENGTH);
|
|
18
|
+
return sanitized.length > 0 ? sanitized : "tool";
|
|
12
19
|
}
|
|
20
|
+
/** The MCP namespace prefix the voice/chat dispatchers route on. */
|
|
21
|
+
const MCP_NAMESPACE_PREFIX = "mcp__";
|
|
13
22
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* The hash is deterministic so chat and voice always derive the same id for
|
|
18
|
-
* the same tool name — this is what lets the mint route, the iframe, and the
|
|
19
|
-
* SDK all agree on which decorated id maps back to which host tool name.
|
|
23
|
+
* Resolve a collision-free, model-safe id for a host tool name, given the ids already
|
|
24
|
+
* taken in this manifest (seed `used` with reserved names like `redirect`). Host ids must
|
|
25
|
+
* never start with the `mcp__` namespace, which the dispatcher routes on.
|
|
20
26
|
*/
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
export function uniqueToolId(originalName, used) {
|
|
28
|
+
let base = generateToolId(originalName);
|
|
29
|
+
if (base.startsWith(MCP_NAMESPACE_PREFIX)) {
|
|
30
|
+
base = `t_${base}`.slice(0, MAX_TOOL_NAME_LENGTH);
|
|
31
|
+
}
|
|
32
|
+
if (!used.has(base))
|
|
33
|
+
return base;
|
|
34
|
+
for (let i = 2; i < 1000; i++) {
|
|
35
|
+
const suffix = `_${i}`;
|
|
36
|
+
const candidate = `${base.slice(0, MAX_TOOL_NAME_LENGTH - suffix.length)}${suffix}`;
|
|
37
|
+
if (!used.has(candidate))
|
|
38
|
+
return candidate;
|
|
39
|
+
}
|
|
40
|
+
// Pathological fallback — vanishingly unlikely in practice.
|
|
41
|
+
return `${base.slice(0, 56)}_${used.size}`;
|
|
24
42
|
}
|
package/dist/voice-session.d.ts
CHANGED
|
@@ -81,11 +81,11 @@ export declare class YakVoiceSession {
|
|
|
81
81
|
private execMcpTool;
|
|
82
82
|
private mintToken;
|
|
83
83
|
/**
|
|
84
|
-
* Decorate the host's tool manifest with
|
|
85
|
-
* `this.toolNameById` for reverse lookup. Mirrors the decoration the
|
|
86
|
-
* iframe applies before sending tools to `/api/chat`. GraphQL/REST tools are
|
|
87
|
-
* ordinary manifest entries here (contributed by their adapters), so no
|
|
88
|
-
*
|
|
84
|
+
* Decorate the host's tool manifest with readable, collision-free model-facing ids
|
|
85
|
+
* and populate `this.toolNameById` for reverse lookup. Mirrors the decoration the
|
|
86
|
+
* chat-ui iframe applies before sending tools to `/api/chat`. GraphQL/REST tools are
|
|
87
|
+
* ordinary manifest entries here (contributed by their adapters), so no special-casing
|
|
88
|
+
* is needed.
|
|
89
89
|
*/
|
|
90
90
|
private buildDecoratedManifest;
|
|
91
91
|
private exchangeSdp;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-session.d.ts","sourceRoot":"","sources":["../src/voice-session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC;CACF;AAiBD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,eAAe,CAA6B;IACpD,6EAA6E;IAC7E,OAAO,CAAC,KAAK,CAAkC;IAC/C;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,EAAE,qBAAqB;IAKzC;;;;OAIG;IACH,OAAO,KAAK,SAAS,GAEpB;IAED,0DAA0D;IACnD,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIzD,QAAQ,IAAI,YAAY;IAI/B;;;OAGG;IACI,YAAY,IAAI,MAAM;IAItB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAO9D;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwJnC,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,2FAA2F;IACpF,OAAO,IAAI,IAAI;IAWtB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,mBAAmB;YAeb,aAAa;IA8B3B;;;;OAIG;YACW,WAAW;YAwBX,SAAS;IAsBvB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;
|
|
1
|
+
{"version":3,"file":"voice-session.d.ts","sourceRoot":"","sources":["../src/voice-session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAKL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC;CACF;AAiBD,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,eAAe,CAA6B;IACpD,6EAA6E;IAC7E,OAAO,CAAC,KAAK,CAAkC;IAC/C;;;;OAIG;IACH,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,EAAE,qBAAqB;IAKzC;;;;OAIG;IACH,OAAO,KAAK,SAAS,GAEpB;IAED,0DAA0D;IACnD,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIzD,QAAQ,IAAI,YAAY;IAI/B;;;OAGG;IACI,YAAY,IAAI,MAAM;IAItB,aAAa,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAO9D;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwJnC,oDAAoD;IACvC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,2FAA2F;IACpF,OAAO,IAAI,IAAI;IAWtB,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,mBAAmB;YAeb,aAAa;IA8B3B;;;;OAIG;YACW,WAAW;YAwBX,SAAS;IAsBvB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;YAgBhB,WAAW;IAmBzB,OAAO,CAAC,kBAAkB;YAWZ,gBAAgB;YA2BhB,QAAQ;YAuCR,QAAQ;IAMtB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,cAAc;CAevB"}
|
package/dist/voice-session.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logger } from "./logger.js";
|
|
2
2
|
import { extractPageContext } from "./page-context.js";
|
|
3
|
-
import {
|
|
3
|
+
import { uniqueToolId } from "./tool-name.js";
|
|
4
4
|
import { handleRealtimeMessage, INITIAL_VOICE_MACHINE, voiceReducer, } from "./voice-machine.js";
|
|
5
5
|
const DEFAULT_REALTIME_MODEL = "gpt-realtime";
|
|
6
6
|
const REALTIME_CALLS_URL = "https://api.openai.com/v1/realtime/calls";
|
|
@@ -296,7 +296,7 @@ export class YakVoiceSession {
|
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
async routeToolCall(idOrName, args) {
|
|
299
|
-
// The model calls us back using the decorated id (e.g.
|
|
299
|
+
// The model calls us back using the decorated id (e.g. orders_list).
|
|
300
300
|
// Resolve it to the original host tool name; fall back to the raw value
|
|
301
301
|
// (it might be `redirect` or some non-decorated name).
|
|
302
302
|
const name = this.toolNameById.get(idOrName) ?? idOrName;
|
|
@@ -372,16 +372,18 @@ export class YakVoiceSession {
|
|
|
372
372
|
return (await res.json());
|
|
373
373
|
}
|
|
374
374
|
/**
|
|
375
|
-
* Decorate the host's tool manifest with
|
|
376
|
-
* `this.toolNameById` for reverse lookup. Mirrors the decoration the
|
|
377
|
-
* iframe applies before sending tools to `/api/chat`. GraphQL/REST tools are
|
|
378
|
-
* ordinary manifest entries here (contributed by their adapters), so no
|
|
379
|
-
*
|
|
375
|
+
* Decorate the host's tool manifest with readable, collision-free model-facing ids
|
|
376
|
+
* and populate `this.toolNameById` for reverse lookup. Mirrors the decoration the
|
|
377
|
+
* chat-ui iframe applies before sending tools to `/api/chat`. GraphQL/REST tools are
|
|
378
|
+
* ordinary manifest entries here (contributed by their adapters), so no special-casing
|
|
379
|
+
* is needed.
|
|
380
380
|
*/
|
|
381
381
|
buildDecoratedManifest(chatConfig) {
|
|
382
382
|
this.toolNameById.clear();
|
|
383
|
+
const used = new Set(["redirect"]);
|
|
383
384
|
const decoratedHostTools = (chatConfig?.tools?.tools ?? []).map((t) => {
|
|
384
|
-
const id =
|
|
385
|
+
const id = uniqueToolId(t.name, used);
|
|
386
|
+
used.add(id);
|
|
385
387
|
this.toolNameById.set(id, t.name);
|
|
386
388
|
return { ...t, id };
|
|
387
389
|
});
|