@alexkroman1/aai 0.7.2 → 0.7.4
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/cli.js +337 -255
- package/dist/sdk/_internal_types.d.ts +4 -18
- package/dist/sdk/_internal_types.d.ts.map +1 -1
- package/dist/sdk/_internal_types.js +2 -1
- package/dist/sdk/_internal_types.js.map +1 -1
- package/dist/sdk/_mock_ws.js +1 -1
- package/dist/sdk/_mock_ws.js.map +1 -1
- package/dist/sdk/builtin_tools.d.ts +6 -2
- package/dist/sdk/builtin_tools.d.ts.map +1 -1
- package/dist/sdk/builtin_tools.js +1 -8
- package/dist/sdk/builtin_tools.js.map +1 -1
- package/dist/sdk/capnweb.d.ts +1 -1
- package/dist/sdk/capnweb.d.ts.map +1 -1
- package/dist/sdk/capnweb.js +43 -10
- package/dist/sdk/capnweb.js.map +1 -1
- package/dist/sdk/define_agent.d.ts +1 -1
- package/dist/sdk/define_agent.d.ts.map +1 -1
- package/dist/sdk/define_agent.js +26 -17
- package/dist/sdk/define_agent.js.map +1 -1
- package/dist/sdk/direct_executor.d.ts +2 -0
- package/dist/sdk/direct_executor.d.ts.map +1 -1
- package/dist/sdk/direct_executor.js +6 -1
- package/dist/sdk/direct_executor.js.map +1 -1
- package/dist/sdk/mod.d.ts +2 -1
- package/dist/sdk/mod.d.ts.map +1 -1
- package/dist/sdk/protocol.d.ts +88 -7
- package/dist/sdk/protocol.d.ts.map +1 -1
- package/dist/sdk/protocol.js.map +1 -1
- package/dist/sdk/runtime.d.ts +6 -4
- package/dist/sdk/runtime.d.ts.map +1 -1
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/sdk/s2s.d.ts +2 -1
- package/dist/sdk/s2s.d.ts.map +1 -1
- package/dist/sdk/s2s.js +112 -73
- package/dist/sdk/s2s.js.map +1 -1
- package/dist/sdk/server.d.ts.map +1 -1
- package/dist/sdk/server.js +47 -43
- package/dist/sdk/server.js.map +1 -1
- package/dist/sdk/session.d.ts.map +1 -1
- package/dist/sdk/session.js +47 -44
- package/dist/sdk/session.js.map +1 -1
- package/dist/sdk/system_prompt.d.ts.map +1 -1
- package/dist/sdk/system_prompt.js +1 -1
- package/dist/sdk/system_prompt.js.map +1 -1
- package/dist/sdk/types.d.ts +8 -50
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/types.js +0 -8
- package/dist/sdk/types.js.map +1 -1
- package/dist/sdk/winterc_server.d.ts +4 -1
- package/dist/sdk/winterc_server.d.ts.map +1 -1
- package/dist/sdk/winterc_server.js +3 -2
- package/dist/sdk/winterc_server.js.map +1 -1
- package/dist/sdk/worker_entry.d.ts +3 -1
- package/dist/sdk/worker_entry.d.ts.map +1 -1
- package/dist/sdk/worker_entry.js +24 -17
- package/dist/sdk/worker_entry.js.map +1 -1
- package/dist/sdk/worker_shim.d.ts.map +1 -1
- package/dist/sdk/worker_shim.js +62 -9
- package/dist/sdk/worker_shim.js.map +1 -1
- package/dist/sdk/ws_handler.d.ts.map +1 -1
- package/dist/sdk/ws_handler.js +65 -58
- package/dist/sdk/ws_handler.js.map +1 -1
- package/dist/ui/_components/message_list.d.ts.map +1 -1
- package/dist/ui/_components/message_list.js +10 -6
- package/dist/ui/_components/message_list.js.map +1 -1
- package/dist/ui/audio.js +1 -1
- package/dist/ui/audio.js.map +1 -1
- package/dist/ui/mod.d.ts +10 -2
- package/dist/ui/mod.d.ts.map +1 -1
- package/dist/ui/mod.js +5 -2
- package/dist/ui/mod.js.map +1 -1
- package/dist/ui/session.d.ts.map +1 -1
- package/dist/ui/session.js +3 -1
- package/dist/ui/session.js.map +1 -1
- package/package.json +4 -2
- package/templates/.env +1 -0
- package/templates/_shared/.env.example +5 -0
- package/templates/_shared/CLAUDE.md +710 -0
- package/templates/_shared/package.json +17 -0
- package/templates/_shared/tsconfig.json +16 -0
- package/templates/code-interpreter/agent.ts +27 -0
- package/templates/code-interpreter/client.tsx +2 -0
- package/templates/dispatch-center/agent.ts +1564 -0
- package/templates/dispatch-center/client.tsx +504 -0
- package/templates/embedded-assets/agent.ts +49 -0
- package/templates/embedded-assets/client.tsx +2 -0
- package/templates/embedded-assets/knowledge.json +20 -0
- package/templates/health-assistant/agent.ts +160 -0
- package/templates/health-assistant/client.tsx +2 -0
- package/templates/infocom-adventure/agent.ts +164 -0
- package/templates/infocom-adventure/client.tsx +299 -0
- package/templates/math-buddy/agent.ts +21 -0
- package/templates/math-buddy/client.tsx +2 -0
- package/templates/memory-agent/agent.ts +74 -0
- package/templates/memory-agent/client.tsx +2 -0
- package/templates/night-owl/agent.ts +98 -0
- package/templates/night-owl/client.tsx +28 -0
- package/templates/personal-finance/agent.ts +26 -0
- package/templates/personal-finance/client.tsx +2 -0
- package/templates/simple/agent.ts +6 -0
- package/templates/simple/client.tsx +2 -0
- package/templates/smart-research/agent.ts +164 -0
- package/templates/smart-research/client.tsx +2 -0
- package/templates/support/README.md +62 -0
- package/templates/support/agent.ts +19 -0
- package/templates/support/client.tsx +2 -0
- package/templates/travel-concierge/agent.ts +29 -0
- package/templates/travel-concierge/client.tsx +2 -0
- package/templates/tsconfig.json +1 -0
- package/templates/web-researcher/agent.ts +17 -0
- package/templates/web-researcher/client.tsx +2 -0
- package/dist/sdk/_timeout.d.ts +0 -14
- package/dist/sdk/_timeout.d.ts.map +0 -1
- package/dist/sdk/_timeout.js +0 -24
- package/dist/sdk/_timeout.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -483,16 +483,16 @@ function getBuiltinToolSchemas(names) {
|
|
|
483
483
|
{
|
|
484
484
|
name,
|
|
485
485
|
description: def.description,
|
|
486
|
-
parameters: z3.toJSONSchema(def.parameters ??
|
|
486
|
+
parameters: z3.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
487
487
|
}
|
|
488
488
|
];
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
|
-
var
|
|
491
|
+
var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams, TOOL_CREATORS;
|
|
492
492
|
var init_builtin_tools = __esm({
|
|
493
493
|
"dist/sdk/builtin_tools.js"() {
|
|
494
494
|
"use strict";
|
|
495
|
-
|
|
495
|
+
init_internal_types();
|
|
496
496
|
webSearchParams = z3.object({
|
|
497
497
|
query: z3.string().describe("The search query"),
|
|
498
498
|
max_results: z3.number().describe("Maximum number of results to return (default 5)").optional()
|
|
@@ -601,6 +601,7 @@ var init_kv = __esm({
|
|
|
601
601
|
});
|
|
602
602
|
|
|
603
603
|
// dist/sdk/s2s.js
|
|
604
|
+
import { z as z4 } from "zod";
|
|
604
605
|
function uint8ToBase64(bytes) {
|
|
605
606
|
const CHUNK = 32768;
|
|
606
607
|
const parts = [];
|
|
@@ -617,6 +618,73 @@ function base64ToUint8(base64) {
|
|
|
617
618
|
}
|
|
618
619
|
return bytes;
|
|
619
620
|
}
|
|
621
|
+
function dispatchS2sMessage(target, msg) {
|
|
622
|
+
switch (msg.type) {
|
|
623
|
+
case "session.ready":
|
|
624
|
+
target.dispatchEvent(new CustomEvent("ready", {
|
|
625
|
+
detail: { session_id: msg.session_id }
|
|
626
|
+
}));
|
|
627
|
+
break;
|
|
628
|
+
case "session.updated":
|
|
629
|
+
target.dispatchEvent(new CustomEvent("session_updated", { detail: msg }));
|
|
630
|
+
break;
|
|
631
|
+
case "input.speech.started":
|
|
632
|
+
target.dispatchEvent(new CustomEvent("speech_started"));
|
|
633
|
+
break;
|
|
634
|
+
case "input.speech.stopped":
|
|
635
|
+
target.dispatchEvent(new CustomEvent("speech_stopped"));
|
|
636
|
+
break;
|
|
637
|
+
case "transcript.user.delta":
|
|
638
|
+
target.dispatchEvent(new CustomEvent("user_transcript_delta", {
|
|
639
|
+
detail: { text: msg.text }
|
|
640
|
+
}));
|
|
641
|
+
break;
|
|
642
|
+
case "transcript.user":
|
|
643
|
+
target.dispatchEvent(new CustomEvent("user_transcript", {
|
|
644
|
+
detail: {
|
|
645
|
+
item_id: msg.item_id,
|
|
646
|
+
text: msg.text
|
|
647
|
+
}
|
|
648
|
+
}));
|
|
649
|
+
break;
|
|
650
|
+
case "reply.started":
|
|
651
|
+
target.dispatchEvent(new CustomEvent("reply_started", {
|
|
652
|
+
detail: { reply_id: msg.reply_id }
|
|
653
|
+
}));
|
|
654
|
+
break;
|
|
655
|
+
case "reply.audio": {
|
|
656
|
+
const audioBytes = base64ToUint8(msg.data);
|
|
657
|
+
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
case "transcript.agent":
|
|
661
|
+
target.dispatchEvent(new CustomEvent("agent_transcript", {
|
|
662
|
+
detail: { text: msg.text }
|
|
663
|
+
}));
|
|
664
|
+
break;
|
|
665
|
+
case "tool.call":
|
|
666
|
+
target.dispatchEvent(new CustomEvent("tool_call", {
|
|
667
|
+
detail: {
|
|
668
|
+
call_id: msg.call_id,
|
|
669
|
+
name: msg.name,
|
|
670
|
+
args: msg.args
|
|
671
|
+
}
|
|
672
|
+
}));
|
|
673
|
+
break;
|
|
674
|
+
case "reply.done":
|
|
675
|
+
target.dispatchEvent(new CustomEvent("reply_done", {
|
|
676
|
+
detail: { status: msg.status }
|
|
677
|
+
}));
|
|
678
|
+
break;
|
|
679
|
+
case "session.error": {
|
|
680
|
+
const isExpired = msg.code === "session_not_found" || msg.code === "session_forbidden";
|
|
681
|
+
target.dispatchEvent(new CustomEvent(isExpired ? "session_expired" : "error", {
|
|
682
|
+
detail: { code: msg.code, message: msg.message }
|
|
683
|
+
}));
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
620
688
|
function connectS2s(opts) {
|
|
621
689
|
const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
|
|
622
690
|
return new Promise((resolve, reject) => {
|
|
@@ -629,8 +697,7 @@ function connectS2s(opts) {
|
|
|
629
697
|
function send(msg) {
|
|
630
698
|
if (ws.readyState !== WS_OPEN)
|
|
631
699
|
return;
|
|
632
|
-
|
|
633
|
-
if (type !== "input.audio") {
|
|
700
|
+
if (msg.type !== "input.audio") {
|
|
634
701
|
log.info(`S2S >> ${JSON.stringify(msg)}`);
|
|
635
702
|
}
|
|
636
703
|
ws.send(JSON.stringify(msg));
|
|
@@ -659,86 +726,26 @@ function connectS2s(opts) {
|
|
|
659
726
|
resolve(handle);
|
|
660
727
|
});
|
|
661
728
|
ws.on("message", (data) => {
|
|
662
|
-
let
|
|
729
|
+
let raw;
|
|
663
730
|
try {
|
|
664
|
-
|
|
731
|
+
raw = JSON.parse(String(data));
|
|
665
732
|
} catch {
|
|
666
733
|
return;
|
|
667
734
|
}
|
|
668
|
-
const
|
|
669
|
-
if (
|
|
670
|
-
log.info(`S2S << ${JSON.stringify(
|
|
735
|
+
const parsed = S2sServerMessageSchema.safeParse(raw);
|
|
736
|
+
if (!parsed.success) {
|
|
737
|
+
log.info(`S2S << unrecognised message: ${JSON.stringify(raw)}`);
|
|
738
|
+
return;
|
|
671
739
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
detail: { session_id: msg.session_id }
|
|
676
|
-
}));
|
|
677
|
-
break;
|
|
678
|
-
case "session.updated":
|
|
679
|
-
target.dispatchEvent(new CustomEvent("session_updated", { detail: msg }));
|
|
680
|
-
break;
|
|
681
|
-
case "input.speech.started":
|
|
682
|
-
target.dispatchEvent(new CustomEvent("speech_started"));
|
|
683
|
-
break;
|
|
684
|
-
case "input.speech.stopped":
|
|
685
|
-
target.dispatchEvent(new CustomEvent("speech_stopped"));
|
|
686
|
-
break;
|
|
687
|
-
case "transcript.user.delta":
|
|
688
|
-
target.dispatchEvent(new CustomEvent("user_transcript_delta", {
|
|
689
|
-
detail: { text: msg.text }
|
|
690
|
-
}));
|
|
691
|
-
break;
|
|
692
|
-
case "transcript.user":
|
|
693
|
-
target.dispatchEvent(new CustomEvent("user_transcript", {
|
|
694
|
-
detail: {
|
|
695
|
-
item_id: msg.item_id,
|
|
696
|
-
text: msg.text
|
|
697
|
-
}
|
|
698
|
-
}));
|
|
699
|
-
break;
|
|
700
|
-
case "reply.started":
|
|
701
|
-
target.dispatchEvent(new CustomEvent("reply_started", {
|
|
702
|
-
detail: { reply_id: msg.reply_id }
|
|
703
|
-
}));
|
|
704
|
-
break;
|
|
705
|
-
case "reply.audio": {
|
|
706
|
-
const audioBytes = base64ToUint8(msg.data);
|
|
707
|
-
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
|
|
708
|
-
break;
|
|
709
|
-
}
|
|
710
|
-
case "transcript.agent":
|
|
711
|
-
target.dispatchEvent(new CustomEvent("agent_transcript", {
|
|
712
|
-
detail: { text: msg.text }
|
|
713
|
-
}));
|
|
714
|
-
break;
|
|
715
|
-
case "tool.call":
|
|
716
|
-
target.dispatchEvent(new CustomEvent("tool_call", {
|
|
717
|
-
detail: {
|
|
718
|
-
call_id: msg.call_id,
|
|
719
|
-
name: msg.name,
|
|
720
|
-
args: msg.args ?? {}
|
|
721
|
-
}
|
|
722
|
-
}));
|
|
723
|
-
break;
|
|
724
|
-
case "reply.done":
|
|
725
|
-
target.dispatchEvent(new CustomEvent("reply_done", {
|
|
726
|
-
detail: { status: msg.status ?? void 0 }
|
|
727
|
-
}));
|
|
728
|
-
break;
|
|
729
|
-
case "session.error": {
|
|
730
|
-
const code = msg.code;
|
|
731
|
-
const isExpired = code === "session_not_found" || code === "session_forbidden";
|
|
732
|
-
target.dispatchEvent(new CustomEvent(isExpired ? "session_expired" : "error", {
|
|
733
|
-
detail: { code, message: msg.message }
|
|
734
|
-
}));
|
|
735
|
-
break;
|
|
736
|
-
}
|
|
740
|
+
const msg = parsed.data;
|
|
741
|
+
if (msg.type !== "reply.audio") {
|
|
742
|
+
log.info(`S2S << ${JSON.stringify(msg)}`);
|
|
737
743
|
}
|
|
744
|
+
dispatchS2sMessage(target, msg);
|
|
738
745
|
});
|
|
739
746
|
ws.on("close", (code, reason) => {
|
|
740
747
|
log.info("S2S WebSocket closed", {
|
|
741
|
-
code,
|
|
748
|
+
code: typeof code === "number" ? code : 0,
|
|
742
749
|
reason: reason instanceof Uint8Array ? new TextDecoder().decode(reason) : String(reason ?? "")
|
|
743
750
|
});
|
|
744
751
|
target.dispatchEvent(new CustomEvent("close"));
|
|
@@ -756,12 +763,42 @@ function connectS2s(opts) {
|
|
|
756
763
|
});
|
|
757
764
|
});
|
|
758
765
|
}
|
|
759
|
-
var WS_OPEN;
|
|
766
|
+
var WS_OPEN, S2sServerMessageSchema;
|
|
760
767
|
var init_s2s = __esm({
|
|
761
768
|
"dist/sdk/s2s.js"() {
|
|
762
769
|
"use strict";
|
|
763
770
|
init_runtime();
|
|
764
771
|
WS_OPEN = 1;
|
|
772
|
+
S2sServerMessageSchema = z4.discriminatedUnion("type", [
|
|
773
|
+
z4.object({ type: z4.literal("session.ready"), session_id: z4.string() }),
|
|
774
|
+
z4.object({ type: z4.literal("session.updated") }).passthrough(),
|
|
775
|
+
z4.object({ type: z4.literal("input.speech.started") }),
|
|
776
|
+
z4.object({ type: z4.literal("input.speech.stopped") }),
|
|
777
|
+
z4.object({ type: z4.literal("transcript.user.delta"), text: z4.string() }),
|
|
778
|
+
z4.object({
|
|
779
|
+
type: z4.literal("transcript.user"),
|
|
780
|
+
item_id: z4.string(),
|
|
781
|
+
text: z4.string()
|
|
782
|
+
}),
|
|
783
|
+
z4.object({ type: z4.literal("reply.started"), reply_id: z4.string() }),
|
|
784
|
+
z4.object({ type: z4.literal("reply.audio"), data: z4.string() }),
|
|
785
|
+
z4.object({ type: z4.literal("transcript.agent"), text: z4.string() }),
|
|
786
|
+
z4.object({
|
|
787
|
+
type: z4.literal("tool.call"),
|
|
788
|
+
call_id: z4.string(),
|
|
789
|
+
name: z4.string(),
|
|
790
|
+
args: z4.record(z4.string(), z4.unknown()).optional().default({})
|
|
791
|
+
}),
|
|
792
|
+
z4.object({
|
|
793
|
+
type: z4.literal("reply.done"),
|
|
794
|
+
status: z4.string().optional()
|
|
795
|
+
}),
|
|
796
|
+
z4.object({
|
|
797
|
+
type: z4.literal("session.error"),
|
|
798
|
+
code: z4.string(),
|
|
799
|
+
message: z4.string()
|
|
800
|
+
})
|
|
801
|
+
]);
|
|
765
802
|
}
|
|
766
803
|
});
|
|
767
804
|
|
|
@@ -787,7 +824,7 @@ Voice-First Rules:
|
|
|
787
824
|
// dist/sdk/system_prompt.js
|
|
788
825
|
function buildSystemPrompt(config, opts) {
|
|
789
826
|
const { hasTools } = opts;
|
|
790
|
-
const agentInstructions = config.instructions ? `
|
|
827
|
+
const agentInstructions = config.instructions && config.instructions !== DEFAULT_INSTRUCTIONS ? `
|
|
791
828
|
|
|
792
829
|
Agent-Specific Instructions:
|
|
793
830
|
${config.instructions}` : "";
|
|
@@ -844,10 +881,10 @@ function createS2sSession(opts) {
|
|
|
844
881
|
return null;
|
|
845
882
|
}
|
|
846
883
|
}
|
|
847
|
-
|
|
884
|
+
function invokeHook(hook, arg) {
|
|
848
885
|
if (!hookInvoker)
|
|
849
886
|
return;
|
|
850
|
-
|
|
887
|
+
const run = async () => {
|
|
851
888
|
switch (hook) {
|
|
852
889
|
case "onConnect":
|
|
853
890
|
await hookInvoker.onConnect(id, HOOK_TIMEOUT_MS);
|
|
@@ -856,20 +893,21 @@ function createS2sSession(opts) {
|
|
|
856
893
|
await hookInvoker.onDisconnect(id, HOOK_TIMEOUT_MS);
|
|
857
894
|
break;
|
|
858
895
|
case "onTurn":
|
|
859
|
-
await hookInvoker.onTurn(id,
|
|
896
|
+
await hookInvoker.onTurn(id, arg, HOOK_TIMEOUT_MS);
|
|
860
897
|
break;
|
|
861
898
|
case "onError":
|
|
862
|
-
await hookInvoker.onError(id,
|
|
899
|
+
await hookInvoker.onError(id, arg, HOOK_TIMEOUT_MS);
|
|
863
900
|
break;
|
|
864
901
|
case "onStep":
|
|
865
|
-
await hookInvoker.onStep(id,
|
|
902
|
+
await hookInvoker.onStep(id, arg, HOOK_TIMEOUT_MS);
|
|
866
903
|
break;
|
|
867
904
|
}
|
|
868
|
-
}
|
|
905
|
+
};
|
|
906
|
+
run().catch((err) => {
|
|
869
907
|
log.warn(`${hook} hook failed`, {
|
|
870
908
|
err: err instanceof Error ? err.message : String(err)
|
|
871
909
|
});
|
|
872
|
-
}
|
|
910
|
+
});
|
|
873
911
|
}
|
|
874
912
|
async function handleToolCall(detail) {
|
|
875
913
|
const { call_id, name, args: parsedArgs } = detail;
|
|
@@ -929,6 +967,9 @@ function createS2sSession(opts) {
|
|
|
929
967
|
pendingTools.push({ call_id, result });
|
|
930
968
|
client.event({ type: "tool_call_done", toolCallId: call_id, result });
|
|
931
969
|
}
|
|
970
|
+
function on(target, event, handler) {
|
|
971
|
+
target.addEventListener(event, handler);
|
|
972
|
+
}
|
|
932
973
|
async function connectAndSetup() {
|
|
933
974
|
try {
|
|
934
975
|
const handle = await _internals3.connectS2s({
|
|
@@ -942,54 +983,55 @@ function createS2sSession(opts) {
|
|
|
942
983
|
session_id: s2sSessionId
|
|
943
984
|
});
|
|
944
985
|
handle.resumeSession(s2sSessionId);
|
|
986
|
+
} else {
|
|
987
|
+
handle.updateSession({
|
|
988
|
+
system_prompt: systemPrompt,
|
|
989
|
+
tools: s2sTools,
|
|
990
|
+
...agentConfig.greeting ? { greeting: agentConfig.greeting } : {}
|
|
991
|
+
});
|
|
945
992
|
}
|
|
946
|
-
handle
|
|
947
|
-
system_prompt: systemPrompt,
|
|
948
|
-
tools: s2sTools,
|
|
949
|
-
...agentConfig.greeting ? { greeting: agentConfig.greeting } : {}
|
|
950
|
-
});
|
|
951
|
-
handle.addEventListener("ready", ((e) => {
|
|
993
|
+
on(handle, "ready", (e) => {
|
|
952
994
|
s2sSessionId = e.detail.session_id;
|
|
953
995
|
log.info("S2S session ready", { session_id: s2sSessionId });
|
|
954
|
-
})
|
|
955
|
-
handle
|
|
996
|
+
});
|
|
997
|
+
on(handle, "session_expired", () => {
|
|
956
998
|
log.info("S2S session expired, reconnecting fresh");
|
|
957
999
|
s2sSessionId = null;
|
|
958
1000
|
handle.close();
|
|
959
|
-
})
|
|
1001
|
+
});
|
|
960
1002
|
handle.addEventListener("speech_started", () => {
|
|
961
1003
|
client.event({ type: "speech_started" });
|
|
962
1004
|
});
|
|
963
1005
|
handle.addEventListener("speech_stopped", () => {
|
|
964
1006
|
client.event({ type: "speech_stopped" });
|
|
965
1007
|
});
|
|
966
|
-
handle
|
|
1008
|
+
on(handle, "user_transcript_delta", (e) => {
|
|
967
1009
|
client.event({
|
|
968
1010
|
type: "transcript",
|
|
969
1011
|
text: e.detail.text,
|
|
970
1012
|
isFinal: false
|
|
971
1013
|
});
|
|
972
|
-
})
|
|
973
|
-
handle
|
|
1014
|
+
});
|
|
1015
|
+
on(handle, "user_transcript", (e) => {
|
|
974
1016
|
const { text } = e.detail;
|
|
975
1017
|
log.info("S2S user transcript", { text });
|
|
976
1018
|
client.event({ type: "transcript", text, isFinal: true });
|
|
977
1019
|
client.event({ type: "turn", text });
|
|
978
1020
|
conversationMessages.push({ role: "user", content: text });
|
|
979
1021
|
invokeHook("onTurn", text);
|
|
980
|
-
})
|
|
1022
|
+
});
|
|
981
1023
|
handle.addEventListener("reply_started", () => {
|
|
982
1024
|
toolCallCount = 0;
|
|
983
1025
|
});
|
|
984
|
-
handle
|
|
1026
|
+
on(handle, "audio", (e) => {
|
|
985
1027
|
client.playAudioChunk(e.detail.audio);
|
|
986
|
-
})
|
|
987
|
-
handle
|
|
1028
|
+
});
|
|
1029
|
+
on(handle, "agent_transcript", (e) => {
|
|
988
1030
|
const { text } = e.detail;
|
|
989
1031
|
client.event({ type: "chat", text });
|
|
990
1032
|
conversationMessages.push({ role: "assistant", content: text });
|
|
991
|
-
})
|
|
992
|
-
handle
|
|
1033
|
+
});
|
|
1034
|
+
on(handle, "tool_call", (e) => {
|
|
993
1035
|
const p = handleToolCall(e.detail).catch((err) => {
|
|
994
1036
|
log.error("Tool call handler failed", {
|
|
995
1037
|
err: err instanceof Error ? err.message : String(err)
|
|
@@ -999,25 +1041,23 @@ function createS2sSession(opts) {
|
|
|
999
1041
|
turnPromise = (prev ?? Promise.resolve()).then(() => p).finally(() => {
|
|
1000
1042
|
turnPromise = null;
|
|
1001
1043
|
});
|
|
1002
|
-
})
|
|
1003
|
-
handle
|
|
1044
|
+
});
|
|
1045
|
+
on(handle, "reply_done", (e) => {
|
|
1004
1046
|
if (e.detail.status === "interrupted") {
|
|
1005
1047
|
log.info("S2S reply interrupted (barge-in)");
|
|
1006
1048
|
pendingTools = [];
|
|
1007
1049
|
client.event({ type: "cancelled" });
|
|
1008
|
-
} else {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
s2s?.sendToolResult(tool.call_id, tool.result);
|
|
1012
|
-
}
|
|
1013
|
-
pendingTools = [];
|
|
1014
|
-
} else {
|
|
1015
|
-
client.playAudioDone();
|
|
1016
|
-
client.event({ type: "tts_done" });
|
|
1050
|
+
} else if (pendingTools.length > 0) {
|
|
1051
|
+
for (const tool of pendingTools) {
|
|
1052
|
+
s2s?.sendToolResult(tool.call_id, tool.result);
|
|
1017
1053
|
}
|
|
1054
|
+
pendingTools = [];
|
|
1055
|
+
} else {
|
|
1056
|
+
client.playAudioDone();
|
|
1057
|
+
client.event({ type: "tts_done" });
|
|
1018
1058
|
}
|
|
1019
|
-
})
|
|
1020
|
-
handle
|
|
1059
|
+
});
|
|
1060
|
+
on(handle, "error", (e) => {
|
|
1021
1061
|
log.error("S2S error", {
|
|
1022
1062
|
code: e.detail.code,
|
|
1023
1063
|
message: e.detail.message
|
|
@@ -1027,7 +1067,7 @@ function createS2sSession(opts) {
|
|
|
1027
1067
|
code: "internal",
|
|
1028
1068
|
message: e.detail.message
|
|
1029
1069
|
});
|
|
1030
|
-
})
|
|
1070
|
+
});
|
|
1031
1071
|
handle.addEventListener("close", () => {
|
|
1032
1072
|
log.info("S2S closed");
|
|
1033
1073
|
s2s = null;
|
|
@@ -1106,31 +1146,80 @@ var init_session = __esm({
|
|
|
1106
1146
|
}
|
|
1107
1147
|
});
|
|
1108
1148
|
|
|
1149
|
+
// dist/sdk/vector.js
|
|
1150
|
+
function createMemoryVectorStore() {
|
|
1151
|
+
const store = /* @__PURE__ */ new Map();
|
|
1152
|
+
return {
|
|
1153
|
+
upsert(id, data, metadata) {
|
|
1154
|
+
store.set(id, { data, metadata });
|
|
1155
|
+
return Promise.resolve();
|
|
1156
|
+
},
|
|
1157
|
+
query(text, options) {
|
|
1158
|
+
const topK = options?.topK ?? 10;
|
|
1159
|
+
const query = text.toLowerCase();
|
|
1160
|
+
const results = [];
|
|
1161
|
+
for (const [id, entry] of store) {
|
|
1162
|
+
const data = entry.data.toLowerCase();
|
|
1163
|
+
const words = query.split(/\s+/).filter(Boolean);
|
|
1164
|
+
const matches = words.filter((w) => data.includes(w)).length;
|
|
1165
|
+
if (matches > 0) {
|
|
1166
|
+
results.push({
|
|
1167
|
+
id,
|
|
1168
|
+
score: matches / Math.max(words.length, 1),
|
|
1169
|
+
data: entry.data,
|
|
1170
|
+
metadata: entry.metadata
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
results.sort((a, b) => b.score - a.score);
|
|
1175
|
+
return Promise.resolve(results.slice(0, topK));
|
|
1176
|
+
},
|
|
1177
|
+
remove(ids) {
|
|
1178
|
+
const idArray = Array.isArray(ids) ? ids : [ids];
|
|
1179
|
+
for (const id of idArray) {
|
|
1180
|
+
store.delete(id);
|
|
1181
|
+
}
|
|
1182
|
+
return Promise.resolve();
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
var init_vector = __esm({
|
|
1187
|
+
"dist/sdk/vector.js"() {
|
|
1188
|
+
"use strict";
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1109
1192
|
// dist/sdk/worker_entry.js
|
|
1110
|
-
|
|
1193
|
+
function buildToolContext(opts) {
|
|
1194
|
+
const { env, sessionId, state, kv, vector, messages } = opts;
|
|
1195
|
+
return {
|
|
1196
|
+
sessionId: sessionId ?? "",
|
|
1197
|
+
env: { ...env },
|
|
1198
|
+
abortSignal: AbortSignal.timeout(TOOL_HANDLER_TIMEOUT),
|
|
1199
|
+
state: state ?? {},
|
|
1200
|
+
get kv() {
|
|
1201
|
+
if (!kv)
|
|
1202
|
+
throw new Error("KV not available");
|
|
1203
|
+
return kv;
|
|
1204
|
+
},
|
|
1205
|
+
get vector() {
|
|
1206
|
+
if (!vector)
|
|
1207
|
+
throw new Error("Vector store not available");
|
|
1208
|
+
return vector;
|
|
1209
|
+
},
|
|
1210
|
+
messages: messages ?? []
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1111
1213
|
async function executeToolCall(name, args, options) {
|
|
1112
|
-
const { tool
|
|
1113
|
-
const schema = tool.parameters ??
|
|
1214
|
+
const { tool } = options;
|
|
1215
|
+
const schema = tool.parameters ?? EMPTY_PARAMS;
|
|
1114
1216
|
const parsed = schema.safeParse(args);
|
|
1115
1217
|
if (!parsed.success) {
|
|
1116
1218
|
const issues = (parsed.error?.issues ?? []).map((i) => `${i.path.map(String).join(".")}: ${i.message}`).join(", ");
|
|
1117
1219
|
return `Error: Invalid arguments for tool "${name}": ${issues}`;
|
|
1118
1220
|
}
|
|
1119
1221
|
try {
|
|
1120
|
-
const
|
|
1121
|
-
const envCopy = { ...env };
|
|
1122
|
-
const ctx = {
|
|
1123
|
-
sessionId: sessionId ?? "",
|
|
1124
|
-
env: envCopy,
|
|
1125
|
-
abortSignal,
|
|
1126
|
-
state: state ?? {},
|
|
1127
|
-
get kv() {
|
|
1128
|
-
if (!kv)
|
|
1129
|
-
throw new Error("KV not available");
|
|
1130
|
-
return kv;
|
|
1131
|
-
},
|
|
1132
|
-
messages: messages ?? []
|
|
1133
|
-
};
|
|
1222
|
+
const ctx = buildToolContext(options);
|
|
1134
1223
|
const result = await Promise.resolve(tool.execute(parsed.data, ctx));
|
|
1135
1224
|
if (result == null)
|
|
1136
1225
|
return "null";
|
|
@@ -1148,6 +1237,7 @@ var TOOL_HANDLER_TIMEOUT;
|
|
|
1148
1237
|
var init_worker_entry = __esm({
|
|
1149
1238
|
"dist/sdk/worker_entry.js"() {
|
|
1150
1239
|
"use strict";
|
|
1240
|
+
init_internal_types();
|
|
1151
1241
|
TOOL_HANDLER_TIMEOUT = 3e4;
|
|
1152
1242
|
}
|
|
1153
1243
|
});
|
|
@@ -1173,7 +1263,7 @@ function buildAgentConfig(agent) {
|
|
|
1173
1263
|
return config;
|
|
1174
1264
|
}
|
|
1175
1265
|
function createDirectExecutor(opts) {
|
|
1176
|
-
const { agent, env, kv = createMemoryKv(), vectorSearch, createWebSocket, logger = consoleLogger, metrics = noopMetrics, s2sConfig = DEFAULT_S2S_CONFIG } = opts;
|
|
1266
|
+
const { agent, env, kv = createMemoryKv(), vector = createMemoryVectorStore(), vectorSearch, createWebSocket, logger = consoleLogger, metrics = noopMetrics, s2sConfig = DEFAULT_S2S_CONFIG } = opts;
|
|
1177
1267
|
const agentConfig = buildAgentConfig(agent);
|
|
1178
1268
|
const builtinDefs = getBuiltinToolDefs(agent.builtinTools ?? [], vectorSearch ? { vectorSearch } : void 0);
|
|
1179
1269
|
const allTools = {
|
|
@@ -1198,6 +1288,9 @@ function createDirectExecutor(opts) {
|
|
|
1198
1288
|
state: getState(sessionId),
|
|
1199
1289
|
get kv() {
|
|
1200
1290
|
return kv;
|
|
1291
|
+
},
|
|
1292
|
+
get vector() {
|
|
1293
|
+
return vector;
|
|
1201
1294
|
}
|
|
1202
1295
|
};
|
|
1203
1296
|
}
|
|
@@ -1211,6 +1304,7 @@ function createDirectExecutor(opts) {
|
|
|
1211
1304
|
sessionId,
|
|
1212
1305
|
state: getState(sessionId ?? ""),
|
|
1213
1306
|
kv,
|
|
1307
|
+
vector,
|
|
1214
1308
|
messages
|
|
1215
1309
|
});
|
|
1216
1310
|
};
|
|
@@ -1283,6 +1377,7 @@ var init_direct_executor = __esm({
|
|
|
1283
1377
|
init_kv();
|
|
1284
1378
|
init_runtime();
|
|
1285
1379
|
init_session();
|
|
1380
|
+
init_vector();
|
|
1286
1381
|
init_worker_entry();
|
|
1287
1382
|
}
|
|
1288
1383
|
});
|
|
@@ -1313,6 +1408,64 @@ function createClientSink(ws) {
|
|
|
1313
1408
|
}
|
|
1314
1409
|
};
|
|
1315
1410
|
}
|
|
1411
|
+
function isBinaryData(data) {
|
|
1412
|
+
return globalThis.Buffer?.isBuffer(data) || data instanceof ArrayBuffer || data instanceof Uint8Array;
|
|
1413
|
+
}
|
|
1414
|
+
function toUint8Array(data) {
|
|
1415
|
+
if (data instanceof Uint8Array)
|
|
1416
|
+
return data;
|
|
1417
|
+
if (data instanceof ArrayBuffer)
|
|
1418
|
+
return new Uint8Array(data);
|
|
1419
|
+
const buf = data;
|
|
1420
|
+
return new Uint8Array(buf.buffer ?? data, buf.byteOffset ?? 0, buf.byteLength);
|
|
1421
|
+
}
|
|
1422
|
+
function handleBinaryAudio(data, session, log, ctx, sid) {
|
|
1423
|
+
if (!isBinaryData(data))
|
|
1424
|
+
return false;
|
|
1425
|
+
const chunk = toUint8Array(data);
|
|
1426
|
+
if (!isValidAudioChunk(chunk)) {
|
|
1427
|
+
log.warn("Invalid audio chunk, dropping", {
|
|
1428
|
+
...ctx,
|
|
1429
|
+
sid,
|
|
1430
|
+
bytes: chunk.byteLength,
|
|
1431
|
+
aligned: chunk.byteLength % 2 === 0
|
|
1432
|
+
});
|
|
1433
|
+
return true;
|
|
1434
|
+
}
|
|
1435
|
+
session.onAudio(chunk);
|
|
1436
|
+
return true;
|
|
1437
|
+
}
|
|
1438
|
+
function handleTextMessage(data, session, log, ctx, sid) {
|
|
1439
|
+
if (typeof data !== "string")
|
|
1440
|
+
return;
|
|
1441
|
+
let json;
|
|
1442
|
+
try {
|
|
1443
|
+
json = JSON.parse(data);
|
|
1444
|
+
} catch {
|
|
1445
|
+
log.warn("Invalid JSON from client", { ...ctx, sid });
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
const parsed = ClientMessageSchema.safeParse(json);
|
|
1449
|
+
if (!parsed.success) {
|
|
1450
|
+
log.warn("Invalid client message", { ...ctx, sid, error: parsed.error.message });
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
const msg = parsed.data;
|
|
1454
|
+
switch (msg.type) {
|
|
1455
|
+
case "audio_ready":
|
|
1456
|
+
session.onAudioReady();
|
|
1457
|
+
break;
|
|
1458
|
+
case "cancel":
|
|
1459
|
+
session.onCancel();
|
|
1460
|
+
break;
|
|
1461
|
+
case "reset":
|
|
1462
|
+
session.onReset();
|
|
1463
|
+
break;
|
|
1464
|
+
case "history":
|
|
1465
|
+
session.onHistory(msg.messages);
|
|
1466
|
+
break;
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1316
1469
|
function wireSessionSocket(ws, opts) {
|
|
1317
1470
|
const { sessions, logger: log = consoleLogger } = opts;
|
|
1318
1471
|
const sessionId = crypto.randomUUID();
|
|
@@ -1337,56 +1490,10 @@ function wireSessionSocket(ws, opts) {
|
|
|
1337
1490
|
ws.addEventListener("message", (event) => {
|
|
1338
1491
|
if (!session)
|
|
1339
1492
|
return;
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
const isBinary = globalThis.Buffer?.isBuffer(data) || data instanceof ArrayBuffer || data instanceof Uint8Array;
|
|
1343
|
-
if (isBinary) {
|
|
1344
|
-
const chunk = data instanceof Uint8Array ? data : new Uint8Array(data.buffer ?? data, data.byteOffset ?? 0, data.byteLength ?? data.byteLength);
|
|
1345
|
-
if (!isValidAudioChunk(chunk)) {
|
|
1346
|
-
log.warn("Invalid audio chunk, dropping", {
|
|
1347
|
-
...ctx,
|
|
1348
|
-
sid,
|
|
1349
|
-
bytes: chunk.byteLength,
|
|
1350
|
-
aligned: chunk.byteLength % 2 === 0
|
|
1351
|
-
});
|
|
1352
|
-
return;
|
|
1353
|
-
}
|
|
1354
|
-
session.onAudio(chunk);
|
|
1493
|
+
const { data } = event;
|
|
1494
|
+
if (handleBinaryAudio(data, session, log, ctx, sid))
|
|
1355
1495
|
return;
|
|
1356
|
-
|
|
1357
|
-
if (typeof data !== "string")
|
|
1358
|
-
return;
|
|
1359
|
-
let json;
|
|
1360
|
-
try {
|
|
1361
|
-
json = JSON.parse(data);
|
|
1362
|
-
} catch {
|
|
1363
|
-
log.warn("Invalid JSON from client", { ...ctx, sid });
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
const parsed = ClientMessageSchema.safeParse(json);
|
|
1367
|
-
if (!parsed.success) {
|
|
1368
|
-
log.warn("Invalid client message", {
|
|
1369
|
-
...ctx,
|
|
1370
|
-
sid,
|
|
1371
|
-
error: parsed.error.message
|
|
1372
|
-
});
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
const msg = parsed.data;
|
|
1376
|
-
switch (msg.type) {
|
|
1377
|
-
case "audio_ready":
|
|
1378
|
-
session.onAudioReady();
|
|
1379
|
-
break;
|
|
1380
|
-
case "cancel":
|
|
1381
|
-
session.onCancel();
|
|
1382
|
-
break;
|
|
1383
|
-
case "reset":
|
|
1384
|
-
session.onReset();
|
|
1385
|
-
break;
|
|
1386
|
-
case "history":
|
|
1387
|
-
session.onHistory(msg.messages);
|
|
1388
|
-
break;
|
|
1389
|
-
}
|
|
1496
|
+
handleTextMessage(data, session, log, ctx, sid);
|
|
1390
1497
|
});
|
|
1391
1498
|
ws.addEventListener("close", () => {
|
|
1392
1499
|
log.info("Session disconnected", { ...ctx, sid });
|
|
@@ -1414,11 +1521,12 @@ var init_ws_handler = __esm({
|
|
|
1414
1521
|
|
|
1415
1522
|
// dist/sdk/winterc_server.js
|
|
1416
1523
|
function createWintercServer(options) {
|
|
1417
|
-
const { agent, env, kv = createMemoryKv(), vectorSearch, clientHtml, logger = consoleLogger, metrics = noopMetrics, s2sConfig = DEFAULT_S2S_CONFIG } = options;
|
|
1524
|
+
const { agent, env, kv = createMemoryKv(), vector = createMemoryVectorStore(), vectorSearch, clientHtml, logger = consoleLogger, metrics = noopMetrics, s2sConfig = DEFAULT_S2S_CONFIG } = options;
|
|
1418
1525
|
const executor = createDirectExecutor({
|
|
1419
1526
|
agent,
|
|
1420
1527
|
env,
|
|
1421
1528
|
kv,
|
|
1529
|
+
vector,
|
|
1422
1530
|
...vectorSearch ? { vectorSearch } : {},
|
|
1423
1531
|
createWebSocket: options.createWebSocket,
|
|
1424
1532
|
logger,
|
|
@@ -1430,8 +1538,7 @@ function createWintercServer(options) {
|
|
|
1430
1538
|
protocolVersion: PROTOCOL_VERSION,
|
|
1431
1539
|
audioFormat: AUDIO_FORMAT,
|
|
1432
1540
|
sampleRate: s2sConfig.inputSampleRate,
|
|
1433
|
-
ttsSampleRate: s2sConfig.outputSampleRate
|
|
1434
|
-
mode: "s2s"
|
|
1541
|
+
ttsSampleRate: s2sConfig.outputSampleRate
|
|
1435
1542
|
};
|
|
1436
1543
|
return {
|
|
1437
1544
|
async fetch(request) {
|
|
@@ -1479,6 +1586,7 @@ var init_winterc_server = __esm({
|
|
|
1479
1586
|
init_kv();
|
|
1480
1587
|
init_protocol();
|
|
1481
1588
|
init_runtime();
|
|
1589
|
+
init_vector();
|
|
1482
1590
|
init_ws_handler();
|
|
1483
1591
|
}
|
|
1484
1592
|
});
|
|
@@ -1522,7 +1630,9 @@ function createServer(options) {
|
|
|
1522
1630
|
agent,
|
|
1523
1631
|
env,
|
|
1524
1632
|
...kv ? { kv } : {},
|
|
1525
|
-
createWebSocket: wsFactory
|
|
1633
|
+
createWebSocket: wsFactory ?? (() => {
|
|
1634
|
+
throw new Error("WebSocket factory not loaded");
|
|
1635
|
+
}),
|
|
1526
1636
|
...clientHtml !== void 0 ? { clientHtml } : {},
|
|
1527
1637
|
logger,
|
|
1528
1638
|
s2sConfig
|
|
@@ -1539,46 +1649,9 @@ function createServer(options) {
|
|
|
1539
1649
|
await getWsFactory();
|
|
1540
1650
|
const http = await import("node:http");
|
|
1541
1651
|
const nodeServer = http.createServer(async (req, res) => {
|
|
1542
|
-
|
|
1543
|
-
const protocol = req.socket.encrypted ? "https" : "http";
|
|
1544
|
-
const host = req.headers.host ?? `localhost:${port}`;
|
|
1545
|
-
const url = new URL(req.url ?? "/", `${protocol}://${host}`);
|
|
1546
|
-
const headers = new Headers();
|
|
1547
|
-
for (const [key, val] of Object.entries(req.headers)) {
|
|
1548
|
-
if (val)
|
|
1549
|
-
headers.set(key, Array.isArray(val) ? val[0] : val);
|
|
1550
|
-
}
|
|
1551
|
-
const request = new Request(url, {
|
|
1552
|
-
method: req.method ?? "GET",
|
|
1553
|
-
headers
|
|
1554
|
-
});
|
|
1555
|
-
const response = await getWinterc().fetch(request);
|
|
1556
|
-
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
1557
|
-
const body = await response.text();
|
|
1558
|
-
res.end(body);
|
|
1559
|
-
} catch (err) {
|
|
1560
|
-
res.writeHead(500);
|
|
1561
|
-
res.end(err instanceof Error ? err.message : "Internal Server Error");
|
|
1562
|
-
}
|
|
1652
|
+
await nodeHttpHandler(req, res, port, getWinterc);
|
|
1563
1653
|
});
|
|
1564
|
-
|
|
1565
|
-
const wsMod = await import("ws");
|
|
1566
|
-
const WSServer = wsMod.WebSocketServer;
|
|
1567
|
-
if (WSServer) {
|
|
1568
|
-
const wss = new WSServer({ noServer: true });
|
|
1569
|
-
nodeServer.on("upgrade", (req, socket, head) => {
|
|
1570
|
-
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
1571
|
-
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
1572
|
-
const resume = reqUrl.searchParams.has("resume");
|
|
1573
|
-
getWinterc().handleWebSocket(ws, {
|
|
1574
|
-
skipGreeting: resume
|
|
1575
|
-
});
|
|
1576
|
-
});
|
|
1577
|
-
});
|
|
1578
|
-
}
|
|
1579
|
-
} catch {
|
|
1580
|
-
logger.warn("ws package not available for Node.js WebSocket upgrade");
|
|
1581
|
-
}
|
|
1654
|
+
attachWsUpgrade(nodeServer, port, getWinterc, logger);
|
|
1582
1655
|
await new Promise((resolve) => {
|
|
1583
1656
|
nodeServer.listen(port, () => {
|
|
1584
1657
|
logger.info(`Agent "${agent.name}" listening on http://localhost:${port}`);
|
|
@@ -1599,6 +1672,43 @@ function createServer(options) {
|
|
|
1599
1672
|
}
|
|
1600
1673
|
};
|
|
1601
1674
|
}
|
|
1675
|
+
async function nodeHttpHandler(req, res, port, getWinterc) {
|
|
1676
|
+
try {
|
|
1677
|
+
const protocol = req.socket.encrypted ? "https" : "http";
|
|
1678
|
+
const host = req.headers.host ?? `localhost:${port}`;
|
|
1679
|
+
const url = new URL(req.url ?? "/", `${protocol}://${host}`);
|
|
1680
|
+
const headers = new Headers();
|
|
1681
|
+
for (const [key, val] of Object.entries(req.headers)) {
|
|
1682
|
+
if (val)
|
|
1683
|
+
headers.set(key, Array.isArray(val) ? val[0] ?? "" : val);
|
|
1684
|
+
}
|
|
1685
|
+
const request = new Request(url, { method: req.method ?? "GET", headers });
|
|
1686
|
+
const response = await getWinterc().fetch(request);
|
|
1687
|
+
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
1688
|
+
res.end(await response.text());
|
|
1689
|
+
} catch (err) {
|
|
1690
|
+
res.writeHead(500);
|
|
1691
|
+
res.end(err instanceof Error ? err.message : "Internal Server Error");
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
function attachWsUpgrade(nodeServer, port, getWinterc, logger) {
|
|
1695
|
+
import("ws").then((wsMod) => {
|
|
1696
|
+
const WSServer = wsMod.WebSocketServer;
|
|
1697
|
+
if (!WSServer)
|
|
1698
|
+
return;
|
|
1699
|
+
const wss = new WSServer({ noServer: true });
|
|
1700
|
+
nodeServer.on("upgrade", (req, socket, head) => {
|
|
1701
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
1702
|
+
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
1703
|
+
getWinterc().handleWebSocket(ws, {
|
|
1704
|
+
skipGreeting: reqUrl.searchParams.has("resume")
|
|
1705
|
+
});
|
|
1706
|
+
});
|
|
1707
|
+
});
|
|
1708
|
+
}).catch(() => {
|
|
1709
|
+
logger.warn("ws package not available for Node.js WebSocket upgrade");
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1602
1712
|
var init_server = __esm({
|
|
1603
1713
|
"dist/sdk/server.js"() {
|
|
1604
1714
|
init_runtime();
|
|
@@ -2261,39 +2371,11 @@ async function writeBuildOutput(agentDir, bundle) {
|
|
|
2261
2371
|
fs3.writeFile(path3.join(buildDir, "index.html"), bundle.html)
|
|
2262
2372
|
]);
|
|
2263
2373
|
}
|
|
2264
|
-
async function checkAgent(agentDir) {
|
|
2265
|
-
const userFiles = ["agent.ts"];
|
|
2266
|
-
for (const f of ["client.tsx", "components.tsx"]) {
|
|
2267
|
-
try {
|
|
2268
|
-
await fs3.stat(path3.join(agentDir, f));
|
|
2269
|
-
userFiles.push(f);
|
|
2270
|
-
} catch {
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
const checks = [{ args: ["--noEmit", ...userFiles], label: "Type-check" }];
|
|
2274
|
-
const results = await Promise.allSettled(
|
|
2275
|
-
checks.map(({ args }) => execFileAsync("npx", ["tsc", ...args], { cwd: agentDir }))
|
|
2276
|
-
);
|
|
2277
|
-
const errors = [];
|
|
2278
|
-
for (const [i, r] of results.entries()) {
|
|
2279
|
-
if (r.status === "rejected") {
|
|
2280
|
-
const label = checks[i]?.label ?? "unknown";
|
|
2281
|
-
const msg = r.reason.stderr?.trim() ?? String(r.reason);
|
|
2282
|
-
error2(`${label}: ${msg}`);
|
|
2283
|
-
errors.push(label);
|
|
2284
|
-
}
|
|
2285
|
-
}
|
|
2286
|
-
if (errors.length > 0) {
|
|
2287
|
-
throw new Error(`${errors.join(", ")} failed \u2014 fix the errors above`);
|
|
2288
|
-
}
|
|
2289
|
-
}
|
|
2290
2374
|
async function runBuild(opts) {
|
|
2291
2375
|
const agent = await loadAgent(opts.agentDir);
|
|
2292
2376
|
if (!agent) {
|
|
2293
2377
|
throw new Error("No agent found \u2014 run `aai new` first");
|
|
2294
2378
|
}
|
|
2295
|
-
step("Check", agent.slug);
|
|
2296
|
-
await checkAgent(opts.agentDir);
|
|
2297
2379
|
step("Bundle", agent.slug);
|
|
2298
2380
|
let bundle;
|
|
2299
2381
|
try {
|