@alexkroman1/aai 0.6.1 → 0.7.3
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 +422 -707
- 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 -9
- 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
|
@@ -65,13 +65,13 @@ __export(new_exports, {
|
|
|
65
65
|
listTemplates: () => listTemplates,
|
|
66
66
|
runNew: () => runNew
|
|
67
67
|
});
|
|
68
|
-
import
|
|
68
|
+
import fs4 from "node:fs/promises";
|
|
69
69
|
import path4 from "node:path";
|
|
70
70
|
import glob from "fast-glob";
|
|
71
71
|
import fsExtra from "fs-extra";
|
|
72
72
|
async function listTemplates(dir) {
|
|
73
73
|
const templates = [];
|
|
74
|
-
const entries = await
|
|
74
|
+
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
75
75
|
for (const entry of entries) {
|
|
76
76
|
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
77
77
|
templates.push(entry.name);
|
|
@@ -84,10 +84,10 @@ async function copyDirNoOverwrite(src, dest) {
|
|
|
84
84
|
for (const file of files) {
|
|
85
85
|
const destPath = path4.join(dest, file);
|
|
86
86
|
try {
|
|
87
|
-
await
|
|
87
|
+
await fs4.access(destPath);
|
|
88
88
|
} catch {
|
|
89
|
-
await
|
|
90
|
-
await
|
|
89
|
+
await fs4.mkdir(path4.dirname(destPath), { recursive: true });
|
|
90
|
+
await fs4.copyFile(path4.join(src, file), destPath);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -101,12 +101,12 @@ async function runNew(opts) {
|
|
|
101
101
|
await fsExtra.copy(path4.join(templatesDir, template), targetDir, { overwrite: true });
|
|
102
102
|
await copyDirNoOverwrite(path4.join(templatesDir, "_shared"), targetDir);
|
|
103
103
|
try {
|
|
104
|
-
await
|
|
104
|
+
await fs4.copyFile(path4.join(targetDir, ".env.example"), path4.join(targetDir, ".env"));
|
|
105
105
|
} catch {
|
|
106
106
|
}
|
|
107
107
|
const readmePath = path4.join(targetDir, "README.md");
|
|
108
108
|
try {
|
|
109
|
-
await
|
|
109
|
+
await fs4.access(readmePath);
|
|
110
110
|
} catch {
|
|
111
111
|
const slug = path4.basename(path4.resolve(targetDir));
|
|
112
112
|
const readme = `# ${slug}
|
|
@@ -138,7 +138,7 @@ Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
|
138
138
|
|
|
139
139
|
See \`CLAUDE.md\` for the full agent API reference.
|
|
140
140
|
`;
|
|
141
|
-
await
|
|
141
|
+
await fs4.writeFile(readmePath, readme);
|
|
142
142
|
}
|
|
143
143
|
_internals2.step("Done", targetDir);
|
|
144
144
|
return targetDir;
|
|
@@ -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,21 +763,51 @@ 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
|
|
|
768
805
|
// dist/sdk/types.js
|
|
769
|
-
var
|
|
806
|
+
var DEFAULT_INSTRUCTIONS;
|
|
770
807
|
var init_types = __esm({
|
|
771
808
|
"dist/sdk/types.js"() {
|
|
772
809
|
"use strict";
|
|
773
|
-
|
|
810
|
+
DEFAULT_INSTRUCTIONS = `You are AAI, a helpful AI assistant.
|
|
774
811
|
|
|
775
812
|
Voice-First Rules:
|
|
776
813
|
- Optimize for natural speech. Avoid jargon unless central to the answer. Use short, punchy sentences.
|
|
@@ -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}` : "";
|
|
@@ -798,7 +835,7 @@ ${config.instructions}` : "";
|
|
|
798
835
|
month: "long",
|
|
799
836
|
day: "numeric"
|
|
800
837
|
});
|
|
801
|
-
return
|
|
838
|
+
return DEFAULT_INSTRUCTIONS + `
|
|
802
839
|
|
|
803
840
|
Today's date is ${today}.` + agentInstructions + toolPreamble + (opts?.voice ? VOICE_RULES : "");
|
|
804
841
|
}
|
|
@@ -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);
|
|
1355
|
-
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 });
|
|
1493
|
+
const { data } = event;
|
|
1494
|
+
if (handleBinaryAudio(data, session, log, ctx, sid))
|
|
1364
1495
|
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();
|
|
@@ -1844,9 +1954,7 @@ async function loadAgent(dir) {
|
|
|
1844
1954
|
slug,
|
|
1845
1955
|
dir,
|
|
1846
1956
|
entryPoint: path.join(dir, "agent.ts"),
|
|
1847
|
-
|
|
1848
|
-
clientEntry,
|
|
1849
|
-
transport: ["websocket"]
|
|
1957
|
+
clientEntry
|
|
1850
1958
|
};
|
|
1851
1959
|
}
|
|
1852
1960
|
async function ensureClaudeMd(targetDir) {
|
|
@@ -1880,7 +1988,7 @@ init_output();
|
|
|
1880
1988
|
var _internals = {
|
|
1881
1989
|
fetch: globalThis.fetch.bind(globalThis)
|
|
1882
1990
|
};
|
|
1883
|
-
async function attemptDeploy(url, slug, apiKey, env,
|
|
1991
|
+
async function attemptDeploy(url, slug, apiKey, env, worker, html) {
|
|
1884
1992
|
return await _internals.fetch(`${url}/${slug}/deploy`, {
|
|
1885
1993
|
method: "POST",
|
|
1886
1994
|
headers: {
|
|
@@ -1890,21 +1998,14 @@ async function attemptDeploy(url, slug, apiKey, env, transport, worker, html, co
|
|
|
1890
1998
|
body: JSON.stringify({
|
|
1891
1999
|
env,
|
|
1892
2000
|
worker,
|
|
1893
|
-
html
|
|
1894
|
-
transport,
|
|
1895
|
-
config,
|
|
1896
|
-
toolSchemas
|
|
2001
|
+
html
|
|
1897
2002
|
})
|
|
1898
2003
|
});
|
|
1899
2004
|
}
|
|
1900
2005
|
var MAX_RETRIES = 20;
|
|
1901
2006
|
async function runDeploy(opts) {
|
|
1902
|
-
const manifest = JSON.parse(opts.bundle.manifest);
|
|
1903
2007
|
const worker = opts.bundle.worker;
|
|
1904
2008
|
const html = opts.bundle.html;
|
|
1905
|
-
const transport = manifest.transport ?? ["websocket"];
|
|
1906
|
-
const config = manifest.config;
|
|
1907
|
-
const toolSchemas = manifest.toolSchemas;
|
|
1908
2009
|
let slug = opts.slug;
|
|
1909
2010
|
if (opts.dryRun) {
|
|
1910
2011
|
stepInfo("Dry run", "would deploy:");
|
|
@@ -1912,17 +2013,7 @@ async function runDeploy(opts) {
|
|
|
1912
2013
|
return { slug };
|
|
1913
2014
|
}
|
|
1914
2015
|
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
1915
|
-
const resp = await attemptDeploy(
|
|
1916
|
-
opts.url,
|
|
1917
|
-
slug,
|
|
1918
|
-
opts.apiKey,
|
|
1919
|
-
opts.env,
|
|
1920
|
-
transport,
|
|
1921
|
-
worker,
|
|
1922
|
-
html,
|
|
1923
|
-
config,
|
|
1924
|
-
toolSchemas
|
|
1925
|
-
);
|
|
2016
|
+
const resp = await attemptDeploy(opts.url, slug, opts.apiKey, opts.env, worker, html);
|
|
1926
2017
|
if (resp.ok) {
|
|
1927
2018
|
step("Deploy", `${slug} -> ${opts.url}/${slug}`);
|
|
1928
2019
|
try {
|
|
@@ -2078,365 +2169,16 @@ async function runWithInk(label, fn) {
|
|
|
2078
2169
|
}
|
|
2079
2170
|
|
|
2080
2171
|
// cli/build.ts
|
|
2081
|
-
import
|
|
2172
|
+
import fs3 from "node:fs/promises";
|
|
2082
2173
|
import path3 from "node:path";
|
|
2083
2174
|
|
|
2084
2175
|
// cli/_bundler.ts
|
|
2085
|
-
import
|
|
2176
|
+
import fs2 from "node:fs/promises";
|
|
2086
2177
|
import path2 from "node:path";
|
|
2087
2178
|
import preact from "@preact/preset-vite";
|
|
2088
2179
|
import tailwindcss from "@tailwindcss/vite";
|
|
2089
2180
|
import { build } from "vite";
|
|
2090
2181
|
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
2091
|
-
|
|
2092
|
-
// cli/_static_config.ts
|
|
2093
|
-
import fs2 from "node:fs/promises";
|
|
2094
|
-
import {
|
|
2095
|
-
Project,
|
|
2096
|
-
SyntaxKind
|
|
2097
|
-
} from "ts-morph";
|
|
2098
|
-
|
|
2099
|
-
// sdk/types.ts
|
|
2100
|
-
var DEFAULT_INSTRUCTIONS = `You are AAI, a helpful AI assistant.
|
|
2101
|
-
|
|
2102
|
-
Voice-First Rules:
|
|
2103
|
-
- Optimize for natural speech. Avoid jargon unless central to the answer. Use short, punchy sentences.
|
|
2104
|
-
- Never mention "search results," "sources," or "the provided text." Speak as if the knowledge is your own.
|
|
2105
|
-
- No visual formatting. Do not say "bullet point," "bold," or "bracketed one." If you need to list items, say "First," "Next," and "Finally."
|
|
2106
|
-
- Start with the most important information. No introductory filler.
|
|
2107
|
-
- Be concise. Keep answers to 1-3 sentences. For complex topics, provide a high-level summary.
|
|
2108
|
-
- Be confident. Avoid hedging phrases like "It seems that" or "I believe."
|
|
2109
|
-
- If you don't have enough information, say so directly rather than guessing.
|
|
2110
|
-
- Never use exclamation points. Keep your tone calm and conversational.`;
|
|
2111
|
-
var DEFAULT_GREETING = "Hey there. I'm a voice assistant. What can I help you with?";
|
|
2112
|
-
|
|
2113
|
-
// cli/_static_config.ts
|
|
2114
|
-
var project = new Project({ useInMemoryFileSystem: true });
|
|
2115
|
-
async function extractStaticConfig(agentPath) {
|
|
2116
|
-
const source = await fs2.readFile(agentPath, "utf-8");
|
|
2117
|
-
return extractStaticConfigFromSource(source, agentPath);
|
|
2118
|
-
}
|
|
2119
|
-
function extractStaticConfigFromSource(source, fileName = "agent.ts") {
|
|
2120
|
-
const sf = project.createSourceFile(fileName, source, { overwrite: true });
|
|
2121
|
-
const call = findDefineAgentCall(sf);
|
|
2122
|
-
if (!call) {
|
|
2123
|
-
throw new BundleError(
|
|
2124
|
-
`Could not find a defineAgent({...}) call in ${fileName}. Make sure your agent.ts has \`export default defineAgent({...})\`.`
|
|
2125
|
-
);
|
|
2126
|
-
}
|
|
2127
|
-
const args = call.getArguments();
|
|
2128
|
-
const arg = args[0];
|
|
2129
|
-
if (!arg || !arg.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
2130
|
-
throw new BundleError("The argument to defineAgent() must be an inline object literal");
|
|
2131
|
-
}
|
|
2132
|
-
const obj = arg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
2133
|
-
const config = extractConfig(obj, fileName);
|
|
2134
|
-
const toolSchemas = extractToolSchemas(obj, fileName);
|
|
2135
|
-
return { config, toolSchemas };
|
|
2136
|
-
}
|
|
2137
|
-
function findDefineAgentCall(sf) {
|
|
2138
|
-
return sf.getFirstDescendant((node) => {
|
|
2139
|
-
if (!node.isKind(SyntaxKind.CallExpression)) return false;
|
|
2140
|
-
const expr = node.getExpression();
|
|
2141
|
-
return expr.isKind(SyntaxKind.Identifier) && expr.getText() === "defineAgent";
|
|
2142
|
-
});
|
|
2143
|
-
}
|
|
2144
|
-
function extractConfig(obj, fileName) {
|
|
2145
|
-
const name = requireString(obj, "name", fileName);
|
|
2146
|
-
const config = {
|
|
2147
|
-
name,
|
|
2148
|
-
instructions: optionalString(obj, "instructions", fileName) ?? DEFAULT_INSTRUCTIONS,
|
|
2149
|
-
greeting: optionalString(obj, "greeting", fileName) ?? DEFAULT_GREETING,
|
|
2150
|
-
voice: optionalString(obj, "voice", fileName) ?? ""
|
|
2151
|
-
};
|
|
2152
|
-
const mode = optionalString(obj, "mode", fileName);
|
|
2153
|
-
config.mode = mode ?? "s2s";
|
|
2154
|
-
const sttPrompt = optionalString(obj, "sttPrompt", fileName);
|
|
2155
|
-
if (sttPrompt !== void 0) config.sttPrompt = sttPrompt;
|
|
2156
|
-
const maxStepsProp = getProperty(obj, "maxSteps");
|
|
2157
|
-
if (maxStepsProp) {
|
|
2158
|
-
const init = maxStepsProp.getInitializer();
|
|
2159
|
-
if (init.isKind(SyntaxKind.NumericLiteral)) {
|
|
2160
|
-
config.maxSteps = Number(init.getLiteralValue());
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
const toolChoiceProp = getProperty(obj, "toolChoice");
|
|
2164
|
-
if (toolChoiceProp) {
|
|
2165
|
-
config.toolChoice = evalLiteral(
|
|
2166
|
-
toolChoiceProp.getInitializer(),
|
|
2167
|
-
"toolChoice",
|
|
2168
|
-
fileName
|
|
2169
|
-
);
|
|
2170
|
-
}
|
|
2171
|
-
const builtinToolsProp = getProperty(obj, "builtinTools");
|
|
2172
|
-
if (builtinToolsProp) {
|
|
2173
|
-
config.builtinTools = evalStringArray(
|
|
2174
|
-
builtinToolsProp.getInitializer(),
|
|
2175
|
-
"builtinTools",
|
|
2176
|
-
fileName
|
|
2177
|
-
);
|
|
2178
|
-
}
|
|
2179
|
-
const activeToolsProp = getProperty(obj, "activeTools");
|
|
2180
|
-
if (activeToolsProp) {
|
|
2181
|
-
config.activeTools = evalStringArray(
|
|
2182
|
-
activeToolsProp.getInitializer(),
|
|
2183
|
-
"activeTools",
|
|
2184
|
-
fileName
|
|
2185
|
-
);
|
|
2186
|
-
}
|
|
2187
|
-
const transportProp = getProperty(obj, "transport");
|
|
2188
|
-
if (transportProp) {
|
|
2189
|
-
const init = transportProp.getInitializer();
|
|
2190
|
-
if (init.isKind(SyntaxKind.StringLiteral)) {
|
|
2191
|
-
config.transport = [init.getLiteralValue()];
|
|
2192
|
-
} else if (init.isKind(SyntaxKind.ArrayLiteralExpression)) {
|
|
2193
|
-
config.transport = evalStringArray(init, "transport", fileName);
|
|
2194
|
-
} else {
|
|
2195
|
-
throw new BundleError(
|
|
2196
|
-
`${fileName}: \`transport\` must be a string literal or array of strings.`
|
|
2197
|
-
);
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
return config;
|
|
2201
|
-
}
|
|
2202
|
-
function extractToolSchemas(obj, fileName) {
|
|
2203
|
-
const toolsProp = getProperty(obj, "tools");
|
|
2204
|
-
if (!toolsProp) return [];
|
|
2205
|
-
const init = toolsProp.getInitializer();
|
|
2206
|
-
if (!init.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
2207
|
-
throw new BundleError(`${fileName}: \`tools\` must be an inline object literal.`);
|
|
2208
|
-
}
|
|
2209
|
-
const toolsObj = init.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
2210
|
-
const schemas = [];
|
|
2211
|
-
for (const member of toolsObj.getProperties()) {
|
|
2212
|
-
if (member.isKind(SyntaxKind.SpreadAssignment)) {
|
|
2213
|
-
const text = member.getExpression().getText();
|
|
2214
|
-
throw new BundleError(
|
|
2215
|
-
`${fileName}: Spread expressions like \`...${text}\` in tools cannot be statically analyzed. Define each tool directly in the \`tools\` object.`
|
|
2216
|
-
);
|
|
2217
|
-
}
|
|
2218
|
-
if (!member.isKind(SyntaxKind.PropertyAssignment)) continue;
|
|
2219
|
-
const prop = member;
|
|
2220
|
-
const toolName = prop.getName();
|
|
2221
|
-
const toolInit = prop.getInitializer();
|
|
2222
|
-
if (!toolInit.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
2223
|
-
throw new BundleError(`${fileName}: Tool \`${toolName}\` must be an inline object literal.`);
|
|
2224
|
-
}
|
|
2225
|
-
const toolObj = toolInit.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
2226
|
-
const descProp = getProperty(toolObj, "description");
|
|
2227
|
-
if (!descProp) {
|
|
2228
|
-
throw new BundleError(`${fileName}: Tool \`${toolName}\` is missing a \`description\`.`);
|
|
2229
|
-
}
|
|
2230
|
-
const description = evalStringLiteral(descProp.getInitializer(), toolName, fileName);
|
|
2231
|
-
const paramsProp = getProperty(toolObj, "parameters");
|
|
2232
|
-
const parameters = paramsProp ? zodAstToJsonSchema(paramsProp.getInitializer(), toolName, fileName) : { type: "object", properties: {}, additionalProperties: false };
|
|
2233
|
-
schemas.push({ name: toolName, description, parameters });
|
|
2234
|
-
}
|
|
2235
|
-
return schemas;
|
|
2236
|
-
}
|
|
2237
|
-
function zodAstToJsonSchema(node, toolName, fileName) {
|
|
2238
|
-
return parseZodExpr(node, toolName, fileName).schema;
|
|
2239
|
-
}
|
|
2240
|
-
function parseZodExpr(node, toolName, fileName) {
|
|
2241
|
-
if (!node.isKind(SyntaxKind.CallExpression)) {
|
|
2242
|
-
throw zodError(node, toolName, fileName);
|
|
2243
|
-
}
|
|
2244
|
-
const call = node.asKindOrThrow(SyntaxKind.CallExpression);
|
|
2245
|
-
const expr = call.getExpression();
|
|
2246
|
-
if (expr.isKind(SyntaxKind.PropertyAccessExpression)) {
|
|
2247
|
-
const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);
|
|
2248
|
-
const obj = propAccess.getExpression();
|
|
2249
|
-
const method = propAccess.getName();
|
|
2250
|
-
if (obj.isKind(SyntaxKind.Identifier) && obj.getText() === "z") {
|
|
2251
|
-
return parseZodBase(method, call, toolName, fileName);
|
|
2252
|
-
}
|
|
2253
|
-
if (method === "describe") {
|
|
2254
|
-
const result = parseZodExpr(obj, toolName, fileName);
|
|
2255
|
-
const args = call.getArguments();
|
|
2256
|
-
if (args[0]) {
|
|
2257
|
-
result.schema.description = evalStringLiteral(args[0], toolName, fileName);
|
|
2258
|
-
}
|
|
2259
|
-
return result;
|
|
2260
|
-
}
|
|
2261
|
-
if (method === "optional") {
|
|
2262
|
-
const result = parseZodExpr(obj, toolName, fileName);
|
|
2263
|
-
result.optional = true;
|
|
2264
|
-
return result;
|
|
2265
|
-
}
|
|
2266
|
-
if (method === "default" || method === "nullable") {
|
|
2267
|
-
return parseZodExpr(obj, toolName, fileName);
|
|
2268
|
-
}
|
|
2269
|
-
return parseZodExpr(obj, toolName, fileName);
|
|
2270
|
-
}
|
|
2271
|
-
throw zodError(node, toolName, fileName);
|
|
2272
|
-
}
|
|
2273
|
-
function parseZodBase(method, call, toolName, fileName) {
|
|
2274
|
-
switch (method) {
|
|
2275
|
-
case "string":
|
|
2276
|
-
return { schema: { type: "string" }, optional: false };
|
|
2277
|
-
case "number":
|
|
2278
|
-
return { schema: { type: "number" }, optional: false };
|
|
2279
|
-
case "boolean":
|
|
2280
|
-
return { schema: { type: "boolean" }, optional: false };
|
|
2281
|
-
case "enum": {
|
|
2282
|
-
const args = call.getArguments();
|
|
2283
|
-
const arg = args[0];
|
|
2284
|
-
if (!arg || !arg.isKind(SyntaxKind.ArrayLiteralExpression)) {
|
|
2285
|
-
throw new BundleError(
|
|
2286
|
-
`${fileName}: Tool \`${toolName}\`: z.enum() requires an array literal argument.`
|
|
2287
|
-
);
|
|
2288
|
-
}
|
|
2289
|
-
const arr = arg.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
2290
|
-
const values = arr.getElements().map((el) => {
|
|
2291
|
-
if (!el.isKind(SyntaxKind.StringLiteral)) {
|
|
2292
|
-
throw new BundleError(
|
|
2293
|
-
`${fileName}: Tool \`${toolName}\`: z.enum() values must be string literals.`
|
|
2294
|
-
);
|
|
2295
|
-
}
|
|
2296
|
-
return el.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
2297
|
-
});
|
|
2298
|
-
return {
|
|
2299
|
-
schema: { type: "string", enum: values },
|
|
2300
|
-
optional: false
|
|
2301
|
-
};
|
|
2302
|
-
}
|
|
2303
|
-
case "array": {
|
|
2304
|
-
const args = call.getArguments();
|
|
2305
|
-
const arg = args[0];
|
|
2306
|
-
if (!arg) {
|
|
2307
|
-
return { schema: { type: "array" }, optional: false };
|
|
2308
|
-
}
|
|
2309
|
-
const items = parseZodExpr(arg, toolName, fileName);
|
|
2310
|
-
return {
|
|
2311
|
-
schema: { type: "array", items: items.schema },
|
|
2312
|
-
optional: false
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
case "object": {
|
|
2316
|
-
const args = call.getArguments();
|
|
2317
|
-
const arg = args[0];
|
|
2318
|
-
if (!arg || !arg.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
2319
|
-
return {
|
|
2320
|
-
schema: {
|
|
2321
|
-
type: "object",
|
|
2322
|
-
properties: {},
|
|
2323
|
-
additionalProperties: false
|
|
2324
|
-
},
|
|
2325
|
-
optional: false
|
|
2326
|
-
};
|
|
2327
|
-
}
|
|
2328
|
-
const objLit = arg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
2329
|
-
const properties = {};
|
|
2330
|
-
const required = [];
|
|
2331
|
-
for (const member of objLit.getProperties()) {
|
|
2332
|
-
if (!member.isKind(SyntaxKind.PropertyAssignment)) continue;
|
|
2333
|
-
const prop = member;
|
|
2334
|
-
const propName = prop.getName();
|
|
2335
|
-
const result = parseZodExpr(prop.getInitializer(), toolName, fileName);
|
|
2336
|
-
properties[propName] = result.schema;
|
|
2337
|
-
if (!result.optional) {
|
|
2338
|
-
required.push(propName);
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
const schema = {
|
|
2342
|
-
type: "object",
|
|
2343
|
-
properties,
|
|
2344
|
-
additionalProperties: false
|
|
2345
|
-
};
|
|
2346
|
-
if (required.length > 0) {
|
|
2347
|
-
schema.required = required;
|
|
2348
|
-
}
|
|
2349
|
-
return { schema, optional: false };
|
|
2350
|
-
}
|
|
2351
|
-
default:
|
|
2352
|
-
throw new BundleError(
|
|
2353
|
-
`${fileName}: Tool \`${toolName}\`: unsupported Zod type \`z.${method}()\`. Supported: z.string(), z.number(), z.boolean(), z.enum([...]), z.array(...), z.object({...}).`
|
|
2354
|
-
);
|
|
2355
|
-
}
|
|
2356
|
-
}
|
|
2357
|
-
function zodError(node, toolName, fileName) {
|
|
2358
|
-
const text = node.getText().slice(0, 60);
|
|
2359
|
-
return new BundleError(
|
|
2360
|
-
`${fileName}: Tool \`${toolName}\`: unsupported Zod pattern \`${text}\`. Supported: z.string(), z.number(), z.boolean(), z.enum([...]), z.array(...), z.object({...}), .describe(), .optional().`
|
|
2361
|
-
);
|
|
2362
|
-
}
|
|
2363
|
-
function getProperty(obj, name) {
|
|
2364
|
-
const prop = obj.getProperty(name);
|
|
2365
|
-
if (!prop) return void 0;
|
|
2366
|
-
if (!prop.isKind(SyntaxKind.PropertyAssignment)) return void 0;
|
|
2367
|
-
return prop;
|
|
2368
|
-
}
|
|
2369
|
-
function requireString(obj, field, fileName) {
|
|
2370
|
-
const prop = getProperty(obj, field);
|
|
2371
|
-
if (!prop) {
|
|
2372
|
-
throw new BundleError(`${fileName}: The \`${field}\` field is required in defineAgent({...}).`);
|
|
2373
|
-
}
|
|
2374
|
-
return evalStringLiteral(prop.getInitializer(), field, fileName);
|
|
2375
|
-
}
|
|
2376
|
-
function optionalString(obj, field, fileName) {
|
|
2377
|
-
const prop = getProperty(obj, field);
|
|
2378
|
-
if (!prop) return void 0;
|
|
2379
|
-
return evalStringLiteral(prop.getInitializer(), field, fileName);
|
|
2380
|
-
}
|
|
2381
|
-
function evalStringLiteral(node, context, fileName) {
|
|
2382
|
-
if (node.isKind(SyntaxKind.StringLiteral)) {
|
|
2383
|
-
return node.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
2384
|
-
}
|
|
2385
|
-
if (node.isKind(SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
2386
|
-
return node.asKindOrThrow(SyntaxKind.NoSubstitutionTemplateLiteral).getLiteralValue();
|
|
2387
|
-
}
|
|
2388
|
-
if (node.isKind(SyntaxKind.TemplateExpression)) {
|
|
2389
|
-
throw new BundleError(
|
|
2390
|
-
`${fileName}: \`${context}\` uses template expressions with substitutions, which cannot be statically analyzed. Use a plain string literal.`
|
|
2391
|
-
);
|
|
2392
|
-
}
|
|
2393
|
-
throw new BundleError(
|
|
2394
|
-
`${fileName}: \`${context}\` must be a static string literal. Dynamic expressions cannot be analyzed at build time.`
|
|
2395
|
-
);
|
|
2396
|
-
}
|
|
2397
|
-
function evalStringArray(node, context, fileName) {
|
|
2398
|
-
if (!node.isKind(SyntaxKind.ArrayLiteralExpression)) {
|
|
2399
|
-
throw new BundleError(`${fileName}: \`${context}\` must be an array literal.`);
|
|
2400
|
-
}
|
|
2401
|
-
const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
2402
|
-
return arr.getElements().map((el) => evalStringLiteral(el, context, fileName));
|
|
2403
|
-
}
|
|
2404
|
-
function evalLiteral(node, context, fileName) {
|
|
2405
|
-
if (node.isKind(SyntaxKind.StringLiteral)) {
|
|
2406
|
-
return node.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
|
|
2407
|
-
}
|
|
2408
|
-
if (node.isKind(SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
|
2409
|
-
return node.asKindOrThrow(SyntaxKind.NoSubstitutionTemplateLiteral).getLiteralValue();
|
|
2410
|
-
}
|
|
2411
|
-
if (node.isKind(SyntaxKind.NumericLiteral)) {
|
|
2412
|
-
return Number(node.asKindOrThrow(SyntaxKind.NumericLiteral).getLiteralValue());
|
|
2413
|
-
}
|
|
2414
|
-
if (node.isKind(SyntaxKind.TrueKeyword)) return true;
|
|
2415
|
-
if (node.isKind(SyntaxKind.FalseKeyword)) return false;
|
|
2416
|
-
if (node.isKind(SyntaxKind.ArrayLiteralExpression)) {
|
|
2417
|
-
return node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression).getElements().map((el) => evalLiteral(el, context, fileName));
|
|
2418
|
-
}
|
|
2419
|
-
if (node.isKind(SyntaxKind.ObjectLiteralExpression)) {
|
|
2420
|
-
const obj = node.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
2421
|
-
const result = {};
|
|
2422
|
-
for (const member of obj.getProperties()) {
|
|
2423
|
-
if (member.isKind(SyntaxKind.PropertyAssignment)) {
|
|
2424
|
-
const prop = member;
|
|
2425
|
-
result[prop.getName()] = evalLiteral(
|
|
2426
|
-
prop.getInitializer(),
|
|
2427
|
-
context,
|
|
2428
|
-
fileName
|
|
2429
|
-
);
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
return result;
|
|
2433
|
-
}
|
|
2434
|
-
throw new BundleError(
|
|
2435
|
-
`${fileName}: \`${context}\` must be a static literal value. Dynamic expressions cannot be analyzed at build time.`
|
|
2436
|
-
);
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
// cli/_bundler.ts
|
|
2440
2182
|
var BundleError = class extends Error {
|
|
2441
2183
|
constructor(message) {
|
|
2442
2184
|
super(message);
|
|
@@ -2558,14 +2300,13 @@ var INDEX_HTML = `<!DOCTYPE html>
|
|
|
2558
2300
|
async function bundleAgent(agent, opts) {
|
|
2559
2301
|
const aaiDir = path2.join(agent.dir, ".aai");
|
|
2560
2302
|
const buildDir = path2.join(aaiDir, "build");
|
|
2561
|
-
await
|
|
2562
|
-
|
|
2563
|
-
await fs3.writeFile(path2.join(aaiDir, "index.html"), INDEX_HTML);
|
|
2303
|
+
await fs2.mkdir(aaiDir, { recursive: true });
|
|
2304
|
+
await fs2.writeFile(path2.join(aaiDir, "index.html"), INDEX_HTML);
|
|
2564
2305
|
const stylesPath = path2.join(agent.dir, "styles.css");
|
|
2565
2306
|
try {
|
|
2566
|
-
await
|
|
2307
|
+
await fs2.access(stylesPath);
|
|
2567
2308
|
} catch {
|
|
2568
|
-
await
|
|
2309
|
+
await fs2.writeFile(stylesPath, DEFAULT_STYLES_CSS);
|
|
2569
2310
|
}
|
|
2570
2311
|
try {
|
|
2571
2312
|
await build({
|
|
@@ -2610,22 +2351,12 @@ async function bundleAgent(agent, opts) {
|
|
|
2610
2351
|
throw new BundleError(err instanceof Error ? err.message : String(err));
|
|
2611
2352
|
}
|
|
2612
2353
|
}
|
|
2613
|
-
const worker = await
|
|
2354
|
+
const worker = await fs2.readFile(path2.join(buildDir, "worker.js"), "utf-8");
|
|
2614
2355
|
const htmlPath = skipClient ? path2.join(aaiDir, "index.html") : path2.join(buildDir, "index.html");
|
|
2615
|
-
const html = await
|
|
2616
|
-
const manifest = JSON.stringify(
|
|
2617
|
-
{
|
|
2618
|
-
transport: agentConfig.transport ?? agent.transport,
|
|
2619
|
-
config: agentConfig,
|
|
2620
|
-
toolSchemas
|
|
2621
|
-
},
|
|
2622
|
-
null,
|
|
2623
|
-
2
|
|
2624
|
-
);
|
|
2356
|
+
const html = await fs2.readFile(htmlPath, "utf-8");
|
|
2625
2357
|
return {
|
|
2626
2358
|
worker,
|
|
2627
2359
|
html,
|
|
2628
|
-
manifest,
|
|
2629
2360
|
workerBytes: Buffer.byteLength(worker)
|
|
2630
2361
|
};
|
|
2631
2362
|
}
|
|
@@ -2634,46 +2365,17 @@ async function bundleAgent(agent, opts) {
|
|
|
2634
2365
|
init_output();
|
|
2635
2366
|
async function writeBuildOutput(agentDir, bundle) {
|
|
2636
2367
|
const buildDir = path3.join(agentDir, ".aai", "build");
|
|
2637
|
-
await
|
|
2368
|
+
await fs3.mkdir(buildDir, { recursive: true });
|
|
2638
2369
|
await Promise.all([
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
fs4.writeFile(path3.join(buildDir, "index.html"), bundle.html)
|
|
2370
|
+
fs3.writeFile(path3.join(buildDir, "worker.js"), bundle.worker),
|
|
2371
|
+
fs3.writeFile(path3.join(buildDir, "index.html"), bundle.html)
|
|
2642
2372
|
]);
|
|
2643
2373
|
}
|
|
2644
|
-
async function checkAgent(agentDir) {
|
|
2645
|
-
const userFiles = ["agent.ts"];
|
|
2646
|
-
for (const f of ["client.tsx", "components.tsx"]) {
|
|
2647
|
-
try {
|
|
2648
|
-
await fs4.stat(path3.join(agentDir, f));
|
|
2649
|
-
userFiles.push(f);
|
|
2650
|
-
} catch {
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
const checks = [{ args: ["--noEmit", ...userFiles], label: "Type-check" }];
|
|
2654
|
-
const results = await Promise.allSettled(
|
|
2655
|
-
checks.map(({ args }) => execFileAsync("npx", ["tsc", ...args], { cwd: agentDir }))
|
|
2656
|
-
);
|
|
2657
|
-
const errors = [];
|
|
2658
|
-
for (let i = 0; i < results.length; i++) {
|
|
2659
|
-
const r = results[i];
|
|
2660
|
-
if (r.status === "rejected") {
|
|
2661
|
-
const msg = r.reason.stderr?.trim() ?? String(r.reason);
|
|
2662
|
-
error2(`${checks[i].label}: ${msg}`);
|
|
2663
|
-
errors.push(checks[i].label);
|
|
2664
|
-
}
|
|
2665
|
-
}
|
|
2666
|
-
if (errors.length > 0) {
|
|
2667
|
-
throw new Error(`${errors.join(", ")} failed \u2014 fix the errors above`);
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
2374
|
async function runBuild(opts) {
|
|
2671
2375
|
const agent = await loadAgent(opts.agentDir);
|
|
2672
2376
|
if (!agent) {
|
|
2673
2377
|
throw new Error("No agent found \u2014 run `aai new` first");
|
|
2674
2378
|
}
|
|
2675
|
-
step("Check", agent.slug);
|
|
2676
|
-
await checkAgent(opts.agentDir);
|
|
2677
2379
|
step("Bundle", agent.slug);
|
|
2678
2380
|
let bundle;
|
|
2679
2381
|
try {
|
|
@@ -2691,7 +2393,7 @@ async function runBuild(opts) {
|
|
|
2691
2393
|
|
|
2692
2394
|
// cli/new.tsx
|
|
2693
2395
|
init_colors();
|
|
2694
|
-
import
|
|
2396
|
+
import fs5 from "node:fs/promises";
|
|
2695
2397
|
import path5 from "node:path";
|
|
2696
2398
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2697
2399
|
import minimist from "minimist";
|
|
@@ -2767,14 +2469,14 @@ async function runNewCommand(args, version) {
|
|
|
2767
2469
|
if (isDevMode()) {
|
|
2768
2470
|
const monorepoRoot = path5.join(cliDir2, "..");
|
|
2769
2471
|
const pkgJsonPath2 = path5.join(cwd, "package.json");
|
|
2770
|
-
const pkgJson2 = JSON.parse(await
|
|
2472
|
+
const pkgJson2 = JSON.parse(await fs5.readFile(pkgJsonPath2, "utf-8"));
|
|
2771
2473
|
for (const pkg of ["sdk", "ui"]) {
|
|
2772
2474
|
const localPkgPath = path5.join(monorepoRoot, pkg, "package.json");
|
|
2773
|
-
const localPkg = JSON.parse(await
|
|
2475
|
+
const localPkg = JSON.parse(await fs5.readFile(localPkgPath, "utf-8"));
|
|
2774
2476
|
const pkgName = localPkg.name;
|
|
2775
2477
|
pkgJson2.dependencies[pkgName] = `file:${path5.join(monorepoRoot, pkg)}`;
|
|
2776
2478
|
}
|
|
2777
|
-
await
|
|
2479
|
+
await fs5.writeFile(pkgJsonPath2, `${JSON.stringify(pkgJson2, null, 2)}
|
|
2778
2480
|
`);
|
|
2779
2481
|
}
|
|
2780
2482
|
await ensureClaudeMd(cwd);
|
|
@@ -2868,7 +2570,9 @@ async function loadAgentDef(cwd) {
|
|
|
2868
2570
|
}
|
|
2869
2571
|
}
|
|
2870
2572
|
async function resolveServerEnv() {
|
|
2871
|
-
const env =
|
|
2573
|
+
const env = Object.fromEntries(
|
|
2574
|
+
Object.entries(process.env).filter((e) => e[1] !== void 0)
|
|
2575
|
+
);
|
|
2872
2576
|
if (!env.ASSEMBLYAI_API_KEY) {
|
|
2873
2577
|
try {
|
|
2874
2578
|
env.ASSEMBLYAI_API_KEY = await getApiKey();
|
|
@@ -3042,14 +2746,26 @@ async function runRag(opts) {
|
|
|
3042
2746
|
log(/* @__PURE__ */ jsx4(Step, { action: "Parsed", msg: `${pages.length} pages` }));
|
|
3043
2747
|
const { RecursiveChunker } = await import("@chonkiejs/core");
|
|
3044
2748
|
const chunker = await RecursiveChunker.create({ chunkSize });
|
|
3045
|
-
const allChunks = [];
|
|
3046
2749
|
const siteSlug = slugify(origin);
|
|
2750
|
+
const allChunks = await chunkPages(pages, chunker, origin, siteSlug);
|
|
2751
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Chunked", msg: `${allChunks.length} chunks` }));
|
|
2752
|
+
const vectorUrl = `${serverUrl}/${slug}/vector`;
|
|
2753
|
+
log(/* @__PURE__ */ jsx4(Info, { msg: `target: ${vectorUrl}` }));
|
|
2754
|
+
const result = await upsertChunks(allChunks, vectorUrl, apiKey, setProgress);
|
|
2755
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Done", msg: `${result.upserted} chunks upserted` }));
|
|
2756
|
+
if (result.errors > 0) {
|
|
2757
|
+
log(/* @__PURE__ */ jsx4(Warn, { msg: `${result.errors} failed` }));
|
|
2758
|
+
if (result.lastError) log(/* @__PURE__ */ jsx4(Info, { msg: `last error: ${result.lastError}` }));
|
|
2759
|
+
}
|
|
2760
|
+
log(/* @__PURE__ */ jsx4(Detail, { msg: `Agent: ${slug}` }));
|
|
2761
|
+
}
|
|
2762
|
+
async function chunkPages(pages, chunker, origin, siteSlug) {
|
|
2763
|
+
const allChunks = [];
|
|
3047
2764
|
for (const page of pages) {
|
|
3048
2765
|
page.body = stripNoise(page.body);
|
|
3049
2766
|
if (!page.body) continue;
|
|
3050
2767
|
const raw = await chunker.chunk(page.body);
|
|
3051
|
-
for (
|
|
3052
|
-
const c = raw[i];
|
|
2768
|
+
for (const [i, c] of raw.entries()) {
|
|
3053
2769
|
const data = page.title ? `${page.title}
|
|
3054
2770
|
|
|
3055
2771
|
${c.text}` : c.text;
|
|
@@ -3065,10 +2781,10 @@ ${c.text}` : c.text;
|
|
|
3065
2781
|
});
|
|
3066
2782
|
}
|
|
3067
2783
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
const total =
|
|
2784
|
+
return allChunks;
|
|
2785
|
+
}
|
|
2786
|
+
async function upsertChunks(chunks, vectorUrl, apiKey, setProgress) {
|
|
2787
|
+
const total = chunks.length;
|
|
3072
2788
|
let completed = 0;
|
|
3073
2789
|
let upserted = 0;
|
|
3074
2790
|
let errors = 0;
|
|
@@ -3076,7 +2792,7 @@ ${c.text}` : c.text;
|
|
|
3076
2792
|
setProgress({ completed: 0, total });
|
|
3077
2793
|
const limit = pLimit(5);
|
|
3078
2794
|
await Promise.all(
|
|
3079
|
-
|
|
2795
|
+
chunks.map(
|
|
3080
2796
|
(chunk) => limit(async () => {
|
|
3081
2797
|
try {
|
|
3082
2798
|
const r = await fetch(vectorUrl, {
|
|
@@ -3107,12 +2823,7 @@ ${c.text}` : c.text;
|
|
|
3107
2823
|
})
|
|
3108
2824
|
)
|
|
3109
2825
|
);
|
|
3110
|
-
|
|
3111
|
-
if (errors > 0) {
|
|
3112
|
-
log(/* @__PURE__ */ jsx4(Warn, { msg: `${errors} failed` }));
|
|
3113
|
-
if (lastError) log(/* @__PURE__ */ jsx4(Info, { msg: `last error: ${lastError}` }));
|
|
3114
|
-
}
|
|
3115
|
-
log(/* @__PURE__ */ jsx4(Detail, { msg: `Agent: ${slug}` }));
|
|
2826
|
+
return { upserted, errors, lastError };
|
|
3116
2827
|
}
|
|
3117
2828
|
async function runRagCommand(args, version) {
|
|
3118
2829
|
const parsed = minimist4(args, {
|
|
@@ -3170,34 +2881,38 @@ function splitPages(content) {
|
|
|
3170
2881
|
for (const section of raw) {
|
|
3171
2882
|
const trimmed = section.trim();
|
|
3172
2883
|
if (!trimmed) continue;
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
if (dashIndex !== -1) {
|
|
3177
|
-
const frontmatter = trimmed.slice(0, dashIndex);
|
|
3178
|
-
body = trimmed.slice(dashIndex).replace(/^-+$/m, "").trim();
|
|
3179
|
-
const titleMatch = frontmatter.match(/^title:\s*(.+)$/m);
|
|
3180
|
-
if (titleMatch) {
|
|
3181
|
-
title = titleMatch[1].trim();
|
|
3182
|
-
}
|
|
2884
|
+
const page = parsePage(trimmed);
|
|
2885
|
+
if (page.body.length > 0) {
|
|
2886
|
+
pages.push(page);
|
|
3183
2887
|
}
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
2888
|
+
}
|
|
2889
|
+
return pages;
|
|
2890
|
+
}
|
|
2891
|
+
function parsePage(trimmed) {
|
|
2892
|
+
let title = "";
|
|
2893
|
+
let body = trimmed;
|
|
2894
|
+
const dashIndex = trimmed.search(/^-{3,}$/m);
|
|
2895
|
+
if (dashIndex !== -1) {
|
|
2896
|
+
const frontmatter = trimmed.slice(0, dashIndex);
|
|
2897
|
+
body = trimmed.slice(dashIndex).replace(/^-+$/m, "").trim();
|
|
2898
|
+
const titleMatch = frontmatter.match(/^title:\s*(.+)$/m);
|
|
2899
|
+
if (titleMatch) {
|
|
2900
|
+
title = titleMatch[1]?.trim() ?? "";
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
if (!title) {
|
|
2904
|
+
const titleLineMatch = body.match(/^#{1,2}\s+title:\s*(.+)$/m);
|
|
2905
|
+
if (titleLineMatch) {
|
|
2906
|
+
title = titleLineMatch[1]?.trim() ?? "";
|
|
2907
|
+
body = body.replace(/^#{1,2}\s+title:\s*.+\n?/m, "").trim();
|
|
2908
|
+
} else {
|
|
2909
|
+
const headingMatch = body.match(/^(#{1,3})\s+(.+)$/m);
|
|
2910
|
+
if (headingMatch) {
|
|
2911
|
+
title = headingMatch[2]?.trim() ?? "";
|
|
3194
2912
|
}
|
|
3195
2913
|
}
|
|
3196
|
-
if (body.length > 0) {
|
|
3197
|
-
pages.push({ title, body });
|
|
3198
|
-
}
|
|
3199
2914
|
}
|
|
3200
|
-
return
|
|
2915
|
+
return { title, body };
|
|
3201
2916
|
}
|
|
3202
2917
|
function stripNoise(text) {
|
|
3203
2918
|
return text.replace(/^(`{3,}|~{3,}).*[\s\S]*?^\1/gm, "").replace(/^(?:[ ]{4,}|\t).+$/gm, "").replace(/`[^`]+`/g, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<[^>]+>/g, "").replace(/^\s*\}[^}\n]*$/gm, "").replace(/^\s+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
@@ -3247,7 +2962,7 @@ async function runSecretCommand(args, version) {
|
|
|
3247
2962
|
}
|
|
3248
2963
|
switch (sub) {
|
|
3249
2964
|
case "put":
|
|
3250
|
-
await secretPut(cwd, String(parsed._[1] ?? ""), secretValue);
|
|
2965
|
+
await secretPut(cwd, String(parsed._[1] ?? ""), secretValue ?? "");
|
|
3251
2966
|
break;
|
|
3252
2967
|
case "delete":
|
|
3253
2968
|
await secretDelete(cwd, String(parsed._[1] ?? ""));
|
|
@@ -3326,11 +3041,11 @@ import minimist6 from "minimist";
|
|
|
3326
3041
|
|
|
3327
3042
|
// cli/_start.ts
|
|
3328
3043
|
init_output();
|
|
3329
|
-
import
|
|
3044
|
+
import fs6 from "node:fs/promises";
|
|
3330
3045
|
import path9 from "node:path";
|
|
3331
3046
|
async function _startProductionServer(cwd, port) {
|
|
3332
3047
|
const buildDir = path9.join(cwd, ".aai", "build");
|
|
3333
|
-
const html = await
|
|
3048
|
+
const html = await fs6.readFile(path9.join(buildDir, "index.html"), "utf-8");
|
|
3334
3049
|
step("Load", "agent");
|
|
3335
3050
|
const agentDef = await loadAgentDef(cwd);
|
|
3336
3051
|
const env = await resolveServerEnv();
|