@alexkroman1/aai 0.8.3 → 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 +1223 -1701
- 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 +29 -2
- 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 +26 -10
- 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 +0 -1
- package/dist/sdk/winterc_server.d.ts.map +1 -1
- package/dist/sdk/winterc_server.js +0 -1
- 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 -3
- package/dist/sdk/ws_handler.d.ts.map +1 -1
- package/dist/sdk/ws_handler.js +14 -25
- 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 -18
- 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 +37 -17
- package/templates/_shared/CLAUDE.md +4 -7
- package/templates/dispatch-center/agent.ts +85 -397
- package/templates/solo-rpg/agent.ts +3 -3
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,90 +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
|
-
const userPreact = path2.join(agent.dir, "node_modules/preact");
|
|
392
|
-
const userSignals = path2.join(agent.dir, "node_modules/@preact/signals");
|
|
393
|
-
devAlias.preact = userPreact;
|
|
394
|
-
devAlias["@preact/signals"] = userSignals;
|
|
395
|
-
}
|
|
396
475
|
try {
|
|
397
476
|
await build({
|
|
398
477
|
root: agent.dir,
|
|
399
478
|
base: "./",
|
|
400
479
|
logLevel: "warn",
|
|
401
480
|
plugins: [preact(), tailwindcss()],
|
|
402
|
-
|
|
481
|
+
resolve: {
|
|
482
|
+
...devResolve,
|
|
483
|
+
...devMode && { dedupe: ["preact", "@preact/signals"] }
|
|
484
|
+
},
|
|
403
485
|
build: {
|
|
404
486
|
outDir: clientDir,
|
|
405
487
|
emptyOutDir: true,
|
|
@@ -408,11 +490,11 @@ async function bundleAgent(agent, opts) {
|
|
|
408
490
|
}
|
|
409
491
|
});
|
|
410
492
|
} catch (err) {
|
|
411
|
-
throw new BundleError(
|
|
493
|
+
throw new BundleError(errorMessage(err));
|
|
412
494
|
}
|
|
413
495
|
}
|
|
414
|
-
const worker = await
|
|
415
|
-
const clientFiles = await
|
|
496
|
+
const worker = await fs3.readFile(path3.join(buildDir, "worker.js"), "utf-8");
|
|
497
|
+
const clientFiles = await readDirFiles(clientDir);
|
|
416
498
|
return {
|
|
417
499
|
worker,
|
|
418
500
|
clientFiles,
|
|
@@ -424,6 +506,7 @@ var BundleError;
|
|
|
424
506
|
var init_bundler = __esm({
|
|
425
507
|
"cli/_bundler.ts"() {
|
|
426
508
|
"use strict";
|
|
509
|
+
init_utils();
|
|
427
510
|
init_discover();
|
|
428
511
|
BundleError = class extends Error {
|
|
429
512
|
constructor(message) {
|
|
@@ -434,280 +517,68 @@ var init_bundler = __esm({
|
|
|
434
517
|
}
|
|
435
518
|
});
|
|
436
519
|
|
|
437
|
-
// cli/
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
function Step({ action, msg }) {
|
|
443
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
444
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.primary, children: action }),
|
|
445
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
446
|
-
" ",
|
|
447
|
-
msg
|
|
448
|
-
] })
|
|
449
|
-
] });
|
|
450
|
-
}
|
|
451
|
-
function StepInfo({ action, msg }) {
|
|
452
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
453
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.interactive, children: action }),
|
|
454
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
455
|
-
" ",
|
|
456
|
-
msg
|
|
457
|
-
] })
|
|
458
|
-
] });
|
|
459
|
-
}
|
|
460
|
-
function Info({ msg }) {
|
|
461
|
-
return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
462
|
-
" ",
|
|
463
|
-
msg
|
|
464
|
-
] });
|
|
465
|
-
}
|
|
466
|
-
function Detail({ msg }) {
|
|
467
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
468
|
-
" ",
|
|
469
|
-
msg
|
|
470
|
-
] });
|
|
471
|
-
}
|
|
472
|
-
function Warn({ msg }) {
|
|
473
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
474
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.warning, children: "\u25B2" }),
|
|
475
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
476
|
-
" ",
|
|
477
|
-
msg
|
|
478
|
-
] })
|
|
479
|
-
] });
|
|
480
|
-
}
|
|
481
|
-
function ErrorLine({ msg }) {
|
|
482
|
-
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
483
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.error, children: "\u2717" }),
|
|
484
|
-
/* @__PURE__ */ jsxs2(Text2, { children: [
|
|
485
|
-
" ",
|
|
486
|
-
msg
|
|
487
|
-
] })
|
|
488
|
-
] });
|
|
489
|
-
}
|
|
490
|
-
function StepLog({ items }) {
|
|
491
|
-
return /* @__PURE__ */ jsx2(Static, { items, children: (item) => /* @__PURE__ */ jsx2(Box2, { children: item.node }, item.id) });
|
|
492
|
-
}
|
|
493
|
-
function useStepLog() {
|
|
494
|
-
const [items, setItems] = useState([]);
|
|
495
|
-
const nextId = useRef(0);
|
|
496
|
-
const log = (node) => {
|
|
497
|
-
const id = nextId.current++;
|
|
498
|
-
setItems((prev) => [...prev, { id, node }]);
|
|
499
|
-
};
|
|
500
|
-
return { items, log };
|
|
501
|
-
}
|
|
502
|
-
function CommandRunner({
|
|
503
|
-
run,
|
|
504
|
-
onError
|
|
505
|
-
}) {
|
|
506
|
-
const { exit } = useApp();
|
|
507
|
-
const { items, log } = useStepLog();
|
|
508
|
-
const [spinning, setSpinning] = useState(true);
|
|
509
|
-
const [currentStep, setCurrentStep] = useState(null);
|
|
510
|
-
const [err, setErr] = useState(null);
|
|
511
|
-
const currentStepRef = useRef(null);
|
|
512
|
-
const wrappedLog = (node) => {
|
|
513
|
-
if (currentStepRef.current) {
|
|
514
|
-
log(currentStepRef.current);
|
|
515
|
-
}
|
|
516
|
-
currentStepRef.current = node;
|
|
517
|
-
setCurrentStep(node);
|
|
518
|
-
};
|
|
519
|
-
const started = useRef(false);
|
|
520
|
-
React.useEffect(() => {
|
|
521
|
-
if (started.current) return;
|
|
522
|
-
started.current = true;
|
|
523
|
-
(async () => {
|
|
524
|
-
try {
|
|
525
|
-
await run(wrappedLog);
|
|
526
|
-
} catch (e) {
|
|
527
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
528
|
-
setErr(error.message);
|
|
529
|
-
onError?.(error);
|
|
530
|
-
}
|
|
531
|
-
if (currentStepRef.current) {
|
|
532
|
-
log(currentStepRef.current);
|
|
533
|
-
currentStepRef.current = null;
|
|
534
|
-
}
|
|
535
|
-
setCurrentStep(null);
|
|
536
|
-
setSpinning(false);
|
|
537
|
-
setTimeout(() => exit(), 0);
|
|
538
|
-
})();
|
|
539
|
-
});
|
|
540
|
-
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
541
|
-
/* @__PURE__ */ jsx2(StepLog, { items }),
|
|
542
|
-
err && /* @__PURE__ */ jsx2(ErrorLine, { msg: err }),
|
|
543
|
-
spinning && currentStep && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
544
|
-
/* @__PURE__ */ jsx2(Spinner, {}),
|
|
545
|
-
/* @__PURE__ */ jsx2(Text2, { children: " " }),
|
|
546
|
-
currentStep
|
|
547
|
-
] })
|
|
548
|
-
] });
|
|
549
|
-
}
|
|
550
|
-
async function runWithInk(fn) {
|
|
551
|
-
let thrownError;
|
|
552
|
-
const app = render2(
|
|
553
|
-
/* @__PURE__ */ jsx2(
|
|
554
|
-
CommandRunner,
|
|
555
|
-
{
|
|
556
|
-
onError: (e) => {
|
|
557
|
-
thrownError = e;
|
|
558
|
-
},
|
|
559
|
-
run: fn
|
|
560
|
-
}
|
|
561
|
-
)
|
|
562
|
-
);
|
|
563
|
-
await app.waitUntilExit();
|
|
564
|
-
if (thrownError) process.exit(1);
|
|
565
|
-
}
|
|
566
|
-
var init_ink = __esm({
|
|
567
|
-
"cli/_ink.tsx"() {
|
|
568
|
-
"use strict";
|
|
569
|
-
init_colors();
|
|
570
|
-
}
|
|
520
|
+
// cli/_build.tsx
|
|
521
|
+
var build_exports = {};
|
|
522
|
+
__export(build_exports, {
|
|
523
|
+
buildAgentBundle: () => buildAgentBundle,
|
|
524
|
+
runBuildCommand: () => runBuildCommand
|
|
571
525
|
});
|
|
572
|
-
|
|
573
|
-
// cli/_build.ts
|
|
574
|
-
import React2 from "react";
|
|
526
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
575
527
|
async function buildAgentBundle(cwd, log, opts) {
|
|
576
528
|
const agent = await loadAgent(cwd);
|
|
577
529
|
if (!agent) {
|
|
578
530
|
throw new Error("No agent found \u2014 run `aai init` first");
|
|
579
531
|
}
|
|
580
|
-
log(
|
|
532
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Bundle", msg: agent.slug }));
|
|
581
533
|
let bundle;
|
|
582
534
|
try {
|
|
583
535
|
bundle = await bundleAgent(agent);
|
|
584
536
|
} catch (err) {
|
|
585
|
-
if (err instanceof BundleError) {
|
|
586
|
-
throw new Error(`Bundle failed: ${err.message}`);
|
|
587
|
-
}
|
|
588
|
-
throw err;
|
|
589
|
-
}
|
|
590
|
-
const kb = (bundle.workerBytes / 1024).toFixed(1);
|
|
591
|
-
const clientCount = Object.keys(bundle.clientFiles).length;
|
|
592
|
-
log(React2.createElement(Info, { msg: `worker: ${kb} KB, client: ${clientCount} file(s)` }));
|
|
593
|
-
if (agent.clientEntry && !opts?.skipRenderCheck) {
|
|
594
|
-
try {
|
|
595
|
-
const renderCheckPath = "../sdk/_render_check.ts";
|
|
596
|
-
const { renderCheck } = await import(
|
|
597
|
-
/* @vite-ignore */
|
|
598
|
-
renderCheckPath
|
|
599
|
-
);
|
|
600
|
-
log(React2.createElement(Step, { action: "Render", msg: "check" }));
|
|
601
|
-
await renderCheck(agent.clientEntry, cwd);
|
|
602
|
-
} catch (err) {
|
|
603
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
604
|
-
if (msg.includes("linkedom") || msg.includes("_render_check")) return bundle;
|
|
605
|
-
throw new Error(`Render check failed: ${msg}`);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
return bundle;
|
|
609
|
-
}
|
|
610
|
-
var init_build = __esm({
|
|
611
|
-
"cli/_build.ts"() {
|
|
612
|
-
"use strict";
|
|
613
|
-
init_bundler();
|
|
614
|
-
init_discover();
|
|
615
|
-
init_ink();
|
|
616
|
-
}
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
// cli/_init.ts
|
|
620
|
-
var init_exports = {};
|
|
621
|
-
__export(init_exports, {
|
|
622
|
-
listTemplates: () => listTemplates,
|
|
623
|
-
runInit: () => runInit
|
|
624
|
-
});
|
|
625
|
-
import fs3 from "node:fs/promises";
|
|
626
|
-
import path3 from "node:path";
|
|
627
|
-
import glob from "fast-glob";
|
|
628
|
-
import fsExtra from "fs-extra";
|
|
629
|
-
async function listTemplates(dir) {
|
|
630
|
-
const templates = [];
|
|
631
|
-
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
632
|
-
for (const entry of entries) {
|
|
633
|
-
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
634
|
-
templates.push(entry.name);
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
return templates.sort();
|
|
638
|
-
}
|
|
639
|
-
async function copyDirNoOverwrite(src, dest) {
|
|
640
|
-
const files = await glob("**/*", { cwd: src, dot: true, onlyFiles: true });
|
|
641
|
-
for (const file of files) {
|
|
642
|
-
const destPath = path3.join(dest, file);
|
|
643
|
-
try {
|
|
644
|
-
await fs3.access(destPath);
|
|
645
|
-
} catch {
|
|
646
|
-
await fs3.mkdir(path3.dirname(destPath), { recursive: true });
|
|
647
|
-
await fs3.copyFile(path3.join(src, file), destPath);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
async function runInit(opts) {
|
|
652
|
-
const { targetDir, template, templatesDir } = opts;
|
|
653
|
-
const available = await listTemplates(templatesDir);
|
|
654
|
-
if (!available.includes(template)) {
|
|
655
|
-
throw new Error(`unknown template '${template}' -- available: ${available.join(", ")}`);
|
|
656
|
-
}
|
|
657
|
-
await fsExtra.copy(path3.join(templatesDir, template), targetDir, { overwrite: true });
|
|
658
|
-
await copyDirNoOverwrite(path3.join(templatesDir, "_shared"), targetDir);
|
|
659
|
-
try {
|
|
660
|
-
await fs3.copyFile(path3.join(targetDir, ".env.example"), path3.join(targetDir, ".env"));
|
|
661
|
-
} catch {
|
|
662
|
-
}
|
|
663
|
-
const readmePath = path3.join(targetDir, "README.md");
|
|
664
|
-
try {
|
|
665
|
-
await fs3.access(readmePath);
|
|
666
|
-
} catch {
|
|
667
|
-
const slug = path3.basename(path3.resolve(targetDir));
|
|
668
|
-
const readme = `# ${slug}
|
|
669
|
-
|
|
670
|
-
A voice agent built with [aai](https://github.com/anthropics/aai).
|
|
671
|
-
|
|
672
|
-
## Getting started
|
|
673
|
-
|
|
674
|
-
\`\`\`sh
|
|
675
|
-
npm install # Install dependencies
|
|
676
|
-
npm run dev # Run locally (opens browser)
|
|
677
|
-
npm run deploy # Deploy to production
|
|
678
|
-
\`\`\`
|
|
679
|
-
|
|
680
|
-
## Environment variables
|
|
681
|
-
|
|
682
|
-
Secrets are managed on the server, not in local files:
|
|
683
|
-
|
|
684
|
-
\`\`\`sh
|
|
685
|
-
aai env add MY_KEY # Set a secret (prompts for value)
|
|
686
|
-
aai env ls # List secret names
|
|
687
|
-
aai env pull # Pull names into .env for reference
|
|
688
|
-
aai env rm MY_KEY # Remove a secret
|
|
689
|
-
\`\`\`
|
|
690
|
-
|
|
691
|
-
Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
692
|
-
|
|
693
|
-
## Learn more
|
|
694
|
-
|
|
695
|
-
See \`CLAUDE.md\` for the full agent API reference.
|
|
696
|
-
`;
|
|
697
|
-
await fs3.writeFile(readmePath, readme);
|
|
537
|
+
if (err instanceof BundleError) {
|
|
538
|
+
throw new Error(`Bundle failed: ${err.message}`);
|
|
539
|
+
}
|
|
540
|
+
throw err;
|
|
698
541
|
}
|
|
699
|
-
|
|
542
|
+
const kb = (bundle.workerBytes / 1024).toFixed(1);
|
|
543
|
+
const clientCount = Object.keys(bundle.clientFiles).length;
|
|
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
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
return bundle;
|
|
700
561
|
}
|
|
701
|
-
|
|
702
|
-
|
|
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
|
+
}
|
|
568
|
+
var init_build = __esm({
|
|
569
|
+
"cli/_build.tsx"() {
|
|
703
570
|
"use strict";
|
|
571
|
+
init_utils();
|
|
572
|
+
init_bundler();
|
|
573
|
+
init_discover();
|
|
574
|
+
init_ink();
|
|
704
575
|
}
|
|
705
576
|
});
|
|
706
577
|
|
|
707
578
|
// cli/_deploy.ts
|
|
708
|
-
async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
579
|
+
async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
|
|
709
580
|
try {
|
|
710
|
-
return await
|
|
581
|
+
return await fetchFn(`${url}/${slug}/deploy`, {
|
|
711
582
|
method: "POST",
|
|
712
583
|
headers: {
|
|
713
584
|
"Content-Type": "application/json",
|
|
@@ -724,37 +595,36 @@ async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
|
724
595
|
}
|
|
725
596
|
}
|
|
726
597
|
async function runDeploy(opts) {
|
|
727
|
-
const worker = opts.bundle
|
|
728
|
-
const
|
|
598
|
+
const { worker, clientFiles } = opts.bundle;
|
|
599
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
729
600
|
let slug = opts.slug;
|
|
730
|
-
if (opts.dryRun) {
|
|
731
|
-
return { slug };
|
|
732
|
-
}
|
|
733
601
|
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
734
|
-
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
|
+
);
|
|
735
611
|
if (resp.ok) {
|
|
736
612
|
return { slug };
|
|
737
613
|
}
|
|
738
|
-
if (resp.status === 403) {
|
|
739
|
-
const text2 = await resp.text();
|
|
740
|
-
if (text2.includes("Slug")) {
|
|
741
|
-
slug = generateSlug();
|
|
742
|
-
continue;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
614
|
const text = await resp.text();
|
|
615
|
+
if (resp.status === 403 && text.includes("Slug")) {
|
|
616
|
+
slug = generateSlug();
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
746
619
|
throw new Error(`deploy failed (${resp.status}): ${text}`);
|
|
747
620
|
}
|
|
748
621
|
throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
|
|
749
622
|
}
|
|
750
|
-
var
|
|
623
|
+
var MAX_RETRIES;
|
|
751
624
|
var init_deploy = __esm({
|
|
752
625
|
"cli/_deploy.ts"() {
|
|
753
626
|
"use strict";
|
|
754
627
|
init_discover();
|
|
755
|
-
_internals = {
|
|
756
|
-
fetch: globalThis.fetch.bind(globalThis)
|
|
757
|
-
};
|
|
758
628
|
MAX_RETRIES = 20;
|
|
759
629
|
}
|
|
760
630
|
});
|
|
@@ -764,103 +634,73 @@ var deploy_exports = {};
|
|
|
764
634
|
__export(deploy_exports, {
|
|
765
635
|
runDeployCommand: () => runDeployCommand
|
|
766
636
|
});
|
|
767
|
-
import
|
|
768
|
-
import minimist from "minimist";
|
|
769
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
770
|
-
function resolveServerUrl(parsed) {
|
|
771
|
-
return parsed.server || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
772
|
-
}
|
|
637
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
773
638
|
async function deployBundle(opts) {
|
|
774
639
|
const { bundle, serverUrl, apiKey, cwd, log } = opts;
|
|
775
640
|
let { slug } = opts;
|
|
776
|
-
log(/* @__PURE__ */
|
|
641
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Deploy", msg: slug }));
|
|
777
642
|
const deployed = await runDeploy({
|
|
778
643
|
url: serverUrl,
|
|
779
644
|
bundle,
|
|
780
645
|
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
781
646
|
slug,
|
|
782
|
-
dryRun: false,
|
|
783
647
|
apiKey
|
|
784
648
|
});
|
|
785
649
|
slug = deployed.slug;
|
|
786
650
|
await writeProjectConfig(cwd, { slug, serverUrl });
|
|
787
651
|
const agentUrl = `${serverUrl}/${slug}`;
|
|
788
|
-
log(/* @__PURE__ */
|
|
652
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Ready", msg: agentUrl }));
|
|
789
653
|
return agentUrl;
|
|
790
654
|
}
|
|
791
|
-
async function runDeployCommand(
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
boolean: ["dry-run", "help", "yes"],
|
|
795
|
-
alias: { s: "server", h: "help", y: "yes" }
|
|
796
|
-
});
|
|
797
|
-
if (parsed.help) {
|
|
798
|
-
console.log(subcommandHelp(deployCommandDef, version));
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
802
|
-
if (!await fileExists(path4.join(cwd, "agent.ts"))) {
|
|
803
|
-
await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
|
|
804
|
-
}
|
|
805
|
-
const serverUrl = resolveServerUrl(parsed);
|
|
806
|
-
const dryRun = parsed["dry-run"] ?? false;
|
|
655
|
+
async function runDeployCommand(opts) {
|
|
656
|
+
const { cwd } = opts;
|
|
657
|
+
const dryRun = opts.dryRun ?? false;
|
|
807
658
|
const apiKey = dryRun ? "" : await getApiKey();
|
|
808
659
|
const projectConfig = await readProjectConfig(cwd);
|
|
660
|
+
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
809
661
|
const slug = projectConfig?.slug ?? generateSlug();
|
|
810
662
|
let agentUrl = "";
|
|
811
|
-
await runWithInk(async (log) => {
|
|
663
|
+
await runWithInk(async ({ log }) => {
|
|
812
664
|
const bundle = await buildAgentBundle(cwd, log);
|
|
813
665
|
if (dryRun) {
|
|
814
|
-
log(/* @__PURE__ */
|
|
666
|
+
log(/* @__PURE__ */ jsx4(StepInfo, { action: "Dry run", msg: `would deploy as ${slug}` }));
|
|
815
667
|
return;
|
|
816
668
|
}
|
|
817
669
|
agentUrl = await deployBundle({ bundle, serverUrl, apiKey, slug, cwd, log });
|
|
818
670
|
});
|
|
819
|
-
if (agentUrl
|
|
671
|
+
if (agentUrl) {
|
|
820
672
|
await askEnter("Press enter to open in browser");
|
|
821
673
|
const { exec } = await import("node:child_process");
|
|
822
674
|
exec(`open "${agentUrl}"`);
|
|
823
675
|
}
|
|
824
676
|
}
|
|
825
|
-
var deployCommandDef;
|
|
826
677
|
var init_deploy2 = __esm({
|
|
827
678
|
"cli/deploy.tsx"() {
|
|
828
679
|
"use strict";
|
|
829
680
|
init_build();
|
|
830
681
|
init_deploy();
|
|
831
682
|
init_discover();
|
|
832
|
-
init_help();
|
|
833
683
|
init_ink();
|
|
834
684
|
init_prompts();
|
|
835
|
-
init_init2();
|
|
836
|
-
deployCommandDef = {
|
|
837
|
-
name: "deploy",
|
|
838
|
-
description: "Bundle and deploy to production",
|
|
839
|
-
options: [
|
|
840
|
-
{ flags: "-s, --server <url>", description: "Server URL" },
|
|
841
|
-
{
|
|
842
|
-
flags: "--dry-run",
|
|
843
|
-
description: "Validate and bundle without deploying"
|
|
844
|
-
},
|
|
845
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
846
|
-
]
|
|
847
|
-
};
|
|
848
685
|
}
|
|
849
686
|
});
|
|
850
687
|
|
|
851
688
|
// cli/init.tsx
|
|
689
|
+
var init_exports2 = {};
|
|
690
|
+
__export(init_exports2, {
|
|
691
|
+
runInitCommand: () => runInitCommand
|
|
692
|
+
});
|
|
852
693
|
import { execFile } from "node:child_process";
|
|
853
694
|
import fs4 from "node:fs/promises";
|
|
854
|
-
import
|
|
695
|
+
import path4 from "node:path";
|
|
855
696
|
import { fileURLToPath } from "node:url";
|
|
856
697
|
import { promisify } from "node:util";
|
|
857
|
-
import
|
|
858
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
698
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
859
699
|
async function rewriteDevDeps(cwd, cliDir2) {
|
|
860
|
-
const monorepoRoot =
|
|
861
|
-
const pkgJsonPath2 =
|
|
700
|
+
const monorepoRoot = path4.join(cliDir2, "..");
|
|
701
|
+
const pkgJsonPath2 = path4.join(cwd, "package.json");
|
|
862
702
|
const pkgJson2 = JSON.parse(await fs4.readFile(pkgJsonPath2, "utf-8"));
|
|
863
|
-
const rootPkg = JSON.parse(await fs4.readFile(
|
|
703
|
+
const rootPkg = JSON.parse(await fs4.readFile(path4.join(monorepoRoot, "package.json"), "utf-8"));
|
|
864
704
|
const rootPkgName = rootPkg.name;
|
|
865
705
|
if (pkgJson2.dependencies[rootPkgName]) {
|
|
866
706
|
pkgJson2.dependencies[rootPkgName] = `file:${monorepoRoot}`;
|
|
@@ -869,56 +709,45 @@ async function rewriteDevDeps(cwd, cliDir2) {
|
|
|
869
709
|
`);
|
|
870
710
|
}
|
|
871
711
|
async function installDeps(cwd, log) {
|
|
872
|
-
if (await fileExists(
|
|
712
|
+
if (await fileExists(path4.join(cwd, "node_modules"))) return;
|
|
873
713
|
let pkgJson2;
|
|
874
714
|
try {
|
|
875
|
-
pkgJson2 = JSON.parse(await fs4.readFile(
|
|
715
|
+
pkgJson2 = JSON.parse(await fs4.readFile(path4.join(cwd, "package.json"), "utf-8"));
|
|
876
716
|
} catch {
|
|
877
717
|
pkgJson2 = {};
|
|
878
718
|
}
|
|
879
719
|
const deps = Object.keys(pkgJson2.dependencies ?? {});
|
|
880
720
|
const devDeps = Object.keys(pkgJson2.devDependencies ?? {});
|
|
881
721
|
if (deps.length > 0) {
|
|
882
|
-
log(/* @__PURE__ */
|
|
722
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: deps.join(", ") }));
|
|
883
723
|
}
|
|
884
724
|
if (devDeps.length > 0) {
|
|
885
|
-
log(/* @__PURE__ */
|
|
725
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: `dev: ${devDeps.join(", ")}` }));
|
|
886
726
|
}
|
|
887
727
|
try {
|
|
888
728
|
await execFileAsync("npm", ["install"], { cwd });
|
|
889
729
|
} catch {
|
|
890
|
-
log(/* @__PURE__ */
|
|
730
|
+
log(/* @__PURE__ */ jsx5(Warn, { msg: "npm install failed" }));
|
|
891
731
|
}
|
|
892
732
|
}
|
|
893
|
-
async function runInitCommand(
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
boolean: ["force", "help"],
|
|
897
|
-
alias: { t: "template", f: "force", h: "help" }
|
|
898
|
-
});
|
|
899
|
-
if (parsed.help) {
|
|
900
|
-
console.log(subcommandHelp(initCommandDef, version));
|
|
901
|
-
return "";
|
|
902
|
-
}
|
|
903
|
-
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
904
|
-
await getApiKey2();
|
|
905
|
-
let dir = parsed._[0];
|
|
733
|
+
async function runInitCommand(opts, extra) {
|
|
734
|
+
await getApiKey();
|
|
735
|
+
let dir = opts.dir;
|
|
906
736
|
if (!dir) {
|
|
907
737
|
dir = await askText("What is your project named?", "my-voice-agent");
|
|
908
738
|
}
|
|
909
|
-
const cwd =
|
|
910
|
-
if (!
|
|
911
|
-
|
|
739
|
+
const cwd = path4.resolve(resolveCwd(), dir);
|
|
740
|
+
if (!opts.force && await fileExists(path4.join(cwd, "agent.ts"))) {
|
|
741
|
+
throw new Error(
|
|
912
742
|
`agent.ts already exists in this directory. Use ${interactive("--force")} to overwrite.`
|
|
913
743
|
);
|
|
914
|
-
process.exit(1);
|
|
915
744
|
}
|
|
916
|
-
const cliDir2 =
|
|
917
|
-
const templatesDir =
|
|
745
|
+
const cliDir2 = path4.dirname(fileURLToPath(import.meta.url));
|
|
746
|
+
const templatesDir = path4.join(cliDir2, "..", "templates");
|
|
918
747
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
919
|
-
const template =
|
|
920
|
-
await runWithInk(async (log) => {
|
|
921
|
-
log(/* @__PURE__ */
|
|
748
|
+
const template = opts.template || "simple";
|
|
749
|
+
await runWithInk(async ({ log }) => {
|
|
750
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Create", msg: dir }));
|
|
922
751
|
await runInit2({ targetDir: cwd, template, templatesDir });
|
|
923
752
|
if (isDevMode()) {
|
|
924
753
|
await rewriteDevDeps(cwd, cliDir2);
|
|
@@ -927,60 +756,32 @@ async function runInitCommand(args, version, opts) {
|
|
|
927
756
|
});
|
|
928
757
|
process.chdir(cwd);
|
|
929
758
|
delete process.env.INIT_CWD;
|
|
930
|
-
if (!
|
|
759
|
+
if (!extra?.quiet) {
|
|
931
760
|
const { runDeployCommand: runDeployCommand2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
|
|
932
|
-
await runDeployCommand2(
|
|
761
|
+
await runDeployCommand2({ cwd });
|
|
933
762
|
}
|
|
934
763
|
return cwd;
|
|
935
764
|
}
|
|
936
|
-
var execFileAsync
|
|
765
|
+
var execFileAsync;
|
|
937
766
|
var init_init2 = __esm({
|
|
938
767
|
"cli/init.tsx"() {
|
|
939
768
|
"use strict";
|
|
940
|
-
init_colors();
|
|
941
769
|
init_discover();
|
|
942
|
-
init_help();
|
|
943
770
|
init_ink();
|
|
944
771
|
init_prompts();
|
|
945
772
|
execFileAsync = promisify(execFile);
|
|
946
|
-
initCommandDef = {
|
|
947
|
-
name: "init",
|
|
948
|
-
description: "Scaffold a new agent project",
|
|
949
|
-
args: [{ name: "dir", optional: true }],
|
|
950
|
-
options: [
|
|
951
|
-
{
|
|
952
|
-
flags: "-t, --template <template>",
|
|
953
|
-
description: "Template to use"
|
|
954
|
-
},
|
|
955
|
-
{ flags: "-f, --force", description: "Overwrite existing agent.ts" }
|
|
956
|
-
]
|
|
957
|
-
};
|
|
958
773
|
}
|
|
959
774
|
});
|
|
960
775
|
|
|
961
776
|
// sdk/protocol.ts
|
|
962
777
|
import { z } from "zod";
|
|
963
|
-
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;
|
|
964
779
|
var init_protocol = __esm({
|
|
965
780
|
"sdk/protocol.ts"() {
|
|
966
781
|
"use strict";
|
|
967
782
|
DEFAULT_TTS_SAMPLE_RATE = 24e3;
|
|
968
783
|
AUDIO_FORMAT = "pcm16";
|
|
969
|
-
|
|
970
|
-
_channels = 1;
|
|
971
|
-
AudioFrameSpec = {
|
|
972
|
-
/** Audio codec identifier sent in the `ready` message. */
|
|
973
|
-
format: AUDIO_FORMAT,
|
|
974
|
-
/** Signed 16-bit integer samples. */
|
|
975
|
-
bitsPerSample: _bitsPerSample,
|
|
976
|
-
/** Little-endian byte order. */
|
|
977
|
-
endianness: "little",
|
|
978
|
-
/** Mono audio. */
|
|
979
|
-
channels: _channels,
|
|
980
|
-
/** Bytes per sample — derived from bitsPerSample and channels. */
|
|
981
|
-
bytesPerSample: _bitsPerSample / 8 * _channels
|
|
982
|
-
};
|
|
983
|
-
KvRequestBaseSchema = z.discriminatedUnion("op", [
|
|
784
|
+
KvRequestSchema = z.discriminatedUnion("op", [
|
|
984
785
|
z.object({ op: z.literal("get"), key: z.string().min(1) }),
|
|
985
786
|
z.object({
|
|
986
787
|
op: z.literal("set"),
|
|
@@ -994,9 +795,29 @@ var init_protocol = __esm({
|
|
|
994
795
|
prefix: z.string(),
|
|
995
796
|
limit: z.number().int().positive().optional(),
|
|
996
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)
|
|
997
817
|
})
|
|
998
818
|
]);
|
|
999
819
|
HOOK_TIMEOUT_MS = 5e3;
|
|
820
|
+
TOOL_EXECUTION_TIMEOUT_MS = 3e4;
|
|
1000
821
|
SessionErrorCodeSchema = z.enum([
|
|
1001
822
|
"stt",
|
|
1002
823
|
"llm",
|
|
@@ -1007,23 +828,16 @@ var init_protocol = __esm({
|
|
|
1007
828
|
"audio",
|
|
1008
829
|
"internal"
|
|
1009
830
|
]);
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
isFinal: z.boolean(),
|
|
1014
|
-
turnOrder: z.number().int().nonnegative().optional()
|
|
1015
|
-
});
|
|
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();
|
|
1016
834
|
ClientEventSchema = z.discriminatedUnion("type", [
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
turnOrder: z.number().int().nonnegative().optional()
|
|
1024
|
-
}),
|
|
1025
|
-
z.object({ type: z.literal("chat"), text: z.string() }),
|
|
1026
|
-
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"),
|
|
1027
841
|
z.object({
|
|
1028
842
|
type: z.literal("tool_call_start"),
|
|
1029
843
|
toolCallId: z.string(),
|
|
@@ -1035,55 +849,35 @@ var init_protocol = __esm({
|
|
|
1035
849
|
toolCallId: z.string(),
|
|
1036
850
|
result: z.string().max(4e3)
|
|
1037
851
|
}),
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
z.object({
|
|
1042
|
-
type: z.literal("error"),
|
|
1043
|
-
code: SessionErrorCodeSchema,
|
|
1044
|
-
message: z.string()
|
|
1045
|
-
})
|
|
852
|
+
ev("tts_done"),
|
|
853
|
+
ev("cancelled"),
|
|
854
|
+
ev("reset"),
|
|
855
|
+
z.object({ type: z.literal("error"), code: SessionErrorCodeSchema, message: z.string() })
|
|
1046
856
|
]);
|
|
1047
857
|
ClientMessageSchema = z.discriminatedUnion("type", [
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
858
|
+
ev("audio_ready"),
|
|
859
|
+
ev("cancel"),
|
|
860
|
+
ev("reset"),
|
|
1051
861
|
z.object({
|
|
1052
862
|
type: z.literal("history"),
|
|
1053
|
-
messages: z.array(
|
|
1054
|
-
z.object({
|
|
1055
|
-
role: z.enum(["user", "assistant"]),
|
|
1056
|
-
text: z.string().max(1e5)
|
|
1057
|
-
})
|
|
1058
|
-
).max(200)
|
|
863
|
+
messages: z.array(z.object({ role: z.enum(["user", "assistant"]), text: z.string().max(1e5) })).max(200)
|
|
1059
864
|
})
|
|
1060
865
|
]);
|
|
1061
866
|
}
|
|
1062
867
|
});
|
|
1063
868
|
|
|
1064
869
|
// sdk/runtime.ts
|
|
1065
|
-
var consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
870
|
+
var _log, consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
1066
871
|
var init_runtime = __esm({
|
|
1067
872
|
"sdk/runtime.ts"() {
|
|
1068
873
|
"use strict";
|
|
1069
874
|
init_protocol();
|
|
875
|
+
_log = (m) => (msg, ctx) => console[m](msg, ...ctx ? [ctx] : []);
|
|
1070
876
|
consoleLogger = {
|
|
1071
|
-
info(
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
warn(msg, ctx) {
|
|
1076
|
-
if (ctx) console.warn(msg, ctx);
|
|
1077
|
-
else console.warn(msg);
|
|
1078
|
-
},
|
|
1079
|
-
error(msg, ctx) {
|
|
1080
|
-
if (ctx) console.error(msg, ctx);
|
|
1081
|
-
else console.error(msg);
|
|
1082
|
-
},
|
|
1083
|
-
debug(msg, ctx) {
|
|
1084
|
-
if (ctx) console.debug(msg, ctx);
|
|
1085
|
-
else console.debug(msg);
|
|
1086
|
-
}
|
|
877
|
+
info: _log("log"),
|
|
878
|
+
warn: _log("warn"),
|
|
879
|
+
error: _log("error"),
|
|
880
|
+
debug: _log("debug")
|
|
1087
881
|
};
|
|
1088
882
|
noopMetrics = {
|
|
1089
883
|
sessionsTotal: { inc() {
|
|
@@ -1100,20 +894,230 @@ var init_runtime = __esm({
|
|
|
1100
894
|
}
|
|
1101
895
|
});
|
|
1102
896
|
|
|
1103
|
-
// sdk/
|
|
897
|
+
// sdk/s2s.ts
|
|
898
|
+
var s2s_exports = {};
|
|
899
|
+
__export(s2s_exports, {
|
|
900
|
+
connectS2s: () => connectS2s,
|
|
901
|
+
wrapOnStyleWebSocket: () => wrapOnStyleWebSocket
|
|
902
|
+
});
|
|
1104
903
|
import { z as z2 } from "zod";
|
|
904
|
+
function uint8ToBase64(bytes) {
|
|
905
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
906
|
+
}
|
|
907
|
+
function base64ToUint8(base64) {
|
|
908
|
+
const buf = Buffer.from(base64, "base64");
|
|
909
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
910
|
+
}
|
|
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
|
+
);
|
|
956
|
+
}
|
|
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();
|
|
978
|
+
}
|
|
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;
|
|
993
|
+
}
|
|
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
|
+
);
|
|
1000
|
+
}
|
|
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
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
var WS_OPEN, S2sServerMessageSchema, S2S_DISPATCH;
|
|
1040
|
+
var init_s2s = __esm({
|
|
1041
|
+
"sdk/s2s.ts"() {
|
|
1042
|
+
"use strict";
|
|
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";
|
|
1105
1109
|
function agentToolsToSchemas(tools) {
|
|
1106
1110
|
return Object.entries(tools).map(([name, def]) => ({
|
|
1107
1111
|
name,
|
|
1108
1112
|
description: def.description,
|
|
1109
|
-
parameters:
|
|
1113
|
+
parameters: z3.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1110
1114
|
}));
|
|
1111
1115
|
}
|
|
1112
1116
|
var EMPTY_PARAMS;
|
|
1113
1117
|
var init_internal_types = __esm({
|
|
1114
1118
|
"sdk/_internal_types.ts"() {
|
|
1115
1119
|
"use strict";
|
|
1116
|
-
EMPTY_PARAMS =
|
|
1120
|
+
EMPTY_PARAMS = z3.object({});
|
|
1117
1121
|
}
|
|
1118
1122
|
});
|
|
1119
1123
|
|
|
@@ -1139,68 +1143,16 @@ Voice-First Rules:
|
|
|
1139
1143
|
}
|
|
1140
1144
|
});
|
|
1141
1145
|
|
|
1142
|
-
// sdk/memory_tools.ts
|
|
1143
|
-
import { z as z3 } from "zod";
|
|
1144
|
-
function memoryTools() {
|
|
1145
|
-
return {
|
|
1146
|
-
save_memory: tool({
|
|
1147
|
-
description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
|
|
1148
|
-
parameters: z3.object({
|
|
1149
|
-
key: z3.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
|
|
1150
|
-
value: z3.string().describe("The information to remember")
|
|
1151
|
-
}),
|
|
1152
|
-
execute: async ({ key, value }, ctx) => {
|
|
1153
|
-
await ctx.kv.set(key, value);
|
|
1154
|
-
return { saved: key };
|
|
1155
|
-
}
|
|
1156
|
-
}),
|
|
1157
|
-
recall_memory: tool({
|
|
1158
|
-
description: "Retrieve a previously saved memory by its key.",
|
|
1159
|
-
parameters: z3.object({
|
|
1160
|
-
key: z3.string().describe("The key to look up")
|
|
1161
|
-
}),
|
|
1162
|
-
execute: async ({ key }, ctx) => {
|
|
1163
|
-
const value = await ctx.kv.get(key);
|
|
1164
|
-
if (value === null) return { found: false, key };
|
|
1165
|
-
return { found: true, key, value };
|
|
1166
|
-
}
|
|
1167
|
-
}),
|
|
1168
|
-
list_memories: tool({
|
|
1169
|
-
description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
|
|
1170
|
-
parameters: z3.object({
|
|
1171
|
-
prefix: z3.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional()
|
|
1172
|
-
}),
|
|
1173
|
-
execute: async ({ prefix }, ctx) => {
|
|
1174
|
-
const entries = await ctx.kv.list(prefix ?? "");
|
|
1175
|
-
return { count: entries.length, keys: entries.map((e) => e.key) };
|
|
1176
|
-
}
|
|
1177
|
-
}),
|
|
1178
|
-
forget_memory: tool({
|
|
1179
|
-
description: "Delete a previously saved memory by its key.",
|
|
1180
|
-
parameters: z3.object({
|
|
1181
|
-
key: z3.string().describe("The key to delete")
|
|
1182
|
-
}),
|
|
1183
|
-
execute: async ({ key }, ctx) => {
|
|
1184
|
-
await ctx.kv.delete(key);
|
|
1185
|
-
return { deleted: key };
|
|
1186
|
-
}
|
|
1187
|
-
})
|
|
1188
|
-
};
|
|
1189
|
-
}
|
|
1190
|
-
var init_memory_tools = __esm({
|
|
1191
|
-
"sdk/memory_tools.ts"() {
|
|
1192
|
-
"use strict";
|
|
1193
|
-
init_types();
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
|
|
1197
1146
|
// sdk/builtin_tools.ts
|
|
1198
1147
|
import { convert } from "html-to-text";
|
|
1199
1148
|
import { z as z4 } from "zod";
|
|
1149
|
+
function fetchSignal(toolSignal) {
|
|
1150
|
+
return AbortSignal.any([toolSignal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]);
|
|
1151
|
+
}
|
|
1200
1152
|
function htmlToText(html) {
|
|
1201
1153
|
return convert(html, { wordwrap: false });
|
|
1202
1154
|
}
|
|
1203
|
-
function createWebSearch() {
|
|
1155
|
+
function createWebSearch(fetchFn = globalThis.fetch) {
|
|
1204
1156
|
return {
|
|
1205
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.",
|
|
1206
1158
|
parameters: webSearchParams,
|
|
@@ -1215,9 +1167,9 @@ function createWebSearch() {
|
|
|
1215
1167
|
count: String(maxResults),
|
|
1216
1168
|
text_decorations: "false"
|
|
1217
1169
|
})}`;
|
|
1218
|
-
const resp = await
|
|
1170
|
+
const resp = await fetchFn(url, {
|
|
1219
1171
|
headers: { "X-Subscription-Token": apiKey },
|
|
1220
|
-
signal: ctx.abortSignal
|
|
1172
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1221
1173
|
});
|
|
1222
1174
|
if (!resp.ok) return [];
|
|
1223
1175
|
const raw = await resp.json();
|
|
@@ -1231,19 +1183,19 @@ function createWebSearch() {
|
|
|
1231
1183
|
}
|
|
1232
1184
|
};
|
|
1233
1185
|
}
|
|
1234
|
-
function createVisitWebpage() {
|
|
1186
|
+
function createVisitWebpage(fetchFn = globalThis.fetch) {
|
|
1235
1187
|
return {
|
|
1236
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.",
|
|
1237
1189
|
parameters: visitWebpageParams,
|
|
1238
1190
|
async execute(args, ctx) {
|
|
1239
1191
|
const { url } = args;
|
|
1240
|
-
const resp = await
|
|
1192
|
+
const resp = await fetchFn(url, {
|
|
1241
1193
|
headers: {
|
|
1242
1194
|
"User-Agent": "Mozilla/5.0 (compatible; VoiceAgent/1.0; +https://github.com/AssemblyAI/aai)",
|
|
1243
1195
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
1244
1196
|
},
|
|
1245
1197
|
redirect: "follow",
|
|
1246
|
-
signal: ctx.abortSignal
|
|
1198
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1247
1199
|
});
|
|
1248
1200
|
if (!resp.ok) {
|
|
1249
1201
|
return { error: `Failed to fetch: ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1261,15 +1213,15 @@ function createVisitWebpage() {
|
|
|
1261
1213
|
}
|
|
1262
1214
|
};
|
|
1263
1215
|
}
|
|
1264
|
-
function createFetchJson() {
|
|
1216
|
+
function createFetchJson(fetchFn = globalThis.fetch) {
|
|
1265
1217
|
return {
|
|
1266
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.",
|
|
1267
1219
|
parameters: fetchJsonParams,
|
|
1268
1220
|
async execute(args, ctx) {
|
|
1269
1221
|
const { url, headers } = args;
|
|
1270
|
-
const resp = await
|
|
1222
|
+
const resp = await fetchFn(url, {
|
|
1271
1223
|
...headers && { headers },
|
|
1272
|
-
signal: ctx.abortSignal
|
|
1224
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1273
1225
|
});
|
|
1274
1226
|
if (!resp.ok) {
|
|
1275
1227
|
return { error: `HTTP ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1299,7 +1251,6 @@ function createRunCode() {
|
|
|
1299
1251
|
error: capture,
|
|
1300
1252
|
debug: capture
|
|
1301
1253
|
};
|
|
1302
|
-
const RUN_CODE_TIMEOUT = 5e3;
|
|
1303
1254
|
const AsyncFunction = Object.getPrototypeOf(async () => {
|
|
1304
1255
|
}).constructor;
|
|
1305
1256
|
try {
|
|
@@ -1313,7 +1264,7 @@ function createRunCode() {
|
|
|
1313
1264
|
const result = output.join("\n").trim();
|
|
1314
1265
|
return result || "Code ran successfully (no output)";
|
|
1315
1266
|
} catch (err) {
|
|
1316
|
-
return { error:
|
|
1267
|
+
return { error: errorMessage(err) };
|
|
1317
1268
|
}
|
|
1318
1269
|
}
|
|
1319
1270
|
};
|
|
@@ -1328,66 +1279,84 @@ function createVectorSearch(vectorSearchFn) {
|
|
|
1328
1279
|
}
|
|
1329
1280
|
};
|
|
1330
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
|
+
}
|
|
1331
1289
|
function getBuiltinToolDefs(names, opts) {
|
|
1332
1290
|
const defs = {};
|
|
1333
1291
|
for (const name of names) {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1292
|
+
for (const [k, v] of resolveBuiltin(name, opts)) defs[k] = v;
|
|
1293
|
+
}
|
|
1294
|
+
return defs;
|
|
1295
|
+
}
|
|
1296
|
+
function getBuiltinToolSchemas(names) {
|
|
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
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
function memoryTools() {
|
|
1306
|
+
return {
|
|
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 };
|
|
1316
|
+
}
|
|
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 };
|
|
1327
|
+
}
|
|
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) };
|
|
1358
1337
|
}
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
name: toolName,
|
|
1369
|
-
description: def2.description,
|
|
1370
|
-
parameters: z4.toJSONSchema(def2.parameters ?? EMPTY_PARAMS)
|
|
1371
|
-
}));
|
|
1372
|
-
}
|
|
1373
|
-
const creator = TOOL_CREATORS[name];
|
|
1374
|
-
if (!creator) return [];
|
|
1375
|
-
const def = creator();
|
|
1376
|
-
return [
|
|
1377
|
-
{
|
|
1378
|
-
name,
|
|
1379
|
-
description: def.description,
|
|
1380
|
-
parameters: z4.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
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 };
|
|
1381
1347
|
}
|
|
1382
|
-
|
|
1383
|
-
}
|
|
1348
|
+
})
|
|
1349
|
+
};
|
|
1384
1350
|
}
|
|
1385
|
-
var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams,
|
|
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;
|
|
1386
1352
|
var init_builtin_tools = __esm({
|
|
1387
1353
|
"sdk/builtin_tools.ts"() {
|
|
1388
1354
|
"use strict";
|
|
1389
1355
|
init_internal_types();
|
|
1390
|
-
|
|
1356
|
+
init_utils();
|
|
1357
|
+
init_types();
|
|
1358
|
+
FETCH_TIMEOUT_MS = 15e3;
|
|
1359
|
+
RUN_CODE_TIMEOUT = 5e3;
|
|
1391
1360
|
webSearchParams = z4.object({
|
|
1392
1361
|
query: z4.string().describe("The search query"),
|
|
1393
1362
|
max_results: z4.number().describe("Maximum number of results to return (default 5)").optional()
|
|
@@ -1422,16 +1391,13 @@ var init_builtin_tools = __esm({
|
|
|
1422
1391
|
),
|
|
1423
1392
|
topK: z4.number().describe("Maximum results to return (default: 5)").optional()
|
|
1424
1393
|
});
|
|
1425
|
-
|
|
1426
|
-
web_search: createWebSearch,
|
|
1427
|
-
visit_webpage: createVisitWebpage,
|
|
1428
|
-
fetch_json: createFetchJson,
|
|
1429
|
-
run_code: createRunCode,
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
};
|
|
1433
|
-
MULTI_TOOL_BUILTINS = {
|
|
1434
|
-
memory: memoryTools
|
|
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 }
|
|
1435
1401
|
};
|
|
1436
1402
|
}
|
|
1437
1403
|
});
|
|
@@ -1502,291 +1468,6 @@ var init_kv = __esm({
|
|
|
1502
1468
|
}
|
|
1503
1469
|
});
|
|
1504
1470
|
|
|
1505
|
-
// sdk/s2s.ts
|
|
1506
|
-
import { z as z5 } from "zod";
|
|
1507
|
-
function uint8ToBase64(bytes) {
|
|
1508
|
-
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
1509
|
-
}
|
|
1510
|
-
function base64ToUint8(base64) {
|
|
1511
|
-
const buf = Buffer.from(base64, "base64");
|
|
1512
|
-
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
1513
|
-
}
|
|
1514
|
-
function dispatchS2sMessage(target, msg) {
|
|
1515
|
-
switch (msg.type) {
|
|
1516
|
-
case "session.ready":
|
|
1517
|
-
target.dispatchEvent(
|
|
1518
|
-
new CustomEvent("ready", {
|
|
1519
|
-
detail: { session_id: msg.session_id }
|
|
1520
|
-
})
|
|
1521
|
-
);
|
|
1522
|
-
break;
|
|
1523
|
-
case "session.updated":
|
|
1524
|
-
target.dispatchEvent(new CustomEvent("session_updated", { detail: msg }));
|
|
1525
|
-
break;
|
|
1526
|
-
case "input.speech.started":
|
|
1527
|
-
target.dispatchEvent(new CustomEvent("speech_started"));
|
|
1528
|
-
break;
|
|
1529
|
-
case "input.speech.stopped":
|
|
1530
|
-
target.dispatchEvent(new CustomEvent("speech_stopped"));
|
|
1531
|
-
break;
|
|
1532
|
-
case "transcript.user.delta":
|
|
1533
|
-
target.dispatchEvent(
|
|
1534
|
-
new CustomEvent("user_transcript_delta", {
|
|
1535
|
-
detail: { text: msg.text }
|
|
1536
|
-
})
|
|
1537
|
-
);
|
|
1538
|
-
break;
|
|
1539
|
-
case "transcript.user":
|
|
1540
|
-
target.dispatchEvent(
|
|
1541
|
-
new CustomEvent("user_transcript", {
|
|
1542
|
-
detail: {
|
|
1543
|
-
item_id: msg.item_id,
|
|
1544
|
-
text: msg.text
|
|
1545
|
-
}
|
|
1546
|
-
})
|
|
1547
|
-
);
|
|
1548
|
-
break;
|
|
1549
|
-
case "reply.started":
|
|
1550
|
-
target.dispatchEvent(
|
|
1551
|
-
new CustomEvent("reply_started", {
|
|
1552
|
-
detail: { reply_id: msg.reply_id }
|
|
1553
|
-
})
|
|
1554
|
-
);
|
|
1555
|
-
break;
|
|
1556
|
-
// reply.audio handled on the fast path — never reaches dispatch.
|
|
1557
|
-
case "transcript.agent.delta":
|
|
1558
|
-
target.dispatchEvent(
|
|
1559
|
-
new CustomEvent("agent_transcript_delta", {
|
|
1560
|
-
detail: { text: msg.delta }
|
|
1561
|
-
})
|
|
1562
|
-
);
|
|
1563
|
-
break;
|
|
1564
|
-
case "transcript.agent":
|
|
1565
|
-
target.dispatchEvent(
|
|
1566
|
-
new CustomEvent("agent_transcript", {
|
|
1567
|
-
detail: { text: msg.text }
|
|
1568
|
-
})
|
|
1569
|
-
);
|
|
1570
|
-
break;
|
|
1571
|
-
case "tool.call":
|
|
1572
|
-
target.dispatchEvent(
|
|
1573
|
-
new CustomEvent("tool_call", {
|
|
1574
|
-
detail: {
|
|
1575
|
-
call_id: msg.call_id,
|
|
1576
|
-
name: msg.name,
|
|
1577
|
-
args: msg.args
|
|
1578
|
-
}
|
|
1579
|
-
})
|
|
1580
|
-
);
|
|
1581
|
-
break;
|
|
1582
|
-
case "reply.done":
|
|
1583
|
-
target.dispatchEvent(
|
|
1584
|
-
new CustomEvent("reply_done", {
|
|
1585
|
-
detail: { status: msg.status }
|
|
1586
|
-
})
|
|
1587
|
-
);
|
|
1588
|
-
break;
|
|
1589
|
-
case "session.error": {
|
|
1590
|
-
const isExpired = msg.code === "session_not_found" || msg.code === "session_forbidden";
|
|
1591
|
-
target.dispatchEvent(
|
|
1592
|
-
new CustomEvent(isExpired ? "session_expired" : "error", {
|
|
1593
|
-
detail: { code: msg.code, message: msg.message }
|
|
1594
|
-
})
|
|
1595
|
-
);
|
|
1596
|
-
break;
|
|
1597
|
-
}
|
|
1598
|
-
case "reply.content_part.started":
|
|
1599
|
-
case "reply.content_part.done":
|
|
1600
|
-
break;
|
|
1601
|
-
case "error":
|
|
1602
|
-
target.dispatchEvent(
|
|
1603
|
-
new CustomEvent("error", {
|
|
1604
|
-
detail: { code: "connection", message: msg.message }
|
|
1605
|
-
})
|
|
1606
|
-
);
|
|
1607
|
-
break;
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
function connectS2s(opts) {
|
|
1611
|
-
const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
|
|
1612
|
-
return new Promise((resolve, reject) => {
|
|
1613
|
-
log.debug("S2S connecting", { url: config.wssUrl });
|
|
1614
|
-
const ws = createWebSocket(config.wssUrl, {
|
|
1615
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
1616
|
-
});
|
|
1617
|
-
const target = new EventTarget();
|
|
1618
|
-
let opened = false;
|
|
1619
|
-
function send(msg) {
|
|
1620
|
-
if (ws.readyState !== WS_OPEN) return;
|
|
1621
|
-
const json = JSON.stringify(msg);
|
|
1622
|
-
if (msg.type !== "input.audio") {
|
|
1623
|
-
log.debug(
|
|
1624
|
-
`S2S >> ${msg.type}`,
|
|
1625
|
-
msg.type === "session.update" ? { payload: json } : void 0
|
|
1626
|
-
);
|
|
1627
|
-
}
|
|
1628
|
-
ws.send(json);
|
|
1629
|
-
}
|
|
1630
|
-
const handle = Object.assign(target, {
|
|
1631
|
-
sendAudio(audio) {
|
|
1632
|
-
if (ws.readyState !== WS_OPEN) return;
|
|
1633
|
-
if (ws.sendBinary) {
|
|
1634
|
-
const ab = audio.buffer.slice(
|
|
1635
|
-
audio.byteOffset,
|
|
1636
|
-
audio.byteOffset + audio.byteLength
|
|
1637
|
-
);
|
|
1638
|
-
ws.sendBinary(ab);
|
|
1639
|
-
} else {
|
|
1640
|
-
ws.send(`{"type":"input.audio","audio":"${uint8ToBase64(audio)}"}`);
|
|
1641
|
-
}
|
|
1642
|
-
},
|
|
1643
|
-
sendToolResult(callId, result) {
|
|
1644
|
-
const msg = { type: "tool.result", call_id: callId, result };
|
|
1645
|
-
log.debug("S2S >> tool.result", { call_id: callId, resultLength: result.length });
|
|
1646
|
-
send(msg);
|
|
1647
|
-
},
|
|
1648
|
-
updateSession(sessionConfig) {
|
|
1649
|
-
send({ type: "session.update", session: sessionConfig });
|
|
1650
|
-
},
|
|
1651
|
-
resumeSession(sessionId) {
|
|
1652
|
-
send({ type: "session.resume", session_id: sessionId });
|
|
1653
|
-
},
|
|
1654
|
-
close() {
|
|
1655
|
-
log.debug("S2S closing");
|
|
1656
|
-
ws.close();
|
|
1657
|
-
}
|
|
1658
|
-
});
|
|
1659
|
-
ws.on("open", () => {
|
|
1660
|
-
opened = true;
|
|
1661
|
-
log.info("S2S WebSocket open");
|
|
1662
|
-
resolve(handle);
|
|
1663
|
-
});
|
|
1664
|
-
ws.on("audio", (data) => {
|
|
1665
|
-
const ab = data;
|
|
1666
|
-
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: new Uint8Array(ab) } }));
|
|
1667
|
-
});
|
|
1668
|
-
ws.on("message", (data) => {
|
|
1669
|
-
let raw;
|
|
1670
|
-
try {
|
|
1671
|
-
raw = JSON.parse(String(data));
|
|
1672
|
-
} catch {
|
|
1673
|
-
return;
|
|
1674
|
-
}
|
|
1675
|
-
const obj = raw;
|
|
1676
|
-
if (obj.type !== "reply.audio" && obj.type !== "input.audio" && obj.type !== "transcript.agent.delta") {
|
|
1677
|
-
log.info(`S2S << ${obj.type}`);
|
|
1678
|
-
}
|
|
1679
|
-
if (obj.type === "reply.audio" && typeof obj.data === "string") {
|
|
1680
|
-
const audioBytes = base64ToUint8(obj.data);
|
|
1681
|
-
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
const parsed = S2sServerMessageSchema.safeParse(raw);
|
|
1685
|
-
if (!parsed.success) {
|
|
1686
|
-
log.warn(
|
|
1687
|
-
`S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 200)}`
|
|
1688
|
-
);
|
|
1689
|
-
return;
|
|
1690
|
-
}
|
|
1691
|
-
const msg = parsed.data;
|
|
1692
|
-
dispatchS2sMessage(target, msg);
|
|
1693
|
-
});
|
|
1694
|
-
ws.on("close", (code, reason) => {
|
|
1695
|
-
log.info("S2S WebSocket closed", {
|
|
1696
|
-
code: typeof code === "number" ? code : 0,
|
|
1697
|
-
reason: reason instanceof Uint8Array ? new TextDecoder().decode(reason) : String(reason ?? "")
|
|
1698
|
-
});
|
|
1699
|
-
target.dispatchEvent(new CustomEvent("close"));
|
|
1700
|
-
});
|
|
1701
|
-
ws.on("error", (err) => {
|
|
1702
|
-
const errObj = err instanceof Error ? err : new Error(String(err));
|
|
1703
|
-
log.error("S2S WebSocket error", { error: errObj.message });
|
|
1704
|
-
if (!opened) {
|
|
1705
|
-
reject(errObj);
|
|
1706
|
-
} else {
|
|
1707
|
-
target.dispatchEvent(
|
|
1708
|
-
new CustomEvent("error", {
|
|
1709
|
-
detail: { code: "ws_error", message: errObj.message }
|
|
1710
|
-
})
|
|
1711
|
-
);
|
|
1712
|
-
}
|
|
1713
|
-
});
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
var WS_OPEN, S2sServerMessageSchema;
|
|
1717
|
-
var init_s2s = __esm({
|
|
1718
|
-
"sdk/s2s.ts"() {
|
|
1719
|
-
"use strict";
|
|
1720
|
-
init_runtime();
|
|
1721
|
-
WS_OPEN = 1;
|
|
1722
|
-
S2sServerMessageSchema = z5.discriminatedUnion("type", [
|
|
1723
|
-
z5.object({ type: z5.literal("session.ready"), session_id: z5.string() }),
|
|
1724
|
-
z5.object({ type: z5.literal("session.updated") }).passthrough(),
|
|
1725
|
-
z5.object({ type: z5.literal("input.speech.started") }),
|
|
1726
|
-
z5.object({ type: z5.literal("input.speech.stopped") }),
|
|
1727
|
-
z5.object({ type: z5.literal("transcript.user.delta"), text: z5.string() }),
|
|
1728
|
-
z5.object({
|
|
1729
|
-
type: z5.literal("transcript.user"),
|
|
1730
|
-
item_id: z5.string(),
|
|
1731
|
-
text: z5.string()
|
|
1732
|
-
}),
|
|
1733
|
-
z5.object({ type: z5.literal("reply.started"), reply_id: z5.string() }),
|
|
1734
|
-
// reply.audio is handled on the fast path before Zod — see message handler.
|
|
1735
|
-
z5.object({ type: z5.literal("transcript.agent.delta"), delta: z5.string() }).passthrough(),
|
|
1736
|
-
z5.object({ type: z5.literal("transcript.agent"), text: z5.string() }),
|
|
1737
|
-
z5.object({ type: z5.literal("reply.content_part.started") }).passthrough(),
|
|
1738
|
-
z5.object({ type: z5.literal("reply.content_part.done") }).passthrough(),
|
|
1739
|
-
z5.object({
|
|
1740
|
-
type: z5.literal("tool.call"),
|
|
1741
|
-
call_id: z5.string(),
|
|
1742
|
-
name: z5.string(),
|
|
1743
|
-
args: z5.record(z5.string(), z5.unknown()).optional().default({})
|
|
1744
|
-
}),
|
|
1745
|
-
z5.object({
|
|
1746
|
-
type: z5.literal("reply.done"),
|
|
1747
|
-
status: z5.string().optional()
|
|
1748
|
-
}),
|
|
1749
|
-
z5.object({
|
|
1750
|
-
type: z5.literal("session.error"),
|
|
1751
|
-
code: z5.string(),
|
|
1752
|
-
message: z5.string()
|
|
1753
|
-
}),
|
|
1754
|
-
// Connection-level error (bare "error" without "session." prefix).
|
|
1755
|
-
z5.object({
|
|
1756
|
-
type: z5.literal("error"),
|
|
1757
|
-
message: z5.string()
|
|
1758
|
-
})
|
|
1759
|
-
]);
|
|
1760
|
-
}
|
|
1761
|
-
});
|
|
1762
|
-
|
|
1763
|
-
// sdk/system_prompt.ts
|
|
1764
|
-
function buildSystemPrompt(config, opts) {
|
|
1765
|
-
const { hasTools } = opts;
|
|
1766
|
-
const agentInstructions = config.instructions && config.instructions !== DEFAULT_INSTRUCTIONS ? `
|
|
1767
|
-
|
|
1768
|
-
Agent-Specific Instructions:
|
|
1769
|
-
${config.instructions}` : "";
|
|
1770
|
-
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.' : "";
|
|
1771
|
-
const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
1772
|
-
weekday: "long",
|
|
1773
|
-
year: "numeric",
|
|
1774
|
-
month: "long",
|
|
1775
|
-
day: "numeric"
|
|
1776
|
-
});
|
|
1777
|
-
return DEFAULT_INSTRUCTIONS + `
|
|
1778
|
-
|
|
1779
|
-
Today's date is ${today}.` + agentInstructions + toolPreamble + (opts?.voice ? VOICE_RULES : "");
|
|
1780
|
-
}
|
|
1781
|
-
var VOICE_RULES;
|
|
1782
|
-
var init_system_prompt = __esm({
|
|
1783
|
-
"sdk/system_prompt.ts"() {
|
|
1784
|
-
"use strict";
|
|
1785
|
-
init_types();
|
|
1786
|
-
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';
|
|
1787
|
-
}
|
|
1788
|
-
});
|
|
1789
|
-
|
|
1790
1471
|
// sdk/session.ts
|
|
1791
1472
|
function createS2sSession(opts) {
|
|
1792
1473
|
const {
|
|
@@ -1817,7 +1498,6 @@ function createS2sSession(opts) {
|
|
|
1817
1498
|
}));
|
|
1818
1499
|
let s2s = null;
|
|
1819
1500
|
const sessionAbort = new AbortController();
|
|
1820
|
-
let audioReady = false;
|
|
1821
1501
|
let toolCallCount = 0;
|
|
1822
1502
|
let turnPromise = null;
|
|
1823
1503
|
let conversationMessages = [];
|
|
@@ -1829,36 +1509,21 @@ function createS2sSession(opts) {
|
|
|
1829
1509
|
if (!hookInvoker) return null;
|
|
1830
1510
|
try {
|
|
1831
1511
|
return await hookInvoker.resolveTurnConfig(id, HOOK_TIMEOUT_MS);
|
|
1832
|
-
} catch {
|
|
1512
|
+
} catch (err) {
|
|
1513
|
+
log.warn("resolveTurnConfig hook failed", { err: errorMessage(err) });
|
|
1833
1514
|
return null;
|
|
1834
1515
|
}
|
|
1835
1516
|
}
|
|
1836
1517
|
function invokeHook(hook, arg) {
|
|
1837
1518
|
if (!hookInvoker) return;
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
break;
|
|
1843
|
-
case "onDisconnect":
|
|
1844
|
-
await hookInvoker.onDisconnect(id, HOOK_TIMEOUT_MS);
|
|
1845
|
-
break;
|
|
1846
|
-
case "onTurn":
|
|
1847
|
-
await hookInvoker.onTurn(id, arg, HOOK_TIMEOUT_MS);
|
|
1848
|
-
break;
|
|
1849
|
-
case "onError":
|
|
1850
|
-
await hookInvoker.onError(id, arg, HOOK_TIMEOUT_MS);
|
|
1851
|
-
break;
|
|
1852
|
-
case "onStep":
|
|
1853
|
-
await hookInvoker.onStep(id, arg, HOOK_TIMEOUT_MS);
|
|
1854
|
-
break;
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1857
|
-
run().catch((err) => {
|
|
1858
|
-
log.warn(`${hook} hook failed`, {
|
|
1859
|
-
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) });
|
|
1860
1523
|
});
|
|
1861
|
-
})
|
|
1524
|
+
} catch (err) {
|
|
1525
|
+
log.warn(`${hook} hook failed`, { err: errorMessage(err) });
|
|
1526
|
+
}
|
|
1862
1527
|
}
|
|
1863
1528
|
function checkTurnLimits(turnConfig, name) {
|
|
1864
1529
|
const maxSteps = turnConfig?.maxSteps ?? agentConfig.maxSteps;
|
|
@@ -1898,7 +1563,7 @@ function createS2sSession(opts) {
|
|
|
1898
1563
|
try {
|
|
1899
1564
|
result = await executeTool(name, parsedArgs, id, conversationMessages);
|
|
1900
1565
|
} catch (err) {
|
|
1901
|
-
const msg =
|
|
1566
|
+
const msg = errorMessage(err);
|
|
1902
1567
|
log.error("Tool execution failed", { tool: name, error: msg });
|
|
1903
1568
|
result = JSON.stringify({ error: msg });
|
|
1904
1569
|
}
|
|
@@ -1913,6 +1578,79 @@ function createS2sSession(opts) {
|
|
|
1913
1578
|
function on(target, event, handler) {
|
|
1914
1579
|
target.addEventListener(event, handler);
|
|
1915
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
|
+
}
|
|
1916
1654
|
async function connectAndSetup() {
|
|
1917
1655
|
if (connecting) {
|
|
1918
1656
|
pendingReconnect = true;
|
|
@@ -1920,106 +1658,15 @@ function createS2sSession(opts) {
|
|
|
1920
1658
|
}
|
|
1921
1659
|
connecting = true;
|
|
1922
1660
|
try {
|
|
1923
|
-
const handle = await
|
|
1661
|
+
const handle = await _internals.connectS2s({
|
|
1924
1662
|
apiKey,
|
|
1925
1663
|
config: s2sConfig,
|
|
1926
1664
|
createWebSocket,
|
|
1927
1665
|
logger: log
|
|
1928
1666
|
});
|
|
1929
|
-
|
|
1930
|
-
s2sSessionId = e.detail.session_id;
|
|
1931
|
-
log.info("S2S session ready", { session_id: s2sSessionId });
|
|
1932
|
-
});
|
|
1933
|
-
on(handle, "session_expired", () => {
|
|
1934
|
-
log.info("S2S session expired, reconnecting fresh");
|
|
1935
|
-
s2sSessionId = null;
|
|
1936
|
-
handle.close();
|
|
1937
|
-
});
|
|
1938
|
-
handle.addEventListener("speech_started", () => {
|
|
1939
|
-
client.event({ type: "speech_started" });
|
|
1940
|
-
});
|
|
1941
|
-
handle.addEventListener("speech_stopped", () => {
|
|
1942
|
-
client.event({ type: "speech_stopped" });
|
|
1943
|
-
});
|
|
1944
|
-
on(handle, "user_transcript_delta", (e) => {
|
|
1945
|
-
client.event({
|
|
1946
|
-
type: "transcript",
|
|
1947
|
-
text: e.detail.text,
|
|
1948
|
-
isFinal: false
|
|
1949
|
-
});
|
|
1950
|
-
});
|
|
1951
|
-
on(handle, "user_transcript", (e) => {
|
|
1952
|
-
const { text } = e.detail;
|
|
1953
|
-
log.info("S2S user transcript", { text });
|
|
1954
|
-
client.event({ type: "transcript", text, isFinal: true });
|
|
1955
|
-
client.event({ type: "turn", text });
|
|
1956
|
-
conversationMessages.push({ role: "user", content: text });
|
|
1957
|
-
invokeHook("onTurn", text);
|
|
1958
|
-
});
|
|
1959
|
-
handle.addEventListener("reply_started", () => {
|
|
1960
|
-
toolCallCount = 0;
|
|
1961
|
-
});
|
|
1962
|
-
on(handle, "audio", (e) => {
|
|
1963
|
-
client.playAudioChunk(e.detail.audio);
|
|
1964
|
-
});
|
|
1965
|
-
on(handle, "agent_transcript_delta", (e) => {
|
|
1966
|
-
client.event({ type: "chat_delta", text: e.detail.text });
|
|
1967
|
-
});
|
|
1968
|
-
on(handle, "agent_transcript", (e) => {
|
|
1969
|
-
const { text } = e.detail;
|
|
1970
|
-
client.event({ type: "chat", text });
|
|
1971
|
-
conversationMessages.push({ role: "assistant", content: text });
|
|
1972
|
-
});
|
|
1973
|
-
on(handle, "tool_call", (e) => {
|
|
1974
|
-
const p = handleToolCall(e.detail).catch((err) => {
|
|
1975
|
-
log.error("Tool call handler failed", {
|
|
1976
|
-
err: err instanceof Error ? err.message : String(err)
|
|
1977
|
-
});
|
|
1978
|
-
});
|
|
1979
|
-
turnPromise = (turnPromise ?? Promise.resolve()).then(() => p);
|
|
1980
|
-
});
|
|
1981
|
-
on(handle, "reply_done", (e) => {
|
|
1982
|
-
if (e.detail.status === "interrupted") {
|
|
1983
|
-
log.info("S2S reply interrupted (barge-in)");
|
|
1984
|
-
pendingTools = [];
|
|
1985
|
-
client.event({ type: "cancelled" });
|
|
1986
|
-
} else if (pendingTools.length > 0) {
|
|
1987
|
-
for (const tool2 of pendingTools) {
|
|
1988
|
-
s2s?.sendToolResult(tool2.call_id, tool2.result);
|
|
1989
|
-
}
|
|
1990
|
-
pendingTools = [];
|
|
1991
|
-
} else {
|
|
1992
|
-
client.playAudioDone();
|
|
1993
|
-
client.event({ type: "tts_done" });
|
|
1994
|
-
}
|
|
1995
|
-
});
|
|
1996
|
-
on(handle, "error", (e) => {
|
|
1997
|
-
log.error("S2S error", {
|
|
1998
|
-
code: e.detail.code,
|
|
1999
|
-
message: e.detail.message
|
|
2000
|
-
});
|
|
2001
|
-
client.event({
|
|
2002
|
-
type: "error",
|
|
2003
|
-
code: "internal",
|
|
2004
|
-
message: e.detail.message
|
|
2005
|
-
});
|
|
2006
|
-
handle.close();
|
|
2007
|
-
});
|
|
2008
|
-
handle.addEventListener("close", () => {
|
|
2009
|
-
log.info("S2S closed");
|
|
2010
|
-
s2s = null;
|
|
2011
|
-
if (!sessionAbort.signal.aborted) {
|
|
2012
|
-
log.info("Attempting S2S reconnect");
|
|
2013
|
-
connectAndSetup().catch((err) => {
|
|
2014
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2015
|
-
log.error("S2S reconnect failed", { error: msg });
|
|
2016
|
-
});
|
|
2017
|
-
}
|
|
2018
|
-
});
|
|
1667
|
+
setupListeners(handle);
|
|
2019
1668
|
if (s2sSessionId) {
|
|
2020
|
-
log.info("Attempting S2S session resume", {
|
|
2021
|
-
session_id: s2sSessionId
|
|
2022
|
-
});
|
|
1669
|
+
log.info("Attempting S2S session resume", { session_id: s2sSessionId });
|
|
2023
1670
|
handle.resumeSession(s2sSessionId);
|
|
2024
1671
|
} else {
|
|
2025
1672
|
handle.updateSession({
|
|
@@ -2030,7 +1677,7 @@ function createS2sSession(opts) {
|
|
|
2030
1677
|
}
|
|
2031
1678
|
s2s = handle;
|
|
2032
1679
|
} catch (err) {
|
|
2033
|
-
const msg =
|
|
1680
|
+
const msg = errorMessage(err);
|
|
2034
1681
|
log.error("S2S connect failed", { error: msg });
|
|
2035
1682
|
client.event({ type: "error", code: "internal", message: msg });
|
|
2036
1683
|
} finally {
|
|
@@ -2038,8 +1685,7 @@ function createS2sSession(opts) {
|
|
|
2038
1685
|
if (pendingReconnect && !sessionAbort.signal.aborted) {
|
|
2039
1686
|
pendingReconnect = false;
|
|
2040
1687
|
connectAndSetup().catch((err) => {
|
|
2041
|
-
|
|
2042
|
-
log.error("S2S deferred reconnect failed", { error: msg });
|
|
1688
|
+
log.error("S2S deferred reconnect failed", { error: errorMessage(err) });
|
|
2043
1689
|
});
|
|
2044
1690
|
}
|
|
2045
1691
|
}
|
|
@@ -2063,8 +1709,6 @@ function createS2sSession(opts) {
|
|
|
2063
1709
|
s2s?.sendAudio(data);
|
|
2064
1710
|
},
|
|
2065
1711
|
onAudioReady() {
|
|
2066
|
-
if (audioReady) return;
|
|
2067
|
-
audioReady = true;
|
|
2068
1712
|
},
|
|
2069
1713
|
onCancel() {
|
|
2070
1714
|
client.event({ type: "cancelled" });
|
|
@@ -2088,17 +1732,36 @@ function createS2sSession(opts) {
|
|
|
2088
1732
|
}
|
|
2089
1733
|
};
|
|
2090
1734
|
}
|
|
2091
|
-
|
|
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;
|
|
2092
1753
|
var init_session = __esm({
|
|
2093
1754
|
"sdk/session.ts"() {
|
|
2094
1755
|
"use strict";
|
|
1756
|
+
init_utils();
|
|
2095
1757
|
init_protocol();
|
|
2096
1758
|
init_runtime();
|
|
2097
1759
|
init_s2s();
|
|
2098
|
-
|
|
2099
|
-
|
|
1760
|
+
init_types();
|
|
1761
|
+
_internals = {
|
|
2100
1762
|
connectS2s
|
|
2101
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';
|
|
2102
1765
|
}
|
|
2103
1766
|
});
|
|
2104
1767
|
|
|
@@ -2149,11 +1812,10 @@ var init_vector = __esm({
|
|
|
2149
1812
|
|
|
2150
1813
|
// sdk/worker_entry.ts
|
|
2151
1814
|
function buildToolContext(opts) {
|
|
2152
|
-
const { env,
|
|
1815
|
+
const { env, state, kv, vector, messages } = opts;
|
|
2153
1816
|
return {
|
|
2154
|
-
sessionId: sessionId ?? "",
|
|
2155
1817
|
env: { ...env },
|
|
2156
|
-
abortSignal: AbortSignal.timeout(
|
|
1818
|
+
abortSignal: AbortSignal.timeout(TOOL_EXECUTION_TIMEOUT_MS),
|
|
2157
1819
|
state: state ?? {},
|
|
2158
1820
|
get kv() {
|
|
2159
1821
|
if (!kv) throw new Error("KV not available");
|
|
@@ -2182,21 +1844,18 @@ async function executeToolCall(name, args, options) {
|
|
|
2182
1844
|
if (result == null) return "null";
|
|
2183
1845
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
2184
1846
|
} catch (err) {
|
|
2185
|
-
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
2186
|
-
console.warn(`[tool-executor] Tool execution timed out: ${name}`);
|
|
2187
|
-
return `Error: Tool "${name}" timed out after ${TOOL_HANDLER_TIMEOUT}ms`;
|
|
2188
|
-
}
|
|
2189
1847
|
console.warn(`[tool-executor] Tool execution failed: ${name}`, err);
|
|
2190
|
-
return `Error: ${
|
|
1848
|
+
return `Error: ${errorMessage(err)}`;
|
|
2191
1849
|
}
|
|
2192
1850
|
}
|
|
2193
|
-
var yieldTick
|
|
1851
|
+
var yieldTick;
|
|
2194
1852
|
var init_worker_entry = __esm({
|
|
2195
1853
|
"sdk/worker_entry.ts"() {
|
|
2196
1854
|
"use strict";
|
|
2197
1855
|
init_internal_types();
|
|
1856
|
+
init_utils();
|
|
1857
|
+
init_protocol();
|
|
2198
1858
|
yieldTick = () => new Promise((r) => setTimeout(r, 0));
|
|
2199
|
-
TOOL_HANDLER_TIMEOUT = 3e4;
|
|
2200
1859
|
}
|
|
2201
1860
|
});
|
|
2202
1861
|
|
|
@@ -2248,7 +1907,6 @@ function createDirectExecutor(opts) {
|
|
|
2248
1907
|
}
|
|
2249
1908
|
function makeHookContext(sessionId) {
|
|
2250
1909
|
return {
|
|
2251
|
-
sessionId,
|
|
2252
1910
|
env: frozenEnv,
|
|
2253
1911
|
state: getState(sessionId),
|
|
2254
1912
|
get kv() {
|
|
@@ -2265,7 +1923,6 @@ function createDirectExecutor(opts) {
|
|
|
2265
1923
|
return executeToolCall(name, args, {
|
|
2266
1924
|
tool: tool2,
|
|
2267
1925
|
env: frozenEnv,
|
|
2268
|
-
sessionId,
|
|
2269
1926
|
state: getState(sessionId ?? ""),
|
|
2270
1927
|
kv,
|
|
2271
1928
|
vector,
|
|
@@ -2344,9 +2001,6 @@ var init_direct_executor = __esm({
|
|
|
2344
2001
|
});
|
|
2345
2002
|
|
|
2346
2003
|
// sdk/ws_handler.ts
|
|
2347
|
-
function isValidAudioChunk(data) {
|
|
2348
|
-
return data.byteLength > 0 && data.byteLength <= MAX_AUDIO_CHUNK_BYTES && data.byteLength % 2 === 0;
|
|
2349
|
-
}
|
|
2350
2004
|
function createClientSink(ws) {
|
|
2351
2005
|
function safeSend(data) {
|
|
2352
2006
|
try {
|
|
@@ -2378,19 +2032,9 @@ function toUint8Array(data) {
|
|
|
2378
2032
|
const buf = data;
|
|
2379
2033
|
return new Uint8Array(buf.buffer ?? data, buf.byteOffset ?? 0, buf.byteLength);
|
|
2380
2034
|
}
|
|
2381
|
-
function handleBinaryAudio(data, session
|
|
2035
|
+
function handleBinaryAudio(data, session) {
|
|
2382
2036
|
if (!isBinaryData(data)) return false;
|
|
2383
|
-
|
|
2384
|
-
if (!isValidAudioChunk(chunk)) {
|
|
2385
|
-
log.warn("Invalid audio chunk, dropping", {
|
|
2386
|
-
...ctx,
|
|
2387
|
-
sid,
|
|
2388
|
-
bytes: chunk.byteLength,
|
|
2389
|
-
aligned: chunk.byteLength % 2 === 0
|
|
2390
|
-
});
|
|
2391
|
-
return true;
|
|
2392
|
-
}
|
|
2393
|
-
session.onAudio(chunk);
|
|
2037
|
+
session.onAudio(toUint8Array(data));
|
|
2394
2038
|
return true;
|
|
2395
2039
|
}
|
|
2396
2040
|
function handleTextMessage(data, session, log, ctx, sid) {
|
|
@@ -2425,7 +2069,7 @@ function handleTextMessage(data, session, log, ctx, sid) {
|
|
|
2425
2069
|
}
|
|
2426
2070
|
function wireSessionSocket(ws, opts) {
|
|
2427
2071
|
const { sessions, logger: log = consoleLogger } = opts;
|
|
2428
|
-
const sessionId =
|
|
2072
|
+
const sessionId = crypto.randomUUID();
|
|
2429
2073
|
const sid = sessionId.slice(0, 8);
|
|
2430
2074
|
const ctx = opts.logContext ?? {};
|
|
2431
2075
|
let session = null;
|
|
@@ -2436,8 +2080,11 @@ function wireSessionSocket(ws, opts) {
|
|
|
2436
2080
|
session = opts.createSession(sessionId, client);
|
|
2437
2081
|
sessions.set(sessionId, session);
|
|
2438
2082
|
ws.send(JSON.stringify({ type: "config", ...opts.readyConfig }));
|
|
2439
|
-
|
|
2440
|
-
|
|
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
|
+
});
|
|
2441
2088
|
}
|
|
2442
2089
|
if (ws.readyState === 1) {
|
|
2443
2090
|
onOpen();
|
|
@@ -2447,7 +2094,7 @@ function wireSessionSocket(ws, opts) {
|
|
|
2447
2094
|
ws.addEventListener("message", (event) => {
|
|
2448
2095
|
if (!session) return;
|
|
2449
2096
|
const { data } = event;
|
|
2450
|
-
if (handleBinaryAudio(data, session
|
|
2097
|
+
if (handleBinaryAudio(data, session)) return;
|
|
2451
2098
|
handleTextMessage(data, session, log, ctx, sid);
|
|
2452
2099
|
});
|
|
2453
2100
|
ws.addEventListener("close", () => {
|
|
@@ -2464,13 +2111,12 @@ function wireSessionSocket(ws, opts) {
|
|
|
2464
2111
|
log.error("WebSocket error", { ...ctx, sid, error: msg });
|
|
2465
2112
|
});
|
|
2466
2113
|
}
|
|
2467
|
-
var MAX_AUDIO_CHUNK_BYTES;
|
|
2468
2114
|
var init_ws_handler = __esm({
|
|
2469
2115
|
"sdk/ws_handler.ts"() {
|
|
2470
2116
|
"use strict";
|
|
2117
|
+
init_utils();
|
|
2471
2118
|
init_protocol();
|
|
2472
2119
|
init_runtime();
|
|
2473
|
-
MAX_AUDIO_CHUNK_BYTES = 1048576;
|
|
2474
2120
|
}
|
|
2475
2121
|
});
|
|
2476
2122
|
|
|
@@ -2529,8 +2175,7 @@ function createWintercServer(options) {
|
|
|
2529
2175
|
skipGreeting: wsOpts?.skipGreeting ?? false
|
|
2530
2176
|
}),
|
|
2531
2177
|
readyConfig,
|
|
2532
|
-
logger
|
|
2533
|
-
uid: wsOpts?.uid
|
|
2178
|
+
logger
|
|
2534
2179
|
});
|
|
2535
2180
|
},
|
|
2536
2181
|
async close() {
|
|
@@ -2565,7 +2210,7 @@ async function loadWsFactory() {
|
|
|
2565
2210
|
try {
|
|
2566
2211
|
const mod = await import("ws");
|
|
2567
2212
|
const WS = mod.default ?? mod;
|
|
2568
|
-
return (url, opts) => new WS(url, { headers: opts.headers });
|
|
2213
|
+
return (url, opts) => wrapOnStyleWebSocket(new WS(url, { headers: opts.headers }));
|
|
2569
2214
|
} catch {
|
|
2570
2215
|
throw new Error(
|
|
2571
2216
|
"WebSocket factory not provided and `ws` package not found. Install `ws` (`npm install ws`) or pass `createWebSocket` option."
|
|
@@ -2573,11 +2218,7 @@ async function loadWsFactory() {
|
|
|
2573
2218
|
}
|
|
2574
2219
|
}
|
|
2575
2220
|
function resolveEnv(env) {
|
|
2576
|
-
|
|
2577
|
-
for (const [key, value] of Object.entries(env)) {
|
|
2578
|
-
if (value !== void 0) resolved[key] = value;
|
|
2579
|
-
}
|
|
2580
|
-
return resolved;
|
|
2221
|
+
return Object.fromEntries(Object.entries(env).filter(([, v]) => v !== void 0));
|
|
2581
2222
|
}
|
|
2582
2223
|
function createServer(options) {
|
|
2583
2224
|
const {
|
|
@@ -2624,6 +2265,23 @@ function createServer(options) {
|
|
|
2624
2265
|
await getWsFactory();
|
|
2625
2266
|
const wintercServer = getWinterc();
|
|
2626
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`);
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2627
2285
|
if (clientDir) {
|
|
2628
2286
|
app.use("/*", serveStatic({ root: clientDir }));
|
|
2629
2287
|
}
|
|
@@ -2636,11 +2294,12 @@ function createServer(options) {
|
|
|
2636
2294
|
const wsMod = await import("ws");
|
|
2637
2295
|
const wss = new wsMod.WebSocketServer({ noServer: true });
|
|
2638
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)" : ""}`);
|
|
2639
2300
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
2640
|
-
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2641
2301
|
wintercServer.handleWebSocket(ws, {
|
|
2642
|
-
skipGreeting:
|
|
2643
|
-
uid: reqUrl.searchParams.get("uid") ?? void 0
|
|
2302
|
+
skipGreeting: resume
|
|
2644
2303
|
});
|
|
2645
2304
|
});
|
|
2646
2305
|
});
|
|
@@ -2665,88 +2324,30 @@ var init_server = __esm({
|
|
|
2665
2324
|
"sdk/server.ts"() {
|
|
2666
2325
|
"use strict";
|
|
2667
2326
|
init_runtime();
|
|
2327
|
+
init_s2s();
|
|
2668
2328
|
init_winterc_server();
|
|
2669
2329
|
}
|
|
2670
2330
|
});
|
|
2671
2331
|
|
|
2672
|
-
// cli/cli.ts
|
|
2673
|
-
init_help();
|
|
2674
|
-
import { readFileSync } from "node:fs";
|
|
2675
|
-
import path11 from "node:path";
|
|
2676
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2677
|
-
import minimist8 from "minimist";
|
|
2678
|
-
|
|
2679
|
-
// cli/build.tsx
|
|
2680
|
-
init_build();
|
|
2681
|
-
init_discover();
|
|
2682
|
-
init_help();
|
|
2683
|
-
init_ink();
|
|
2684
|
-
init_init2();
|
|
2685
|
-
import path6 from "node:path";
|
|
2686
|
-
import minimist3 from "minimist";
|
|
2687
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2688
|
-
var buildCommandDef = {
|
|
2689
|
-
name: "build",
|
|
2690
|
-
description: "Bundle agent and client (validates code without deploying or starting a server)",
|
|
2691
|
-
options: [{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }]
|
|
2692
|
-
};
|
|
2693
|
-
async function runBuildCommand(args, version) {
|
|
2694
|
-
const parsed = minimist3(args, {
|
|
2695
|
-
boolean: ["help", "yes"],
|
|
2696
|
-
alias: { h: "help", y: "yes" }
|
|
2697
|
-
});
|
|
2698
|
-
if (parsed.help) {
|
|
2699
|
-
console.log(subcommandHelp(buildCommandDef, version));
|
|
2700
|
-
return;
|
|
2701
|
-
}
|
|
2702
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
2703
|
-
if (!await fileExists(path6.join(cwd, "agent.ts"))) {
|
|
2704
|
-
await runInitCommand(parsed.yes ? ["-y"] : [], version, { quiet: true });
|
|
2705
|
-
}
|
|
2706
|
-
await runWithInk(async (log) => {
|
|
2707
|
-
await buildAgentBundle(cwd, log);
|
|
2708
|
-
log(/* @__PURE__ */ jsx5(Step, { action: "Build", msg: "ok" }));
|
|
2709
|
-
});
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
// cli/cli.ts
|
|
2713
|
-
init_deploy2();
|
|
2714
|
-
|
|
2715
|
-
// cli/dev.tsx
|
|
2716
|
-
import path8 from "node:path";
|
|
2717
|
-
import minimist4 from "minimist";
|
|
2718
|
-
|
|
2719
|
-
// cli/_dev.ts
|
|
2720
|
-
init_build();
|
|
2721
|
-
init_ink();
|
|
2722
|
-
import React3 from "react";
|
|
2723
|
-
|
|
2724
2332
|
// cli/_server_common.ts
|
|
2725
|
-
init_discover();
|
|
2726
2333
|
import fs5 from "node:fs/promises";
|
|
2727
|
-
import
|
|
2728
|
-
import {
|
|
2334
|
+
import path5 from "node:path";
|
|
2335
|
+
import { tsImport } from "tsx/esm/api";
|
|
2729
2336
|
async function loadAgentDef(cwd) {
|
|
2730
|
-
const agentPath =
|
|
2731
|
-
const
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
const agentDef = agentModule.default;
|
|
2739
|
-
if (!agentDef || typeof agentDef !== "object" || !agentDef.name) {
|
|
2740
|
-
throw new Error("agent.ts must export a default agent definition (from defineAgent())");
|
|
2741
|
-
}
|
|
2742
|
-
return agentDef;
|
|
2743
|
-
} finally {
|
|
2744
|
-
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())");
|
|
2745
2345
|
}
|
|
2346
|
+
return agentDef;
|
|
2746
2347
|
}
|
|
2747
|
-
async function resolveServerEnv() {
|
|
2348
|
+
async function resolveServerEnv(baseEnv) {
|
|
2748
2349
|
const env = Object.fromEntries(
|
|
2749
|
-
Object.entries(process.env).filter((e) => e[1] !== void 0)
|
|
2350
|
+
Object.entries(baseEnv ?? process.env).filter((e) => e[1] !== void 0)
|
|
2750
2351
|
);
|
|
2751
2352
|
if (!env.ASSEMBLYAI_API_KEY) {
|
|
2752
2353
|
env.ASSEMBLYAI_API_KEY = await getApiKey();
|
|
@@ -2754,10 +2355,11 @@ async function resolveServerEnv() {
|
|
|
2754
2355
|
return env;
|
|
2755
2356
|
}
|
|
2756
2357
|
async function bootServer(agentDef, clientDir, env, port) {
|
|
2358
|
+
const { wrapOnStyleWebSocket: wrapOnStyleWebSocket2 } = await Promise.resolve().then(() => (init_s2s(), s2s_exports));
|
|
2757
2359
|
const wsMod = await import("ws");
|
|
2758
2360
|
const WS = wsMod.default ?? wsMod;
|
|
2759
|
-
const createWebSocket = (url, opts) => new WS(url, { headers: opts.headers });
|
|
2760
|
-
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");
|
|
2761
2363
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
2762
2364
|
const server = createServer2({
|
|
2763
2365
|
agent: agentDef,
|
|
@@ -2768,155 +2370,186 @@ async function bootServer(agentDef, clientDir, env, port) {
|
|
|
2768
2370
|
});
|
|
2769
2371
|
await server.listen(port);
|
|
2770
2372
|
}
|
|
2373
|
+
var init_server_common = __esm({
|
|
2374
|
+
"cli/_server_common.ts"() {
|
|
2375
|
+
"use strict";
|
|
2376
|
+
init_discover();
|
|
2377
|
+
}
|
|
2378
|
+
});
|
|
2771
2379
|
|
|
2772
|
-
// 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";
|
|
2773
2387
|
async function _startDevServer(cwd, port, log) {
|
|
2774
2388
|
const bundle = await buildAgentBundle(cwd, log, { skipRenderCheck: true });
|
|
2775
2389
|
const agentDef = await loadAgentDef(cwd);
|
|
2776
2390
|
const env = await resolveServerEnv();
|
|
2777
2391
|
await bootServer(agentDef, bundle.clientDir, env, port);
|
|
2778
|
-
log(
|
|
2392
|
+
log(/* @__PURE__ */ jsx6(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
2779
2393
|
}
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
init_ink();
|
|
2785
|
-
init_init2();
|
|
2786
|
-
var devCommandDef = {
|
|
2787
|
-
name: "dev",
|
|
2788
|
-
description: "Start a local development server",
|
|
2789
|
-
options: [
|
|
2790
|
-
{
|
|
2791
|
-
flags: "-p, --port <number>",
|
|
2792
|
-
description: "Port to listen on (default: 3000)"
|
|
2793
|
-
},
|
|
2794
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
2795
|
-
]
|
|
2796
|
-
};
|
|
2797
|
-
async function runDevCommand(args, version) {
|
|
2798
|
-
const parsed = minimist4(args, {
|
|
2799
|
-
string: ["port"],
|
|
2800
|
-
boolean: ["help", "yes"],
|
|
2801
|
-
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);
|
|
2802
2398
|
});
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2399
|
+
}
|
|
2400
|
+
var init_dev = __esm({
|
|
2401
|
+
"cli/dev.tsx"() {
|
|
2402
|
+
"use strict";
|
|
2403
|
+
init_build();
|
|
2404
|
+
init_ink();
|
|
2405
|
+
init_server_common();
|
|
2806
2406
|
}
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
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");
|
|
2811
2430
|
}
|
|
2812
|
-
await
|
|
2813
|
-
|
|
2814
|
-
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);
|
|
2815
2434
|
});
|
|
2816
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
|
+
});
|
|
2817
2444
|
|
|
2818
|
-
// cli/
|
|
2819
|
-
|
|
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
|
+
});
|
|
2820
2504
|
|
|
2821
2505
|
// cli/rag.tsx
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
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";
|
|
2827
2517
|
import pLimit from "p-limit";
|
|
2828
|
-
import {
|
|
2829
|
-
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2830
|
-
var ragCommandDef = {
|
|
2831
|
-
name: "rag",
|
|
2832
|
-
description: "Ingest a site's llms-full.txt into the vector store",
|
|
2833
|
-
args: [{ name: "url" }],
|
|
2834
|
-
options: [
|
|
2835
|
-
{ flags: "-s, --server <url>", description: "Server URL" },
|
|
2836
|
-
{
|
|
2837
|
-
flags: "--chunk-size <n>",
|
|
2838
|
-
description: "Max chunk size in tokens (default: 512)"
|
|
2839
|
-
},
|
|
2840
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
2841
|
-
]
|
|
2842
|
-
};
|
|
2843
|
-
var FETCH_TIMEOUT_MS = 6e4;
|
|
2844
|
-
var PAD = 2;
|
|
2845
|
-
function RagUI({ url, apiKey, serverUrl, slug, chunkSize, onError }) {
|
|
2846
|
-
const { exit } = useApp2();
|
|
2847
|
-
const { items, log } = useStepLog();
|
|
2848
|
-
const [progress, setProgress] = useState2(null);
|
|
2849
|
-
const [err, setErr] = useState2(null);
|
|
2850
|
-
useEffect(() => {
|
|
2851
|
-
(async () => {
|
|
2852
|
-
try {
|
|
2853
|
-
await runRag({
|
|
2854
|
-
url,
|
|
2855
|
-
apiKey,
|
|
2856
|
-
serverUrl,
|
|
2857
|
-
slug,
|
|
2858
|
-
chunkSize,
|
|
2859
|
-
log,
|
|
2860
|
-
setProgress
|
|
2861
|
-
});
|
|
2862
|
-
} catch (e) {
|
|
2863
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
2864
|
-
setErr(error.message);
|
|
2865
|
-
onError?.(error);
|
|
2866
|
-
}
|
|
2867
|
-
setProgress(null);
|
|
2868
|
-
exit();
|
|
2869
|
-
})();
|
|
2870
|
-
}, [apiKey, chunkSize, exit, log, onError, serverUrl, slug, url]);
|
|
2871
|
-
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
2872
|
-
/* @__PURE__ */ jsx6(StepLog, { items }),
|
|
2873
|
-
err && /* @__PURE__ */ jsx6(ErrorLine, { msg: err }),
|
|
2874
|
-
progress && /* @__PURE__ */ jsxs3(Text3, { children: [
|
|
2875
|
-
" ".repeat(PAD + 1),
|
|
2876
|
-
"Upsert ",
|
|
2877
|
-
progress.completed,
|
|
2878
|
-
"/",
|
|
2879
|
-
progress.total,
|
|
2880
|
-
" (",
|
|
2881
|
-
Math.round(progress.completed / progress.total * 100),
|
|
2882
|
-
"%)"
|
|
2883
|
-
] })
|
|
2884
|
-
] });
|
|
2885
|
-
}
|
|
2518
|
+
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2886
2519
|
async function runRag(opts) {
|
|
2887
|
-
const { url, apiKey, serverUrl, slug, chunkSize, log,
|
|
2888
|
-
log(/* @__PURE__ */
|
|
2520
|
+
const { url, apiKey, serverUrl, slug, chunkSize, log, setStatus } = opts;
|
|
2521
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Fetch", msg: url }));
|
|
2889
2522
|
const resp = await fetch(url, {
|
|
2890
2523
|
headers: { "User-Agent": "aai-cli/1.0" },
|
|
2891
2524
|
redirect: "follow",
|
|
2892
|
-
signal: AbortSignal.timeout(
|
|
2525
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
2893
2526
|
});
|
|
2894
2527
|
if (!resp.ok) {
|
|
2895
2528
|
throw new Error(`Failed to fetch: ${resp.status} ${resp.statusText}`);
|
|
2896
2529
|
}
|
|
2897
2530
|
const content = await resp.text();
|
|
2898
2531
|
if (content.length === 0) {
|
|
2899
|
-
log(/* @__PURE__ */
|
|
2532
|
+
log(/* @__PURE__ */ jsx9(Warn, { msg: "File is empty" }));
|
|
2900
2533
|
return;
|
|
2901
2534
|
}
|
|
2902
|
-
log(/* @__PURE__ */
|
|
2535
|
+
log(/* @__PURE__ */ jsx9(Info, { msg: `${(content.length / 1024).toFixed(0)} KB` }));
|
|
2903
2536
|
const origin = new URL(url).origin;
|
|
2904
2537
|
const pages = splitPages(content);
|
|
2905
|
-
log(/* @__PURE__ */
|
|
2538
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Parse", msg: `${pages.length} pages` }));
|
|
2906
2539
|
const { RecursiveChunker } = await import("@chonkiejs/core");
|
|
2907
2540
|
const chunker = await RecursiveChunker.create({ chunkSize });
|
|
2908
2541
|
const siteSlug = slugify(origin);
|
|
2909
2542
|
const allChunks = await chunkPages(pages, chunker, origin, siteSlug);
|
|
2910
|
-
log(/* @__PURE__ */
|
|
2543
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Chunk", msg: `${allChunks.length} chunks` }));
|
|
2911
2544
|
const vectorUrl = `${serverUrl}/${slug}/vector`;
|
|
2912
|
-
log(/* @__PURE__ */
|
|
2913
|
-
const result = await upsertChunks(allChunks, vectorUrl, apiKey,
|
|
2914
|
-
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` }));
|
|
2915
2548
|
if (result.errors > 0) {
|
|
2916
|
-
log(/* @__PURE__ */
|
|
2917
|
-
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}` }));
|
|
2918
2551
|
}
|
|
2919
|
-
log(/* @__PURE__ */
|
|
2552
|
+
log(/* @__PURE__ */ jsx9(Detail, { msg: `Agent: ${slug}` }));
|
|
2920
2553
|
}
|
|
2921
2554
|
async function chunkPages(pages, chunker, origin, siteSlug) {
|
|
2922
2555
|
const allChunks = [];
|
|
@@ -2942,19 +2575,34 @@ ${c.text}` : c.text;
|
|
|
2942
2575
|
}
|
|
2943
2576
|
return allChunks;
|
|
2944
2577
|
}
|
|
2945
|
-
async function upsertChunks(chunks, vectorUrl, apiKey,
|
|
2578
|
+
async function upsertChunks(chunks, vectorUrl, apiKey, setStatus, fetchFn = globalThis.fetch) {
|
|
2946
2579
|
const total = chunks.length;
|
|
2947
2580
|
let completed = 0;
|
|
2948
2581
|
let upserted = 0;
|
|
2949
2582
|
let errors = 0;
|
|
2950
2583
|
let lastError = "";
|
|
2951
|
-
|
|
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();
|
|
2952
2600
|
const limit = pLimit(5);
|
|
2953
2601
|
await Promise.all(
|
|
2954
2602
|
chunks.map(
|
|
2955
2603
|
(chunk) => limit(async () => {
|
|
2956
2604
|
try {
|
|
2957
|
-
const r = await
|
|
2605
|
+
const r = await fetchFn(vectorUrl, {
|
|
2958
2606
|
method: "POST",
|
|
2959
2607
|
headers: {
|
|
2960
2608
|
"Content-Type": "application/json",
|
|
@@ -2974,65 +2622,29 @@ async function upsertChunks(chunks, vectorUrl, apiKey, setProgress) {
|
|
|
2974
2622
|
upserted++;
|
|
2975
2623
|
}
|
|
2976
2624
|
} catch (err) {
|
|
2977
|
-
lastError =
|
|
2625
|
+
lastError = errorMessage(err);
|
|
2978
2626
|
errors++;
|
|
2979
2627
|
}
|
|
2980
2628
|
completed++;
|
|
2981
|
-
|
|
2629
|
+
updateStatus();
|
|
2982
2630
|
})
|
|
2983
2631
|
)
|
|
2984
2632
|
);
|
|
2633
|
+
setStatus(null);
|
|
2985
2634
|
return { upserted, errors, lastError };
|
|
2986
2635
|
}
|
|
2987
|
-
async function runRagCommand(
|
|
2988
|
-
const
|
|
2989
|
-
string: ["server", "chunk-size"],
|
|
2990
|
-
boolean: ["help", "yes"],
|
|
2991
|
-
alias: { s: "server", h: "help", y: "yes" },
|
|
2992
|
-
stopEarly: true
|
|
2993
|
-
});
|
|
2994
|
-
if (parsed.help) {
|
|
2995
|
-
console.log(subcommandHelp(ragCommandDef, version));
|
|
2996
|
-
return;
|
|
2997
|
-
}
|
|
2998
|
-
const url = String(parsed._[0] ?? "");
|
|
2999
|
-
if (!url) {
|
|
3000
|
-
throw new Error(
|
|
3001
|
-
"Usage: aai rag <url>\n\nProvide the full URL to a site's llms-full.txt file"
|
|
3002
|
-
);
|
|
3003
|
-
}
|
|
2636
|
+
async function runRagCommand(opts) {
|
|
2637
|
+
const { url, cwd } = opts;
|
|
3004
2638
|
try {
|
|
3005
2639
|
new URL(url);
|
|
3006
2640
|
} catch {
|
|
3007
2641
|
throw new Error(`Invalid URL: ${url}`);
|
|
3008
2642
|
}
|
|
3009
|
-
const
|
|
3010
|
-
const
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
}
|
|
3014
|
-
const apiKey = await getApiKey();
|
|
3015
|
-
const serverUrl = parsed.server || config.serverUrl || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
3016
|
-
const slug = config.slug;
|
|
3017
|
-
const chunkSize = Number.parseInt(parsed["chunk-size"] ?? "512", 10);
|
|
3018
|
-
let thrownError;
|
|
3019
|
-
const app = render3(
|
|
3020
|
-
/* @__PURE__ */ jsx6(
|
|
3021
|
-
RagUI,
|
|
3022
|
-
{
|
|
3023
|
-
url,
|
|
3024
|
-
apiKey,
|
|
3025
|
-
serverUrl,
|
|
3026
|
-
slug,
|
|
3027
|
-
chunkSize,
|
|
3028
|
-
onError: (e) => {
|
|
3029
|
-
thrownError = e;
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
)
|
|
3033
|
-
);
|
|
3034
|
-
await app.waitUntilExit();
|
|
3035
|
-
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
|
+
});
|
|
3036
2648
|
}
|
|
3037
2649
|
function splitPages(content) {
|
|
3038
2650
|
const raw = content.split(/^\*{3,}$/m);
|
|
@@ -3079,243 +2691,153 @@ function stripNoise(text) {
|
|
|
3079
2691
|
function slugify(s) {
|
|
3080
2692
|
return s.replace(/^https?:\/\//, "").replace(/^#+\s*/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase().slice(0, 80);
|
|
3081
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
|
+
});
|
|
3082
2704
|
|
|
3083
|
-
// cli/
|
|
2705
|
+
// cli/cli.ts
|
|
2706
|
+
init_utils();
|
|
3084
2707
|
init_discover();
|
|
3085
|
-
init_help();
|
|
3086
2708
|
init_ink();
|
|
3087
|
-
|
|
3088
|
-
import
|
|
3089
|
-
import {
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
}
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
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());
|
|
3111
2742
|
});
|
|
3112
|
-
if (parsed.help || parsed._.length === 0) {
|
|
3113
|
-
console.log(subcommandHelp(secretCommandDef, version));
|
|
3114
|
-
return;
|
|
3115
|
-
}
|
|
3116
|
-
const sub = String(parsed._[0]);
|
|
3117
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
3118
|
-
await getApiKey();
|
|
3119
|
-
let secretValue;
|
|
3120
|
-
if (sub === "put") {
|
|
3121
|
-
const name = String(parsed._[1] ?? "");
|
|
3122
|
-
if (!name) throw new Error("Usage: aai secret put <NAME>");
|
|
3123
|
-
secretValue = await askPassword(`Enter value for ${name}`);
|
|
3124
|
-
if (!secretValue) throw new Error("No value provided");
|
|
3125
|
-
}
|
|
3126
|
-
switch (sub) {
|
|
3127
|
-
case "put":
|
|
3128
|
-
await secretPut(cwd, String(parsed._[1] ?? ""), secretValue ?? "");
|
|
3129
|
-
break;
|
|
3130
|
-
case "delete":
|
|
3131
|
-
await secretDelete(cwd, String(parsed._[1] ?? ""));
|
|
3132
|
-
break;
|
|
3133
|
-
case "list":
|
|
3134
|
-
await secretList(cwd);
|
|
3135
|
-
break;
|
|
3136
|
-
default:
|
|
3137
|
-
throw new Error(`Unknown secret subcommand: ${sub}`);
|
|
3138
|
-
}
|
|
3139
|
-
}
|
|
3140
|
-
async function getServerInfo(cwd) {
|
|
3141
|
-
const config = await requireProjectConfig(cwd);
|
|
3142
|
-
const apiKey = await getApiKey();
|
|
3143
|
-
const serverUrl = config.serverUrl || DEFAULT_SERVER;
|
|
3144
|
-
const slug = config.slug;
|
|
3145
|
-
return { serverUrl, slug, apiKey };
|
|
3146
2743
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
const resp = await fetch(`${serverUrl}/${slug}/secret`, {
|
|
3151
|
-
method: "PUT",
|
|
3152
|
-
headers: {
|
|
3153
|
-
"Content-Type": "application/json",
|
|
3154
|
-
Authorization: `Bearer ${apiKey}`
|
|
3155
|
-
},
|
|
3156
|
-
body: JSON.stringify({ [name]: value })
|
|
3157
|
-
});
|
|
3158
|
-
if (!resp.ok) {
|
|
3159
|
-
const text = await resp.text();
|
|
3160
|
-
throw new Error(`Failed to set secret: ${text}`);
|
|
3161
|
-
}
|
|
3162
|
-
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);
|
|
3163
2747
|
});
|
|
3164
2748
|
}
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
|
|
3169
|
-
const resp = await fetch(`${serverUrl}/${slug}/secret/${name}`, {
|
|
3170
|
-
method: "DELETE",
|
|
3171
|
-
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3172
|
-
});
|
|
3173
|
-
if (!resp.ok) {
|
|
3174
|
-
const text = await resp.text();
|
|
3175
|
-
throw new Error(`Failed to delete secret: ${text}`);
|
|
3176
|
-
}
|
|
3177
|
-
log(/* @__PURE__ */ jsx7(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
|
|
2749
|
+
function withApiKey(cmd) {
|
|
2750
|
+
return cmd.hook("preAction", async () => {
|
|
2751
|
+
await getApiKey();
|
|
3178
2752
|
});
|
|
3179
2753
|
}
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
const text = await resp.text();
|
|
3188
|
-
throw new Error(`Failed to list secrets: ${text}`);
|
|
3189
|
-
}
|
|
3190
|
-
const { vars } = await resp.json();
|
|
3191
|
-
if (vars.length === 0) {
|
|
3192
|
-
log(/* @__PURE__ */ jsx7(StepInfo, { action: "Secrets", msg: "none set" }));
|
|
3193
|
-
} else {
|
|
3194
|
-
for (const name of vars) {
|
|
3195
|
-
log(/* @__PURE__ */ jsx7(Detail, { msg: name }));
|
|
3196
|
-
}
|
|
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 });
|
|
3197
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);
|
|
3198
2803
|
});
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
init_help();
|
|
3204
|
-
init_ink();
|
|
3205
|
-
import path10 from "node:path";
|
|
3206
|
-
import minimist7 from "minimist";
|
|
3207
|
-
|
|
3208
|
-
// cli/_start.ts
|
|
3209
|
-
init_ink();
|
|
3210
|
-
import path9 from "node:path";
|
|
3211
|
-
import React4 from "react";
|
|
3212
|
-
async function _startProductionServer(cwd, port, log) {
|
|
3213
|
-
const clientDir = path9.join(cwd, ".aai", "client");
|
|
3214
|
-
log(React4.createElement(Step, { action: "Start", msg: "loading agent" }));
|
|
3215
|
-
const agentDef = await loadAgentDef(cwd);
|
|
3216
|
-
const env = await resolveServerEnv();
|
|
3217
|
-
await bootServer(agentDef, clientDir, env, port);
|
|
3218
|
-
log(React4.createElement(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
3219
|
-
}
|
|
3220
|
-
|
|
3221
|
-
// cli/start.tsx
|
|
3222
|
-
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
3223
|
-
var startCommandDef = {
|
|
3224
|
-
name: "start",
|
|
3225
|
-
description: "Start the production server from a build",
|
|
3226
|
-
options: [
|
|
3227
|
-
{
|
|
3228
|
-
flags: "-p, --port <number>",
|
|
3229
|
-
description: "Port to listen on (default: 3000)"
|
|
3230
|
-
},
|
|
3231
|
-
{ flags: "-y, --yes", description: "Accept defaults (no prompts)" }
|
|
3232
|
-
]
|
|
3233
|
-
};
|
|
3234
|
-
async function runStartCommand(args, version) {
|
|
3235
|
-
const parsed = minimist7(args, {
|
|
3236
|
-
string: ["port"],
|
|
3237
|
-
boolean: ["help", "yes"],
|
|
3238
|
-
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);
|
|
3239
2808
|
});
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
const cwd = process.env.INIT_CWD || process.cwd();
|
|
3245
|
-
const port = Number.parseInt(parsed.port ?? "3000", 10);
|
|
3246
|
-
const buildDir = path10.join(cwd, ".aai", "build");
|
|
3247
|
-
if (!await fileExists(path10.join(buildDir, "worker.js"))) {
|
|
3248
|
-
throw new Error("No build found \u2014 run `aai build` first");
|
|
3249
|
-
}
|
|
3250
|
-
await getApiKey();
|
|
3251
|
-
await runWithInk(async (log) => {
|
|
3252
|
-
log(/* @__PURE__ */ jsx8(Step, { action: "Start", msg: `production server on port ${port}` }));
|
|
3253
|
-
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);
|
|
3254
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;
|
|
3255
2823
|
}
|
|
3256
|
-
|
|
3257
|
-
// cli/cli.ts
|
|
3258
|
-
var cliDir = path11.dirname(fileURLToPath2(import.meta.url));
|
|
3259
|
-
var pkgJsonPath = path11.join(cliDir, "..", "package.json");
|
|
3260
|
-
var pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
3261
|
-
var VERSION = pkgJson.version;
|
|
3262
2824
|
async function main(args) {
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
stopEarly: true
|
|
3267
|
-
});
|
|
3268
|
-
if (parsed.version) {
|
|
3269
|
-
console.log(VERSION);
|
|
2825
|
+
if (args.length === 0) {
|
|
2826
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2827
|
+
await runInitCommand2({});
|
|
3270
2828
|
return;
|
|
3271
2829
|
}
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
return;
|
|
3275
|
-
}
|
|
3276
|
-
const [subcommand, ...rest] = parsed._;
|
|
3277
|
-
const subArgs = rest.map(String);
|
|
3278
|
-
switch (subcommand) {
|
|
3279
|
-
case "init":
|
|
3280
|
-
await runInitCommand(subArgs, VERSION);
|
|
3281
|
-
return;
|
|
3282
|
-
case "build":
|
|
3283
|
-
await runBuildCommand(subArgs, VERSION);
|
|
3284
|
-
return;
|
|
3285
|
-
case "deploy":
|
|
3286
|
-
await runDeployCommand(subArgs, VERSION);
|
|
3287
|
-
return;
|
|
3288
|
-
case "dev":
|
|
3289
|
-
await runDevCommand(subArgs, VERSION);
|
|
3290
|
-
return;
|
|
3291
|
-
case "start":
|
|
3292
|
-
await runStartCommand(subArgs, VERSION);
|
|
3293
|
-
return;
|
|
3294
|
-
case "secret":
|
|
3295
|
-
await runSecretCommand(subArgs, VERSION);
|
|
3296
|
-
return;
|
|
3297
|
-
case "rag":
|
|
3298
|
-
await runRagCommand(subArgs, VERSION);
|
|
3299
|
-
return;
|
|
3300
|
-
case "help":
|
|
3301
|
-
console.log(rootHelp(VERSION));
|
|
3302
|
-
return;
|
|
3303
|
-
case void 0:
|
|
3304
|
-
await runInitCommand(subArgs, VERSION);
|
|
3305
|
-
return;
|
|
3306
|
-
default:
|
|
3307
|
-
console.error(`Unknown command: ${subcommand}`);
|
|
3308
|
-
console.log(rootHelp(VERSION));
|
|
3309
|
-
process.exit(1);
|
|
3310
|
-
}
|
|
2830
|
+
const program = createProgram();
|
|
2831
|
+
await program.parseAsync(args, { from: "user" });
|
|
3311
2832
|
}
|
|
3312
2833
|
if (process.env.VITEST !== "true") {
|
|
3313
2834
|
process.on("SIGINT", () => process.exit(0));
|
|
3314
2835
|
main(process.argv.slice(2)).catch((err) => {
|
|
3315
|
-
console.error(
|
|
2836
|
+
console.error(errorMessage(err));
|
|
3316
2837
|
process.exit(1);
|
|
3317
2838
|
});
|
|
3318
2839
|
}
|
|
3319
2840
|
export {
|
|
2841
|
+
createProgram,
|
|
3320
2842
|
main
|
|
3321
2843
|
};
|