@craftedxp/voice-js 0.4.0 → 0.4.2
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/README.md +4 -1
- package/dist/browser.d.ts +259 -327
- package/dist/browser.js +727 -710
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +64 -39
- package/dist/browser.mjs.map +1 -1
- package/dist/embed.iife.js +4 -1094
- package/dist/node.d.ts +256 -317
- package/dist/node.js +431 -440
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +5 -0
- package/dist/node.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser.mjs
CHANGED
|
@@ -838,9 +838,18 @@ var BrowserVoiceClient = class {
|
|
|
838
838
|
|
|
839
839
|
// src/webrtc/createWebRtcCall.ts
|
|
840
840
|
async function createWebRtcCall(opts) {
|
|
841
|
+
validateClientToolMap(opts.clientTools);
|
|
841
842
|
const proto = createProtocolState();
|
|
842
843
|
let muted = false;
|
|
843
844
|
let ended = false;
|
|
845
|
+
const tools = opts.clientTools ?? {};
|
|
846
|
+
const sendControl = (frame) => {
|
|
847
|
+
if (dc?.readyState !== "open") return;
|
|
848
|
+
try {
|
|
849
|
+
dc.send(JSON.stringify(frame));
|
|
850
|
+
} catch {
|
|
851
|
+
}
|
|
852
|
+
};
|
|
844
853
|
const fireState = (next) => {
|
|
845
854
|
if (proto.state === next) return;
|
|
846
855
|
proto.state = next;
|
|
@@ -857,8 +866,12 @@ async function createWebRtcCall(opts) {
|
|
|
857
866
|
},
|
|
858
867
|
onCallEnd: () => teardown(),
|
|
859
868
|
onConnected: () => {
|
|
869
|
+
if (Object.keys(tools).length > 0) {
|
|
870
|
+
sendControl(buildRegisterFrame(tools));
|
|
871
|
+
}
|
|
860
872
|
},
|
|
861
|
-
onClientToolCall: () => {
|
|
873
|
+
onClientToolCall: (frame) => {
|
|
874
|
+
dispatchClientToolCall(sendControl, tools, frame);
|
|
862
875
|
}
|
|
863
876
|
});
|
|
864
877
|
};
|
|
@@ -895,11 +908,57 @@ async function createWebRtcCall(opts) {
|
|
|
895
908
|
dc.onerror = () => {
|
|
896
909
|
opts.onError?.({ code: "socket_error", message: "control channel error" });
|
|
897
910
|
};
|
|
911
|
+
dc.onopen = () => {
|
|
912
|
+
if (Object.keys(tools).length > 0) {
|
|
913
|
+
sendControl(buildRegisterFrame(tools));
|
|
914
|
+
}
|
|
915
|
+
};
|
|
898
916
|
const gateway = opts.webrtcGatewayBase || "";
|
|
899
917
|
const offerUrl = gateway ? `${gateway}/webrtc/offer?token=${encodeURIComponent(opts.token)}` : `${opts.apiBase}/v1/agents/${encodeURIComponent(opts.agentId)}/webrtc/offer?token=${encodeURIComponent(opts.token)}`;
|
|
900
918
|
const iceUrl = gateway ? `${gateway}/webrtc/ice?token=${encodeURIComponent(opts.token)}` : `${opts.apiBase}/v1/agents/${encodeURIComponent(opts.agentId)}/webrtc/ice?token=${encodeURIComponent(opts.token)}`;
|
|
919
|
+
const teardown = () => {
|
|
920
|
+
if (ended) return;
|
|
921
|
+
ended = true;
|
|
922
|
+
try {
|
|
923
|
+
mic.getTracks().forEach((t) => t.stop());
|
|
924
|
+
} catch {
|
|
925
|
+
}
|
|
926
|
+
try {
|
|
927
|
+
pc.close();
|
|
928
|
+
} catch {
|
|
929
|
+
}
|
|
930
|
+
try {
|
|
931
|
+
audioEl.remove();
|
|
932
|
+
} catch {
|
|
933
|
+
}
|
|
934
|
+
fireState("ended");
|
|
935
|
+
opts.onEnd?.();
|
|
936
|
+
};
|
|
937
|
+
let callId = null;
|
|
938
|
+
const pendingCandidates = [];
|
|
939
|
+
const postCandidate = (candidate) => {
|
|
940
|
+
void fetch(iceUrl, {
|
|
941
|
+
method: "POST",
|
|
942
|
+
headers: { "content-type": "application/json" },
|
|
943
|
+
body: JSON.stringify({ callId, candidate })
|
|
944
|
+
}).catch(() => {
|
|
945
|
+
});
|
|
946
|
+
};
|
|
947
|
+
pc.onicecandidate = (e) => {
|
|
948
|
+
if (!e.candidate) return;
|
|
949
|
+
if (callId) postCandidate(e.candidate);
|
|
950
|
+
else pendingCandidates.push(e.candidate);
|
|
951
|
+
};
|
|
952
|
+
pc.onconnectionstatechange = () => {
|
|
953
|
+
const s = pc.connectionState;
|
|
954
|
+
if (s === "connected") fireState("listening");
|
|
955
|
+
if (s === "failed" || s === "disconnected") {
|
|
956
|
+
opts.onError?.({ code: "socket_error", message: `webrtc connection ${s}` });
|
|
957
|
+
teardown();
|
|
958
|
+
}
|
|
959
|
+
if (s === "closed" && !ended) teardown();
|
|
960
|
+
};
|
|
901
961
|
await pc.setLocalDescription(await pc.createOffer());
|
|
902
|
-
let callId;
|
|
903
962
|
try {
|
|
904
963
|
const offerRes = await fetch(offerUrl, {
|
|
905
964
|
method: "POST",
|
|
@@ -918,6 +977,7 @@ async function createWebRtcCall(opts) {
|
|
|
918
977
|
const body = await offerRes.json();
|
|
919
978
|
callId = body.callId;
|
|
920
979
|
await pc.setRemoteDescription({ type: "answer", sdp: body.sdp });
|
|
980
|
+
while (pendingCandidates.length > 0) postCandidate(pendingCandidates.shift());
|
|
921
981
|
} catch (err) {
|
|
922
982
|
if (!ended) {
|
|
923
983
|
opts.onError?.({
|
|
@@ -931,42 +991,6 @@ async function createWebRtcCall(opts) {
|
|
|
931
991
|
}
|
|
932
992
|
throw err;
|
|
933
993
|
}
|
|
934
|
-
pc.onicecandidate = (e) => {
|
|
935
|
-
if (!e.candidate) return;
|
|
936
|
-
void fetch(iceUrl, {
|
|
937
|
-
method: "POST",
|
|
938
|
-
headers: { "content-type": "application/json" },
|
|
939
|
-
body: JSON.stringify({ callId, candidate: e.candidate })
|
|
940
|
-
}).catch(() => {
|
|
941
|
-
});
|
|
942
|
-
};
|
|
943
|
-
pc.onconnectionstatechange = () => {
|
|
944
|
-
const s = pc.connectionState;
|
|
945
|
-
if (s === "connected") fireState("listening");
|
|
946
|
-
if (s === "failed" || s === "disconnected") {
|
|
947
|
-
opts.onError?.({ code: "socket_error", message: `webrtc connection ${s}` });
|
|
948
|
-
teardown();
|
|
949
|
-
}
|
|
950
|
-
if (s === "closed" && !ended) teardown();
|
|
951
|
-
};
|
|
952
|
-
const teardown = () => {
|
|
953
|
-
if (ended) return;
|
|
954
|
-
ended = true;
|
|
955
|
-
try {
|
|
956
|
-
mic.getTracks().forEach((t) => t.stop());
|
|
957
|
-
} catch {
|
|
958
|
-
}
|
|
959
|
-
try {
|
|
960
|
-
pc.close();
|
|
961
|
-
} catch {
|
|
962
|
-
}
|
|
963
|
-
try {
|
|
964
|
-
audioEl.remove();
|
|
965
|
-
} catch {
|
|
966
|
-
}
|
|
967
|
-
fireState("ended");
|
|
968
|
-
opts.onEnd?.();
|
|
969
|
-
};
|
|
970
994
|
return {
|
|
971
995
|
get state() {
|
|
972
996
|
return proto.state;
|
|
@@ -1033,7 +1057,8 @@ var BrowserVoiceFactory = class {
|
|
|
1033
1057
|
// tracked at 0 until the followup lands (see spec Followups section).
|
|
1034
1058
|
onEnd: options.onEnd ? () => options.onEnd({ reason: "agent_ended", durationMs: 0 }) : void 0,
|
|
1035
1059
|
onInterrupt: options.onInterrupt,
|
|
1036
|
-
onAgentTurnStart: options.onAgentTurnStart
|
|
1060
|
+
onAgentTurnStart: options.onAgentTurnStart,
|
|
1061
|
+
clientTools: options.clientTools
|
|
1037
1062
|
});
|
|
1038
1063
|
}
|
|
1039
1064
|
const client = new BrowserVoiceClient({
|