@alexkroman1/aai 0.8.2 → 0.8.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/tsconfig.tsbuildinfo +1 -0
- package/dist/cli.js +1368 -1904
- package/dist/sdk/_mock_ws.js +2 -2
- package/dist/sdk/_mock_ws.js.map +1 -1
- package/dist/sdk/_render_check.d.ts.map +1 -1
- package/dist/sdk/_render_check.js +30 -0
- package/dist/sdk/_render_check.js.map +1 -1
- package/dist/sdk/_utils.d.ts +4 -0
- package/dist/sdk/_utils.d.ts.map +1 -0
- package/dist/sdk/_utils.js +7 -0
- package/dist/sdk/_utils.js.map +1 -0
- package/dist/sdk/builtin_tools.d.ts +35 -11
- package/dist/sdk/builtin_tools.d.ts.map +1 -1
- package/dist/sdk/builtin_tools.js +118 -76
- package/dist/sdk/builtin_tools.js.map +1 -1
- package/dist/sdk/capnweb.d.ts +76 -47
- package/dist/sdk/capnweb.d.ts.map +1 -1
- package/dist/sdk/capnweb.js +99 -242
- package/dist/sdk/capnweb.js.map +1 -1
- package/dist/sdk/direct_executor.d.ts.map +1 -1
- package/dist/sdk/direct_executor.js +0 -2
- package/dist/sdk/direct_executor.js.map +1 -1
- package/dist/sdk/host.d.ts +59 -0
- package/dist/sdk/host.d.ts.map +1 -0
- package/dist/sdk/host.js +131 -0
- package/dist/sdk/host.js.map +1 -0
- package/dist/sdk/mod.d.ts +2 -4
- package/dist/sdk/mod.d.ts.map +1 -1
- package/dist/sdk/mod.js +2 -3
- package/dist/sdk/mod.js.map +1 -1
- package/dist/sdk/protocol.d.ts +33 -135
- package/dist/sdk/protocol.d.ts.map +1 -1
- package/dist/sdk/protocol.js +49 -51
- package/dist/sdk/protocol.js.map +1 -1
- package/dist/sdk/runtime.d.ts +0 -1
- package/dist/sdk/runtime.d.ts.map +1 -1
- package/dist/sdk/runtime.js +5 -24
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/sdk/s2s.d.ts +14 -3
- package/dist/sdk/s2s.d.ts.map +1 -1
- package/dist/sdk/s2s.js +72 -113
- package/dist/sdk/s2s.js.map +1 -1
- package/dist/sdk/server.d.ts +1 -1
- package/dist/sdk/server.d.ts.map +1 -1
- package/dist/sdk/server.js +51 -92
- package/dist/sdk/server.js.map +1 -1
- package/dist/sdk/session.d.ts +5 -1
- package/dist/sdk/session.d.ts.map +1 -1
- package/dist/sdk/session.js +131 -137
- package/dist/sdk/session.js.map +1 -1
- package/dist/sdk/tsconfig.tsbuildinfo +1 -0
- package/dist/sdk/types.d.ts +30 -3
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/types.js +37 -0
- package/dist/sdk/types.js.map +1 -1
- package/dist/sdk/winterc_server.d.ts.map +1 -1
- package/dist/sdk/winterc_server.js +10 -15
- package/dist/sdk/winterc_server.js.map +1 -1
- package/dist/sdk/worker_entry.d.ts +3 -11
- package/dist/sdk/worker_entry.d.ts.map +1 -1
- package/dist/sdk/worker_entry.js +8 -18
- package/dist/sdk/worker_entry.js.map +1 -1
- package/dist/sdk/worker_shim.d.ts +5 -6
- package/dist/sdk/worker_shim.d.ts.map +1 -1
- package/dist/sdk/worker_shim.js +93 -136
- package/dist/sdk/worker_shim.js.map +1 -1
- package/dist/sdk/ws_handler.d.ts +1 -1
- package/dist/sdk/ws_handler.d.ts.map +1 -1
- package/dist/sdk/ws_handler.js +13 -22
- package/dist/sdk/ws_handler.js.map +1 -1
- package/dist/ui/_cn.d.ts +5 -0
- package/dist/ui/_cn.d.ts.map +1 -0
- package/dist/ui/_cn.js +22 -0
- package/dist/ui/_cn.js.map +1 -0
- package/dist/ui/_components/app.d.ts +3 -1
- package/dist/ui/_components/app.d.ts.map +1 -1
- package/dist/ui/_components/app.js +2 -2
- package/dist/ui/_components/app.js.map +1 -1
- package/dist/ui/_components/button.d.ts +11 -0
- package/dist/ui/_components/button.d.ts.map +1 -0
- package/dist/ui/_components/button.js +17 -0
- package/dist/ui/_components/button.js.map +1 -0
- package/dist/ui/_components/chat_view.d.ts +3 -1
- package/dist/ui/_components/chat_view.d.ts.map +1 -1
- package/dist/ui/_components/chat_view.js +4 -2
- package/dist/ui/_components/chat_view.js.map +1 -1
- package/dist/ui/_components/controls.d.ts +3 -1
- package/dist/ui/_components/controls.d.ts.map +1 -1
- package/dist/ui/_components/controls.js +4 -5
- package/dist/ui/_components/controls.js.map +1 -1
- package/dist/ui/_components/error_banner.d.ts +2 -1
- package/dist/ui/_components/error_banner.d.ts.map +1 -1
- package/dist/ui/_components/error_banner.js +3 -2
- package/dist/ui/_components/error_banner.js.map +1 -1
- package/dist/ui/_components/message_bubble.d.ts +2 -1
- package/dist/ui/_components/message_bubble.d.ts.map +1 -1
- package/dist/ui/_components/message_bubble.js +5 -3
- package/dist/ui/_components/message_bubble.js.map +1 -1
- package/dist/ui/_components/message_list.d.ts +3 -1
- package/dist/ui/_components/message_list.d.ts.map +1 -1
- package/dist/ui/_components/message_list.js +7 -15
- package/dist/ui/_components/message_list.js.map +1 -1
- package/dist/ui/_components/sidebar_layout.d.ts +2 -1
- package/dist/ui/_components/sidebar_layout.d.ts.map +1 -1
- package/dist/ui/_components/sidebar_layout.js +5 -7
- package/dist/ui/_components/sidebar_layout.js.map +1 -1
- package/dist/ui/_components/start_screen.d.ts +2 -1
- package/dist/ui/_components/start_screen.d.ts.map +1 -1
- package/dist/ui/_components/start_screen.js +5 -2
- package/dist/ui/_components/start_screen.js.map +1 -1
- package/dist/ui/_components/state_indicator.d.ts +2 -1
- package/dist/ui/_components/state_indicator.d.ts.map +1 -1
- package/dist/ui/_components/state_indicator.js +3 -2
- package/dist/ui/_components/state_indicator.js.map +1 -1
- package/dist/ui/_components/thinking_indicator.d.ts +3 -1
- package/dist/ui/_components/thinking_indicator.d.ts.map +1 -1
- package/dist/ui/_components/thinking_indicator.js +4 -2
- package/dist/ui/_components/thinking_indicator.js.map +1 -1
- package/dist/ui/_components/tool_call_block.d.ts +2 -1
- package/dist/ui/_components/tool_call_block.d.ts.map +1 -1
- package/dist/ui/_components/tool_call_block.js +13 -25
- package/dist/ui/_components/tool_call_block.js.map +1 -1
- package/dist/ui/_components/transcript.d.ts +2 -1
- package/dist/ui/_components/transcript.d.ts.map +1 -1
- package/dist/ui/_components/transcript.js +3 -2
- package/dist/ui/_components/transcript.js.map +1 -1
- package/dist/ui/_jsdom_setup.d.ts +1 -0
- package/dist/ui/_jsdom_setup.d.ts.map +1 -0
- package/dist/ui/_jsdom_setup.js +6 -0
- package/dist/ui/_jsdom_setup.js.map +1 -0
- package/dist/ui/audio.d.ts.map +1 -1
- package/dist/ui/audio.js +4 -4
- package/dist/ui/audio.js.map +1 -1
- package/dist/ui/components.d.ts +13 -55
- package/dist/ui/components.d.ts.map +1 -1
- package/dist/ui/components.js +13 -42
- package/dist/ui/components.js.map +1 -1
- package/dist/ui/components_mod.d.ts +14 -3
- package/dist/ui/components_mod.d.ts.map +1 -1
- package/dist/ui/components_mod.js +14 -3
- package/dist/ui/components_mod.js.map +1 -1
- package/dist/ui/mod.d.ts +1 -8
- package/dist/ui/mod.d.ts.map +1 -1
- package/dist/ui/mod.js +1 -5
- package/dist/ui/mod.js.map +1 -1
- package/dist/ui/mount.d.ts +1 -1
- package/dist/ui/mount.d.ts.map +1 -1
- package/dist/ui/mount.js +1 -0
- package/dist/ui/mount.js.map +1 -1
- package/dist/ui/session.d.ts +0 -2
- package/dist/ui/session.d.ts.map +1 -1
- package/dist/ui/session.js +9 -6
- package/dist/ui/session.js.map +1 -1
- package/dist/ui/signals.d.ts +8 -3
- package/dist/ui/signals.d.ts.map +1 -1
- package/dist/ui/signals.js +22 -11
- package/dist/ui/signals.js.map +1 -1
- package/dist/ui/tsconfig.tsbuildinfo +1 -0
- package/dist/ui/worklets/playback-processor.js +3 -3
- package/package.json +39 -16
- package/templates/_shared/CLAUDE.md +50 -30
- package/templates/_shared/global.d.ts +1 -0
- package/templates/_shared/package.json +2 -1
- package/templates/dispatch-center/agent.ts +85 -397
- package/templates/solo-rpg/agent.ts +1240 -0
- package/templates/solo-rpg/client.tsx +698 -0
package/dist/cli.js
CHANGED
|
@@ -9,17 +9,143 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
//
|
|
12
|
+
// sdk/_utils.ts
|
|
13
|
+
function errorMessage(err) {
|
|
14
|
+
return err instanceof Error ? err.message : String(err);
|
|
15
|
+
}
|
|
16
|
+
var init_utils = __esm({
|
|
17
|
+
"sdk/_utils.ts"() {
|
|
18
|
+
"use strict";
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// cli/_ink.tsx
|
|
23
|
+
import { Spinner, StatusMessage } from "@inkjs/ui";
|
|
13
24
|
import chalk from "chalk";
|
|
25
|
+
import { Box, render, Static, Text, useApp } from "ink";
|
|
26
|
+
import React, { useRef, useState } from "react";
|
|
27
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
28
|
function primary(s) {
|
|
15
29
|
return chalk.hex(COLORS.primary)(s);
|
|
16
30
|
}
|
|
17
31
|
function interactive(s) {
|
|
18
32
|
return chalk.hex(COLORS.interactive)(s);
|
|
19
33
|
}
|
|
34
|
+
function StepBase({ action, msg, color }) {
|
|
35
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
36
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color, children: action }),
|
|
37
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
38
|
+
" ",
|
|
39
|
+
msg
|
|
40
|
+
] })
|
|
41
|
+
] });
|
|
42
|
+
}
|
|
43
|
+
function Step({ action, msg }) {
|
|
44
|
+
return /* @__PURE__ */ jsx(StepBase, { action, msg, color: COLORS.primary });
|
|
45
|
+
}
|
|
46
|
+
function StepInfo({ action, msg }) {
|
|
47
|
+
return /* @__PURE__ */ jsx(StepBase, { action, msg, color: COLORS.interactive });
|
|
48
|
+
}
|
|
49
|
+
function Info({ msg }) {
|
|
50
|
+
return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
51
|
+
" ",
|
|
52
|
+
msg
|
|
53
|
+
] });
|
|
54
|
+
}
|
|
55
|
+
function Detail({ msg }) {
|
|
56
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
57
|
+
" ",
|
|
58
|
+
msg
|
|
59
|
+
] });
|
|
60
|
+
}
|
|
61
|
+
function Warn({ msg }) {
|
|
62
|
+
return /* @__PURE__ */ jsx(StatusMessage, { variant: "warning", children: msg });
|
|
63
|
+
}
|
|
64
|
+
function ErrorLine({ msg }) {
|
|
65
|
+
return /* @__PURE__ */ jsx(StatusMessage, { variant: "error", children: msg });
|
|
66
|
+
}
|
|
67
|
+
function StepLog({ items }) {
|
|
68
|
+
return /* @__PURE__ */ jsx(Static, { items, children: (item) => /* @__PURE__ */ jsx(Box, { children: item.node }, item.id) });
|
|
69
|
+
}
|
|
70
|
+
function useStepLog() {
|
|
71
|
+
const [items, setItems] = useState([]);
|
|
72
|
+
const nextId = useRef(0);
|
|
73
|
+
const log = (node) => {
|
|
74
|
+
const id = nextId.current++;
|
|
75
|
+
setItems((prev) => [...prev, { id, node }]);
|
|
76
|
+
};
|
|
77
|
+
return { items, log };
|
|
78
|
+
}
|
|
79
|
+
function CommandRunner({
|
|
80
|
+
run,
|
|
81
|
+
onError
|
|
82
|
+
}) {
|
|
83
|
+
const { exit } = useApp();
|
|
84
|
+
const { items, log } = useStepLog();
|
|
85
|
+
const [spinning, setSpinning] = useState(true);
|
|
86
|
+
const [currentStep, setCurrentStep] = useState(null);
|
|
87
|
+
const [statusLine, setStatusLine] = useState(null);
|
|
88
|
+
const [err, setErr] = useState(null);
|
|
89
|
+
const currentStepRef = useRef(null);
|
|
90
|
+
const wrappedLog = (node) => {
|
|
91
|
+
if (currentStepRef.current) {
|
|
92
|
+
log(currentStepRef.current);
|
|
93
|
+
}
|
|
94
|
+
currentStepRef.current = node;
|
|
95
|
+
setCurrentStep(node);
|
|
96
|
+
};
|
|
97
|
+
const started = useRef(false);
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
if (started.current) return;
|
|
100
|
+
started.current = true;
|
|
101
|
+
(async () => {
|
|
102
|
+
try {
|
|
103
|
+
await run({ log: wrappedLog, setStatus: setStatusLine });
|
|
104
|
+
} catch (e) {
|
|
105
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
106
|
+
setErr(error.message);
|
|
107
|
+
onError?.(error);
|
|
108
|
+
}
|
|
109
|
+
if (currentStepRef.current) {
|
|
110
|
+
log(currentStepRef.current);
|
|
111
|
+
currentStepRef.current = null;
|
|
112
|
+
}
|
|
113
|
+
setCurrentStep(null);
|
|
114
|
+
setStatusLine(null);
|
|
115
|
+
setSpinning(false);
|
|
116
|
+
setTimeout(() => exit(), 0);
|
|
117
|
+
})();
|
|
118
|
+
});
|
|
119
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
120
|
+
/* @__PURE__ */ jsx(StepLog, { items }),
|
|
121
|
+
err && /* @__PURE__ */ jsx(ErrorLine, { msg: err }),
|
|
122
|
+
spinning && currentStep && /* @__PURE__ */ jsxs(Box, { children: [
|
|
123
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
124
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
125
|
+
currentStep
|
|
126
|
+
] }),
|
|
127
|
+
spinning && statusLine && /* @__PURE__ */ jsx(Box, { children: statusLine })
|
|
128
|
+
] });
|
|
129
|
+
}
|
|
130
|
+
async function runWithInk(fn) {
|
|
131
|
+
let thrownError;
|
|
132
|
+
const app = render(
|
|
133
|
+
/* @__PURE__ */ jsx(
|
|
134
|
+
CommandRunner,
|
|
135
|
+
{
|
|
136
|
+
onError: (e) => {
|
|
137
|
+
thrownError = e;
|
|
138
|
+
},
|
|
139
|
+
run: fn
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
await app.waitUntilExit();
|
|
144
|
+
if (thrownError) throw thrownError;
|
|
145
|
+
}
|
|
20
146
|
var COLORS;
|
|
21
|
-
var
|
|
22
|
-
"cli/
|
|
147
|
+
var init_ink = __esm({
|
|
148
|
+
"cli/_ink.tsx"() {
|
|
23
149
|
"use strict";
|
|
24
150
|
if (chalk.level === 0 && !process.env.NO_COLOR) {
|
|
25
151
|
const ct = process.env.COLORTERM;
|
|
@@ -43,200 +169,61 @@ var init_colors = __esm({
|
|
|
43
169
|
}
|
|
44
170
|
});
|
|
45
171
|
|
|
46
|
-
// cli/_help.ts
|
|
47
|
-
import chalk2 from "chalk";
|
|
48
|
-
function rootHelp(version) {
|
|
49
|
-
const lines = [];
|
|
50
|
-
lines.push("");
|
|
51
|
-
lines.push(
|
|
52
|
-
` ${primary(chalk2.bold(" \u2584\u2580\u2588 \u2584\u2580\u2588 \u2588"))} ${chalk2.dim("Voice agent development kit")}`
|
|
53
|
-
);
|
|
54
|
-
lines.push(` ${primary(chalk2.bold(" \u2588\u2580\u2588 \u2588\u2580\u2588 \u2588"))} ${primary(`v${version}`)}`);
|
|
55
|
-
lines.push("");
|
|
56
|
-
lines.push(
|
|
57
|
-
` ${chalk2.bold(interactive("Usage"))} ${primary("aai")} ${chalk2.dim("<command> [options]")}`
|
|
58
|
-
);
|
|
59
|
-
lines.push("");
|
|
60
|
-
lines.push(` ${chalk2.bold(interactive("Commands"))}`);
|
|
61
|
-
lines.push("");
|
|
62
|
-
const cmds = [
|
|
63
|
-
["init", "[dir]", "Scaffold a new agent project"],
|
|
64
|
-
["dev", "", "Start a local development server"],
|
|
65
|
-
["build", "", "Bundle and validate (no server or deploy)"],
|
|
66
|
-
["deploy", "", "Bundle and deploy to production"],
|
|
67
|
-
["start", "", "Start production server from build"],
|
|
68
|
-
["secret", "<cmd>", "Manage secrets"],
|
|
69
|
-
["rag", "<url>", "Ingest a site into the vector store"]
|
|
70
|
-
];
|
|
71
|
-
for (const [name, args, desc] of cmds) {
|
|
72
|
-
const nameStr = interactive(name.padEnd(8));
|
|
73
|
-
const argsStr = args ? primary(args.padEnd(6)) : " ";
|
|
74
|
-
lines.push(` ${nameStr} ${argsStr} ${chalk2.dim(desc)}`);
|
|
75
|
-
}
|
|
76
|
-
lines.push("");
|
|
77
|
-
lines.push(` ${chalk2.bold(interactive("Options"))}`);
|
|
78
|
-
lines.push("");
|
|
79
|
-
lines.push(
|
|
80
|
-
` ${interactive("-h")}${chalk2.dim(",")} ${interactive("--help")} ${chalk2.dim(
|
|
81
|
-
"Show this help"
|
|
82
|
-
)}`
|
|
83
|
-
);
|
|
84
|
-
lines.push(
|
|
85
|
-
` ${interactive("-V")}${chalk2.dim(",")} ${interactive("--version")} ${chalk2.dim(
|
|
86
|
-
"Show the version number"
|
|
87
|
-
)}`
|
|
88
|
-
);
|
|
89
|
-
lines.push("");
|
|
90
|
-
lines.push(` ${chalk2.bold(interactive("Getting started"))}`);
|
|
91
|
-
lines.push("");
|
|
92
|
-
lines.push(` ${chalk2.dim("$")} ${primary("aai init")} ${interactive("my-agent")}`);
|
|
93
|
-
lines.push(` ${chalk2.dim("$")} ${primary("cd")} ${interactive("my-agent")}`);
|
|
94
|
-
lines.push(` ${chalk2.dim("$")} ${primary("aai dev")}`);
|
|
95
|
-
lines.push("");
|
|
96
|
-
return lines.join("\n");
|
|
97
|
-
}
|
|
98
|
-
function subcommandHelp(cmd, version) {
|
|
99
|
-
const lines = [];
|
|
100
|
-
lines.push("");
|
|
101
|
-
lines.push(
|
|
102
|
-
` ${primary(chalk2.bold("aai"))} ${interactive(chalk2.bold(cmd.name))}${version ? chalk2.dim(` v${version}`) : ""}`
|
|
103
|
-
);
|
|
104
|
-
lines.push(` ${chalk2.dim(cmd.description)}`);
|
|
105
|
-
lines.push("");
|
|
106
|
-
if (cmd.args && cmd.args.length > 0) {
|
|
107
|
-
lines.push(` ${chalk2.bold(interactive("Arguments"))}`);
|
|
108
|
-
lines.push("");
|
|
109
|
-
for (const arg of cmd.args) {
|
|
110
|
-
const label = arg.optional ? primary(`[${arg.name}]`) : primary(`<${arg.name}>`);
|
|
111
|
-
lines.push(` ${label}`);
|
|
112
|
-
}
|
|
113
|
-
lines.push("");
|
|
114
|
-
}
|
|
115
|
-
const visibleOptions = (cmd.options ?? []).filter((o) => !o.hidden);
|
|
116
|
-
if (visibleOptions.length > 0) {
|
|
117
|
-
lines.push(` ${chalk2.bold(interactive("Options"))}`);
|
|
118
|
-
lines.push("");
|
|
119
|
-
for (const opt of visibleOptions) {
|
|
120
|
-
lines.push(` ${interactive(opt.flags)}`);
|
|
121
|
-
lines.push(` ${chalk2.dim(opt.description)}`);
|
|
122
|
-
}
|
|
123
|
-
lines.push(` ${interactive("-h")}${chalk2.dim(",")} ${interactive("--help")}`);
|
|
124
|
-
lines.push(` ${chalk2.dim("Show this help")}`);
|
|
125
|
-
lines.push("");
|
|
126
|
-
}
|
|
127
|
-
return lines.join("\n");
|
|
128
|
-
}
|
|
129
|
-
var init_help = __esm({
|
|
130
|
-
"cli/_help.ts"() {
|
|
131
|
-
"use strict";
|
|
132
|
-
init_colors();
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
|
|
136
172
|
// cli/_prompts.tsx
|
|
137
173
|
import { ConfirmInput, PasswordInput, Select, TextInput } from "@inkjs/ui";
|
|
138
|
-
import { Box, render, Text } from "ink";
|
|
139
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
140
|
-
|
|
141
|
-
return new Promise((resolve) => {
|
|
142
|
-
const app = render(
|
|
143
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
144
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
145
|
-
message,
|
|
146
|
-
": "
|
|
147
|
-
] }),
|
|
148
|
-
/* @__PURE__ */ jsx(
|
|
149
|
-
PasswordInput,
|
|
150
|
-
{
|
|
151
|
-
onSubmit: (value) => {
|
|
152
|
-
resolve(value);
|
|
153
|
-
app.unmount();
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
)
|
|
157
|
-
] })
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
async function askText(message, defaultValue) {
|
|
174
|
+
import { Box as Box2, render as render2, Text as Text2 } from "ink";
|
|
175
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
176
|
+
function inkPrompt(ui) {
|
|
162
177
|
return new Promise((resolve) => {
|
|
163
|
-
const app =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
] }),
|
|
169
|
-
/* @__PURE__ */ jsx(
|
|
170
|
-
TextInput,
|
|
171
|
-
{
|
|
172
|
-
placeholder: defaultValue,
|
|
173
|
-
onSubmit: (value) => {
|
|
174
|
-
resolve(value || defaultValue);
|
|
175
|
-
app.unmount();
|
|
176
|
-
app.clear();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
)
|
|
180
|
-
] })
|
|
178
|
+
const app = render2(
|
|
179
|
+
ui((value) => {
|
|
180
|
+
resolve(value);
|
|
181
|
+
app.unmount();
|
|
182
|
+
})
|
|
181
183
|
);
|
|
182
184
|
});
|
|
183
185
|
}
|
|
184
|
-
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
186
|
+
function askPassword(message) {
|
|
187
|
+
return inkPrompt((done) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
188
|
+
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
189
|
+
message,
|
|
190
|
+
": "
|
|
191
|
+
] }),
|
|
192
|
+
/* @__PURE__ */ jsx2(PasswordInput, { onSubmit: done })
|
|
193
|
+
] }));
|
|
194
|
+
}
|
|
195
|
+
function askText(message, defaultValue) {
|
|
196
|
+
return inkPrompt((done) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
197
|
+
/* @__PURE__ */ jsxs2(Text2, { color: COLORS.interactive, children: [
|
|
198
|
+
message,
|
|
199
|
+
" \u203A "
|
|
200
|
+
] }),
|
|
201
|
+
/* @__PURE__ */ jsx2(TextInput, { placeholder: defaultValue, onSubmit: (value) => done(value || defaultValue) })
|
|
202
|
+
] }));
|
|
203
|
+
}
|
|
204
|
+
function askEnter(message) {
|
|
205
|
+
return inkPrompt((done) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
206
|
+
/* @__PURE__ */ jsx2(Text2, { color: COLORS.interactive, children: message }),
|
|
207
|
+
/* @__PURE__ */ jsx2(TextInput, { placeholder: "", onSubmit: () => done(void 0) })
|
|
208
|
+
] }));
|
|
202
209
|
}
|
|
203
210
|
var init_prompts = __esm({
|
|
204
211
|
"cli/_prompts.tsx"() {
|
|
205
212
|
"use strict";
|
|
206
|
-
|
|
213
|
+
init_ink();
|
|
207
214
|
}
|
|
208
215
|
});
|
|
209
216
|
|
|
210
217
|
// cli/_discover.ts
|
|
211
|
-
var discover_exports = {};
|
|
212
|
-
__export(discover_exports, {
|
|
213
|
-
DEFAULT_SERVER: () => DEFAULT_SERVER,
|
|
214
|
-
fileExists: () => fileExists,
|
|
215
|
-
generateSlug: () => generateSlug,
|
|
216
|
-
getApiKey: () => getApiKey,
|
|
217
|
-
isDevMode: () => isDevMode,
|
|
218
|
-
loadAgent: () => loadAgent,
|
|
219
|
-
readProjectConfig: () => readProjectConfig,
|
|
220
|
-
writeProjectConfig: () => writeProjectConfig
|
|
221
|
-
});
|
|
222
|
-
import { accessSync } from "node:fs";
|
|
223
218
|
import fs from "node:fs/promises";
|
|
224
219
|
import path from "node:path";
|
|
225
220
|
import { humanId } from "human-id";
|
|
226
|
-
function
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
accessSync(path.join(dir, "sdk"));
|
|
233
|
-
accessSync(path.join(dir, "cli"));
|
|
234
|
-
return true;
|
|
235
|
-
} catch {
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
return false;
|
|
221
|
+
function resolveCwd() {
|
|
222
|
+
return process.env.INIT_CWD || process.cwd();
|
|
223
|
+
}
|
|
224
|
+
function isDevMode(script) {
|
|
225
|
+
script ??= process.argv[1] ?? "";
|
|
226
|
+
return script.endsWith(".ts") || script.endsWith(".tsx");
|
|
240
227
|
}
|
|
241
228
|
function generateSlug() {
|
|
242
229
|
return humanId({ separator: "-", capitalize: false });
|
|
@@ -284,6 +271,18 @@ async function writeProjectConfig(agentDir, data) {
|
|
|
284
271
|
await fs.writeFile(path.join(aaiDir, "project.json"), `${JSON.stringify(data, null, 2)}
|
|
285
272
|
`);
|
|
286
273
|
}
|
|
274
|
+
async function getServerInfo(cwd, explicitServer, explicitApiKey) {
|
|
275
|
+
const config = await readProjectConfig(cwd);
|
|
276
|
+
if (!config) {
|
|
277
|
+
throw new Error("No .aai/project.json found \u2014 deploy first with `aai deploy`");
|
|
278
|
+
}
|
|
279
|
+
const apiKey = explicitApiKey ?? await getApiKey();
|
|
280
|
+
const serverUrl = resolveServerUrl(explicitServer, config.serverUrl);
|
|
281
|
+
return { serverUrl, slug: config.slug, apiKey };
|
|
282
|
+
}
|
|
283
|
+
function resolveServerUrl(explicit, configUrl) {
|
|
284
|
+
return explicit || configUrl || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
285
|
+
}
|
|
287
286
|
async function fileExists(p) {
|
|
288
287
|
try {
|
|
289
288
|
await fs.access(p);
|
|
@@ -316,86 +315,173 @@ var init_discover = __esm({
|
|
|
316
315
|
}
|
|
317
316
|
});
|
|
318
317
|
|
|
319
|
-
// cli/
|
|
318
|
+
// cli/_init.ts
|
|
319
|
+
var init_exports = {};
|
|
320
|
+
__export(init_exports, {
|
|
321
|
+
listTemplates: () => listTemplates,
|
|
322
|
+
runInit: () => runInit
|
|
323
|
+
});
|
|
320
324
|
import fs2 from "node:fs/promises";
|
|
321
325
|
import path2 from "node:path";
|
|
326
|
+
async function listTemplates(dir) {
|
|
327
|
+
const templates = [];
|
|
328
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
329
|
+
for (const entry of entries) {
|
|
330
|
+
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
331
|
+
templates.push(entry.name);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return templates.sort();
|
|
335
|
+
}
|
|
336
|
+
async function copyDirNoOverwrite(src, dest) {
|
|
337
|
+
const entries = await fs2.readdir(src, { recursive: true, withFileTypes: true });
|
|
338
|
+
for (const entry of entries) {
|
|
339
|
+
if (!entry.isFile()) continue;
|
|
340
|
+
const rel = path2.relative(src, path2.join(entry.parentPath, entry.name));
|
|
341
|
+
const destPath = path2.join(dest, rel);
|
|
342
|
+
await fs2.mkdir(path2.dirname(destPath), { recursive: true });
|
|
343
|
+
try {
|
|
344
|
+
await fs2.copyFile(path2.join(src, rel), destPath, fs2.constants.COPYFILE_EXCL);
|
|
345
|
+
} catch (err) {
|
|
346
|
+
if (err.code !== "EEXIST") throw err;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async function runInit(opts) {
|
|
351
|
+
const { targetDir, template, templatesDir } = opts;
|
|
352
|
+
const available = await listTemplates(templatesDir);
|
|
353
|
+
if (!available.includes(template)) {
|
|
354
|
+
throw new Error(`unknown template '${template}' -- available: ${available.join(", ")}`);
|
|
355
|
+
}
|
|
356
|
+
await fs2.cp(path2.join(templatesDir, template), targetDir, { recursive: true, force: true });
|
|
357
|
+
await copyDirNoOverwrite(path2.join(templatesDir, "_shared"), targetDir);
|
|
358
|
+
try {
|
|
359
|
+
await fs2.copyFile(path2.join(targetDir, ".env.example"), path2.join(targetDir, ".env"));
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
const readmePath = path2.join(targetDir, "README.md");
|
|
363
|
+
const slug = path2.basename(path2.resolve(targetDir));
|
|
364
|
+
const readme = `# ${slug}
|
|
365
|
+
|
|
366
|
+
A voice agent built with [aai](https://github.com/anthropics/aai).
|
|
367
|
+
|
|
368
|
+
## Getting started
|
|
369
|
+
|
|
370
|
+
\`\`\`sh
|
|
371
|
+
npm install # Install dependencies
|
|
372
|
+
npm run dev # Run locally (opens browser)
|
|
373
|
+
npm run deploy # Deploy to production
|
|
374
|
+
\`\`\`
|
|
375
|
+
|
|
376
|
+
## Environment variables
|
|
377
|
+
|
|
378
|
+
Secrets are managed on the server, not in local files:
|
|
379
|
+
|
|
380
|
+
\`\`\`sh
|
|
381
|
+
aai env add MY_KEY # Set a secret (prompts for value)
|
|
382
|
+
aai env ls # List secret names
|
|
383
|
+
aai env pull # Pull names into .env for reference
|
|
384
|
+
aai env rm MY_KEY # Remove a secret
|
|
385
|
+
\`\`\`
|
|
386
|
+
|
|
387
|
+
Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
388
|
+
|
|
389
|
+
## Learn more
|
|
390
|
+
|
|
391
|
+
See \`CLAUDE.md\` for the full agent API reference.
|
|
392
|
+
`;
|
|
393
|
+
try {
|
|
394
|
+
await fs2.writeFile(readmePath, readme, { flag: "wx" });
|
|
395
|
+
} catch (err) {
|
|
396
|
+
if (err.code !== "EEXIST") throw err;
|
|
397
|
+
}
|
|
398
|
+
return targetDir;
|
|
399
|
+
}
|
|
400
|
+
var init_init = __esm({
|
|
401
|
+
"cli/_init.ts"() {
|
|
402
|
+
"use strict";
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// cli/_bundler.ts
|
|
407
|
+
import fs3 from "node:fs/promises";
|
|
408
|
+
import path3 from "node:path";
|
|
322
409
|
import preact from "@preact/preset-vite";
|
|
323
410
|
import tailwindcss from "@tailwindcss/vite";
|
|
324
411
|
import { build } from "vite";
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
412
|
+
function workerEntryPlugin() {
|
|
413
|
+
const virtualId = "virtual:worker-entry";
|
|
414
|
+
const resolvedId = `\0${virtualId}`;
|
|
415
|
+
return {
|
|
416
|
+
name: "aai-worker-entry",
|
|
417
|
+
resolveId(source) {
|
|
418
|
+
return source === virtualId ? resolvedId : null;
|
|
419
|
+
},
|
|
420
|
+
load(id) {
|
|
421
|
+
if (id !== resolvedId) return null;
|
|
422
|
+
return [
|
|
423
|
+
`import agent from "./agent.ts";`,
|
|
424
|
+
`import { initWorker } from "@alexkroman1/aai/worker-shim";`,
|
|
425
|
+
`initWorker(agent);`
|
|
426
|
+
].join("\n");
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
async function readDirFiles(dir) {
|
|
431
|
+
let entries;
|
|
328
432
|
try {
|
|
329
|
-
|
|
433
|
+
entries = await fs3.readdir(dir, { recursive: true, withFileTypes: true });
|
|
330
434
|
} catch {
|
|
331
|
-
return
|
|
332
|
-
}
|
|
333
|
-
for (const name of names) {
|
|
334
|
-
const full = path2.join(dir, name);
|
|
335
|
-
const stat = await fs2.stat(full);
|
|
336
|
-
const entry = { name, isDirectory: () => stat.isDirectory() };
|
|
337
|
-
if (entry.isDirectory()) {
|
|
338
|
-
Object.assign(files, await readDirRecursive(full, base));
|
|
339
|
-
} else {
|
|
340
|
-
const rel = path2.relative(base, full);
|
|
341
|
-
files[rel] = await fs2.readFile(full, "utf-8");
|
|
342
|
-
}
|
|
435
|
+
return {};
|
|
343
436
|
}
|
|
437
|
+
const files = {};
|
|
438
|
+
await Promise.all(
|
|
439
|
+
entries.filter((e) => e.isFile()).map(async (e) => {
|
|
440
|
+
const full = path3.join(e.parentPath, e.name);
|
|
441
|
+
files[path3.relative(dir, full)] = await fs3.readFile(full, "utf-8");
|
|
442
|
+
})
|
|
443
|
+
);
|
|
344
444
|
return files;
|
|
345
445
|
}
|
|
346
446
|
async function bundleAgent(agent, opts) {
|
|
347
|
-
const aaiDir =
|
|
348
|
-
const buildDir =
|
|
349
|
-
const clientDir =
|
|
350
|
-
|
|
351
|
-
const
|
|
352
|
-
await fs2.writeFile(
|
|
353
|
-
workerEntry,
|
|
354
|
-
[
|
|
355
|
-
`import agent from "../agent.ts";`,
|
|
356
|
-
`import { initWorker } from "@alexkroman1/aai/worker-shim";`,
|
|
357
|
-
`initWorker(agent);`
|
|
358
|
-
].join("\n")
|
|
359
|
-
);
|
|
447
|
+
const aaiDir = path3.join(agent.dir, ".aai");
|
|
448
|
+
const buildDir = path3.join(aaiDir, "build");
|
|
449
|
+
const clientDir = path3.join(aaiDir, "client");
|
|
450
|
+
const devMode = isDevMode();
|
|
451
|
+
const devResolve = devMode ? { conditions: ["source"] } : {};
|
|
360
452
|
try {
|
|
361
453
|
await build({
|
|
362
454
|
configFile: false,
|
|
363
455
|
root: agent.dir,
|
|
364
456
|
logLevel: "warn",
|
|
457
|
+
plugins: [workerEntryPlugin()],
|
|
458
|
+
resolve: devResolve,
|
|
365
459
|
build: {
|
|
460
|
+
rollupOptions: {
|
|
461
|
+
input: "virtual:worker-entry",
|
|
462
|
+
output: { format: "es", entryFileNames: "worker.js" }
|
|
463
|
+
},
|
|
366
464
|
outDir: buildDir,
|
|
367
465
|
emptyOutDir: true,
|
|
368
466
|
minify: true,
|
|
369
|
-
target: "es2022"
|
|
370
|
-
rollupOptions: {
|
|
371
|
-
input: workerEntry,
|
|
372
|
-
output: {
|
|
373
|
-
format: "es",
|
|
374
|
-
entryFileNames: "worker.js",
|
|
375
|
-
inlineDynamicImports: true
|
|
376
|
-
}
|
|
377
|
-
}
|
|
467
|
+
target: "es2022"
|
|
378
468
|
}
|
|
379
469
|
});
|
|
380
470
|
} catch (err) {
|
|
381
|
-
throw new BundleError(
|
|
471
|
+
throw new BundleError(errorMessage(err));
|
|
382
472
|
}
|
|
383
473
|
const skipClient = opts?.skipClient || !agent.clientEntry;
|
|
384
474
|
if (!skipClient) {
|
|
385
|
-
const devAlias = {};
|
|
386
|
-
if (isDevMode()) {
|
|
387
|
-
const monorepoRoot = path2.resolve(import.meta.dirname ?? __dirname, "..");
|
|
388
|
-
devAlias["@alexkroman1/aai/ui/styles.css"] = path2.join(monorepoRoot, "ui/styles.css");
|
|
389
|
-
devAlias["@alexkroman1/aai/ui"] = path2.join(monorepoRoot, "ui/mod.ts");
|
|
390
|
-
devAlias["@alexkroman1/aai"] = path2.join(monorepoRoot, "sdk/mod.ts");
|
|
391
|
-
}
|
|
392
475
|
try {
|
|
393
476
|
await build({
|
|
394
477
|
root: agent.dir,
|
|
395
478
|
base: "./",
|
|
396
479
|
logLevel: "warn",
|
|
397
480
|
plugins: [preact(), tailwindcss()],
|
|
398
|
-
|
|
481
|
+
resolve: {
|
|
482
|
+
...devResolve,
|
|
483
|
+
...devMode && { dedupe: ["preact", "@preact/signals"] }
|
|
484
|
+
},
|
|
399
485
|
build: {
|
|
400
486
|
outDir: clientDir,
|
|
401
487
|
emptyOutDir: true,
|
|
@@ -404,11 +490,11 @@ async function bundleAgent(agent, opts) {
|
|
|
404
490
|
}
|
|
405
491
|
});
|
|
406
492
|
} catch (err) {
|
|
407
|
-
throw new BundleError(
|
|
493
|
+
throw new BundleError(errorMessage(err));
|
|
408
494
|
}
|
|
409
495
|
}
|
|
410
|
-
const worker = await
|
|
411
|
-
const clientFiles = await
|
|
496
|
+
const worker = await fs3.readFile(path3.join(buildDir, "worker.js"), "utf-8");
|
|
497
|
+
const clientFiles = await readDirFiles(clientDir);
|
|
412
498
|
return {
|
|
413
499
|
worker,
|
|
414
500
|
clientFiles,
|
|
@@ -420,6 +506,7 @@ var BundleError;
|
|
|
420
506
|
var init_bundler = __esm({
|
|
421
507
|
"cli/_bundler.ts"() {
|
|
422
508
|
"use strict";
|
|
509
|
+
init_utils();
|
|
423
510
|
init_discover();
|
|
424
511
|
BundleError = class extends Error {
|
|
425
512
|
constructor(message) {
|
|
@@ -430,150 +517,19 @@ var init_bundler = __esm({
|
|
|
430
517
|
}
|
|
431
518
|
});
|
|
432
519
|
|
|
433
|
-
// cli/
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
function Step({ action, msg }) {
|
|
439
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
440
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.primary, children: action }),
|
|
441
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
442
|
-
" ",
|
|
443
|
-
msg
|
|
444
|
-
] })
|
|
445
|
-
] });
|
|
446
|
-
}
|
|
447
|
-
function StepInfo({ action, msg }) {
|
|
448
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
449
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.interactive, children: action }),
|
|
450
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
451
|
-
" ",
|
|
452
|
-
msg
|
|
453
|
-
] })
|
|
454
|
-
] });
|
|
455
|
-
}
|
|
456
|
-
function Info({ msg }) {
|
|
457
|
-
return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
458
|
-
" ",
|
|
459
|
-
msg
|
|
460
|
-
] });
|
|
461
|
-
}
|
|
462
|
-
function Detail({ msg }) {
|
|
463
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
464
|
-
" ",
|
|
465
|
-
msg
|
|
466
|
-
] });
|
|
467
|
-
}
|
|
468
|
-
function Warn({ msg }) {
|
|
469
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
470
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.warning, children: "\u25B2" }),
|
|
471
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
472
|
-
" ",
|
|
473
|
-
msg
|
|
474
|
-
] })
|
|
475
|
-
] });
|
|
476
|
-
}
|
|
477
|
-
function ErrorLine({ msg }) {
|
|
478
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
479
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.error, children: "\u2717" }),
|
|
480
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
481
|
-
" ",
|
|
482
|
-
msg
|
|
483
|
-
] })
|
|
484
|
-
] });
|
|
485
|
-
}
|
|
486
|
-
function StepLog({ items }) {
|
|
487
|
-
return /* @__PURE__ */ jsx2(Static, { items, children: (item) => /* @__PURE__ */ jsx2(Box2, { children: item.node }, item.id) });
|
|
488
|
-
}
|
|
489
|
-
function useStepLog() {
|
|
490
|
-
const [items, setItems] = useState([]);
|
|
491
|
-
const nextId = useRef(0);
|
|
492
|
-
const log = (node) => {
|
|
493
|
-
const id = nextId.current++;
|
|
494
|
-
setItems((prev) => [...prev, { id, node }]);
|
|
495
|
-
};
|
|
496
|
-
return { items, log };
|
|
497
|
-
}
|
|
498
|
-
function CommandRunner({
|
|
499
|
-
run,
|
|
500
|
-
onError
|
|
501
|
-
}) {
|
|
502
|
-
const { exit } = useApp();
|
|
503
|
-
const { items, log } = useStepLog();
|
|
504
|
-
const [spinning, setSpinning] = useState(true);
|
|
505
|
-
const [currentStep, setCurrentStep] = useState(null);
|
|
506
|
-
const [err, setErr] = useState(null);
|
|
507
|
-
const currentStepRef = useRef(null);
|
|
508
|
-
const wrappedLog = (node) => {
|
|
509
|
-
if (currentStepRef.current) {
|
|
510
|
-
log(currentStepRef.current);
|
|
511
|
-
}
|
|
512
|
-
currentStepRef.current = node;
|
|
513
|
-
setCurrentStep(node);
|
|
514
|
-
};
|
|
515
|
-
const started = useRef(false);
|
|
516
|
-
React.useEffect(() => {
|
|
517
|
-
if (started.current) return;
|
|
518
|
-
started.current = true;
|
|
519
|
-
(async () => {
|
|
520
|
-
try {
|
|
521
|
-
await run(wrappedLog);
|
|
522
|
-
} catch (e) {
|
|
523
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
524
|
-
setErr(error.message);
|
|
525
|
-
onError?.(error);
|
|
526
|
-
}
|
|
527
|
-
if (currentStepRef.current) {
|
|
528
|
-
log(currentStepRef.current);
|
|
529
|
-
currentStepRef.current = null;
|
|
530
|
-
}
|
|
531
|
-
setCurrentStep(null);
|
|
532
|
-
setSpinning(false);
|
|
533
|
-
setTimeout(() => exit(), 0);
|
|
534
|
-
})();
|
|
535
|
-
});
|
|
536
|
-
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
537
|
-
/* @__PURE__ */ jsx2(StepLog, { items }),
|
|
538
|
-
err && /* @__PURE__ */ jsx2(ErrorLine, { msg: err }),
|
|
539
|
-
spinning && currentStep && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
540
|
-
/* @__PURE__ */ jsx2(Spinner, {}),
|
|
541
|
-
/* @__PURE__ */ jsx2(Text2, { children: " " }),
|
|
542
|
-
currentStep
|
|
543
|
-
] })
|
|
544
|
-
] });
|
|
545
|
-
}
|
|
546
|
-
async function runWithInk(fn) {
|
|
547
|
-
let thrownError;
|
|
548
|
-
const app = render2(
|
|
549
|
-
/* @__PURE__ */ jsx2(
|
|
550
|
-
CommandRunner,
|
|
551
|
-
{
|
|
552
|
-
onError: (e) => {
|
|
553
|
-
thrownError = e;
|
|
554
|
-
},
|
|
555
|
-
run: fn
|
|
556
|
-
}
|
|
557
|
-
)
|
|
558
|
-
);
|
|
559
|
-
await app.waitUntilExit();
|
|
560
|
-
if (thrownError) process.exit(1);
|
|
561
|
-
}
|
|
562
|
-
var init_ink = __esm({
|
|
563
|
-
"cli/_ink.tsx"() {
|
|
564
|
-
"use strict";
|
|
565
|
-
init_colors();
|
|
566
|
-
}
|
|
520
|
+
// cli/_build.tsx
|
|
521
|
+
var build_exports = {};
|
|
522
|
+
__export(build_exports, {
|
|
523
|
+
buildAgentBundle: () => buildAgentBundle,
|
|
524
|
+
runBuildCommand: () => runBuildCommand
|
|
567
525
|
});
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
import React2 from "react";
|
|
571
|
-
async function buildAgentBundle(cwd, log) {
|
|
526
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
527
|
+
async function buildAgentBundle(cwd, log, opts) {
|
|
572
528
|
const agent = await loadAgent(cwd);
|
|
573
529
|
if (!agent) {
|
|
574
530
|
throw new Error("No agent found \u2014 run `aai init` first");
|
|
575
531
|
}
|
|
576
|
-
log(
|
|
532
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Bundle", msg: agent.slug }));
|
|
577
533
|
let bundle;
|
|
578
534
|
try {
|
|
579
535
|
bundle = await bundleAgent(agent);
|
|
@@ -585,125 +541,44 @@ async function buildAgentBundle(cwd, log) {
|
|
|
585
541
|
}
|
|
586
542
|
const kb = (bundle.workerBytes / 1024).toFixed(1);
|
|
587
543
|
const clientCount = Object.keys(bundle.clientFiles).length;
|
|
588
|
-
log(
|
|
589
|
-
if (agent.clientEntry) {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
log(
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
544
|
+
log(/* @__PURE__ */ jsx3(Info, { msg: `worker: ${kb} KB, client: ${clientCount} file(s)` }));
|
|
545
|
+
if (agent.clientEntry && !opts?.skipRenderCheck) {
|
|
546
|
+
const renderCheckPath = "../sdk/_render_check.ts";
|
|
547
|
+
const mod = await import(
|
|
548
|
+
/* @vite-ignore */
|
|
549
|
+
renderCheckPath
|
|
550
|
+
).catch(() => null);
|
|
551
|
+
if (mod) {
|
|
552
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Render", msg: "check" }));
|
|
553
|
+
try {
|
|
554
|
+
await mod.renderCheck(agent.clientEntry, cwd);
|
|
555
|
+
} catch (err) {
|
|
556
|
+
throw new Error(`Render check failed: ${errorMessage(err)}`);
|
|
557
|
+
}
|
|
602
558
|
}
|
|
603
559
|
}
|
|
604
560
|
return bundle;
|
|
605
561
|
}
|
|
562
|
+
async function runBuildCommand(cwd) {
|
|
563
|
+
await runWithInk(async ({ log }) => {
|
|
564
|
+
await buildAgentBundle(cwd, log);
|
|
565
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Build", msg: "ok" }));
|
|
566
|
+
});
|
|
567
|
+
}
|
|
606
568
|
var init_build = __esm({
|
|
607
|
-
"cli/_build.
|
|
569
|
+
"cli/_build.tsx"() {
|
|
608
570
|
"use strict";
|
|
571
|
+
init_utils();
|
|
609
572
|
init_bundler();
|
|
610
573
|
init_discover();
|
|
611
574
|
init_ink();
|
|
612
575
|
}
|
|
613
576
|
});
|
|
614
577
|
|
|
615
|
-
// cli/_init.ts
|
|
616
|
-
var init_exports = {};
|
|
617
|
-
__export(init_exports, {
|
|
618
|
-
listTemplates: () => listTemplates,
|
|
619
|
-
runInit: () => runInit
|
|
620
|
-
});
|
|
621
|
-
import fs3 from "node:fs/promises";
|
|
622
|
-
import path3 from "node:path";
|
|
623
|
-
import glob from "fast-glob";
|
|
624
|
-
import fsExtra from "fs-extra";
|
|
625
|
-
async function listTemplates(dir) {
|
|
626
|
-
const templates = [];
|
|
627
|
-
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
628
|
-
for (const entry of entries) {
|
|
629
|
-
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
630
|
-
templates.push(entry.name);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
return templates.sort();
|
|
634
|
-
}
|
|
635
|
-
async function copyDirNoOverwrite(src, dest) {
|
|
636
|
-
const files = await glob("**/*", { cwd: src, dot: true, onlyFiles: true });
|
|
637
|
-
for (const file of files) {
|
|
638
|
-
const destPath = path3.join(dest, file);
|
|
639
|
-
try {
|
|
640
|
-
await fs3.access(destPath);
|
|
641
|
-
} catch {
|
|
642
|
-
await fs3.mkdir(path3.dirname(destPath), { recursive: true });
|
|
643
|
-
await fs3.copyFile(path3.join(src, file), destPath);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
async function runInit(opts) {
|
|
648
|
-
const { targetDir, template, templatesDir } = opts;
|
|
649
|
-
const available = await listTemplates(templatesDir);
|
|
650
|
-
if (!available.includes(template)) {
|
|
651
|
-
throw new Error(`unknown template '${template}' -- available: ${available.join(", ")}`);
|
|
652
|
-
}
|
|
653
|
-
await fsExtra.copy(path3.join(templatesDir, template), targetDir, { overwrite: true });
|
|
654
|
-
await copyDirNoOverwrite(path3.join(templatesDir, "_shared"), targetDir);
|
|
655
|
-
try {
|
|
656
|
-
await fs3.copyFile(path3.join(targetDir, ".env.example"), path3.join(targetDir, ".env"));
|
|
657
|
-
} catch {
|
|
658
|
-
}
|
|
659
|
-
const readmePath = path3.join(targetDir, "README.md");
|
|
660
|
-
try {
|
|
661
|
-
await fs3.access(readmePath);
|
|
662
|
-
} catch {
|
|
663
|
-
const slug = path3.basename(path3.resolve(targetDir));
|
|
664
|
-
const readme = `# ${slug}
|
|
665
|
-
|
|
666
|
-
A voice agent built with [aai](https://github.com/anthropics/aai).
|
|
667
|
-
|
|
668
|
-
## Getting started
|
|
669
|
-
|
|
670
|
-
\`\`\`sh
|
|
671
|
-
npm install # Install dependencies
|
|
672
|
-
npm run dev # Run locally (opens browser)
|
|
673
|
-
npm run deploy # Deploy to production
|
|
674
|
-
\`\`\`
|
|
675
|
-
|
|
676
|
-
## Environment variables
|
|
677
|
-
|
|
678
|
-
Secrets are managed on the server, not in local files:
|
|
679
|
-
|
|
680
|
-
\`\`\`sh
|
|
681
|
-
aai env add MY_KEY # Set a secret (prompts for value)
|
|
682
|
-
aai env ls # List secret names
|
|
683
|
-
aai env pull # Pull names into .env for reference
|
|
684
|
-
aai env rm MY_KEY # Remove a secret
|
|
685
|
-
\`\`\`
|
|
686
|
-
|
|
687
|
-
Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
688
|
-
|
|
689
|
-
## Learn more
|
|
690
|
-
|
|
691
|
-
See \`CLAUDE.md\` for the full agent API reference.
|
|
692
|
-
`;
|
|
693
|
-
await fs3.writeFile(readmePath, readme);
|
|
694
|
-
}
|
|
695
|
-
return targetDir;
|
|
696
|
-
}
|
|
697
|
-
var init_init = __esm({
|
|
698
|
-
"cli/_init.ts"() {
|
|
699
|
-
"use strict";
|
|
700
|
-
}
|
|
701
|
-
});
|
|
702
|
-
|
|
703
578
|
// cli/_deploy.ts
|
|
704
|
-
async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
579
|
+
async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
|
|
705
580
|
try {
|
|
706
|
-
return await
|
|
581
|
+
return await fetchFn(`${url}/${slug}/deploy`, {
|
|
707
582
|
method: "POST",
|
|
708
583
|
headers: {
|
|
709
584
|
"Content-Type": "application/json",
|
|
@@ -720,37 +595,36 @@ async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
|
720
595
|
}
|
|
721
596
|
}
|
|
722
597
|
async function runDeploy(opts) {
|
|
723
|
-
const worker = opts.bundle
|
|
724
|
-
const
|
|
598
|
+
const { worker, clientFiles } = opts.bundle;
|
|
599
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
725
600
|
let slug = opts.slug;
|
|
726
|
-
if (opts.dryRun) {
|
|
727
|
-
return { slug };
|
|
728
|
-
}
|
|
729
601
|
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
730
|
-
const resp = await attemptDeploy(
|
|
602
|
+
const resp = await attemptDeploy(
|
|
603
|
+
fetchFn,
|
|
604
|
+
opts.url,
|
|
605
|
+
slug,
|
|
606
|
+
opts.apiKey,
|
|
607
|
+
opts.env,
|
|
608
|
+
worker,
|
|
609
|
+
clientFiles
|
|
610
|
+
);
|
|
731
611
|
if (resp.ok) {
|
|
732
612
|
return { slug };
|
|
733
613
|
}
|
|
734
|
-
if (resp.status === 403) {
|
|
735
|
-
const text2 = await resp.text();
|
|
736
|
-
if (text2.includes("Slug")) {
|
|
737
|
-
slug = generateSlug();
|
|
738
|
-
continue;
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
614
|
const text = await resp.text();
|
|
615
|
+
if (resp.status === 403 && text.includes("Slug")) {
|
|
616
|
+
slug = generateSlug();
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
742
619
|
throw new Error(`deploy failed (${resp.status}): ${text}`);
|
|
743
620
|
}
|
|
744
621
|
throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
|
|
745
622
|
}
|
|
746
|
-
var
|
|
623
|
+
var MAX_RETRIES;
|
|
747
624
|
var init_deploy = __esm({
|
|
748
625
|
"cli/_deploy.ts"() {
|
|
749
626
|
"use strict";
|
|
750
627
|
init_discover();
|
|
751
|
-
_internals = {
|
|
752
|
-
fetch: globalThis.fetch.bind(globalThis)
|
|
753
|
-
};
|
|
754
628
|
MAX_RETRIES = 20;
|
|
755
629
|
}
|
|
756
630
|
});
|
|
@@ -760,103 +634,73 @@ var deploy_exports = {};
|
|
|
760
634
|
__export(deploy_exports, {
|
|
761
635
|
runDeployCommand: () => runDeployCommand
|
|
762
636
|
});
|
|
763
|
-
import
|
|
764
|
-
import minimist from "minimist";
|
|
765
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
766
|
-
function resolveServerUrl(parsed) {
|
|
767
|
-
return parsed.server || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
768
|
-
}
|
|
637
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
769
638
|
async function deployBundle(opts) {
|
|
770
639
|
const { bundle, serverUrl, apiKey, cwd, log } = opts;
|
|
771
640
|
let { slug } = opts;
|
|
772
|
-
log(/* @__PURE__ */
|
|
641
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Deploy", msg: slug }));
|
|
773
642
|
const deployed = await runDeploy({
|
|
774
643
|
url: serverUrl,
|
|
775
644
|
bundle,
|
|
776
645
|
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
777
646
|
slug,
|
|
778
|
-
dryRun: false,
|
|
779
647
|
apiKey
|
|
780
648
|
});
|
|
781
649
|
slug = deployed.slug;
|
|
782
650
|
await writeProjectConfig(cwd, { slug, serverUrl });
|
|
783
651
|
const agentUrl = `${serverUrl}/${slug}`;
|
|
784
|
-
log(/* @__PURE__ */
|
|
652
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Ready", msg: agentUrl }));
|
|
785
653
|
return agentUrl;
|
|
786
654
|
}
|
|
787
|
-
async function runDeployCommand(
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
boolean: ["dry-run", "help", "yes"],
|
|
791
|
-
alias: { s: "server", h: "help", y: "yes" }
|
|
792
|
-
});
|
|
793
|
-
if (parsed.help) {
|
|
794
|
-
console.log(subcommandHelp(deployCommandDef, version));
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
798
|
-
if (!await fileExists(path4.join(cwd, "agent.ts"))) {
|
|
799
|
-
await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
|
|
800
|
-
}
|
|
801
|
-
const serverUrl = resolveServerUrl(parsed);
|
|
802
|
-
const dryRun = parsed["dry-run"] ?? false;
|
|
655
|
+
async function runDeployCommand(opts) {
|
|
656
|
+
const { cwd } = opts;
|
|
657
|
+
const dryRun = opts.dryRun ?? false;
|
|
803
658
|
const apiKey = dryRun ? "" : await getApiKey();
|
|
804
659
|
const projectConfig = await readProjectConfig(cwd);
|
|
660
|
+
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
805
661
|
const slug = projectConfig?.slug ?? generateSlug();
|
|
806
662
|
let agentUrl = "";
|
|
807
|
-
await runWithInk(async (log) => {
|
|
663
|
+
await runWithInk(async ({ log }) => {
|
|
808
664
|
const bundle = await buildAgentBundle(cwd, log);
|
|
809
665
|
if (dryRun) {
|
|
810
|
-
log(/* @__PURE__ */
|
|
666
|
+
log(/* @__PURE__ */ jsx4(StepInfo, { action: "Dry run", msg: `would deploy as ${slug}` }));
|
|
811
667
|
return;
|
|
812
668
|
}
|
|
813
669
|
agentUrl = await deployBundle({ bundle, serverUrl, apiKey, slug, cwd, log });
|
|
814
670
|
});
|
|
815
|
-
if (agentUrl
|
|
671
|
+
if (agentUrl) {
|
|
816
672
|
await askEnter("Press enter to open in browser");
|
|
817
673
|
const { exec } = await import("node:child_process");
|
|
818
674
|
exec(`open "${agentUrl}"`);
|
|
819
675
|
}
|
|
820
676
|
}
|
|
821
|
-
var deployCommandDef;
|
|
822
677
|
var init_deploy2 = __esm({
|
|
823
678
|
"cli/deploy.tsx"() {
|
|
824
679
|
"use strict";
|
|
825
680
|
init_build();
|
|
826
681
|
init_deploy();
|
|
827
682
|
init_discover();
|
|
828
|
-
init_help();
|
|
829
683
|
init_ink();
|
|
830
684
|
init_prompts();
|
|
831
|
-
init_init2();
|
|
832
|
-
deployCommandDef = {
|
|
833
|
-
name: "deploy",
|
|
834
|
-
description: "Bundle and deploy to production",
|
|
835
|
-
options: [
|
|
836
|
-
{ flags: "-s, --server <url>", description: "Server URL" },
|
|
837
|
-
{
|
|
838
|
-
flags: "--dry-run",
|
|
839
|
-
description: "Validate and bundle without deploying"
|
|
840
|
-
},
|
|
841
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
842
|
-
]
|
|
843
|
-
};
|
|
844
685
|
}
|
|
845
686
|
});
|
|
846
687
|
|
|
847
688
|
// cli/init.tsx
|
|
689
|
+
var init_exports2 = {};
|
|
690
|
+
__export(init_exports2, {
|
|
691
|
+
runInitCommand: () => runInitCommand
|
|
692
|
+
});
|
|
848
693
|
import { execFile } from "node:child_process";
|
|
849
694
|
import fs4 from "node:fs/promises";
|
|
850
|
-
import
|
|
695
|
+
import path4 from "node:path";
|
|
851
696
|
import { fileURLToPath } from "node:url";
|
|
852
697
|
import { promisify } from "node:util";
|
|
853
|
-
import
|
|
854
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
698
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
855
699
|
async function rewriteDevDeps(cwd, cliDir2) {
|
|
856
|
-
const monorepoRoot =
|
|
857
|
-
const pkgJsonPath2 =
|
|
700
|
+
const monorepoRoot = path4.join(cliDir2, "..");
|
|
701
|
+
const pkgJsonPath2 = path4.join(cwd, "package.json");
|
|
858
702
|
const pkgJson2 = JSON.parse(await fs4.readFile(pkgJsonPath2, "utf-8"));
|
|
859
|
-
const rootPkg = JSON.parse(await fs4.readFile(
|
|
703
|
+
const rootPkg = JSON.parse(await fs4.readFile(path4.join(monorepoRoot, "package.json"), "utf-8"));
|
|
860
704
|
const rootPkgName = rootPkg.name;
|
|
861
705
|
if (pkgJson2.dependencies[rootPkgName]) {
|
|
862
706
|
pkgJson2.dependencies[rootPkgName] = `file:${monorepoRoot}`;
|
|
@@ -865,56 +709,45 @@ async function rewriteDevDeps(cwd, cliDir2) {
|
|
|
865
709
|
`);
|
|
866
710
|
}
|
|
867
711
|
async function installDeps(cwd, log) {
|
|
868
|
-
if (await fileExists(
|
|
712
|
+
if (await fileExists(path4.join(cwd, "node_modules"))) return;
|
|
869
713
|
let pkgJson2;
|
|
870
714
|
try {
|
|
871
|
-
pkgJson2 = JSON.parse(await fs4.readFile(
|
|
715
|
+
pkgJson2 = JSON.parse(await fs4.readFile(path4.join(cwd, "package.json"), "utf-8"));
|
|
872
716
|
} catch {
|
|
873
717
|
pkgJson2 = {};
|
|
874
718
|
}
|
|
875
719
|
const deps = Object.keys(pkgJson2.dependencies ?? {});
|
|
876
720
|
const devDeps = Object.keys(pkgJson2.devDependencies ?? {});
|
|
877
721
|
if (deps.length > 0) {
|
|
878
|
-
log(/* @__PURE__ */
|
|
722
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: deps.join(", ") }));
|
|
879
723
|
}
|
|
880
724
|
if (devDeps.length > 0) {
|
|
881
|
-
log(/* @__PURE__ */
|
|
725
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: `dev: ${devDeps.join(", ")}` }));
|
|
882
726
|
}
|
|
883
727
|
try {
|
|
884
728
|
await execFileAsync("npm", ["install"], { cwd });
|
|
885
729
|
} catch {
|
|
886
|
-
log(/* @__PURE__ */
|
|
730
|
+
log(/* @__PURE__ */ jsx5(Warn, { msg: "npm install failed" }));
|
|
887
731
|
}
|
|
888
732
|
}
|
|
889
|
-
async function runInitCommand(
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
boolean: ["force", "help"],
|
|
893
|
-
alias: { t: "template", f: "force", h: "help" }
|
|
894
|
-
});
|
|
895
|
-
if (parsed.help) {
|
|
896
|
-
console.log(subcommandHelp(initCommandDef, version));
|
|
897
|
-
return "";
|
|
898
|
-
}
|
|
899
|
-
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
900
|
-
await getApiKey2();
|
|
901
|
-
let dir = parsed._[0];
|
|
733
|
+
async function runInitCommand(opts, extra) {
|
|
734
|
+
await getApiKey();
|
|
735
|
+
let dir = opts.dir;
|
|
902
736
|
if (!dir) {
|
|
903
737
|
dir = await askText("What is your project named?", "my-voice-agent");
|
|
904
738
|
}
|
|
905
|
-
const cwd =
|
|
906
|
-
if (!
|
|
907
|
-
|
|
739
|
+
const cwd = path4.resolve(resolveCwd(), dir);
|
|
740
|
+
if (!opts.force && await fileExists(path4.join(cwd, "agent.ts"))) {
|
|
741
|
+
throw new Error(
|
|
908
742
|
`agent.ts already exists in this directory. Use ${interactive("--force")} to overwrite.`
|
|
909
743
|
);
|
|
910
|
-
process.exit(1);
|
|
911
744
|
}
|
|
912
|
-
const cliDir2 =
|
|
913
|
-
const templatesDir =
|
|
745
|
+
const cliDir2 = path4.dirname(fileURLToPath(import.meta.url));
|
|
746
|
+
const templatesDir = path4.join(cliDir2, "..", "templates");
|
|
914
747
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
915
|
-
const template =
|
|
916
|
-
await runWithInk(async (log) => {
|
|
917
|
-
log(/* @__PURE__ */
|
|
748
|
+
const template = opts.template || "simple";
|
|
749
|
+
await runWithInk(async ({ log }) => {
|
|
750
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Create", msg: dir }));
|
|
918
751
|
await runInit2({ targetDir: cwd, template, templatesDir });
|
|
919
752
|
if (isDevMode()) {
|
|
920
753
|
await rewriteDevDeps(cwd, cliDir2);
|
|
@@ -923,60 +756,32 @@ async function runInitCommand(args, version, opts) {
|
|
|
923
756
|
});
|
|
924
757
|
process.chdir(cwd);
|
|
925
758
|
delete process.env.INIT_CWD;
|
|
926
|
-
if (!
|
|
759
|
+
if (!extra?.quiet) {
|
|
927
760
|
const { runDeployCommand: runDeployCommand2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
|
|
928
|
-
await runDeployCommand2(
|
|
761
|
+
await runDeployCommand2({ cwd });
|
|
929
762
|
}
|
|
930
763
|
return cwd;
|
|
931
764
|
}
|
|
932
|
-
var execFileAsync
|
|
765
|
+
var execFileAsync;
|
|
933
766
|
var init_init2 = __esm({
|
|
934
767
|
"cli/init.tsx"() {
|
|
935
768
|
"use strict";
|
|
936
|
-
init_colors();
|
|
937
769
|
init_discover();
|
|
938
|
-
init_help();
|
|
939
770
|
init_ink();
|
|
940
771
|
init_prompts();
|
|
941
772
|
execFileAsync = promisify(execFile);
|
|
942
|
-
initCommandDef = {
|
|
943
|
-
name: "init",
|
|
944
|
-
description: "Scaffold a new agent project",
|
|
945
|
-
args: [{ name: "dir", optional: true }],
|
|
946
|
-
options: [
|
|
947
|
-
{
|
|
948
|
-
flags: "-t, --template <template>",
|
|
949
|
-
description: "Template to use"
|
|
950
|
-
},
|
|
951
|
-
{ flags: "-f, --force", description: "Overwrite existing agent.ts" }
|
|
952
|
-
]
|
|
953
|
-
};
|
|
954
773
|
}
|
|
955
774
|
});
|
|
956
775
|
|
|
957
776
|
// sdk/protocol.ts
|
|
958
777
|
import { z } from "zod";
|
|
959
|
-
var DEFAULT_TTS_SAMPLE_RATE, AUDIO_FORMAT,
|
|
778
|
+
var DEFAULT_TTS_SAMPLE_RATE, AUDIO_FORMAT, KvRequestSchema, VectorRequestSchema, HOOK_TIMEOUT_MS, TOOL_EXECUTION_TIMEOUT_MS, SessionErrorCodeSchema, ev, textEv, turnOrder, ClientEventSchema, ClientMessageSchema;
|
|
960
779
|
var init_protocol = __esm({
|
|
961
780
|
"sdk/protocol.ts"() {
|
|
962
781
|
"use strict";
|
|
963
782
|
DEFAULT_TTS_SAMPLE_RATE = 24e3;
|
|
964
783
|
AUDIO_FORMAT = "pcm16";
|
|
965
|
-
|
|
966
|
-
_channels = 1;
|
|
967
|
-
AudioFrameSpec = {
|
|
968
|
-
/** Audio codec identifier sent in the `ready` message. */
|
|
969
|
-
format: AUDIO_FORMAT,
|
|
970
|
-
/** Signed 16-bit integer samples. */
|
|
971
|
-
bitsPerSample: _bitsPerSample,
|
|
972
|
-
/** Little-endian byte order. */
|
|
973
|
-
endianness: "little",
|
|
974
|
-
/** Mono audio. */
|
|
975
|
-
channels: _channels,
|
|
976
|
-
/** Bytes per sample — derived from bitsPerSample and channels. */
|
|
977
|
-
bytesPerSample: _bitsPerSample / 8 * _channels
|
|
978
|
-
};
|
|
979
|
-
KvRequestBaseSchema = z.discriminatedUnion("op", [
|
|
784
|
+
KvRequestSchema = z.discriminatedUnion("op", [
|
|
980
785
|
z.object({ op: z.literal("get"), key: z.string().min(1) }),
|
|
981
786
|
z.object({
|
|
982
787
|
op: z.literal("set"),
|
|
@@ -990,9 +795,29 @@ var init_protocol = __esm({
|
|
|
990
795
|
prefix: z.string(),
|
|
991
796
|
limit: z.number().int().positive().optional(),
|
|
992
797
|
reverse: z.boolean().optional()
|
|
798
|
+
}),
|
|
799
|
+
z.object({ op: z.literal("keys"), pattern: z.string().optional() })
|
|
800
|
+
]);
|
|
801
|
+
VectorRequestSchema = z.discriminatedUnion("op", [
|
|
802
|
+
z.object({
|
|
803
|
+
op: z.literal("upsert"),
|
|
804
|
+
id: z.string().min(1),
|
|
805
|
+
data: z.string().min(1),
|
|
806
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
807
|
+
}),
|
|
808
|
+
z.object({
|
|
809
|
+
op: z.literal("query"),
|
|
810
|
+
text: z.string().min(1),
|
|
811
|
+
topK: z.number().int().positive().max(100).optional(),
|
|
812
|
+
filter: z.string().optional()
|
|
813
|
+
}),
|
|
814
|
+
z.object({
|
|
815
|
+
op: z.literal("remove"),
|
|
816
|
+
ids: z.array(z.string().min(1)).min(1)
|
|
993
817
|
})
|
|
994
818
|
]);
|
|
995
819
|
HOOK_TIMEOUT_MS = 5e3;
|
|
820
|
+
TOOL_EXECUTION_TIMEOUT_MS = 3e4;
|
|
996
821
|
SessionErrorCodeSchema = z.enum([
|
|
997
822
|
"stt",
|
|
998
823
|
"llm",
|
|
@@ -1003,23 +828,16 @@ var init_protocol = __esm({
|
|
|
1003
828
|
"audio",
|
|
1004
829
|
"internal"
|
|
1005
830
|
]);
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
isFinal: z.boolean(),
|
|
1010
|
-
turnOrder: z.number().int().nonnegative().optional()
|
|
1011
|
-
});
|
|
831
|
+
ev = (t) => z.object({ type: z.literal(t) });
|
|
832
|
+
textEv = (t) => z.object({ type: z.literal(t), text: z.string() });
|
|
833
|
+
turnOrder = z.number().int().nonnegative().optional();
|
|
1012
834
|
ClientEventSchema = z.discriminatedUnion("type", [
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
turnOrder: z.number().int().nonnegative().optional()
|
|
1020
|
-
}),
|
|
1021
|
-
z.object({ type: z.literal("chat"), text: z.string() }),
|
|
1022
|
-
z.object({ type: z.literal("chat_delta"), text: z.string() }),
|
|
835
|
+
ev("speech_started"),
|
|
836
|
+
ev("speech_stopped"),
|
|
837
|
+
z.object({ type: z.literal("transcript"), text: z.string(), isFinal: z.boolean(), turnOrder }),
|
|
838
|
+
textEv("turn").extend({ turnOrder }),
|
|
839
|
+
textEv("chat"),
|
|
840
|
+
textEv("chat_delta"),
|
|
1023
841
|
z.object({
|
|
1024
842
|
type: z.literal("tool_call_start"),
|
|
1025
843
|
toolCallId: z.string(),
|
|
@@ -1031,55 +849,35 @@ var init_protocol = __esm({
|
|
|
1031
849
|
toolCallId: z.string(),
|
|
1032
850
|
result: z.string().max(4e3)
|
|
1033
851
|
}),
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
z.object({
|
|
1038
|
-
type: z.literal("error"),
|
|
1039
|
-
code: SessionErrorCodeSchema,
|
|
1040
|
-
message: z.string()
|
|
1041
|
-
})
|
|
852
|
+
ev("tts_done"),
|
|
853
|
+
ev("cancelled"),
|
|
854
|
+
ev("reset"),
|
|
855
|
+
z.object({ type: z.literal("error"), code: SessionErrorCodeSchema, message: z.string() })
|
|
1042
856
|
]);
|
|
1043
857
|
ClientMessageSchema = z.discriminatedUnion("type", [
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
858
|
+
ev("audio_ready"),
|
|
859
|
+
ev("cancel"),
|
|
860
|
+
ev("reset"),
|
|
1047
861
|
z.object({
|
|
1048
862
|
type: z.literal("history"),
|
|
1049
|
-
messages: z.array(
|
|
1050
|
-
z.object({
|
|
1051
|
-
role: z.enum(["user", "assistant"]),
|
|
1052
|
-
text: z.string().max(1e5)
|
|
1053
|
-
})
|
|
1054
|
-
).max(200)
|
|
863
|
+
messages: z.array(z.object({ role: z.enum(["user", "assistant"]), text: z.string().max(1e5) })).max(200)
|
|
1055
864
|
})
|
|
1056
865
|
]);
|
|
1057
866
|
}
|
|
1058
867
|
});
|
|
1059
868
|
|
|
1060
869
|
// sdk/runtime.ts
|
|
1061
|
-
var consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
870
|
+
var _log, consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
1062
871
|
var init_runtime = __esm({
|
|
1063
872
|
"sdk/runtime.ts"() {
|
|
1064
873
|
"use strict";
|
|
1065
874
|
init_protocol();
|
|
875
|
+
_log = (m) => (msg, ctx) => console[m](msg, ...ctx ? [ctx] : []);
|
|
1066
876
|
consoleLogger = {
|
|
1067
|
-
info(
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
warn(msg, ctx) {
|
|
1072
|
-
if (ctx) console.warn(msg, ctx);
|
|
1073
|
-
else console.warn(msg);
|
|
1074
|
-
},
|
|
1075
|
-
error(msg, ctx) {
|
|
1076
|
-
if (ctx) console.error(msg, ctx);
|
|
1077
|
-
else console.error(msg);
|
|
1078
|
-
},
|
|
1079
|
-
debug(msg, ctx) {
|
|
1080
|
-
if (ctx) console.debug(msg, ctx);
|
|
1081
|
-
else console.debug(msg);
|
|
1082
|
-
}
|
|
877
|
+
info: _log("log"),
|
|
878
|
+
warn: _log("warn"),
|
|
879
|
+
error: _log("error"),
|
|
880
|
+
debug: _log("debug")
|
|
1083
881
|
};
|
|
1084
882
|
noopMetrics = {
|
|
1085
883
|
sessionsTotal: { inc() {
|
|
@@ -1096,107 +894,265 @@ var init_runtime = __esm({
|
|
|
1096
894
|
}
|
|
1097
895
|
});
|
|
1098
896
|
|
|
1099
|
-
// sdk/
|
|
897
|
+
// sdk/s2s.ts
|
|
898
|
+
var s2s_exports = {};
|
|
899
|
+
__export(s2s_exports, {
|
|
900
|
+
connectS2s: () => connectS2s,
|
|
901
|
+
wrapOnStyleWebSocket: () => wrapOnStyleWebSocket
|
|
902
|
+
});
|
|
1100
903
|
import { z as z2 } from "zod";
|
|
1101
|
-
function
|
|
1102
|
-
return
|
|
1103
|
-
name,
|
|
1104
|
-
description: def.description,
|
|
1105
|
-
parameters: z2.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1106
|
-
}));
|
|
904
|
+
function uint8ToBase64(bytes) {
|
|
905
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
1107
906
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
"use strict";
|
|
1112
|
-
EMPTY_PARAMS = z2.object({});
|
|
1113
|
-
}
|
|
1114
|
-
});
|
|
1115
|
-
|
|
1116
|
-
// sdk/types.ts
|
|
1117
|
-
function tool(def) {
|
|
1118
|
-
return def;
|
|
907
|
+
function base64ToUint8(base64) {
|
|
908
|
+
const buf = Buffer.from(base64, "base64");
|
|
909
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1119
910
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
911
|
+
function wrapOnStyleWebSocket(ws) {
|
|
912
|
+
const target = new EventTarget();
|
|
913
|
+
ws.on("open", () => target.dispatchEvent(new Event("open")));
|
|
914
|
+
ws.on("message", (data) => target.dispatchEvent(new MessageEvent("message", { data })));
|
|
915
|
+
ws.on("close", (code, reason) => {
|
|
916
|
+
const init = { reason: String(reason ?? "") };
|
|
917
|
+
if (typeof code === "number") init.code = code;
|
|
918
|
+
target.dispatchEvent(new CloseEvent("close", init));
|
|
919
|
+
});
|
|
920
|
+
ws.on(
|
|
921
|
+
"error",
|
|
922
|
+
(err) => target.dispatchEvent(
|
|
923
|
+
new ErrorEvent("error", {
|
|
924
|
+
message: errorMessage(err)
|
|
925
|
+
})
|
|
926
|
+
)
|
|
927
|
+
);
|
|
928
|
+
Object.defineProperties(target, {
|
|
929
|
+
readyState: { get: () => ws.readyState, enumerable: true },
|
|
930
|
+
send: { value: (data) => ws.send(data), enumerable: true },
|
|
931
|
+
close: { value: () => ws.close(), enumerable: true }
|
|
932
|
+
});
|
|
933
|
+
return target;
|
|
934
|
+
}
|
|
935
|
+
function dispatchS2sMessage(target, msg) {
|
|
936
|
+
const entry = S2S_DISPATCH[msg.type]?.(msg);
|
|
937
|
+
if (entry) target.dispatchEvent(new CustomEvent(entry[0], { detail: entry[1] }));
|
|
938
|
+
}
|
|
939
|
+
function connectS2s(opts) {
|
|
940
|
+
const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
|
|
941
|
+
return new Promise((resolve, reject) => {
|
|
942
|
+
log.info("S2S connecting", { url: config.wssUrl });
|
|
943
|
+
const ws = createWebSocket(config.wssUrl, {
|
|
944
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
945
|
+
});
|
|
946
|
+
const target = new EventTarget();
|
|
947
|
+
let opened = false;
|
|
948
|
+
function send(msg) {
|
|
949
|
+
if (ws.readyState !== WS_OPEN) return;
|
|
950
|
+
const json = JSON.stringify(msg);
|
|
951
|
+
if (msg.type !== "input.audio") {
|
|
952
|
+
log.info(
|
|
953
|
+
`S2S >> ${msg.type}`,
|
|
954
|
+
msg.type === "session.update" ? { payload: json } : void 0
|
|
955
|
+
);
|
|
1151
956
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
957
|
+
ws.send(json);
|
|
958
|
+
}
|
|
959
|
+
const handle = Object.assign(target, {
|
|
960
|
+
sendAudio(audio) {
|
|
961
|
+
if (ws.readyState !== WS_OPEN) return;
|
|
962
|
+
ws.send(`{"type":"input.audio","audio":"${uint8ToBase64(audio)}"}`);
|
|
963
|
+
},
|
|
964
|
+
sendToolResult(callId, result) {
|
|
965
|
+
const msg = { type: "tool.result", call_id: callId, result };
|
|
966
|
+
log.info("S2S >> tool.result", { call_id: callId, resultLength: result.length });
|
|
967
|
+
send(msg);
|
|
968
|
+
},
|
|
969
|
+
updateSession(sessionConfig) {
|
|
970
|
+
send({ type: "session.update", session: sessionConfig });
|
|
971
|
+
},
|
|
972
|
+
resumeSession(sessionId) {
|
|
973
|
+
send({ type: "session.resume", session_id: sessionId });
|
|
974
|
+
},
|
|
975
|
+
close() {
|
|
976
|
+
log.info("S2S closing");
|
|
977
|
+
ws.close();
|
|
1162
978
|
}
|
|
1163
|
-
})
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
979
|
+
});
|
|
980
|
+
ws.addEventListener("open", () => {
|
|
981
|
+
opened = true;
|
|
982
|
+
log.info("S2S WebSocket open");
|
|
983
|
+
resolve(handle);
|
|
984
|
+
});
|
|
985
|
+
function handleS2sMessage(ev2) {
|
|
986
|
+
const data = ev2.data;
|
|
987
|
+
let raw;
|
|
988
|
+
try {
|
|
989
|
+
raw = JSON.parse(String(data));
|
|
990
|
+
} catch {
|
|
991
|
+
log.warn("S2S << invalid JSON", { data: String(data).slice(0, 200) });
|
|
992
|
+
return;
|
|
1172
993
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
execute: async ({ key }, ctx) => {
|
|
1180
|
-
await ctx.kv.delete(key);
|
|
1181
|
-
return { deleted: key };
|
|
994
|
+
const obj = raw;
|
|
995
|
+
if (obj.type !== "reply.audio" && obj.type !== "input.audio") {
|
|
996
|
+
log.info(
|
|
997
|
+
`S2S << ${obj.type}`,
|
|
998
|
+
obj.type === "transcript.agent.delta" ? { delta: obj.delta } : void 0
|
|
999
|
+
);
|
|
1182
1000
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1001
|
+
if (obj.type === "reply.audio" && typeof obj.data === "string") {
|
|
1002
|
+
const audioBytes = base64ToUint8(obj.data);
|
|
1003
|
+
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
const parsed = S2sServerMessageSchema.safeParse(raw);
|
|
1007
|
+
if (!parsed.success) {
|
|
1008
|
+
log.warn(
|
|
1009
|
+
`S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 200)}`
|
|
1010
|
+
);
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
dispatchS2sMessage(target, parsed.data);
|
|
1014
|
+
}
|
|
1015
|
+
ws.addEventListener("message", handleS2sMessage);
|
|
1016
|
+
ws.addEventListener("close", ((ev2) => {
|
|
1017
|
+
log.info("S2S WebSocket closed", {
|
|
1018
|
+
code: ev2.code ?? 0,
|
|
1019
|
+
reason: ev2.reason ?? ""
|
|
1020
|
+
});
|
|
1021
|
+
target.dispatchEvent(new CustomEvent("close"));
|
|
1022
|
+
}));
|
|
1023
|
+
ws.addEventListener("error", ((ev2) => {
|
|
1024
|
+
const message = ev2 instanceof ErrorEvent ? ev2.message : "WebSocket error";
|
|
1025
|
+
const errObj = new Error(message);
|
|
1026
|
+
log.error("S2S WebSocket error", { error: errObj.message });
|
|
1027
|
+
if (!opened) {
|
|
1028
|
+
reject(errObj);
|
|
1029
|
+
} else {
|
|
1030
|
+
target.dispatchEvent(
|
|
1031
|
+
new CustomEvent("error", {
|
|
1032
|
+
detail: { code: "ws_error", message: errObj.message }
|
|
1033
|
+
})
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
}));
|
|
1037
|
+
});
|
|
1185
1038
|
}
|
|
1186
|
-
var
|
|
1187
|
-
|
|
1039
|
+
var WS_OPEN, S2sServerMessageSchema, S2S_DISPATCH;
|
|
1040
|
+
var init_s2s = __esm({
|
|
1041
|
+
"sdk/s2s.ts"() {
|
|
1188
1042
|
"use strict";
|
|
1189
|
-
|
|
1043
|
+
init_utils();
|
|
1044
|
+
init_runtime();
|
|
1045
|
+
WS_OPEN = 1;
|
|
1046
|
+
S2sServerMessageSchema = z2.discriminatedUnion("type", [
|
|
1047
|
+
z2.object({ type: z2.literal("session.ready"), session_id: z2.string() }),
|
|
1048
|
+
z2.object({ type: z2.literal("session.updated") }).passthrough(),
|
|
1049
|
+
z2.object({ type: z2.literal("input.speech.started") }),
|
|
1050
|
+
z2.object({ type: z2.literal("input.speech.stopped") }),
|
|
1051
|
+
z2.object({ type: z2.literal("transcript.user.delta"), text: z2.string() }),
|
|
1052
|
+
z2.object({
|
|
1053
|
+
type: z2.literal("transcript.user"),
|
|
1054
|
+
item_id: z2.string(),
|
|
1055
|
+
text: z2.string()
|
|
1056
|
+
}),
|
|
1057
|
+
z2.object({ type: z2.literal("reply.started"), reply_id: z2.string() }),
|
|
1058
|
+
// reply.audio is handled on the fast path before Zod.
|
|
1059
|
+
z2.object({ type: z2.literal("transcript.agent.delta"), delta: z2.string() }).passthrough(),
|
|
1060
|
+
z2.object({ type: z2.literal("transcript.agent"), text: z2.string() }),
|
|
1061
|
+
z2.object({ type: z2.literal("reply.content_part.started") }).passthrough(),
|
|
1062
|
+
z2.object({ type: z2.literal("reply.content_part.done") }).passthrough(),
|
|
1063
|
+
z2.object({
|
|
1064
|
+
type: z2.literal("tool.call"),
|
|
1065
|
+
call_id: z2.string(),
|
|
1066
|
+
name: z2.string(),
|
|
1067
|
+
args: z2.record(z2.string(), z2.unknown()).optional().default({})
|
|
1068
|
+
}),
|
|
1069
|
+
z2.object({
|
|
1070
|
+
type: z2.literal("reply.done"),
|
|
1071
|
+
status: z2.string().optional()
|
|
1072
|
+
}),
|
|
1073
|
+
z2.object({
|
|
1074
|
+
type: z2.literal("session.error"),
|
|
1075
|
+
code: z2.string(),
|
|
1076
|
+
message: z2.string()
|
|
1077
|
+
}),
|
|
1078
|
+
// Connection-level error (bare "error" without "session." prefix).
|
|
1079
|
+
z2.object({
|
|
1080
|
+
type: z2.literal("error"),
|
|
1081
|
+
message: z2.string()
|
|
1082
|
+
})
|
|
1083
|
+
]);
|
|
1084
|
+
S2S_DISPATCH = {
|
|
1085
|
+
"session.ready": (m) => ["ready", { session_id: m.session_id }],
|
|
1086
|
+
"session.updated": (m) => ["session_updated", m],
|
|
1087
|
+
"input.speech.started": () => ["speech_started", void 0],
|
|
1088
|
+
"input.speech.stopped": () => ["speech_stopped", void 0],
|
|
1089
|
+
"transcript.user.delta": (m) => ["user_transcript_delta", { text: m.text }],
|
|
1090
|
+
"transcript.user": (m) => ["user_transcript", { item_id: m.item_id, text: m.text }],
|
|
1091
|
+
"reply.started": (m) => ["reply_started", { reply_id: m.reply_id }],
|
|
1092
|
+
"transcript.agent.delta": (m) => ["agent_transcript_delta", { text: m.delta }],
|
|
1093
|
+
"transcript.agent": (m) => ["agent_transcript", { text: m.text }],
|
|
1094
|
+
"tool.call": (m) => ["tool_call", { call_id: m.call_id, name: m.name, args: m.args }],
|
|
1095
|
+
"reply.done": (m) => ["reply_done", { status: m.status }],
|
|
1096
|
+
"session.error": (m) => [
|
|
1097
|
+
m.code === "session_not_found" || m.code === "session_forbidden" ? "session_expired" : "error",
|
|
1098
|
+
{ code: m.code, message: m.message }
|
|
1099
|
+
],
|
|
1100
|
+
error: (m) => ["error", { code: "connection", message: m.message }],
|
|
1101
|
+
"reply.content_part.started": () => void 0,
|
|
1102
|
+
"reply.content_part.done": () => void 0
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
// sdk/_internal_types.ts
|
|
1108
|
+
import { z as z3 } from "zod";
|
|
1109
|
+
function agentToolsToSchemas(tools) {
|
|
1110
|
+
return Object.entries(tools).map(([name, def]) => ({
|
|
1111
|
+
name,
|
|
1112
|
+
description: def.description,
|
|
1113
|
+
parameters: z3.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1114
|
+
}));
|
|
1115
|
+
}
|
|
1116
|
+
var EMPTY_PARAMS;
|
|
1117
|
+
var init_internal_types = __esm({
|
|
1118
|
+
"sdk/_internal_types.ts"() {
|
|
1119
|
+
"use strict";
|
|
1120
|
+
EMPTY_PARAMS = z3.object({});
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
// sdk/types.ts
|
|
1125
|
+
function tool(def) {
|
|
1126
|
+
return def;
|
|
1127
|
+
}
|
|
1128
|
+
var DEFAULT_INSTRUCTIONS;
|
|
1129
|
+
var init_types = __esm({
|
|
1130
|
+
"sdk/types.ts"() {
|
|
1131
|
+
"use strict";
|
|
1132
|
+
DEFAULT_INSTRUCTIONS = `You are AAI, a helpful AI assistant.
|
|
1133
|
+
|
|
1134
|
+
Voice-First Rules:
|
|
1135
|
+
- Optimize for natural speech. Avoid jargon unless central to the answer. Use short, punchy sentences.
|
|
1136
|
+
- Never mention "search results," "sources," or "the provided text." Speak as if the knowledge is your own.
|
|
1137
|
+
- No visual formatting. Do not say "bullet point," "bold," or "bracketed one." If you need to list items, say "First," "Next," and "Finally."
|
|
1138
|
+
- Start with the most important information. No introductory filler.
|
|
1139
|
+
- Be concise. Keep answers to 1-3 sentences. For complex topics, provide a high-level summary.
|
|
1140
|
+
- Be confident. Avoid hedging phrases like "It seems that" or "I believe."
|
|
1141
|
+
- If you don't have enough information, say so directly rather than guessing.
|
|
1142
|
+
- Never use exclamation points. Keep your tone calm and conversational.`;
|
|
1190
1143
|
}
|
|
1191
1144
|
});
|
|
1192
1145
|
|
|
1193
1146
|
// sdk/builtin_tools.ts
|
|
1194
1147
|
import { convert } from "html-to-text";
|
|
1195
1148
|
import { z as z4 } from "zod";
|
|
1149
|
+
function fetchSignal(toolSignal) {
|
|
1150
|
+
return AbortSignal.any([toolSignal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]);
|
|
1151
|
+
}
|
|
1196
1152
|
function htmlToText(html) {
|
|
1197
1153
|
return convert(html, { wordwrap: false });
|
|
1198
1154
|
}
|
|
1199
|
-
function createWebSearch() {
|
|
1155
|
+
function createWebSearch(fetchFn = globalThis.fetch) {
|
|
1200
1156
|
return {
|
|
1201
1157
|
description: "Search the web for current information, facts, news, or answers to questions. Returns a list of results with title, URL, and description. Use this when the user asks about something you don't know, need up-to-date information, or want to verify facts.",
|
|
1202
1158
|
parameters: webSearchParams,
|
|
@@ -1211,9 +1167,9 @@ function createWebSearch() {
|
|
|
1211
1167
|
count: String(maxResults),
|
|
1212
1168
|
text_decorations: "false"
|
|
1213
1169
|
})}`;
|
|
1214
|
-
const resp = await
|
|
1170
|
+
const resp = await fetchFn(url, {
|
|
1215
1171
|
headers: { "X-Subscription-Token": apiKey },
|
|
1216
|
-
signal: ctx.abortSignal
|
|
1172
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1217
1173
|
});
|
|
1218
1174
|
if (!resp.ok) return [];
|
|
1219
1175
|
const raw = await resp.json();
|
|
@@ -1227,19 +1183,19 @@ function createWebSearch() {
|
|
|
1227
1183
|
}
|
|
1228
1184
|
};
|
|
1229
1185
|
}
|
|
1230
|
-
function createVisitWebpage() {
|
|
1186
|
+
function createVisitWebpage(fetchFn = globalThis.fetch) {
|
|
1231
1187
|
return {
|
|
1232
1188
|
description: "Fetch a webpage and return its content as clean text. Use this to read the full content of a URL found via web_search, or any link the user shares. Good for reading articles, documentation, blog posts, or product pages.",
|
|
1233
1189
|
parameters: visitWebpageParams,
|
|
1234
1190
|
async execute(args, ctx) {
|
|
1235
1191
|
const { url } = args;
|
|
1236
|
-
const resp = await
|
|
1192
|
+
const resp = await fetchFn(url, {
|
|
1237
1193
|
headers: {
|
|
1238
1194
|
"User-Agent": "Mozilla/5.0 (compatible; VoiceAgent/1.0; +https://github.com/AssemblyAI/aai)",
|
|
1239
1195
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
1240
1196
|
},
|
|
1241
1197
|
redirect: "follow",
|
|
1242
|
-
signal: ctx.abortSignal
|
|
1198
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1243
1199
|
});
|
|
1244
1200
|
if (!resp.ok) {
|
|
1245
1201
|
return { error: `Failed to fetch: ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1257,15 +1213,15 @@ function createVisitWebpage() {
|
|
|
1257
1213
|
}
|
|
1258
1214
|
};
|
|
1259
1215
|
}
|
|
1260
|
-
function createFetchJson() {
|
|
1216
|
+
function createFetchJson(fetchFn = globalThis.fetch) {
|
|
1261
1217
|
return {
|
|
1262
1218
|
description: "Call a REST API endpoint via HTTP GET and return the JSON response. Use this to fetch structured data from APIs \u2014 for example, weather data, stock prices, exchange rates, or any public JSON API. Supports custom headers for authenticated APIs.",
|
|
1263
1219
|
parameters: fetchJsonParams,
|
|
1264
1220
|
async execute(args, ctx) {
|
|
1265
1221
|
const { url, headers } = args;
|
|
1266
|
-
const resp = await
|
|
1222
|
+
const resp = await fetchFn(url, {
|
|
1267
1223
|
...headers && { headers },
|
|
1268
|
-
signal: ctx.abortSignal
|
|
1224
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1269
1225
|
});
|
|
1270
1226
|
if (!resp.ok) {
|
|
1271
1227
|
return { error: `HTTP ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1295,7 +1251,6 @@ function createRunCode() {
|
|
|
1295
1251
|
error: capture,
|
|
1296
1252
|
debug: capture
|
|
1297
1253
|
};
|
|
1298
|
-
const RUN_CODE_TIMEOUT = 5e3;
|
|
1299
1254
|
const AsyncFunction = Object.getPrototypeOf(async () => {
|
|
1300
1255
|
}).constructor;
|
|
1301
1256
|
try {
|
|
@@ -1309,7 +1264,7 @@ function createRunCode() {
|
|
|
1309
1264
|
const result = output.join("\n").trim();
|
|
1310
1265
|
return result || "Code ran successfully (no output)";
|
|
1311
1266
|
} catch (err) {
|
|
1312
|
-
return { error:
|
|
1267
|
+
return { error: errorMessage(err) };
|
|
1313
1268
|
}
|
|
1314
1269
|
}
|
|
1315
1270
|
};
|
|
@@ -1324,462 +1279,192 @@ function createVectorSearch(vectorSearchFn) {
|
|
|
1324
1279
|
}
|
|
1325
1280
|
};
|
|
1326
1281
|
}
|
|
1282
|
+
function resolveBuiltin(name, opts) {
|
|
1283
|
+
const entry = TOOL_REGISTRY[name];
|
|
1284
|
+
if (!entry) return [];
|
|
1285
|
+
if ("multi" in entry) return Object.entries(entry.multi());
|
|
1286
|
+
if (name === "vector_search" && !opts?.vectorSearch) return [];
|
|
1287
|
+
return [[name, entry.create(opts)]];
|
|
1288
|
+
}
|
|
1327
1289
|
function getBuiltinToolDefs(names, opts) {
|
|
1328
1290
|
const defs = {};
|
|
1329
1291
|
for (const name of names) {
|
|
1330
|
-
|
|
1331
|
-
case "web_search":
|
|
1332
|
-
defs[name] = createWebSearch();
|
|
1333
|
-
break;
|
|
1334
|
-
case "visit_webpage":
|
|
1335
|
-
defs[name] = createVisitWebpage();
|
|
1336
|
-
break;
|
|
1337
|
-
case "fetch_json":
|
|
1338
|
-
defs[name] = createFetchJson();
|
|
1339
|
-
break;
|
|
1340
|
-
case "run_code":
|
|
1341
|
-
defs[name] = createRunCode();
|
|
1342
|
-
break;
|
|
1343
|
-
case "vector_search":
|
|
1344
|
-
if (opts?.vectorSearch) {
|
|
1345
|
-
defs[name] = createVectorSearch(opts.vectorSearch);
|
|
1346
|
-
}
|
|
1347
|
-
break;
|
|
1348
|
-
case "memory": {
|
|
1349
|
-
const mt = memoryTools();
|
|
1350
|
-
for (const [toolName, toolDef] of Object.entries(mt)) {
|
|
1351
|
-
defs[toolName] = toolDef;
|
|
1352
|
-
}
|
|
1353
|
-
break;
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1292
|
+
for (const [k, v] of resolveBuiltin(name, opts)) defs[k] = v;
|
|
1356
1293
|
}
|
|
1357
1294
|
return defs;
|
|
1358
1295
|
}
|
|
1359
1296
|
function getBuiltinToolSchemas(names) {
|
|
1360
|
-
return names.flatMap(
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
}));
|
|
1368
|
-
}
|
|
1369
|
-
const creator = TOOL_CREATORS[name];
|
|
1370
|
-
if (!creator) return [];
|
|
1371
|
-
const def = creator();
|
|
1372
|
-
return [
|
|
1373
|
-
{
|
|
1374
|
-
name,
|
|
1375
|
-
description: def.description,
|
|
1376
|
-
parameters: z4.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1377
|
-
}
|
|
1378
|
-
];
|
|
1379
|
-
});
|
|
1380
|
-
}
|
|
1381
|
-
var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams, TOOL_CREATORS, MULTI_TOOL_BUILTINS;
|
|
1382
|
-
var init_builtin_tools = __esm({
|
|
1383
|
-
"sdk/builtin_tools.ts"() {
|
|
1384
|
-
"use strict";
|
|
1385
|
-
init_internal_types();
|
|
1386
|
-
init_memory_tools();
|
|
1387
|
-
webSearchParams = z4.object({
|
|
1388
|
-
query: z4.string().describe("The search query"),
|
|
1389
|
-
max_results: z4.number().describe("Maximum number of results to return (default 5)").optional()
|
|
1390
|
-
});
|
|
1391
|
-
BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
1392
|
-
BraveSearchResponseSchema = z4.object({
|
|
1393
|
-
web: z4.object({
|
|
1394
|
-
results: z4.array(
|
|
1395
|
-
z4.object({
|
|
1396
|
-
title: z4.string(),
|
|
1397
|
-
url: z4.string(),
|
|
1398
|
-
description: z4.string()
|
|
1399
|
-
})
|
|
1400
|
-
)
|
|
1401
|
-
}).optional()
|
|
1402
|
-
});
|
|
1403
|
-
MAX_PAGE_CHARS = 1e4;
|
|
1404
|
-
MAX_HTML_BYTES = 2e5;
|
|
1405
|
-
visitWebpageParams = z4.object({
|
|
1406
|
-
url: z4.string().describe("The full URL to fetch (e.g., 'https://example.com/page')")
|
|
1407
|
-
});
|
|
1408
|
-
fetchJsonParams = z4.object({
|
|
1409
|
-
url: z4.string().describe("The URL to fetch JSON from"),
|
|
1410
|
-
headers: z4.record(z4.string(), z4.string()).describe("Optional HTTP headers to include in the request").optional()
|
|
1411
|
-
});
|
|
1412
|
-
runCodeParams = z4.object({
|
|
1413
|
-
code: z4.string().describe("JavaScript code to execute. Use console.log() for output.")
|
|
1414
|
-
});
|
|
1415
|
-
vectorSearchParams = z4.object({
|
|
1416
|
-
query: z4.string().describe(
|
|
1417
|
-
'Short keyword query to search the knowledge base. Use specific topic terms, not full sentences. Do NOT include the company or product name since all documents are from the same source. For example, if the user asks "how much does Acme cost", search for "pricing plans rates".'
|
|
1418
|
-
),
|
|
1419
|
-
topK: z4.number().describe("Maximum results to return (default: 5)").optional()
|
|
1420
|
-
});
|
|
1421
|
-
TOOL_CREATORS = {
|
|
1422
|
-
web_search: createWebSearch,
|
|
1423
|
-
visit_webpage: createVisitWebpage,
|
|
1424
|
-
fetch_json: createFetchJson,
|
|
1425
|
-
run_code: createRunCode,
|
|
1426
|
-
// vector_search uses a stub for schema generation
|
|
1427
|
-
vector_search: () => createVectorSearch(async () => "")
|
|
1428
|
-
};
|
|
1429
|
-
MULTI_TOOL_BUILTINS = {
|
|
1430
|
-
memory: memoryTools
|
|
1431
|
-
};
|
|
1432
|
-
}
|
|
1433
|
-
});
|
|
1434
|
-
|
|
1435
|
-
// sdk/kv.ts
|
|
1436
|
-
function sortAndPaginate(entries, options) {
|
|
1437
|
-
entries.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
1438
|
-
if (options?.reverse) entries.reverse();
|
|
1439
|
-
if (options?.limit && options.limit > 0) {
|
|
1440
|
-
entries.length = Math.min(entries.length, options.limit);
|
|
1441
|
-
}
|
|
1442
|
-
return entries;
|
|
1297
|
+
return names.flatMap(
|
|
1298
|
+
(name) => resolveBuiltin(name, { vectorSearch: async () => "" }).map(([toolName, def]) => ({
|
|
1299
|
+
name: toolName,
|
|
1300
|
+
description: def.description,
|
|
1301
|
+
parameters: z4.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1302
|
+
}))
|
|
1303
|
+
);
|
|
1443
1304
|
}
|
|
1444
|
-
function
|
|
1445
|
-
const store = /* @__PURE__ */ new Map();
|
|
1446
|
-
function isExpired(entry) {
|
|
1447
|
-
return entry.expiresAt !== void 0 && entry.expiresAt <= Date.now();
|
|
1448
|
-
}
|
|
1305
|
+
function memoryTools() {
|
|
1449
1306
|
return {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
const raw = JSON.stringify(value);
|
|
1460
|
-
if (raw.length > MAX_VALUE_SIZE) {
|
|
1461
|
-
throw new Error(`Value exceeds max size of ${MAX_VALUE_SIZE} bytes`);
|
|
1462
|
-
}
|
|
1463
|
-
const expireIn = options?.expireIn;
|
|
1464
|
-
const entry = { raw };
|
|
1465
|
-
if (expireIn && expireIn > 0) {
|
|
1466
|
-
entry.expiresAt = Date.now() + expireIn;
|
|
1467
|
-
}
|
|
1468
|
-
store.set(key, entry);
|
|
1469
|
-
return Promise.resolve();
|
|
1470
|
-
},
|
|
1471
|
-
delete(key) {
|
|
1472
|
-
store.delete(key);
|
|
1473
|
-
return Promise.resolve();
|
|
1474
|
-
},
|
|
1475
|
-
async list(prefix, options) {
|
|
1476
|
-
const now = Date.now();
|
|
1477
|
-
const entries = [];
|
|
1478
|
-
let i = 0;
|
|
1479
|
-
for (const [key, entry] of store) {
|
|
1480
|
-
if (++i % 500 === 0) await new Promise((r) => setTimeout(r, 0));
|
|
1481
|
-
if (entry.expiresAt && entry.expiresAt <= now) {
|
|
1482
|
-
store.delete(key);
|
|
1483
|
-
continue;
|
|
1484
|
-
}
|
|
1485
|
-
if (key.startsWith(prefix)) {
|
|
1486
|
-
entries.push({ key, value: JSON.parse(entry.raw) });
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
return sortAndPaginate(entries, options);
|
|
1490
|
-
}
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
var MAX_VALUE_SIZE;
|
|
1494
|
-
var init_kv = __esm({
|
|
1495
|
-
"sdk/kv.ts"() {
|
|
1496
|
-
"use strict";
|
|
1497
|
-
MAX_VALUE_SIZE = 65536;
|
|
1498
|
-
}
|
|
1499
|
-
});
|
|
1500
|
-
|
|
1501
|
-
// sdk/s2s.ts
|
|
1502
|
-
import { z as z5 } from "zod";
|
|
1503
|
-
function uint8ToBase64(bytes) {
|
|
1504
|
-
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
1505
|
-
}
|
|
1506
|
-
function base64ToUint8(base64) {
|
|
1507
|
-
const buf = Buffer.from(base64, "base64");
|
|
1508
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1509
|
-
}
|
|
1510
|
-
function dispatchS2sMessage(target, msg) {
|
|
1511
|
-
switch (msg.type) {
|
|
1512
|
-
case "session.ready":
|
|
1513
|
-
target.dispatchEvent(
|
|
1514
|
-
new CustomEvent("ready", {
|
|
1515
|
-
detail: { session_id: msg.session_id }
|
|
1516
|
-
})
|
|
1517
|
-
);
|
|
1518
|
-
break;
|
|
1519
|
-
case "session.updated":
|
|
1520
|
-
target.dispatchEvent(new CustomEvent("session_updated", { detail: msg }));
|
|
1521
|
-
break;
|
|
1522
|
-
case "input.speech.started":
|
|
1523
|
-
target.dispatchEvent(new CustomEvent("speech_started"));
|
|
1524
|
-
break;
|
|
1525
|
-
case "input.speech.stopped":
|
|
1526
|
-
target.dispatchEvent(new CustomEvent("speech_stopped"));
|
|
1527
|
-
break;
|
|
1528
|
-
case "transcript.user.delta":
|
|
1529
|
-
target.dispatchEvent(
|
|
1530
|
-
new CustomEvent("user_transcript_delta", {
|
|
1531
|
-
detail: { text: msg.text }
|
|
1532
|
-
})
|
|
1533
|
-
);
|
|
1534
|
-
break;
|
|
1535
|
-
case "transcript.user":
|
|
1536
|
-
target.dispatchEvent(
|
|
1537
|
-
new CustomEvent("user_transcript", {
|
|
1538
|
-
detail: {
|
|
1539
|
-
item_id: msg.item_id,
|
|
1540
|
-
text: msg.text
|
|
1541
|
-
}
|
|
1542
|
-
})
|
|
1543
|
-
);
|
|
1544
|
-
break;
|
|
1545
|
-
case "reply.started":
|
|
1546
|
-
target.dispatchEvent(
|
|
1547
|
-
new CustomEvent("reply_started", {
|
|
1548
|
-
detail: { reply_id: msg.reply_id }
|
|
1549
|
-
})
|
|
1550
|
-
);
|
|
1551
|
-
break;
|
|
1552
|
-
// reply.audio handled on the fast path — never reaches dispatch.
|
|
1553
|
-
case "transcript.agent.delta":
|
|
1554
|
-
target.dispatchEvent(
|
|
1555
|
-
new CustomEvent("agent_transcript_delta", {
|
|
1556
|
-
detail: { text: msg.delta }
|
|
1557
|
-
})
|
|
1558
|
-
);
|
|
1559
|
-
break;
|
|
1560
|
-
case "transcript.agent":
|
|
1561
|
-
target.dispatchEvent(
|
|
1562
|
-
new CustomEvent("agent_transcript", {
|
|
1563
|
-
detail: { text: msg.text }
|
|
1564
|
-
})
|
|
1565
|
-
);
|
|
1566
|
-
break;
|
|
1567
|
-
case "tool.call":
|
|
1568
|
-
target.dispatchEvent(
|
|
1569
|
-
new CustomEvent("tool_call", {
|
|
1570
|
-
detail: {
|
|
1571
|
-
call_id: msg.call_id,
|
|
1572
|
-
name: msg.name,
|
|
1573
|
-
args: msg.args
|
|
1574
|
-
}
|
|
1575
|
-
})
|
|
1576
|
-
);
|
|
1577
|
-
break;
|
|
1578
|
-
case "reply.done":
|
|
1579
|
-
target.dispatchEvent(
|
|
1580
|
-
new CustomEvent("reply_done", {
|
|
1581
|
-
detail: { status: msg.status }
|
|
1582
|
-
})
|
|
1583
|
-
);
|
|
1584
|
-
break;
|
|
1585
|
-
case "session.error": {
|
|
1586
|
-
const isExpired = msg.code === "session_not_found" || msg.code === "session_forbidden";
|
|
1587
|
-
target.dispatchEvent(
|
|
1588
|
-
new CustomEvent(isExpired ? "session_expired" : "error", {
|
|
1589
|
-
detail: { code: msg.code, message: msg.message }
|
|
1590
|
-
})
|
|
1591
|
-
);
|
|
1592
|
-
break;
|
|
1593
|
-
}
|
|
1594
|
-
case "reply.content_part.started":
|
|
1595
|
-
case "reply.content_part.done":
|
|
1596
|
-
break;
|
|
1597
|
-
case "error":
|
|
1598
|
-
target.dispatchEvent(
|
|
1599
|
-
new CustomEvent("error", {
|
|
1600
|
-
detail: { code: "connection", message: msg.message }
|
|
1601
|
-
})
|
|
1602
|
-
);
|
|
1603
|
-
break;
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
function connectS2s(opts) {
|
|
1607
|
-
const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
|
|
1608
|
-
return new Promise((resolve, reject) => {
|
|
1609
|
-
log.debug("S2S connecting", { url: config.wssUrl });
|
|
1610
|
-
const ws = createWebSocket(config.wssUrl, {
|
|
1611
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
1612
|
-
});
|
|
1613
|
-
const target = new EventTarget();
|
|
1614
|
-
let opened = false;
|
|
1615
|
-
function send(msg) {
|
|
1616
|
-
if (ws.readyState !== WS_OPEN) return;
|
|
1617
|
-
const json = JSON.stringify(msg);
|
|
1618
|
-
if (msg.type !== "input.audio") {
|
|
1619
|
-
log.debug(
|
|
1620
|
-
`S2S >> ${msg.type}`,
|
|
1621
|
-
msg.type === "session.update" ? { payload: json } : void 0
|
|
1622
|
-
);
|
|
1623
|
-
}
|
|
1624
|
-
ws.send(json);
|
|
1625
|
-
}
|
|
1626
|
-
const handle = Object.assign(target, {
|
|
1627
|
-
sendAudio(audio) {
|
|
1628
|
-
if (ws.readyState !== WS_OPEN) return;
|
|
1629
|
-
if (ws.sendBinary) {
|
|
1630
|
-
const ab = audio.buffer.slice(
|
|
1631
|
-
audio.byteOffset,
|
|
1632
|
-
audio.byteOffset + audio.byteLength
|
|
1633
|
-
);
|
|
1634
|
-
ws.sendBinary(ab);
|
|
1635
|
-
} else {
|
|
1636
|
-
ws.send(`{"type":"input.audio","audio":"${uint8ToBase64(audio)}"}`);
|
|
1637
|
-
}
|
|
1638
|
-
},
|
|
1639
|
-
sendToolResult(callId, result) {
|
|
1640
|
-
const msg = { type: "tool.result", call_id: callId, result };
|
|
1641
|
-
log.debug("S2S >> tool.result", { call_id: callId, resultLength: result.length });
|
|
1642
|
-
send(msg);
|
|
1643
|
-
},
|
|
1644
|
-
updateSession(sessionConfig) {
|
|
1645
|
-
send({ type: "session.update", session: sessionConfig });
|
|
1646
|
-
},
|
|
1647
|
-
resumeSession(sessionId) {
|
|
1648
|
-
send({ type: "session.resume", session_id: sessionId });
|
|
1649
|
-
},
|
|
1650
|
-
close() {
|
|
1651
|
-
log.debug("S2S closing");
|
|
1652
|
-
ws.close();
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
ws.on("open", () => {
|
|
1656
|
-
opened = true;
|
|
1657
|
-
log.info("S2S WebSocket open");
|
|
1658
|
-
resolve(handle);
|
|
1659
|
-
});
|
|
1660
|
-
ws.on("audio", (data) => {
|
|
1661
|
-
const ab = data;
|
|
1662
|
-
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: new Uint8Array(ab) } }));
|
|
1663
|
-
});
|
|
1664
|
-
ws.on("message", (data) => {
|
|
1665
|
-
let raw;
|
|
1666
|
-
try {
|
|
1667
|
-
raw = JSON.parse(String(data));
|
|
1668
|
-
} catch {
|
|
1669
|
-
return;
|
|
1670
|
-
}
|
|
1671
|
-
const obj = raw;
|
|
1672
|
-
if (obj.type !== "reply.audio" && obj.type !== "input.audio" && obj.type !== "transcript.agent.delta") {
|
|
1673
|
-
log.info(`S2S << ${obj.type}`);
|
|
1307
|
+
save_memory: tool({
|
|
1308
|
+
description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
|
|
1309
|
+
parameters: z4.object({
|
|
1310
|
+
key: z4.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
|
|
1311
|
+
value: z4.string().describe("The information to remember")
|
|
1312
|
+
}),
|
|
1313
|
+
execute: async ({ key, value }, ctx) => {
|
|
1314
|
+
await ctx.kv.set(key, value);
|
|
1315
|
+
return { saved: key };
|
|
1674
1316
|
}
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1317
|
+
}),
|
|
1318
|
+
recall_memory: tool({
|
|
1319
|
+
description: "Retrieve a previously saved memory by its key.",
|
|
1320
|
+
parameters: z4.object({
|
|
1321
|
+
key: z4.string().describe("The key to look up")
|
|
1322
|
+
}),
|
|
1323
|
+
execute: async ({ key }, ctx) => {
|
|
1324
|
+
const value = await ctx.kv.get(key);
|
|
1325
|
+
if (value === null) return { found: false, key };
|
|
1326
|
+
return { found: true, key, value };
|
|
1679
1327
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
)
|
|
1685
|
-
|
|
1328
|
+
}),
|
|
1329
|
+
list_memories: tool({
|
|
1330
|
+
description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
|
|
1331
|
+
parameters: z4.object({
|
|
1332
|
+
prefix: z4.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional()
|
|
1333
|
+
}),
|
|
1334
|
+
execute: async ({ prefix }, ctx) => {
|
|
1335
|
+
const entries = await ctx.kv.list(prefix ?? "");
|
|
1336
|
+
return { count: entries.length, keys: entries.map((e) => e.key) };
|
|
1686
1337
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
});
|
|
1697
|
-
ws.on("error", (err) => {
|
|
1698
|
-
const errObj = err instanceof Error ? err : new Error(String(err));
|
|
1699
|
-
log.error("S2S WebSocket error", { error: errObj.message });
|
|
1700
|
-
if (!opened) {
|
|
1701
|
-
reject(errObj);
|
|
1702
|
-
} else {
|
|
1703
|
-
target.dispatchEvent(
|
|
1704
|
-
new CustomEvent("error", {
|
|
1705
|
-
detail: { code: "ws_error", message: errObj.message }
|
|
1706
|
-
})
|
|
1707
|
-
);
|
|
1338
|
+
}),
|
|
1339
|
+
forget_memory: tool({
|
|
1340
|
+
description: "Delete a previously saved memory by its key.",
|
|
1341
|
+
parameters: z4.object({
|
|
1342
|
+
key: z4.string().describe("The key to delete")
|
|
1343
|
+
}),
|
|
1344
|
+
execute: async ({ key }, ctx) => {
|
|
1345
|
+
await ctx.kv.delete(key);
|
|
1346
|
+
return { deleted: key };
|
|
1708
1347
|
}
|
|
1709
|
-
})
|
|
1710
|
-
}
|
|
1348
|
+
})
|
|
1349
|
+
};
|
|
1711
1350
|
}
|
|
1712
|
-
var
|
|
1713
|
-
var
|
|
1714
|
-
"sdk/
|
|
1351
|
+
var FETCH_TIMEOUT_MS, RUN_CODE_TIMEOUT, webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams, TOOL_REGISTRY;
|
|
1352
|
+
var init_builtin_tools = __esm({
|
|
1353
|
+
"sdk/builtin_tools.ts"() {
|
|
1715
1354
|
"use strict";
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1355
|
+
init_internal_types();
|
|
1356
|
+
init_utils();
|
|
1357
|
+
init_types();
|
|
1358
|
+
FETCH_TIMEOUT_MS = 15e3;
|
|
1359
|
+
RUN_CODE_TIMEOUT = 5e3;
|
|
1360
|
+
webSearchParams = z4.object({
|
|
1361
|
+
query: z4.string().describe("The search query"),
|
|
1362
|
+
max_results: z4.number().describe("Maximum number of results to return (default 5)").optional()
|
|
1363
|
+
});
|
|
1364
|
+
BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
1365
|
+
BraveSearchResponseSchema = z4.object({
|
|
1366
|
+
web: z4.object({
|
|
1367
|
+
results: z4.array(
|
|
1368
|
+
z4.object({
|
|
1369
|
+
title: z4.string(),
|
|
1370
|
+
url: z4.string(),
|
|
1371
|
+
description: z4.string()
|
|
1372
|
+
})
|
|
1373
|
+
)
|
|
1374
|
+
}).optional()
|
|
1375
|
+
});
|
|
1376
|
+
MAX_PAGE_CHARS = 1e4;
|
|
1377
|
+
MAX_HTML_BYTES = 2e5;
|
|
1378
|
+
visitWebpageParams = z4.object({
|
|
1379
|
+
url: z4.string().describe("The full URL to fetch (e.g., 'https://example.com/page')")
|
|
1380
|
+
});
|
|
1381
|
+
fetchJsonParams = z4.object({
|
|
1382
|
+
url: z4.string().describe("The URL to fetch JSON from"),
|
|
1383
|
+
headers: z4.record(z4.string(), z4.string()).describe("Optional HTTP headers to include in the request").optional()
|
|
1384
|
+
});
|
|
1385
|
+
runCodeParams = z4.object({
|
|
1386
|
+
code: z4.string().describe("JavaScript code to execute. Use console.log() for output.")
|
|
1387
|
+
});
|
|
1388
|
+
vectorSearchParams = z4.object({
|
|
1389
|
+
query: z4.string().describe(
|
|
1390
|
+
'Short keyword query to search the knowledge base. Use specific topic terms, not full sentences. Do NOT include the company or product name since all documents are from the same source. For example, if the user asks "how much does Acme cost", search for "pricing plans rates".'
|
|
1391
|
+
),
|
|
1392
|
+
topK: z4.number().describe("Maximum results to return (default: 5)").optional()
|
|
1393
|
+
});
|
|
1394
|
+
TOOL_REGISTRY = {
|
|
1395
|
+
web_search: { create: (opts) => createWebSearch(opts?.fetch) },
|
|
1396
|
+
visit_webpage: { create: (opts) => createVisitWebpage(opts?.fetch) },
|
|
1397
|
+
fetch_json: { create: (opts) => createFetchJson(opts?.fetch) },
|
|
1398
|
+
run_code: { create: createRunCode },
|
|
1399
|
+
vector_search: { create: (opts) => createVectorSearch(opts?.vectorSearch ?? (async () => "")) },
|
|
1400
|
+
memory: { multi: memoryTools }
|
|
1401
|
+
};
|
|
1756
1402
|
}
|
|
1757
1403
|
});
|
|
1758
1404
|
|
|
1759
|
-
// sdk/
|
|
1760
|
-
function
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
}
|
|
1773
|
-
return
|
|
1774
|
-
|
|
1775
|
-
|
|
1405
|
+
// sdk/kv.ts
|
|
1406
|
+
function sortAndPaginate(entries, options) {
|
|
1407
|
+
entries.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
1408
|
+
if (options?.reverse) entries.reverse();
|
|
1409
|
+
if (options?.limit && options.limit > 0) {
|
|
1410
|
+
entries.length = Math.min(entries.length, options.limit);
|
|
1411
|
+
}
|
|
1412
|
+
return entries;
|
|
1413
|
+
}
|
|
1414
|
+
function createMemoryKv() {
|
|
1415
|
+
const store = /* @__PURE__ */ new Map();
|
|
1416
|
+
function isExpired(entry) {
|
|
1417
|
+
return entry.expiresAt !== void 0 && entry.expiresAt <= Date.now();
|
|
1418
|
+
}
|
|
1419
|
+
return {
|
|
1420
|
+
get(key) {
|
|
1421
|
+
const entry = store.get(key);
|
|
1422
|
+
if (!entry || isExpired(entry)) {
|
|
1423
|
+
if (entry) store.delete(key);
|
|
1424
|
+
return Promise.resolve(null);
|
|
1425
|
+
}
|
|
1426
|
+
return Promise.resolve(JSON.parse(entry.raw));
|
|
1427
|
+
},
|
|
1428
|
+
set(key, value, options) {
|
|
1429
|
+
const raw = JSON.stringify(value);
|
|
1430
|
+
if (raw.length > MAX_VALUE_SIZE) {
|
|
1431
|
+
throw new Error(`Value exceeds max size of ${MAX_VALUE_SIZE} bytes`);
|
|
1432
|
+
}
|
|
1433
|
+
const expireIn = options?.expireIn;
|
|
1434
|
+
const entry = { raw };
|
|
1435
|
+
if (expireIn && expireIn > 0) {
|
|
1436
|
+
entry.expiresAt = Date.now() + expireIn;
|
|
1437
|
+
}
|
|
1438
|
+
store.set(key, entry);
|
|
1439
|
+
return Promise.resolve();
|
|
1440
|
+
},
|
|
1441
|
+
delete(key) {
|
|
1442
|
+
store.delete(key);
|
|
1443
|
+
return Promise.resolve();
|
|
1444
|
+
},
|
|
1445
|
+
async list(prefix, options) {
|
|
1446
|
+
const now = Date.now();
|
|
1447
|
+
const entries = [];
|
|
1448
|
+
let i = 0;
|
|
1449
|
+
for (const [key, entry] of store) {
|
|
1450
|
+
if (++i % 500 === 0) await new Promise((r) => setTimeout(r, 0));
|
|
1451
|
+
if (entry.expiresAt && entry.expiresAt <= now) {
|
|
1452
|
+
store.delete(key);
|
|
1453
|
+
continue;
|
|
1454
|
+
}
|
|
1455
|
+
if (key.startsWith(prefix)) {
|
|
1456
|
+
entries.push({ key, value: JSON.parse(entry.raw) });
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return sortAndPaginate(entries, options);
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1776
1462
|
}
|
|
1777
|
-
var
|
|
1778
|
-
var
|
|
1779
|
-
"sdk/
|
|
1463
|
+
var MAX_VALUE_SIZE;
|
|
1464
|
+
var init_kv = __esm({
|
|
1465
|
+
"sdk/kv.ts"() {
|
|
1780
1466
|
"use strict";
|
|
1781
|
-
|
|
1782
|
-
VOICE_RULES = '\n\nCRITICAL OUTPUT RULES \u2014 you MUST follow these for EVERY response:\nYour response will be spoken aloud by a TTS system and displayed as plain text.\n- NEVER use markdown: no **, no *, no _, no #, no `, no [](), no ---\n- NEVER use bullet points (-, *, \u2022) or numbered lists (1., 2.)\n- NEVER use code blocks or inline code\n- NEVER mention tools, search, APIs, or technical failures to the user. If a tool returns no results, just answer naturally without explaining why.\n- Write exactly as you would say it out loud to a friend\n- Use short conversational sentences. To list things, say "First," "Next," "Finally,"\n- Keep responses concise \u2014 1 to 3 sentences max';
|
|
1467
|
+
MAX_VALUE_SIZE = 65536;
|
|
1783
1468
|
}
|
|
1784
1469
|
});
|
|
1785
1470
|
|
|
@@ -1813,7 +1498,6 @@ function createS2sSession(opts) {
|
|
|
1813
1498
|
}));
|
|
1814
1499
|
let s2s = null;
|
|
1815
1500
|
const sessionAbort = new AbortController();
|
|
1816
|
-
let audioReady = false;
|
|
1817
1501
|
let toolCallCount = 0;
|
|
1818
1502
|
let turnPromise = null;
|
|
1819
1503
|
let conversationMessages = [];
|
|
@@ -1825,36 +1509,21 @@ function createS2sSession(opts) {
|
|
|
1825
1509
|
if (!hookInvoker) return null;
|
|
1826
1510
|
try {
|
|
1827
1511
|
return await hookInvoker.resolveTurnConfig(id, HOOK_TIMEOUT_MS);
|
|
1828
|
-
} catch {
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
log.warn("resolveTurnConfig hook failed", { err: errorMessage(err) });
|
|
1829
1514
|
return null;
|
|
1830
1515
|
}
|
|
1831
1516
|
}
|
|
1832
1517
|
function invokeHook(hook, arg) {
|
|
1833
1518
|
if (!hookInvoker) return;
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
break;
|
|
1839
|
-
case "onDisconnect":
|
|
1840
|
-
await hookInvoker.onDisconnect(id, HOOK_TIMEOUT_MS);
|
|
1841
|
-
break;
|
|
1842
|
-
case "onTurn":
|
|
1843
|
-
await hookInvoker.onTurn(id, arg, HOOK_TIMEOUT_MS);
|
|
1844
|
-
break;
|
|
1845
|
-
case "onError":
|
|
1846
|
-
await hookInvoker.onError(id, arg, HOOK_TIMEOUT_MS);
|
|
1847
|
-
break;
|
|
1848
|
-
case "onStep":
|
|
1849
|
-
await hookInvoker.onStep(id, arg, HOOK_TIMEOUT_MS);
|
|
1850
|
-
break;
|
|
1851
|
-
}
|
|
1852
|
-
};
|
|
1853
|
-
run().catch((err) => {
|
|
1854
|
-
log.warn(`${hook} hook failed`, {
|
|
1855
|
-
err: err instanceof Error ? err.message : String(err)
|
|
1519
|
+
try {
|
|
1520
|
+
const h = hookInvoker[hook];
|
|
1521
|
+
Promise.resolve(h.call(hookInvoker, id, arg, HOOK_TIMEOUT_MS)).catch((err) => {
|
|
1522
|
+
log.warn(`${hook} hook failed`, { err: errorMessage(err) });
|
|
1856
1523
|
});
|
|
1857
|
-
})
|
|
1524
|
+
} catch (err) {
|
|
1525
|
+
log.warn(`${hook} hook failed`, { err: errorMessage(err) });
|
|
1526
|
+
}
|
|
1858
1527
|
}
|
|
1859
1528
|
function checkTurnLimits(turnConfig, name) {
|
|
1860
1529
|
const maxSteps = turnConfig?.maxSteps ?? agentConfig.maxSteps;
|
|
@@ -1894,7 +1563,7 @@ function createS2sSession(opts) {
|
|
|
1894
1563
|
try {
|
|
1895
1564
|
result = await executeTool(name, parsedArgs, id, conversationMessages);
|
|
1896
1565
|
} catch (err) {
|
|
1897
|
-
const msg =
|
|
1566
|
+
const msg = errorMessage(err);
|
|
1898
1567
|
log.error("Tool execution failed", { tool: name, error: msg });
|
|
1899
1568
|
result = JSON.stringify({ error: msg });
|
|
1900
1569
|
}
|
|
@@ -1909,6 +1578,79 @@ function createS2sSession(opts) {
|
|
|
1909
1578
|
function on(target, event, handler) {
|
|
1910
1579
|
target.addEventListener(event, handler);
|
|
1911
1580
|
}
|
|
1581
|
+
function setupListeners(handle) {
|
|
1582
|
+
on(handle, "ready", (e) => {
|
|
1583
|
+
s2sSessionId = e.detail.session_id;
|
|
1584
|
+
log.info("S2S session ready", { session_id: s2sSessionId });
|
|
1585
|
+
});
|
|
1586
|
+
on(handle, "session_expired", () => {
|
|
1587
|
+
log.info("S2S session expired, reconnecting fresh");
|
|
1588
|
+
s2sSessionId = null;
|
|
1589
|
+
handle.close();
|
|
1590
|
+
});
|
|
1591
|
+
for (const type of ["speech_started", "speech_stopped"]) {
|
|
1592
|
+
handle.addEventListener(type, () => client.event({ type }));
|
|
1593
|
+
}
|
|
1594
|
+
on(handle, "user_transcript_delta", (e) => {
|
|
1595
|
+
client.event({ type: "transcript", text: e.detail.text, isFinal: false });
|
|
1596
|
+
});
|
|
1597
|
+
on(handle, "user_transcript", (e) => {
|
|
1598
|
+
const { text } = e.detail;
|
|
1599
|
+
log.info("S2S user transcript", { text });
|
|
1600
|
+
client.event({ type: "transcript", text, isFinal: true });
|
|
1601
|
+
client.event({ type: "turn", text });
|
|
1602
|
+
conversationMessages.push({ role: "user", content: text });
|
|
1603
|
+
invokeHook("onTurn", text);
|
|
1604
|
+
});
|
|
1605
|
+
handle.addEventListener("reply_started", () => {
|
|
1606
|
+
toolCallCount = 0;
|
|
1607
|
+
});
|
|
1608
|
+
on(handle, "audio", (e) => {
|
|
1609
|
+
client.playAudioChunk(e.detail.audio);
|
|
1610
|
+
});
|
|
1611
|
+
on(handle, "agent_transcript_delta", (e) => {
|
|
1612
|
+
client.event({ type: "chat_delta", text: e.detail.text });
|
|
1613
|
+
});
|
|
1614
|
+
on(handle, "agent_transcript", (e) => {
|
|
1615
|
+
const { text } = e.detail;
|
|
1616
|
+
client.event({ type: "chat", text });
|
|
1617
|
+
conversationMessages.push({ role: "assistant", content: text });
|
|
1618
|
+
});
|
|
1619
|
+
on(handle, "tool_call", (e) => {
|
|
1620
|
+
const p = handleToolCall(e.detail).catch((err) => {
|
|
1621
|
+
log.error("Tool call handler failed", { err: errorMessage(err) });
|
|
1622
|
+
});
|
|
1623
|
+
turnPromise = (turnPromise ?? Promise.resolve()).then(() => p);
|
|
1624
|
+
});
|
|
1625
|
+
on(handle, "reply_done", (e) => {
|
|
1626
|
+
if (e.detail.status === "interrupted") {
|
|
1627
|
+
log.info("S2S reply interrupted (barge-in)");
|
|
1628
|
+
pendingTools = [];
|
|
1629
|
+
client.event({ type: "cancelled" });
|
|
1630
|
+
} else if (pendingTools.length > 0) {
|
|
1631
|
+
for (const tool2 of pendingTools) s2s?.sendToolResult(tool2.call_id, tool2.result);
|
|
1632
|
+
pendingTools = [];
|
|
1633
|
+
} else {
|
|
1634
|
+
client.playAudioDone();
|
|
1635
|
+
client.event({ type: "tts_done" });
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
on(handle, "error", (e) => {
|
|
1639
|
+
log.error("S2S error", { code: e.detail.code, message: e.detail.message });
|
|
1640
|
+
client.event({ type: "error", code: "internal", message: e.detail.message });
|
|
1641
|
+
handle.close();
|
|
1642
|
+
});
|
|
1643
|
+
handle.addEventListener("close", () => {
|
|
1644
|
+
log.info("S2S closed");
|
|
1645
|
+
s2s = null;
|
|
1646
|
+
if (!sessionAbort.signal.aborted) {
|
|
1647
|
+
log.info("Attempting S2S reconnect");
|
|
1648
|
+
connectAndSetup().catch((err) => {
|
|
1649
|
+
log.error("S2S reconnect failed", { error: errorMessage(err) });
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1912
1654
|
async function connectAndSetup() {
|
|
1913
1655
|
if (connecting) {
|
|
1914
1656
|
pendingReconnect = true;
|
|
@@ -1916,106 +1658,15 @@ function createS2sSession(opts) {
|
|
|
1916
1658
|
}
|
|
1917
1659
|
connecting = true;
|
|
1918
1660
|
try {
|
|
1919
|
-
const handle = await
|
|
1661
|
+
const handle = await _internals.connectS2s({
|
|
1920
1662
|
apiKey,
|
|
1921
1663
|
config: s2sConfig,
|
|
1922
1664
|
createWebSocket,
|
|
1923
1665
|
logger: log
|
|
1924
1666
|
});
|
|
1925
|
-
|
|
1926
|
-
s2sSessionId = e.detail.session_id;
|
|
1927
|
-
log.info("S2S session ready", { session_id: s2sSessionId });
|
|
1928
|
-
});
|
|
1929
|
-
on(handle, "session_expired", () => {
|
|
1930
|
-
log.info("S2S session expired, reconnecting fresh");
|
|
1931
|
-
s2sSessionId = null;
|
|
1932
|
-
handle.close();
|
|
1933
|
-
});
|
|
1934
|
-
handle.addEventListener("speech_started", () => {
|
|
1935
|
-
client.event({ type: "speech_started" });
|
|
1936
|
-
});
|
|
1937
|
-
handle.addEventListener("speech_stopped", () => {
|
|
1938
|
-
client.event({ type: "speech_stopped" });
|
|
1939
|
-
});
|
|
1940
|
-
on(handle, "user_transcript_delta", (e) => {
|
|
1941
|
-
client.event({
|
|
1942
|
-
type: "transcript",
|
|
1943
|
-
text: e.detail.text,
|
|
1944
|
-
isFinal: false
|
|
1945
|
-
});
|
|
1946
|
-
});
|
|
1947
|
-
on(handle, "user_transcript", (e) => {
|
|
1948
|
-
const { text } = e.detail;
|
|
1949
|
-
log.info("S2S user transcript", { text });
|
|
1950
|
-
client.event({ type: "transcript", text, isFinal: true });
|
|
1951
|
-
client.event({ type: "turn", text });
|
|
1952
|
-
conversationMessages.push({ role: "user", content: text });
|
|
1953
|
-
invokeHook("onTurn", text);
|
|
1954
|
-
});
|
|
1955
|
-
handle.addEventListener("reply_started", () => {
|
|
1956
|
-
toolCallCount = 0;
|
|
1957
|
-
});
|
|
1958
|
-
on(handle, "audio", (e) => {
|
|
1959
|
-
client.playAudioChunk(e.detail.audio);
|
|
1960
|
-
});
|
|
1961
|
-
on(handle, "agent_transcript_delta", (e) => {
|
|
1962
|
-
client.event({ type: "chat_delta", text: e.detail.text });
|
|
1963
|
-
});
|
|
1964
|
-
on(handle, "agent_transcript", (e) => {
|
|
1965
|
-
const { text } = e.detail;
|
|
1966
|
-
client.event({ type: "chat", text });
|
|
1967
|
-
conversationMessages.push({ role: "assistant", content: text });
|
|
1968
|
-
});
|
|
1969
|
-
on(handle, "tool_call", (e) => {
|
|
1970
|
-
const p = handleToolCall(e.detail).catch((err) => {
|
|
1971
|
-
log.error("Tool call handler failed", {
|
|
1972
|
-
err: err instanceof Error ? err.message : String(err)
|
|
1973
|
-
});
|
|
1974
|
-
});
|
|
1975
|
-
turnPromise = (turnPromise ?? Promise.resolve()).then(() => p);
|
|
1976
|
-
});
|
|
1977
|
-
on(handle, "reply_done", (e) => {
|
|
1978
|
-
if (e.detail.status === "interrupted") {
|
|
1979
|
-
log.info("S2S reply interrupted (barge-in)");
|
|
1980
|
-
pendingTools = [];
|
|
1981
|
-
client.event({ type: "cancelled" });
|
|
1982
|
-
} else if (pendingTools.length > 0) {
|
|
1983
|
-
for (const tool2 of pendingTools) {
|
|
1984
|
-
s2s?.sendToolResult(tool2.call_id, tool2.result);
|
|
1985
|
-
}
|
|
1986
|
-
pendingTools = [];
|
|
1987
|
-
} else {
|
|
1988
|
-
client.playAudioDone();
|
|
1989
|
-
client.event({ type: "tts_done" });
|
|
1990
|
-
}
|
|
1991
|
-
});
|
|
1992
|
-
on(handle, "error", (e) => {
|
|
1993
|
-
log.error("S2S error", {
|
|
1994
|
-
code: e.detail.code,
|
|
1995
|
-
message: e.detail.message
|
|
1996
|
-
});
|
|
1997
|
-
client.event({
|
|
1998
|
-
type: "error",
|
|
1999
|
-
code: "internal",
|
|
2000
|
-
message: e.detail.message
|
|
2001
|
-
});
|
|
2002
|
-
handle.close();
|
|
2003
|
-
});
|
|
2004
|
-
handle.addEventListener("close", () => {
|
|
2005
|
-
log.info("S2S closed");
|
|
2006
|
-
s2s = null;
|
|
2007
|
-
if (!sessionAbort.signal.aborted) {
|
|
2008
|
-
log.info("Attempting S2S reconnect");
|
|
2009
|
-
connectAndSetup().catch((err) => {
|
|
2010
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2011
|
-
log.error("S2S reconnect failed", { error: msg });
|
|
2012
|
-
});
|
|
2013
|
-
}
|
|
2014
|
-
});
|
|
1667
|
+
setupListeners(handle);
|
|
2015
1668
|
if (s2sSessionId) {
|
|
2016
|
-
log.info("Attempting S2S session resume", {
|
|
2017
|
-
session_id: s2sSessionId
|
|
2018
|
-
});
|
|
1669
|
+
log.info("Attempting S2S session resume", { session_id: s2sSessionId });
|
|
2019
1670
|
handle.resumeSession(s2sSessionId);
|
|
2020
1671
|
} else {
|
|
2021
1672
|
handle.updateSession({
|
|
@@ -2026,7 +1677,7 @@ function createS2sSession(opts) {
|
|
|
2026
1677
|
}
|
|
2027
1678
|
s2s = handle;
|
|
2028
1679
|
} catch (err) {
|
|
2029
|
-
const msg =
|
|
1680
|
+
const msg = errorMessage(err);
|
|
2030
1681
|
log.error("S2S connect failed", { error: msg });
|
|
2031
1682
|
client.event({ type: "error", code: "internal", message: msg });
|
|
2032
1683
|
} finally {
|
|
@@ -2034,8 +1685,7 @@ function createS2sSession(opts) {
|
|
|
2034
1685
|
if (pendingReconnect && !sessionAbort.signal.aborted) {
|
|
2035
1686
|
pendingReconnect = false;
|
|
2036
1687
|
connectAndSetup().catch((err) => {
|
|
2037
|
-
|
|
2038
|
-
log.error("S2S deferred reconnect failed", { error: msg });
|
|
1688
|
+
log.error("S2S deferred reconnect failed", { error: errorMessage(err) });
|
|
2039
1689
|
});
|
|
2040
1690
|
}
|
|
2041
1691
|
}
|
|
@@ -2059,8 +1709,6 @@ function createS2sSession(opts) {
|
|
|
2059
1709
|
s2s?.sendAudio(data);
|
|
2060
1710
|
},
|
|
2061
1711
|
onAudioReady() {
|
|
2062
|
-
if (audioReady) return;
|
|
2063
|
-
audioReady = true;
|
|
2064
1712
|
},
|
|
2065
1713
|
onCancel() {
|
|
2066
1714
|
client.event({ type: "cancelled" });
|
|
@@ -2084,17 +1732,36 @@ function createS2sSession(opts) {
|
|
|
2084
1732
|
}
|
|
2085
1733
|
};
|
|
2086
1734
|
}
|
|
2087
|
-
|
|
1735
|
+
function buildSystemPrompt(config, opts) {
|
|
1736
|
+
const { hasTools } = opts;
|
|
1737
|
+
const agentInstructions = config.instructions && config.instructions !== DEFAULT_INSTRUCTIONS ? `
|
|
1738
|
+
|
|
1739
|
+
Agent-Specific Instructions:
|
|
1740
|
+
${config.instructions}` : "";
|
|
1741
|
+
const toolPreamble = hasTools ? '\n\nWhen you decide to use a tool, ALWAYS say a brief natural phrase BEFORE the tool call (e.g. "Let me look that up" or "One moment while I check"). This fills silence while the tool executes. Keep preambles to one short sentence.' : "";
|
|
1742
|
+
const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
1743
|
+
weekday: "long",
|
|
1744
|
+
year: "numeric",
|
|
1745
|
+
month: "long",
|
|
1746
|
+
day: "numeric"
|
|
1747
|
+
});
|
|
1748
|
+
return DEFAULT_INSTRUCTIONS + `
|
|
1749
|
+
|
|
1750
|
+
Today's date is ${today}.` + agentInstructions + toolPreamble + (opts.voice ? VOICE_RULES : "");
|
|
1751
|
+
}
|
|
1752
|
+
var _internals, VOICE_RULES;
|
|
2088
1753
|
var init_session = __esm({
|
|
2089
1754
|
"sdk/session.ts"() {
|
|
2090
1755
|
"use strict";
|
|
1756
|
+
init_utils();
|
|
2091
1757
|
init_protocol();
|
|
2092
1758
|
init_runtime();
|
|
2093
1759
|
init_s2s();
|
|
2094
|
-
|
|
2095
|
-
|
|
1760
|
+
init_types();
|
|
1761
|
+
_internals = {
|
|
2096
1762
|
connectS2s
|
|
2097
1763
|
};
|
|
1764
|
+
VOICE_RULES = '\n\nCRITICAL OUTPUT RULES \u2014 you MUST follow these for EVERY response:\nYour response will be spoken aloud by a TTS system and displayed as plain text.\n- NEVER use markdown: no **, no *, no _, no #, no `, no [](), no ---\n- NEVER use bullet points (-, *, \u2022) or numbered lists (1., 2.)\n- NEVER use code blocks or inline code\n- NEVER mention tools, search, APIs, or technical failures to the user. If a tool returns no results, just answer naturally without explaining why.\n- Write exactly as you would say it out loud to a friend\n- Use short conversational sentences. To list things, say "First," "Next," "Finally,"\n- Keep responses concise \u2014 1 to 3 sentences max';
|
|
2098
1765
|
}
|
|
2099
1766
|
});
|
|
2100
1767
|
|
|
@@ -2145,11 +1812,10 @@ var init_vector = __esm({
|
|
|
2145
1812
|
|
|
2146
1813
|
// sdk/worker_entry.ts
|
|
2147
1814
|
function buildToolContext(opts) {
|
|
2148
|
-
const { env,
|
|
1815
|
+
const { env, state, kv, vector, messages } = opts;
|
|
2149
1816
|
return {
|
|
2150
|
-
sessionId: sessionId ?? "",
|
|
2151
1817
|
env: { ...env },
|
|
2152
|
-
abortSignal: AbortSignal.timeout(
|
|
1818
|
+
abortSignal: AbortSignal.timeout(TOOL_EXECUTION_TIMEOUT_MS),
|
|
2153
1819
|
state: state ?? {},
|
|
2154
1820
|
get kv() {
|
|
2155
1821
|
if (!kv) throw new Error("KV not available");
|
|
@@ -2178,21 +1844,18 @@ async function executeToolCall(name, args, options) {
|
|
|
2178
1844
|
if (result == null) return "null";
|
|
2179
1845
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
2180
1846
|
} catch (err) {
|
|
2181
|
-
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
2182
|
-
console.warn(`[tool-executor] Tool execution timed out: ${name}`);
|
|
2183
|
-
return `Error: Tool "${name}" timed out after ${TOOL_HANDLER_TIMEOUT}ms`;
|
|
2184
|
-
}
|
|
2185
1847
|
console.warn(`[tool-executor] Tool execution failed: ${name}`, err);
|
|
2186
|
-
return `Error: ${
|
|
1848
|
+
return `Error: ${errorMessage(err)}`;
|
|
2187
1849
|
}
|
|
2188
1850
|
}
|
|
2189
|
-
var yieldTick
|
|
1851
|
+
var yieldTick;
|
|
2190
1852
|
var init_worker_entry = __esm({
|
|
2191
1853
|
"sdk/worker_entry.ts"() {
|
|
2192
1854
|
"use strict";
|
|
2193
1855
|
init_internal_types();
|
|
1856
|
+
init_utils();
|
|
1857
|
+
init_protocol();
|
|
2194
1858
|
yieldTick = () => new Promise((r) => setTimeout(r, 0));
|
|
2195
|
-
TOOL_HANDLER_TIMEOUT = 3e4;
|
|
2196
1859
|
}
|
|
2197
1860
|
});
|
|
2198
1861
|
|
|
@@ -2244,7 +1907,6 @@ function createDirectExecutor(opts) {
|
|
|
2244
1907
|
}
|
|
2245
1908
|
function makeHookContext(sessionId) {
|
|
2246
1909
|
return {
|
|
2247
|
-
sessionId,
|
|
2248
1910
|
env: frozenEnv,
|
|
2249
1911
|
state: getState(sessionId),
|
|
2250
1912
|
get kv() {
|
|
@@ -2261,7 +1923,6 @@ function createDirectExecutor(opts) {
|
|
|
2261
1923
|
return executeToolCall(name, args, {
|
|
2262
1924
|
tool: tool2,
|
|
2263
1925
|
env: frozenEnv,
|
|
2264
|
-
sessionId,
|
|
2265
1926
|
state: getState(sessionId ?? ""),
|
|
2266
1927
|
kv,
|
|
2267
1928
|
vector,
|
|
@@ -2340,9 +2001,6 @@ var init_direct_executor = __esm({
|
|
|
2340
2001
|
});
|
|
2341
2002
|
|
|
2342
2003
|
// sdk/ws_handler.ts
|
|
2343
|
-
function isValidAudioChunk(data) {
|
|
2344
|
-
return data.byteLength > 0 && data.byteLength <= MAX_AUDIO_CHUNK_BYTES && data.byteLength % 2 === 0;
|
|
2345
|
-
}
|
|
2346
2004
|
function createClientSink(ws) {
|
|
2347
2005
|
function safeSend(data) {
|
|
2348
2006
|
try {
|
|
@@ -2374,19 +2032,9 @@ function toUint8Array(data) {
|
|
|
2374
2032
|
const buf = data;
|
|
2375
2033
|
return new Uint8Array(buf.buffer ?? data, buf.byteOffset ?? 0, buf.byteLength);
|
|
2376
2034
|
}
|
|
2377
|
-
function handleBinaryAudio(data, session
|
|
2035
|
+
function handleBinaryAudio(data, session) {
|
|
2378
2036
|
if (!isBinaryData(data)) return false;
|
|
2379
|
-
|
|
2380
|
-
if (!isValidAudioChunk(chunk)) {
|
|
2381
|
-
log.warn("Invalid audio chunk, dropping", {
|
|
2382
|
-
...ctx,
|
|
2383
|
-
sid,
|
|
2384
|
-
bytes: chunk.byteLength,
|
|
2385
|
-
aligned: chunk.byteLength % 2 === 0
|
|
2386
|
-
});
|
|
2387
|
-
return true;
|
|
2388
|
-
}
|
|
2389
|
-
session.onAudio(chunk);
|
|
2037
|
+
session.onAudio(toUint8Array(data));
|
|
2390
2038
|
return true;
|
|
2391
2039
|
}
|
|
2392
2040
|
function handleTextMessage(data, session, log, ctx, sid) {
|
|
@@ -2432,8 +2080,11 @@ function wireSessionSocket(ws, opts) {
|
|
|
2432
2080
|
session = opts.createSession(sessionId, client);
|
|
2433
2081
|
sessions.set(sessionId, session);
|
|
2434
2082
|
ws.send(JSON.stringify({ type: "config", ...opts.readyConfig }));
|
|
2435
|
-
|
|
2436
|
-
|
|
2083
|
+
session.start().then(() => {
|
|
2084
|
+
log.info("Session ready", { ...ctx, sid });
|
|
2085
|
+
}).catch((err) => {
|
|
2086
|
+
log.error("Session start failed", { ...ctx, sid, error: errorMessage(err) });
|
|
2087
|
+
});
|
|
2437
2088
|
}
|
|
2438
2089
|
if (ws.readyState === 1) {
|
|
2439
2090
|
onOpen();
|
|
@@ -2443,7 +2094,7 @@ function wireSessionSocket(ws, opts) {
|
|
|
2443
2094
|
ws.addEventListener("message", (event) => {
|
|
2444
2095
|
if (!session) return;
|
|
2445
2096
|
const { data } = event;
|
|
2446
|
-
if (handleBinaryAudio(data, session
|
|
2097
|
+
if (handleBinaryAudio(data, session)) return;
|
|
2447
2098
|
handleTextMessage(data, session, log, ctx, sid);
|
|
2448
2099
|
});
|
|
2449
2100
|
ws.addEventListener("close", () => {
|
|
@@ -2460,17 +2111,17 @@ function wireSessionSocket(ws, opts) {
|
|
|
2460
2111
|
log.error("WebSocket error", { ...ctx, sid, error: msg });
|
|
2461
2112
|
});
|
|
2462
2113
|
}
|
|
2463
|
-
var MAX_AUDIO_CHUNK_BYTES;
|
|
2464
2114
|
var init_ws_handler = __esm({
|
|
2465
2115
|
"sdk/ws_handler.ts"() {
|
|
2466
2116
|
"use strict";
|
|
2117
|
+
init_utils();
|
|
2467
2118
|
init_protocol();
|
|
2468
2119
|
init_runtime();
|
|
2469
|
-
MAX_AUDIO_CHUNK_BYTES = 1048576;
|
|
2470
2120
|
}
|
|
2471
2121
|
});
|
|
2472
2122
|
|
|
2473
2123
|
// sdk/winterc_server.ts
|
|
2124
|
+
import { Hono } from "hono";
|
|
2474
2125
|
function createWintercServer(options) {
|
|
2475
2126
|
const {
|
|
2476
2127
|
agent,
|
|
@@ -2500,26 +2151,19 @@ function createWintercServer(options) {
|
|
|
2500
2151
|
sampleRate: s2sConfig.inputSampleRate,
|
|
2501
2152
|
ttsSampleRate: s2sConfig.outputSampleRate
|
|
2502
2153
|
};
|
|
2154
|
+
const app = new Hono();
|
|
2155
|
+
app.get("/health", (c) => c.json({ status: "ok", name: agent.name }));
|
|
2156
|
+
app.get("/", (c) => {
|
|
2157
|
+
if (clientHtml) {
|
|
2158
|
+
return c.html(clientHtml);
|
|
2159
|
+
}
|
|
2160
|
+
return c.html(
|
|
2161
|
+
`<!DOCTYPE html><html><body><h1>${agent.name}</h1><p>Agent server running.</p></body></html>`
|
|
2162
|
+
);
|
|
2163
|
+
});
|
|
2503
2164
|
return {
|
|
2504
2165
|
async fetch(request) {
|
|
2505
|
-
|
|
2506
|
-
if (url.pathname === "/health") {
|
|
2507
|
-
return new Response(JSON.stringify({ status: "ok", name: agent.name }), {
|
|
2508
|
-
headers: { "Content-Type": "application/json" }
|
|
2509
|
-
});
|
|
2510
|
-
}
|
|
2511
|
-
if (url.pathname === "/" && clientHtml) {
|
|
2512
|
-
return new Response(clientHtml, {
|
|
2513
|
-
headers: { "Content-Type": "text/html" }
|
|
2514
|
-
});
|
|
2515
|
-
}
|
|
2516
|
-
if (url.pathname === "/") {
|
|
2517
|
-
return new Response(
|
|
2518
|
-
`<!DOCTYPE html><html><body><h1>${agent.name}</h1><p>Agent server running.</p></body></html>`,
|
|
2519
|
-
{ headers: { "Content-Type": "text/html" } }
|
|
2520
|
-
);
|
|
2521
|
-
}
|
|
2522
|
-
return new Response("Not Found", { status: 404 });
|
|
2166
|
+
return app.fetch(request);
|
|
2523
2167
|
},
|
|
2524
2168
|
handleWebSocket(ws, wsOpts) {
|
|
2525
2169
|
wireSessionSocket(ws, {
|
|
@@ -2559,11 +2203,14 @@ var server_exports = {};
|
|
|
2559
2203
|
__export(server_exports, {
|
|
2560
2204
|
createServer: () => createServer
|
|
2561
2205
|
});
|
|
2206
|
+
import { serve } from "@hono/node-server";
|
|
2207
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
2208
|
+
import { Hono as Hono2 } from "hono";
|
|
2562
2209
|
async function loadWsFactory() {
|
|
2563
2210
|
try {
|
|
2564
2211
|
const mod = await import("ws");
|
|
2565
2212
|
const WS = mod.default ?? mod;
|
|
2566
|
-
return (url, opts) => new WS(url, { headers: opts.headers });
|
|
2213
|
+
return (url, opts) => wrapOnStyleWebSocket(new WS(url, { headers: opts.headers }));
|
|
2567
2214
|
} catch {
|
|
2568
2215
|
throw new Error(
|
|
2569
2216
|
"WebSocket factory not provided and `ws` package not found. Install `ws` (`npm install ws`) or pass `createWebSocket` option."
|
|
@@ -2571,11 +2218,7 @@ async function loadWsFactory() {
|
|
|
2571
2218
|
}
|
|
2572
2219
|
}
|
|
2573
2220
|
function resolveEnv(env) {
|
|
2574
|
-
|
|
2575
|
-
for (const [key, value] of Object.entries(env)) {
|
|
2576
|
-
if (value !== void 0) resolved[key] = value;
|
|
2577
|
-
}
|
|
2578
|
-
return resolved;
|
|
2221
|
+
return Object.fromEntries(Object.entries(env).filter(([, v]) => v !== void 0));
|
|
2579
2222
|
}
|
|
2580
2223
|
function createServer(options) {
|
|
2581
2224
|
const {
|
|
@@ -2620,191 +2263,91 @@ function createServer(options) {
|
|
|
2620
2263
|
},
|
|
2621
2264
|
async listen(port = 3e3) {
|
|
2622
2265
|
await getWsFactory();
|
|
2623
|
-
const
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2266
|
+
const wintercServer = getWinterc();
|
|
2267
|
+
const app = new Hono2();
|
|
2268
|
+
app.onError((err, c) => {
|
|
2269
|
+
logger.error(`${c.req.method} ${new URL(c.req.url).pathname} error: ${err.message}`);
|
|
2270
|
+
return c.json({ error: "Internal Server Error" }, 500);
|
|
2271
|
+
});
|
|
2272
|
+
app.use("/*", async (c, next) => {
|
|
2273
|
+
const start = Date.now();
|
|
2274
|
+
await next();
|
|
2275
|
+
const ms = Date.now() - start;
|
|
2276
|
+
const status = c.res.status;
|
|
2277
|
+
const method = c.req.method;
|
|
2278
|
+
const path8 = new URL(c.req.url).pathname;
|
|
2279
|
+
if (status >= 400) {
|
|
2280
|
+
logger.error(`${method} ${path8} ${status} ${ms}ms`);
|
|
2281
|
+
} else {
|
|
2282
|
+
logger.info(`${method} ${path8} ${status} ${ms}ms`);
|
|
2628
2283
|
}
|
|
2629
|
-
await nodeHttpHandler(req, res, port, getWinterc);
|
|
2630
2284
|
});
|
|
2631
|
-
|
|
2285
|
+
if (clientDir) {
|
|
2286
|
+
app.use("/*", serveStatic({ root: clientDir }));
|
|
2287
|
+
}
|
|
2288
|
+
app.all("/*", (c) => wintercServer.fetch(c.req.raw));
|
|
2289
|
+
const nodeServer = serve({ fetch: app.fetch, port });
|
|
2632
2290
|
await new Promise((resolve) => {
|
|
2633
|
-
nodeServer.
|
|
2291
|
+
nodeServer.on("listening", resolve);
|
|
2634
2292
|
});
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2293
|
+
try {
|
|
2294
|
+
const wsMod = await import("ws");
|
|
2295
|
+
const wss = new wsMod.WebSocketServer({ noServer: true });
|
|
2296
|
+
nodeServer.on("upgrade", (req, socket, head) => {
|
|
2297
|
+
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2298
|
+
const resume = reqUrl.searchParams.has("resume");
|
|
2299
|
+
logger.info(`WS upgrade ${reqUrl.pathname}${resume ? " (resume)" : ""}`);
|
|
2300
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
2301
|
+
wintercServer.handleWebSocket(ws, {
|
|
2302
|
+
skipGreeting: resume
|
|
2303
|
+
});
|
|
2639
2304
|
});
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
}
|
|
2649
|
-
async function serveStaticFile(reqUrl, clientDir, res) {
|
|
2650
|
-
const { readFile } = await import("node:fs/promises");
|
|
2651
|
-
const { join, extname, normalize } = await import("node:path");
|
|
2652
|
-
const urlPath = new URL(reqUrl, "http://localhost").pathname;
|
|
2653
|
-
const relPath = urlPath === "/" ? "index.html" : urlPath.slice(1);
|
|
2654
|
-
const filePath = normalize(join(clientDir, relPath));
|
|
2655
|
-
if (!filePath.startsWith(clientDir)) return false;
|
|
2656
|
-
try {
|
|
2657
|
-
const content = await readFile(filePath);
|
|
2658
|
-
const ext = extname(filePath);
|
|
2659
|
-
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
2660
|
-
res.writeHead(200, { "Content-Type": contentType });
|
|
2661
|
-
res.end(content);
|
|
2662
|
-
return true;
|
|
2663
|
-
} catch {
|
|
2664
|
-
return false;
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
async function nodeHttpHandler(req, res, port, getWinterc) {
|
|
2668
|
-
try {
|
|
2669
|
-
const protocol = req.socket.encrypted ? "https" : "http";
|
|
2670
|
-
const host = req.headers.host ?? `localhost:${port}`;
|
|
2671
|
-
const url = new URL(req.url ?? "/", `${protocol}://${host}`);
|
|
2672
|
-
const headers = new Headers();
|
|
2673
|
-
for (const [key, val] of Object.entries(req.headers)) {
|
|
2674
|
-
if (val) headers.set(key, Array.isArray(val) ? val[0] ?? "" : val);
|
|
2675
|
-
}
|
|
2676
|
-
const request = new Request(url, { method: req.method ?? "GET", headers });
|
|
2677
|
-
const response = await getWinterc().fetch(request);
|
|
2678
|
-
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
2679
|
-
res.end(await response.text());
|
|
2680
|
-
} catch (err) {
|
|
2681
|
-
res.writeHead(500);
|
|
2682
|
-
res.end(err instanceof Error ? err.message : "Internal Server Error");
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
function attachWsUpgrade(nodeServer, port, getWinterc, logger) {
|
|
2686
|
-
import("ws").then((wsMod) => {
|
|
2687
|
-
const WSServer = wsMod.WebSocketServer;
|
|
2688
|
-
if (!WSServer) return;
|
|
2689
|
-
const wss = new WSServer({ noServer: true });
|
|
2690
|
-
nodeServer.on("upgrade", (req, socket, head) => {
|
|
2691
|
-
wss.handleUpgrade(
|
|
2692
|
-
req,
|
|
2693
|
-
socket,
|
|
2694
|
-
head,
|
|
2695
|
-
(ws) => {
|
|
2696
|
-
const reqUrl = new URL(
|
|
2697
|
-
req.url ?? "/",
|
|
2698
|
-
`http://localhost:${port}`
|
|
2699
|
-
);
|
|
2700
|
-
getWinterc().handleWebSocket(ws, {
|
|
2701
|
-
skipGreeting: reqUrl.searchParams.has("resume")
|
|
2305
|
+
});
|
|
2306
|
+
} catch {
|
|
2307
|
+
logger.warn("ws package not available for Node.js WebSocket upgrade");
|
|
2308
|
+
}
|
|
2309
|
+
serverHandle = {
|
|
2310
|
+
async shutdown() {
|
|
2311
|
+
await new Promise((resolve, reject) => {
|
|
2312
|
+
nodeServer.close((err) => err ? reject(err) : resolve());
|
|
2702
2313
|
});
|
|
2703
2314
|
}
|
|
2704
|
-
|
|
2705
|
-
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2315
|
+
};
|
|
2316
|
+
},
|
|
2317
|
+
async close() {
|
|
2318
|
+
await winterc?.close();
|
|
2319
|
+
await serverHandle?.shutdown();
|
|
2320
|
+
}
|
|
2321
|
+
};
|
|
2709
2322
|
}
|
|
2710
|
-
var MIME_TYPES;
|
|
2711
2323
|
var init_server = __esm({
|
|
2712
2324
|
"sdk/server.ts"() {
|
|
2713
2325
|
"use strict";
|
|
2714
2326
|
init_runtime();
|
|
2327
|
+
init_s2s();
|
|
2715
2328
|
init_winterc_server();
|
|
2716
|
-
MIME_TYPES = {
|
|
2717
|
-
".html": "text/html",
|
|
2718
|
-
".js": "application/javascript",
|
|
2719
|
-
".css": "text/css",
|
|
2720
|
-
".json": "application/json",
|
|
2721
|
-
".svg": "image/svg+xml",
|
|
2722
|
-
".png": "image/png",
|
|
2723
|
-
".ico": "image/x-icon",
|
|
2724
|
-
".woff": "font/woff",
|
|
2725
|
-
".woff2": "font/woff2"
|
|
2726
|
-
};
|
|
2727
2329
|
}
|
|
2728
2330
|
});
|
|
2729
2331
|
|
|
2730
|
-
// cli/cli.ts
|
|
2731
|
-
init_help();
|
|
2732
|
-
import { readFileSync } from "node:fs";
|
|
2733
|
-
import path11 from "node:path";
|
|
2734
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2735
|
-
import minimist8 from "minimist";
|
|
2736
|
-
|
|
2737
|
-
// cli/build.tsx
|
|
2738
|
-
init_build();
|
|
2739
|
-
init_discover();
|
|
2740
|
-
init_help();
|
|
2741
|
-
init_ink();
|
|
2742
|
-
init_init2();
|
|
2743
|
-
import path6 from "node:path";
|
|
2744
|
-
import minimist3 from "minimist";
|
|
2745
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2746
|
-
var buildCommandDef = {
|
|
2747
|
-
name: "build",
|
|
2748
|
-
description: "Bundle agent and client (validates code without deploying or starting a server)",
|
|
2749
|
-
options: [{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }]
|
|
2750
|
-
};
|
|
2751
|
-
async function runBuildCommand(args, version) {
|
|
2752
|
-
const parsed = minimist3(args, {
|
|
2753
|
-
boolean: ["help", "yes"],
|
|
2754
|
-
alias: { h: "help", y: "yes" }
|
|
2755
|
-
});
|
|
2756
|
-
if (parsed.help) {
|
|
2757
|
-
console.log(subcommandHelp(buildCommandDef, version));
|
|
2758
|
-
return;
|
|
2759
|
-
}
|
|
2760
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
2761
|
-
if (!await fileExists(path6.join(cwd, "agent.ts"))) {
|
|
2762
|
-
await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
|
|
2763
|
-
}
|
|
2764
|
-
await runWithInk(async (log) => {
|
|
2765
|
-
await buildAgentBundle(cwd, log);
|
|
2766
|
-
log(/* @__PURE__ */ jsx5(Step, { action: "Build", msg: "ok" }));
|
|
2767
|
-
});
|
|
2768
|
-
}
|
|
2769
|
-
|
|
2770
|
-
// cli/cli.ts
|
|
2771
|
-
init_deploy2();
|
|
2772
|
-
|
|
2773
|
-
// cli/dev.tsx
|
|
2774
|
-
import path8 from "node:path";
|
|
2775
|
-
import minimist4 from "minimist";
|
|
2776
|
-
|
|
2777
|
-
// cli/_dev.ts
|
|
2778
|
-
init_build();
|
|
2779
|
-
init_ink();
|
|
2780
|
-
import React3 from "react";
|
|
2781
|
-
|
|
2782
2332
|
// cli/_server_common.ts
|
|
2783
|
-
init_discover();
|
|
2784
2333
|
import fs5 from "node:fs/promises";
|
|
2785
|
-
import
|
|
2786
|
-
import {
|
|
2334
|
+
import path5 from "node:path";
|
|
2335
|
+
import { tsImport } from "tsx/esm/api";
|
|
2787
2336
|
async function loadAgentDef(cwd) {
|
|
2788
|
-
const agentPath =
|
|
2789
|
-
const
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
const agentDef = agentModule.default;
|
|
2797
|
-
if (!agentDef || typeof agentDef !== "object" || !agentDef.name) {
|
|
2798
|
-
throw new Error("agent.ts must export a default agent definition (from defineAgent())");
|
|
2799
|
-
}
|
|
2800
|
-
return agentDef;
|
|
2801
|
-
} finally {
|
|
2802
|
-
await vite.close();
|
|
2337
|
+
const agentPath = path5.resolve(cwd, "agent.ts");
|
|
2338
|
+
const agentModule = await tsImport(agentPath, cwd);
|
|
2339
|
+
let agentDef = agentModule.default;
|
|
2340
|
+
if (agentDef?.__esModule && agentDef.default) {
|
|
2341
|
+
agentDef = agentDef.default;
|
|
2342
|
+
}
|
|
2343
|
+
if (!agentDef || typeof agentDef !== "object" || !agentDef.name) {
|
|
2344
|
+
throw new Error("agent.ts must export a default agent definition (from defineAgent())");
|
|
2803
2345
|
}
|
|
2346
|
+
return agentDef;
|
|
2804
2347
|
}
|
|
2805
|
-
async function resolveServerEnv() {
|
|
2348
|
+
async function resolveServerEnv(baseEnv) {
|
|
2806
2349
|
const env = Object.fromEntries(
|
|
2807
|
-
Object.entries(process.env).filter((e) => e[1] !== void 0)
|
|
2350
|
+
Object.entries(baseEnv ?? process.env).filter((e) => e[1] !== void 0)
|
|
2808
2351
|
);
|
|
2809
2352
|
if (!env.ASSEMBLYAI_API_KEY) {
|
|
2810
2353
|
env.ASSEMBLYAI_API_KEY = await getApiKey();
|
|
@@ -2812,10 +2355,11 @@ async function resolveServerEnv() {
|
|
|
2812
2355
|
return env;
|
|
2813
2356
|
}
|
|
2814
2357
|
async function bootServer(agentDef, clientDir, env, port) {
|
|
2358
|
+
const { wrapOnStyleWebSocket: wrapOnStyleWebSocket2 } = await Promise.resolve().then(() => (init_s2s(), s2s_exports));
|
|
2815
2359
|
const wsMod = await import("ws");
|
|
2816
2360
|
const WS = wsMod.default ?? wsMod;
|
|
2817
|
-
const createWebSocket = (url, opts) => new WS(url, { headers: opts.headers });
|
|
2818
|
-
const clientHtml = await fs5.readFile(
|
|
2361
|
+
const createWebSocket = (url, opts) => wrapOnStyleWebSocket2(new WS(url, { headers: opts.headers }));
|
|
2362
|
+
const clientHtml = await fs5.readFile(path5.join(clientDir, "index.html"), "utf-8");
|
|
2819
2363
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
2820
2364
|
const server = createServer2({
|
|
2821
2365
|
agent: agentDef,
|
|
@@ -2826,155 +2370,186 @@ async function bootServer(agentDef, clientDir, env, port) {
|
|
|
2826
2370
|
});
|
|
2827
2371
|
await server.listen(port);
|
|
2828
2372
|
}
|
|
2373
|
+
var init_server_common = __esm({
|
|
2374
|
+
"cli/_server_common.ts"() {
|
|
2375
|
+
"use strict";
|
|
2376
|
+
init_discover();
|
|
2377
|
+
}
|
|
2378
|
+
});
|
|
2829
2379
|
|
|
2830
|
-
// cli/
|
|
2380
|
+
// cli/dev.tsx
|
|
2381
|
+
var dev_exports = {};
|
|
2382
|
+
__export(dev_exports, {
|
|
2383
|
+
_startDevServer: () => _startDevServer,
|
|
2384
|
+
runDevCommand: () => runDevCommand
|
|
2385
|
+
});
|
|
2386
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2831
2387
|
async function _startDevServer(cwd, port, log) {
|
|
2832
|
-
const bundle = await buildAgentBundle(cwd, log);
|
|
2388
|
+
const bundle = await buildAgentBundle(cwd, log, { skipRenderCheck: true });
|
|
2833
2389
|
const agentDef = await loadAgentDef(cwd);
|
|
2834
2390
|
const env = await resolveServerEnv();
|
|
2835
2391
|
await bootServer(agentDef, bundle.clientDir, env, port);
|
|
2836
|
-
log(
|
|
2392
|
+
log(/* @__PURE__ */ jsx6(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
2837
2393
|
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
init_ink();
|
|
2843
|
-
init_init2();
|
|
2844
|
-
var devCommandDef = {
|
|
2845
|
-
name: "dev",
|
|
2846
|
-
description: "Start a local development server",
|
|
2847
|
-
options: [
|
|
2848
|
-
{
|
|
2849
|
-
flags: "-p, --port <number>",
|
|
2850
|
-
description: "Port to listen on (default: 3000)"
|
|
2851
|
-
},
|
|
2852
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
2853
|
-
]
|
|
2854
|
-
};
|
|
2855
|
-
async function runDevCommand(args, version) {
|
|
2856
|
-
const parsed = minimist4(args, {
|
|
2857
|
-
string: ["port"],
|
|
2858
|
-
boolean: ["help", "yes"],
|
|
2859
|
-
alias: { p: "port", h: "help", y: "yes" }
|
|
2394
|
+
async function runDevCommand(opts) {
|
|
2395
|
+
const port = Number.parseInt(opts.port, 10);
|
|
2396
|
+
await runWithInk(async ({ log }) => {
|
|
2397
|
+
await _startDevServer(opts.cwd, port, log);
|
|
2860
2398
|
});
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2399
|
+
}
|
|
2400
|
+
var init_dev = __esm({
|
|
2401
|
+
"cli/dev.tsx"() {
|
|
2402
|
+
"use strict";
|
|
2403
|
+
init_build();
|
|
2404
|
+
init_ink();
|
|
2405
|
+
init_server_common();
|
|
2864
2406
|
}
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2407
|
+
});
|
|
2408
|
+
|
|
2409
|
+
// cli/start.tsx
|
|
2410
|
+
var start_exports = {};
|
|
2411
|
+
__export(start_exports, {
|
|
2412
|
+
_startProductionServer: () => _startProductionServer,
|
|
2413
|
+
runStartCommand: () => runStartCommand
|
|
2414
|
+
});
|
|
2415
|
+
import path6 from "node:path";
|
|
2416
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2417
|
+
async function _startProductionServer(cwd, port, log) {
|
|
2418
|
+
const clientDir = path6.join(cwd, ".aai", "client");
|
|
2419
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Start", msg: "loading agent" }));
|
|
2420
|
+
const agentDef = await loadAgentDef(cwd);
|
|
2421
|
+
const env = await resolveServerEnv();
|
|
2422
|
+
await bootServer(agentDef, clientDir, env, port);
|
|
2423
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
2424
|
+
}
|
|
2425
|
+
async function runStartCommand(opts) {
|
|
2426
|
+
const port = Number.parseInt(opts.port, 10);
|
|
2427
|
+
const buildDir = path6.join(opts.cwd, ".aai", "build");
|
|
2428
|
+
if (!await fileExists(path6.join(buildDir, "worker.js"))) {
|
|
2429
|
+
throw new Error("No build found \u2014 run `aai build` first");
|
|
2869
2430
|
}
|
|
2870
|
-
await
|
|
2871
|
-
|
|
2872
|
-
await
|
|
2431
|
+
await runWithInk(async ({ log }) => {
|
|
2432
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Start", msg: `production server on port ${port}` }));
|
|
2433
|
+
await _startProductionServer(opts.cwd, port, log);
|
|
2873
2434
|
});
|
|
2874
2435
|
}
|
|
2436
|
+
var init_start = __esm({
|
|
2437
|
+
"cli/start.tsx"() {
|
|
2438
|
+
"use strict";
|
|
2439
|
+
init_discover();
|
|
2440
|
+
init_ink();
|
|
2441
|
+
init_server_common();
|
|
2442
|
+
}
|
|
2443
|
+
});
|
|
2875
2444
|
|
|
2876
|
-
// cli/
|
|
2877
|
-
|
|
2445
|
+
// cli/secret.tsx
|
|
2446
|
+
var secret_exports = {};
|
|
2447
|
+
__export(secret_exports, {
|
|
2448
|
+
runSecretDelete: () => runSecretDelete,
|
|
2449
|
+
runSecretList: () => runSecretList,
|
|
2450
|
+
runSecretPut: () => runSecretPut
|
|
2451
|
+
});
|
|
2452
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
2453
|
+
async function apiFetch(cwd, pathSuffix, init) {
|
|
2454
|
+
const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
|
|
2455
|
+
const resp = await fetch(`${serverUrl}/${slug}/secret${pathSuffix}`, {
|
|
2456
|
+
...init,
|
|
2457
|
+
headers: { Authorization: `Bearer ${apiKey}`, ...init?.headers }
|
|
2458
|
+
});
|
|
2459
|
+
if (!resp.ok) {
|
|
2460
|
+
const text = await resp.text();
|
|
2461
|
+
throw new Error(`Secret operation failed: ${text}`);
|
|
2462
|
+
}
|
|
2463
|
+
return { resp, slug };
|
|
2464
|
+
}
|
|
2465
|
+
async function runSecretPut(cwd, name) {
|
|
2466
|
+
const value = await askPassword(`Enter value for ${name}`);
|
|
2467
|
+
if (!value) throw new Error("No value provided");
|
|
2468
|
+
await runWithInk(async ({ log }) => {
|
|
2469
|
+
const { slug } = await apiFetch(cwd, "", {
|
|
2470
|
+
method: "PUT",
|
|
2471
|
+
headers: { "Content-Type": "application/json" },
|
|
2472
|
+
body: JSON.stringify({ [name]: value })
|
|
2473
|
+
});
|
|
2474
|
+
log(/* @__PURE__ */ jsx8(Step, { action: "Set", msg: `${name} for ${slug}` }));
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
async function runSecretDelete(cwd, name) {
|
|
2478
|
+
await runWithInk(async ({ log }) => {
|
|
2479
|
+
const { slug } = await apiFetch(cwd, `/${name}`, { method: "DELETE" });
|
|
2480
|
+
log(/* @__PURE__ */ jsx8(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
|
|
2481
|
+
});
|
|
2482
|
+
}
|
|
2483
|
+
async function runSecretList(cwd) {
|
|
2484
|
+
await runWithInk(async ({ log }) => {
|
|
2485
|
+
const { resp } = await apiFetch(cwd, "");
|
|
2486
|
+
const { vars } = await resp.json();
|
|
2487
|
+
if (vars.length === 0) {
|
|
2488
|
+
log(/* @__PURE__ */ jsx8(StepInfo, { action: "Secrets", msg: "none set" }));
|
|
2489
|
+
} else {
|
|
2490
|
+
for (const name of vars) {
|
|
2491
|
+
log(/* @__PURE__ */ jsx8(Detail, { msg: name }));
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
var init_secret = __esm({
|
|
2497
|
+
"cli/secret.tsx"() {
|
|
2498
|
+
"use strict";
|
|
2499
|
+
init_discover();
|
|
2500
|
+
init_ink();
|
|
2501
|
+
init_prompts();
|
|
2502
|
+
}
|
|
2503
|
+
});
|
|
2878
2504
|
|
|
2879
2505
|
// cli/rag.tsx
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2506
|
+
var rag_exports = {};
|
|
2507
|
+
__export(rag_exports, {
|
|
2508
|
+
chunkPages: () => chunkPages,
|
|
2509
|
+
parsePage: () => parsePage,
|
|
2510
|
+
runRagCommand: () => runRagCommand,
|
|
2511
|
+
slugify: () => slugify,
|
|
2512
|
+
splitPages: () => splitPages,
|
|
2513
|
+
stripNoise: () => stripNoise,
|
|
2514
|
+
upsertChunks: () => upsertChunks
|
|
2515
|
+
});
|
|
2516
|
+
import { Text as Text3 } from "ink";
|
|
2885
2517
|
import pLimit from "p-limit";
|
|
2886
|
-
import {
|
|
2887
|
-
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2888
|
-
var ragCommandDef = {
|
|
2889
|
-
name: "rag",
|
|
2890
|
-
description: "Ingest a site's llms-full.txt into the vector store",
|
|
2891
|
-
args: [{ name: "url" }],
|
|
2892
|
-
options: [
|
|
2893
|
-
{ flags: "-s, --server <url>", description: "Server URL" },
|
|
2894
|
-
{
|
|
2895
|
-
flags: "--chunk-size <n>",
|
|
2896
|
-
description: "Max chunk size in tokens (default: 512)"
|
|
2897
|
-
},
|
|
2898
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
2899
|
-
]
|
|
2900
|
-
};
|
|
2901
|
-
var FETCH_TIMEOUT_MS = 6e4;
|
|
2902
|
-
var PAD = 2;
|
|
2903
|
-
function RagUI({ url, apiKey, serverUrl, slug, chunkSize, onError }) {
|
|
2904
|
-
const { exit } = useApp2();
|
|
2905
|
-
const { items, log } = useStepLog();
|
|
2906
|
-
const [progress, setProgress] = useState2(null);
|
|
2907
|
-
const [err, setErr] = useState2(null);
|
|
2908
|
-
useEffect(() => {
|
|
2909
|
-
(async () => {
|
|
2910
|
-
try {
|
|
2911
|
-
await runRag({
|
|
2912
|
-
url,
|
|
2913
|
-
apiKey,
|
|
2914
|
-
serverUrl,
|
|
2915
|
-
slug,
|
|
2916
|
-
chunkSize,
|
|
2917
|
-
log,
|
|
2918
|
-
setProgress
|
|
2919
|
-
});
|
|
2920
|
-
} catch (e) {
|
|
2921
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
2922
|
-
setErr(error.message);
|
|
2923
|
-
onError?.(error);
|
|
2924
|
-
}
|
|
2925
|
-
setProgress(null);
|
|
2926
|
-
exit();
|
|
2927
|
-
})();
|
|
2928
|
-
}, [apiKey, chunkSize, exit, log, onError, serverUrl, slug, url]);
|
|
2929
|
-
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2930
|
-
/* @__PURE__ */ jsx6(StepLog, { items }),
|
|
2931
|
-
err && /* @__PURE__ */ jsx6(ErrorLine, { msg: err }),
|
|
2932
|
-
progress && /* @__PURE__ */ jsxs3(Text3, { children: [
|
|
2933
|
-
" ".repeat(PAD + 1),
|
|
2934
|
-
"Upsert ",
|
|
2935
|
-
progress.completed,
|
|
2936
|
-
"/",
|
|
2937
|
-
progress.total,
|
|
2938
|
-
" (",
|
|
2939
|
-
Math.round(progress.completed / progress.total * 100),
|
|
2940
|
-
"%)"
|
|
2941
|
-
] })
|
|
2942
|
-
] });
|
|
2943
|
-
}
|
|
2518
|
+
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2944
2519
|
async function runRag(opts) {
|
|
2945
|
-
const { url, apiKey, serverUrl, slug, chunkSize, log,
|
|
2946
|
-
log(/* @__PURE__ */
|
|
2520
|
+
const { url, apiKey, serverUrl, slug, chunkSize, log, setStatus } = opts;
|
|
2521
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Fetch", msg: url }));
|
|
2947
2522
|
const resp = await fetch(url, {
|
|
2948
2523
|
headers: { "User-Agent": "aai-cli/1.0" },
|
|
2949
2524
|
redirect: "follow",
|
|
2950
|
-
signal: AbortSignal.timeout(
|
|
2525
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
2951
2526
|
});
|
|
2952
2527
|
if (!resp.ok) {
|
|
2953
2528
|
throw new Error(`Failed to fetch: ${resp.status} ${resp.statusText}`);
|
|
2954
2529
|
}
|
|
2955
2530
|
const content = await resp.text();
|
|
2956
2531
|
if (content.length === 0) {
|
|
2957
|
-
log(/* @__PURE__ */
|
|
2532
|
+
log(/* @__PURE__ */ jsx9(Warn, { msg: "File is empty" }));
|
|
2958
2533
|
return;
|
|
2959
2534
|
}
|
|
2960
|
-
log(/* @__PURE__ */
|
|
2535
|
+
log(/* @__PURE__ */ jsx9(Info, { msg: `${(content.length / 1024).toFixed(0)} KB` }));
|
|
2961
2536
|
const origin = new URL(url).origin;
|
|
2962
2537
|
const pages = splitPages(content);
|
|
2963
|
-
log(/* @__PURE__ */
|
|
2538
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Parse", msg: `${pages.length} pages` }));
|
|
2964
2539
|
const { RecursiveChunker } = await import("@chonkiejs/core");
|
|
2965
2540
|
const chunker = await RecursiveChunker.create({ chunkSize });
|
|
2966
2541
|
const siteSlug = slugify(origin);
|
|
2967
2542
|
const allChunks = await chunkPages(pages, chunker, origin, siteSlug);
|
|
2968
|
-
log(/* @__PURE__ */
|
|
2543
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Chunk", msg: `${allChunks.length} chunks` }));
|
|
2969
2544
|
const vectorUrl = `${serverUrl}/${slug}/vector`;
|
|
2970
|
-
log(/* @__PURE__ */
|
|
2971
|
-
const result = await upsertChunks(allChunks, vectorUrl, apiKey,
|
|
2972
|
-
log(/* @__PURE__ */
|
|
2545
|
+
log(/* @__PURE__ */ jsx9(Info, { msg: `target: ${vectorUrl}` }));
|
|
2546
|
+
const result = await upsertChunks(allChunks, vectorUrl, apiKey, setStatus);
|
|
2547
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Done", msg: `${result.upserted} chunks upserted` }));
|
|
2973
2548
|
if (result.errors > 0) {
|
|
2974
|
-
log(/* @__PURE__ */
|
|
2975
|
-
if (result.lastError) log(/* @__PURE__ */
|
|
2549
|
+
log(/* @__PURE__ */ jsx9(Warn, { msg: `${result.errors} failed` }));
|
|
2550
|
+
if (result.lastError) log(/* @__PURE__ */ jsx9(Info, { msg: `last error: ${result.lastError}` }));
|
|
2976
2551
|
}
|
|
2977
|
-
log(/* @__PURE__ */
|
|
2552
|
+
log(/* @__PURE__ */ jsx9(Detail, { msg: `Agent: ${slug}` }));
|
|
2978
2553
|
}
|
|
2979
2554
|
async function chunkPages(pages, chunker, origin, siteSlug) {
|
|
2980
2555
|
const allChunks = [];
|
|
@@ -3000,19 +2575,34 @@ ${c.text}` : c.text;
|
|
|
3000
2575
|
}
|
|
3001
2576
|
return allChunks;
|
|
3002
2577
|
}
|
|
3003
|
-
async function upsertChunks(chunks, vectorUrl, apiKey,
|
|
2578
|
+
async function upsertChunks(chunks, vectorUrl, apiKey, setStatus, fetchFn = globalThis.fetch) {
|
|
3004
2579
|
const total = chunks.length;
|
|
3005
2580
|
let completed = 0;
|
|
3006
2581
|
let upserted = 0;
|
|
3007
2582
|
let errors = 0;
|
|
3008
2583
|
let lastError = "";
|
|
3009
|
-
|
|
2584
|
+
const updateStatus = () => {
|
|
2585
|
+
const pct = Math.round(completed / total * 100);
|
|
2586
|
+
setStatus(
|
|
2587
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
2588
|
+
" ",
|
|
2589
|
+
"Upsert ",
|
|
2590
|
+
completed,
|
|
2591
|
+
"/",
|
|
2592
|
+
total,
|
|
2593
|
+
" (",
|
|
2594
|
+
pct,
|
|
2595
|
+
"%)"
|
|
2596
|
+
] })
|
|
2597
|
+
);
|
|
2598
|
+
};
|
|
2599
|
+
updateStatus();
|
|
3010
2600
|
const limit = pLimit(5);
|
|
3011
2601
|
await Promise.all(
|
|
3012
2602
|
chunks.map(
|
|
3013
2603
|
(chunk) => limit(async () => {
|
|
3014
2604
|
try {
|
|
3015
|
-
const r = await
|
|
2605
|
+
const r = await fetchFn(vectorUrl, {
|
|
3016
2606
|
method: "POST",
|
|
3017
2607
|
headers: {
|
|
3018
2608
|
"Content-Type": "application/json",
|
|
@@ -3032,65 +2622,29 @@ async function upsertChunks(chunks, vectorUrl, apiKey, setProgress) {
|
|
|
3032
2622
|
upserted++;
|
|
3033
2623
|
}
|
|
3034
2624
|
} catch (err) {
|
|
3035
|
-
lastError =
|
|
2625
|
+
lastError = errorMessage(err);
|
|
3036
2626
|
errors++;
|
|
3037
2627
|
}
|
|
3038
2628
|
completed++;
|
|
3039
|
-
|
|
2629
|
+
updateStatus();
|
|
3040
2630
|
})
|
|
3041
2631
|
)
|
|
3042
2632
|
);
|
|
2633
|
+
setStatus(null);
|
|
3043
2634
|
return { upserted, errors, lastError };
|
|
3044
2635
|
}
|
|
3045
|
-
async function runRagCommand(
|
|
3046
|
-
const
|
|
3047
|
-
string: ["server", "chunk-size"],
|
|
3048
|
-
boolean: ["help", "yes"],
|
|
3049
|
-
alias: { s: "server", h: "help", y: "yes" },
|
|
3050
|
-
stopEarly: true
|
|
3051
|
-
});
|
|
3052
|
-
if (parsed.help) {
|
|
3053
|
-
console.log(subcommandHelp(ragCommandDef, version));
|
|
3054
|
-
return;
|
|
3055
|
-
}
|
|
3056
|
-
const url = String(parsed._[0] ?? "");
|
|
3057
|
-
if (!url) {
|
|
3058
|
-
throw new Error(
|
|
3059
|
-
"Usage: aai rag <url>\n\nProvide the full URL to a site's llms-full.txt file"
|
|
3060
|
-
);
|
|
3061
|
-
}
|
|
2636
|
+
async function runRagCommand(opts) {
|
|
2637
|
+
const { url, cwd } = opts;
|
|
3062
2638
|
try {
|
|
3063
2639
|
new URL(url);
|
|
3064
2640
|
} catch {
|
|
3065
2641
|
throw new Error(`Invalid URL: ${url}`);
|
|
3066
2642
|
}
|
|
3067
|
-
const
|
|
3068
|
-
const
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
}
|
|
3072
|
-
const apiKey = await getApiKey();
|
|
3073
|
-
const serverUrl = parsed.server || config.serverUrl || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
3074
|
-
const slug = config.slug;
|
|
3075
|
-
const chunkSize = Number.parseInt(parsed["chunk-size"] ?? "512", 10);
|
|
3076
|
-
let thrownError;
|
|
3077
|
-
const app = render3(
|
|
3078
|
-
/* @__PURE__ */ jsx6(
|
|
3079
|
-
RagUI,
|
|
3080
|
-
{
|
|
3081
|
-
url,
|
|
3082
|
-
apiKey,
|
|
3083
|
-
serverUrl,
|
|
3084
|
-
slug,
|
|
3085
|
-
chunkSize,
|
|
3086
|
-
onError: (e) => {
|
|
3087
|
-
thrownError = e;
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
)
|
|
3091
|
-
);
|
|
3092
|
-
await app.waitUntilExit();
|
|
3093
|
-
if (thrownError) throw thrownError;
|
|
2643
|
+
const { apiKey, serverUrl, slug } = await getServerInfo(cwd, opts.server);
|
|
2644
|
+
const chunkSize = Number.parseInt(opts.chunkSize ?? "512", 10);
|
|
2645
|
+
await runWithInk(async ({ log, setStatus }) => {
|
|
2646
|
+
await runRag({ url, apiKey, serverUrl, slug, chunkSize, log, setStatus });
|
|
2647
|
+
});
|
|
3094
2648
|
}
|
|
3095
2649
|
function splitPages(content) {
|
|
3096
2650
|
const raw = content.split(/^\*{3,}$/m);
|
|
@@ -3137,243 +2691,153 @@ function stripNoise(text) {
|
|
|
3137
2691
|
function slugify(s) {
|
|
3138
2692
|
return s.replace(/^https?:\/\//, "").replace(/^#+\s*/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase().slice(0, 80);
|
|
3139
2693
|
}
|
|
2694
|
+
var FETCH_TIMEOUT_MS2;
|
|
2695
|
+
var init_rag = __esm({
|
|
2696
|
+
"cli/rag.tsx"() {
|
|
2697
|
+
"use strict";
|
|
2698
|
+
init_utils();
|
|
2699
|
+
init_discover();
|
|
2700
|
+
init_ink();
|
|
2701
|
+
FETCH_TIMEOUT_MS2 = 6e4;
|
|
2702
|
+
}
|
|
2703
|
+
});
|
|
3140
2704
|
|
|
3141
|
-
// cli/
|
|
2705
|
+
// cli/cli.ts
|
|
2706
|
+
init_utils();
|
|
3142
2707
|
init_discover();
|
|
3143
|
-
init_help();
|
|
3144
2708
|
init_ink();
|
|
3145
|
-
|
|
3146
|
-
import
|
|
3147
|
-
import {
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
}
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
2709
|
+
import { readFileSync } from "node:fs";
|
|
2710
|
+
import path7 from "node:path";
|
|
2711
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2712
|
+
import chalk2 from "chalk";
|
|
2713
|
+
import { Command } from "commander";
|
|
2714
|
+
var cliDir = path7.dirname(fileURLToPath2(import.meta.url));
|
|
2715
|
+
var pkgJsonPath = path7.join(cliDir, "..", "package.json");
|
|
2716
|
+
var pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
2717
|
+
var VERSION = pkgJson.version;
|
|
2718
|
+
var banner = [
|
|
2719
|
+
"",
|
|
2720
|
+
` ${primary(chalk2.bold(" \u2584\u2580\u2588 \u2584\u2580\u2588 \u2588"))} ${chalk2.dim("Voice agent development kit")}`,
|
|
2721
|
+
` ${primary(chalk2.bold(" \u2588\u2580\u2588 \u2588\u2580\u2588 \u2588"))} ${primary(`v${VERSION}`)}`,
|
|
2722
|
+
""
|
|
2723
|
+
].join("\n");
|
|
2724
|
+
var gettingStarted = [
|
|
2725
|
+
"",
|
|
2726
|
+
` ${chalk2.bold(interactive("Getting started"))}`,
|
|
2727
|
+
"",
|
|
2728
|
+
` ${chalk2.dim("$")} ${primary("aai init")} ${interactive("my-agent")}`,
|
|
2729
|
+
` ${chalk2.dim("$")} ${primary("cd")} ${interactive("my-agent")}`,
|
|
2730
|
+
` ${chalk2.dim("$")} ${primary("aai dev")}`,
|
|
2731
|
+
""
|
|
2732
|
+
].join("\n");
|
|
2733
|
+
async function ensureAgent(cwd, yes) {
|
|
2734
|
+
if (!await fileExists(path7.join(cwd, "agent.ts"))) {
|
|
2735
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2736
|
+
await runInitCommand2({ yes }, { quiet: true });
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
function withCwd(cmd) {
|
|
2740
|
+
return cmd.hook("preAction", (thisCmd) => {
|
|
2741
|
+
thisCmd.setOptionValue("cwd", resolveCwd());
|
|
3169
2742
|
});
|
|
3170
|
-
if (parsed.help || parsed._.length === 0) {
|
|
3171
|
-
console.log(subcommandHelp(secretCommandDef, version));
|
|
3172
|
-
return;
|
|
3173
|
-
}
|
|
3174
|
-
const sub = String(parsed._[0]);
|
|
3175
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
3176
|
-
await getApiKey();
|
|
3177
|
-
let secretValue;
|
|
3178
|
-
if (sub === "put") {
|
|
3179
|
-
const name = String(parsed._[1] ?? "");
|
|
3180
|
-
if (!name) throw new Error("Usage: aai secret put <NAME>");
|
|
3181
|
-
secretValue = await askPassword(`Enter value for ${name}`);
|
|
3182
|
-
if (!secretValue) throw new Error("No value provided");
|
|
3183
|
-
}
|
|
3184
|
-
switch (sub) {
|
|
3185
|
-
case "put":
|
|
3186
|
-
await secretPut(cwd, String(parsed._[1] ?? ""), secretValue ?? "");
|
|
3187
|
-
break;
|
|
3188
|
-
case "delete":
|
|
3189
|
-
await secretDelete(cwd, String(parsed._[1] ?? ""));
|
|
3190
|
-
break;
|
|
3191
|
-
case "list":
|
|
3192
|
-
await secretList(cwd);
|
|
3193
|
-
break;
|
|
3194
|
-
default:
|
|
3195
|
-
throw new Error(`Unknown secret subcommand: ${sub}`);
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
async function getServerInfo(cwd) {
|
|
3199
|
-
const config = await requireProjectConfig(cwd);
|
|
3200
|
-
const apiKey = await getApiKey();
|
|
3201
|
-
const serverUrl = config.serverUrl || DEFAULT_SERVER;
|
|
3202
|
-
const slug = config.slug;
|
|
3203
|
-
return { serverUrl, slug, apiKey };
|
|
3204
2743
|
}
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
const resp = await fetch(`${serverUrl}/${slug}/secret`, {
|
|
3209
|
-
method: "PUT",
|
|
3210
|
-
headers: {
|
|
3211
|
-
"Content-Type": "application/json",
|
|
3212
|
-
Authorization: `Bearer ${apiKey}`
|
|
3213
|
-
},
|
|
3214
|
-
body: JSON.stringify({ [name]: value })
|
|
3215
|
-
});
|
|
3216
|
-
if (!resp.ok) {
|
|
3217
|
-
const text = await resp.text();
|
|
3218
|
-
throw new Error(`Failed to set secret: ${text}`);
|
|
3219
|
-
}
|
|
3220
|
-
log(/* @__PURE__ */ jsx7(Step, { action: "Set", msg: `${name} for ${slug}` }));
|
|
2744
|
+
function withAgentGuard(cmd) {
|
|
2745
|
+
return cmd.hook("preAction", async (thisCmd) => {
|
|
2746
|
+
await ensureAgent(thisCmd.getOptionValue("cwd"), thisCmd.opts().yes);
|
|
3221
2747
|
});
|
|
3222
2748
|
}
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
|
|
3227
|
-
const resp = await fetch(`${serverUrl}/${slug}/secret/${name}`, {
|
|
3228
|
-
method: "DELETE",
|
|
3229
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3230
|
-
});
|
|
3231
|
-
if (!resp.ok) {
|
|
3232
|
-
const text = await resp.text();
|
|
3233
|
-
throw new Error(`Failed to delete secret: ${text}`);
|
|
3234
|
-
}
|
|
3235
|
-
log(/* @__PURE__ */ jsx7(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
|
|
2749
|
+
function withApiKey(cmd) {
|
|
2750
|
+
return cmd.hook("preAction", async () => {
|
|
2751
|
+
await getApiKey();
|
|
3236
2752
|
});
|
|
3237
2753
|
}
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
const text = await resp.text();
|
|
3246
|
-
throw new Error(`Failed to list secrets: ${text}`);
|
|
3247
|
-
}
|
|
3248
|
-
const { vars } = await resp.json();
|
|
3249
|
-
if (vars.length === 0) {
|
|
3250
|
-
log(/* @__PURE__ */ jsx7(StepInfo, { action: "Secrets", msg: "none set" }));
|
|
3251
|
-
} else {
|
|
3252
|
-
for (const name of vars) {
|
|
3253
|
-
log(/* @__PURE__ */ jsx7(Detail, { msg: name }));
|
|
3254
|
-
}
|
|
2754
|
+
function createProgram() {
|
|
2755
|
+
const program = new Command();
|
|
2756
|
+
program.name("aai").version(VERSION, "-V, --version").addHelpText("before", banner).addHelpText("after", gettingStarted);
|
|
2757
|
+
program.command("init").description("Scaffold a new agent project").argument("[dir]", "Project directory").option("-t, --template <template>", "Template to use").option("-f, --force", "Overwrite existing agent.ts").option("-y, --yes", "Accept defaults (no prompts)").action(
|
|
2758
|
+
async (dir, opts) => {
|
|
2759
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2760
|
+
await runInitCommand2({ dir, ...opts });
|
|
3255
2761
|
}
|
|
2762
|
+
);
|
|
2763
|
+
withApiKey(
|
|
2764
|
+
withAgentGuard(
|
|
2765
|
+
withCwd(
|
|
2766
|
+
program.command("dev").description("Start a local development server").option("-p, --port <number>", "Port to listen on", "3000").option("-y, --yes", "Accept defaults (no prompts)").action(async (opts) => {
|
|
2767
|
+
const { runDevCommand: runDevCommand2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
|
|
2768
|
+
await runDevCommand2(opts);
|
|
2769
|
+
})
|
|
2770
|
+
)
|
|
2771
|
+
)
|
|
2772
|
+
);
|
|
2773
|
+
withAgentGuard(
|
|
2774
|
+
withCwd(
|
|
2775
|
+
program.command("build").description("Bundle and validate (no server or deploy)").option("-y, --yes", "Accept defaults (no prompts)").action(async (opts) => {
|
|
2776
|
+
const { runBuildCommand: runBuildCommand2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
2777
|
+
await runBuildCommand2(opts.cwd);
|
|
2778
|
+
})
|
|
2779
|
+
)
|
|
2780
|
+
);
|
|
2781
|
+
withAgentGuard(
|
|
2782
|
+
withCwd(
|
|
2783
|
+
program.command("deploy").description("Bundle and deploy to production").option("-s, --server <url>", "Server URL").option("--dry-run", "Validate and bundle without deploying").option("-y, --yes", "Accept defaults (no prompts)").action(async (opts) => {
|
|
2784
|
+
const { runDeployCommand: runDeployCommand2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
|
|
2785
|
+
await runDeployCommand2(opts);
|
|
2786
|
+
})
|
|
2787
|
+
)
|
|
2788
|
+
);
|
|
2789
|
+
withApiKey(
|
|
2790
|
+
withCwd(
|
|
2791
|
+
program.command("start").description("Start production server from build").option("-p, --port <number>", "Port to listen on", "3000").option("-y, --yes", "Accept defaults (no prompts)").action(async (opts) => {
|
|
2792
|
+
const { runStartCommand: runStartCommand2 } = await Promise.resolve().then(() => (init_start(), start_exports));
|
|
2793
|
+
await runStartCommand2(opts);
|
|
2794
|
+
})
|
|
2795
|
+
)
|
|
2796
|
+
);
|
|
2797
|
+
const secret = program.command("secret").description("Manage secrets").action(() => secret.help());
|
|
2798
|
+
withApiKey(withCwd(secret));
|
|
2799
|
+
secret.command("put").description("Create or update a secret").argument("<name>", "Secret name").action(async (name, _opts, cmd) => {
|
|
2800
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2801
|
+
const { runSecretPut: runSecretPut2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2802
|
+
await runSecretPut2(cwd, name);
|
|
3256
2803
|
});
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
init_help();
|
|
3262
|
-
init_ink();
|
|
3263
|
-
import path10 from "node:path";
|
|
3264
|
-
import minimist7 from "minimist";
|
|
3265
|
-
|
|
3266
|
-
// cli/_start.ts
|
|
3267
|
-
init_ink();
|
|
3268
|
-
import path9 from "node:path";
|
|
3269
|
-
import React4 from "react";
|
|
3270
|
-
async function _startProductionServer(cwd, port, log) {
|
|
3271
|
-
const clientDir = path9.join(cwd, ".aai", "client");
|
|
3272
|
-
log(React4.createElement(Step, { action: "Start", msg: "loading agent" }));
|
|
3273
|
-
const agentDef = await loadAgentDef(cwd);
|
|
3274
|
-
const env = await resolveServerEnv();
|
|
3275
|
-
await bootServer(agentDef, clientDir, env, port);
|
|
3276
|
-
log(React4.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
3277
|
-
}
|
|
3278
|
-
|
|
3279
|
-
// cli/start.tsx
|
|
3280
|
-
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
3281
|
-
var startCommandDef = {
|
|
3282
|
-
name: "start",
|
|
3283
|
-
description: "Start the production server from a build",
|
|
3284
|
-
options: [
|
|
3285
|
-
{
|
|
3286
|
-
flags: "-p, --port <number>",
|
|
3287
|
-
description: "Port to listen on (default: 3000)"
|
|
3288
|
-
},
|
|
3289
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
3290
|
-
]
|
|
3291
|
-
};
|
|
3292
|
-
async function runStartCommand(args, version) {
|
|
3293
|
-
const parsed = minimist7(args, {
|
|
3294
|
-
string: ["port"],
|
|
3295
|
-
boolean: ["help", "yes"],
|
|
3296
|
-
alias: { p: "port", h: "help", y: "yes" }
|
|
2804
|
+
secret.command("delete").description("Delete a secret").argument("<name>", "Secret name").action(async (name, _opts, cmd) => {
|
|
2805
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2806
|
+
const { runSecretDelete: runSecretDelete2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2807
|
+
await runSecretDelete2(cwd, name);
|
|
3297
2808
|
});
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
3303
|
-
const port = Number.parseInt(parsed.port ?? "3000", 10);
|
|
3304
|
-
const buildDir = path10.join(cwd, ".aai", "build");
|
|
3305
|
-
if (!await fileExists(path10.join(buildDir, "worker.js"))) {
|
|
3306
|
-
throw new Error("No build found \u2014 run `aai build` first");
|
|
3307
|
-
}
|
|
3308
|
-
await getApiKey();
|
|
3309
|
-
await runWithInk(async (log) => {
|
|
3310
|
-
log(/* @__PURE__ */ jsx8(Step, { action: "Start", msg: `production server on port ${port}` }));
|
|
3311
|
-
await _startProductionServer(cwd, port, log);
|
|
2809
|
+
secret.command("list").description("List secret names").action(async (_opts, cmd) => {
|
|
2810
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2811
|
+
const { runSecretList: runSecretList2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2812
|
+
await runSecretList2(cwd);
|
|
3312
2813
|
});
|
|
2814
|
+
withApiKey(
|
|
2815
|
+
withCwd(
|
|
2816
|
+
program.command("rag").description("Ingest a site's llms-full.txt into the vector store").argument("<url>", "URL to ingest").option("-s, --server <url>", "Server URL").option("--chunk-size <n>", "Max chunk size in tokens", "512").option("-y, --yes", "Accept defaults (no prompts)").action(async (url, opts) => {
|
|
2817
|
+
const { runRagCommand: runRagCommand2 } = await Promise.resolve().then(() => (init_rag(), rag_exports));
|
|
2818
|
+
await runRagCommand2({ url, ...opts });
|
|
2819
|
+
})
|
|
2820
|
+
)
|
|
2821
|
+
);
|
|
2822
|
+
return program;
|
|
3313
2823
|
}
|
|
3314
|
-
|
|
3315
|
-
// cli/cli.ts
|
|
3316
|
-
var cliDir = path11.dirname(fileURLToPath2(import.meta.url));
|
|
3317
|
-
var pkgJsonPath = path11.join(cliDir, "..", "package.json");
|
|
3318
|
-
var pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
3319
|
-
var VERSION = pkgJson.version;
|
|
3320
2824
|
async function main(args) {
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
stopEarly: true
|
|
3325
|
-
});
|
|
3326
|
-
if (parsed.version) {
|
|
3327
|
-
console.log(VERSION);
|
|
2825
|
+
if (args.length === 0) {
|
|
2826
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2827
|
+
await runInitCommand2({});
|
|
3328
2828
|
return;
|
|
3329
2829
|
}
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
return;
|
|
3333
|
-
}
|
|
3334
|
-
const [subcommand, ...rest] = parsed._;
|
|
3335
|
-
const subArgs = rest.map(String);
|
|
3336
|
-
switch (subcommand) {
|
|
3337
|
-
case "init":
|
|
3338
|
-
await runInitCommand(subArgs, VERSION);
|
|
3339
|
-
return;
|
|
3340
|
-
case "build":
|
|
3341
|
-
await runBuildCommand(subArgs, VERSION);
|
|
3342
|
-
return;
|
|
3343
|
-
case "deploy":
|
|
3344
|
-
await runDeployCommand(subArgs, VERSION);
|
|
3345
|
-
return;
|
|
3346
|
-
case "dev":
|
|
3347
|
-
await runDevCommand(subArgs, VERSION);
|
|
3348
|
-
return;
|
|
3349
|
-
case "start":
|
|
3350
|
-
await runStartCommand(subArgs, VERSION);
|
|
3351
|
-
return;
|
|
3352
|
-
case "secret":
|
|
3353
|
-
await runSecretCommand(subArgs, VERSION);
|
|
3354
|
-
return;
|
|
3355
|
-
case "rag":
|
|
3356
|
-
await runRagCommand(subArgs, VERSION);
|
|
3357
|
-
return;
|
|
3358
|
-
case "help":
|
|
3359
|
-
console.log(rootHelp(VERSION));
|
|
3360
|
-
return;
|
|
3361
|
-
case void 0:
|
|
3362
|
-
await runInitCommand(subArgs, VERSION);
|
|
3363
|
-
return;
|
|
3364
|
-
default:
|
|
3365
|
-
console.error(`Unknown command: ${subcommand}`);
|
|
3366
|
-
console.log(rootHelp(VERSION));
|
|
3367
|
-
process.exit(1);
|
|
3368
|
-
}
|
|
2830
|
+
const program = createProgram();
|
|
2831
|
+
await program.parseAsync(args, { from: "user" });
|
|
3369
2832
|
}
|
|
3370
2833
|
if (process.env.VITEST !== "true") {
|
|
3371
2834
|
process.on("SIGINT", () => process.exit(0));
|
|
3372
2835
|
main(process.argv.slice(2)).catch((err) => {
|
|
3373
|
-
console.error(
|
|
2836
|
+
console.error(errorMessage(err));
|
|
3374
2837
|
process.exit(1);
|
|
3375
2838
|
});
|
|
3376
2839
|
}
|
|
3377
2840
|
export {
|
|
2841
|
+
createProgram,
|
|
3378
2842
|
main
|
|
3379
2843
|
};
|