@alexkroman1/aai 0.8.3 → 0.8.5
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 +1215 -1706
- 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,55 @@ 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
|
+
] }));
|
|
202
203
|
}
|
|
203
204
|
var init_prompts = __esm({
|
|
204
205
|
"cli/_prompts.tsx"() {
|
|
205
206
|
"use strict";
|
|
206
|
-
|
|
207
|
+
init_ink();
|
|
207
208
|
}
|
|
208
209
|
});
|
|
209
210
|
|
|
210
211
|
// 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
212
|
import fs from "node:fs/promises";
|
|
224
213
|
import path from "node:path";
|
|
225
214
|
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;
|
|
215
|
+
function resolveCwd() {
|
|
216
|
+
return process.env.INIT_CWD || process.cwd();
|
|
217
|
+
}
|
|
218
|
+
function isDevMode(script) {
|
|
219
|
+
script ??= process.argv[1] ?? "";
|
|
220
|
+
return script.endsWith(".ts") || script.endsWith(".tsx");
|
|
240
221
|
}
|
|
241
222
|
function generateSlug() {
|
|
242
223
|
return humanId({ separator: "-", capitalize: false });
|
|
@@ -284,6 +265,18 @@ async function writeProjectConfig(agentDir, data) {
|
|
|
284
265
|
await fs.writeFile(path.join(aaiDir, "project.json"), `${JSON.stringify(data, null, 2)}
|
|
285
266
|
`);
|
|
286
267
|
}
|
|
268
|
+
async function getServerInfo(cwd, explicitServer, explicitApiKey) {
|
|
269
|
+
const config = await readProjectConfig(cwd);
|
|
270
|
+
if (!config) {
|
|
271
|
+
throw new Error("No .aai/project.json found \u2014 deploy first with `aai deploy`");
|
|
272
|
+
}
|
|
273
|
+
const apiKey = explicitApiKey ?? await getApiKey();
|
|
274
|
+
const serverUrl = resolveServerUrl(explicitServer, config.serverUrl);
|
|
275
|
+
return { serverUrl, slug: config.slug, apiKey };
|
|
276
|
+
}
|
|
277
|
+
function resolveServerUrl(explicit, configUrl) {
|
|
278
|
+
return explicit || configUrl || (isDevMode() ? "http://localhost:3100" : DEFAULT_SERVER);
|
|
279
|
+
}
|
|
287
280
|
async function fileExists(p) {
|
|
288
281
|
try {
|
|
289
282
|
await fs.access(p);
|
|
@@ -316,90 +309,173 @@ var init_discover = __esm({
|
|
|
316
309
|
}
|
|
317
310
|
});
|
|
318
311
|
|
|
319
|
-
// cli/
|
|
312
|
+
// cli/_init.ts
|
|
313
|
+
var init_exports = {};
|
|
314
|
+
__export(init_exports, {
|
|
315
|
+
listTemplates: () => listTemplates,
|
|
316
|
+
runInit: () => runInit
|
|
317
|
+
});
|
|
320
318
|
import fs2 from "node:fs/promises";
|
|
321
319
|
import path2 from "node:path";
|
|
320
|
+
async function listTemplates(dir) {
|
|
321
|
+
const templates = [];
|
|
322
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
323
|
+
for (const entry of entries) {
|
|
324
|
+
if (entry.isDirectory() && !entry.name.startsWith("_")) {
|
|
325
|
+
templates.push(entry.name);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return templates.sort();
|
|
329
|
+
}
|
|
330
|
+
async function copyDirNoOverwrite(src, dest) {
|
|
331
|
+
const entries = await fs2.readdir(src, { recursive: true, withFileTypes: true });
|
|
332
|
+
for (const entry of entries) {
|
|
333
|
+
if (!entry.isFile()) continue;
|
|
334
|
+
const rel = path2.relative(src, path2.join(entry.parentPath, entry.name));
|
|
335
|
+
const destPath = path2.join(dest, rel);
|
|
336
|
+
await fs2.mkdir(path2.dirname(destPath), { recursive: true });
|
|
337
|
+
try {
|
|
338
|
+
await fs2.copyFile(path2.join(src, rel), destPath, fs2.constants.COPYFILE_EXCL);
|
|
339
|
+
} catch (err) {
|
|
340
|
+
if (err.code !== "EEXIST") throw err;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async function runInit(opts) {
|
|
345
|
+
const { targetDir, template, templatesDir } = opts;
|
|
346
|
+
const available = await listTemplates(templatesDir);
|
|
347
|
+
if (!available.includes(template)) {
|
|
348
|
+
throw new Error(`unknown template '${template}' -- available: ${available.join(", ")}`);
|
|
349
|
+
}
|
|
350
|
+
await fs2.cp(path2.join(templatesDir, template), targetDir, { recursive: true, force: true });
|
|
351
|
+
await copyDirNoOverwrite(path2.join(templatesDir, "_shared"), targetDir);
|
|
352
|
+
try {
|
|
353
|
+
await fs2.copyFile(path2.join(targetDir, ".env.example"), path2.join(targetDir, ".env"));
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
356
|
+
const readmePath = path2.join(targetDir, "README.md");
|
|
357
|
+
const slug = path2.basename(path2.resolve(targetDir));
|
|
358
|
+
const readme = `# ${slug}
|
|
359
|
+
|
|
360
|
+
A voice agent built with [aai](https://github.com/anthropics/aai).
|
|
361
|
+
|
|
362
|
+
## Getting started
|
|
363
|
+
|
|
364
|
+
\`\`\`sh
|
|
365
|
+
npm install # Install dependencies
|
|
366
|
+
npm run dev # Run locally (opens browser)
|
|
367
|
+
npm run deploy # Deploy to production
|
|
368
|
+
\`\`\`
|
|
369
|
+
|
|
370
|
+
## Environment variables
|
|
371
|
+
|
|
372
|
+
Secrets are managed on the server, not in local files:
|
|
373
|
+
|
|
374
|
+
\`\`\`sh
|
|
375
|
+
aai env add MY_KEY # Set a secret (prompts for value)
|
|
376
|
+
aai env ls # List secret names
|
|
377
|
+
aai env pull # Pull names into .env for reference
|
|
378
|
+
aai env rm MY_KEY # Remove a secret
|
|
379
|
+
\`\`\`
|
|
380
|
+
|
|
381
|
+
Access secrets in your agent via \`ctx.env.MY_KEY\`.
|
|
382
|
+
|
|
383
|
+
## Learn more
|
|
384
|
+
|
|
385
|
+
See \`CLAUDE.md\` for the full agent API reference.
|
|
386
|
+
`;
|
|
387
|
+
try {
|
|
388
|
+
await fs2.writeFile(readmePath, readme, { flag: "wx" });
|
|
389
|
+
} catch (err) {
|
|
390
|
+
if (err.code !== "EEXIST") throw err;
|
|
391
|
+
}
|
|
392
|
+
return targetDir;
|
|
393
|
+
}
|
|
394
|
+
var init_init = __esm({
|
|
395
|
+
"cli/_init.ts"() {
|
|
396
|
+
"use strict";
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// cli/_bundler.ts
|
|
401
|
+
import fs3 from "node:fs/promises";
|
|
402
|
+
import path3 from "node:path";
|
|
322
403
|
import preact from "@preact/preset-vite";
|
|
323
404
|
import tailwindcss from "@tailwindcss/vite";
|
|
324
405
|
import { build } from "vite";
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
406
|
+
function workerEntryPlugin() {
|
|
407
|
+
const virtualId = "virtual:worker-entry";
|
|
408
|
+
const resolvedId = `\0${virtualId}`;
|
|
409
|
+
return {
|
|
410
|
+
name: "aai-worker-entry",
|
|
411
|
+
resolveId(source) {
|
|
412
|
+
return source === virtualId ? resolvedId : null;
|
|
413
|
+
},
|
|
414
|
+
load(id) {
|
|
415
|
+
if (id !== resolvedId) return null;
|
|
416
|
+
return [
|
|
417
|
+
`import agent from "./agent.ts";`,
|
|
418
|
+
`import { initWorker } from "@alexkroman1/aai/worker-shim";`,
|
|
419
|
+
`initWorker(agent);`
|
|
420
|
+
].join("\n");
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
async function readDirFiles(dir) {
|
|
425
|
+
let entries;
|
|
328
426
|
try {
|
|
329
|
-
|
|
427
|
+
entries = await fs3.readdir(dir, { recursive: true, withFileTypes: true });
|
|
330
428
|
} 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
|
-
}
|
|
429
|
+
return {};
|
|
343
430
|
}
|
|
431
|
+
const files = {};
|
|
432
|
+
await Promise.all(
|
|
433
|
+
entries.filter((e) => e.isFile()).map(async (e) => {
|
|
434
|
+
const full = path3.join(e.parentPath, e.name);
|
|
435
|
+
files[path3.relative(dir, full)] = await fs3.readFile(full, "utf-8");
|
|
436
|
+
})
|
|
437
|
+
);
|
|
344
438
|
return files;
|
|
345
439
|
}
|
|
346
440
|
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
|
-
);
|
|
441
|
+
const aaiDir = path3.join(agent.dir, ".aai");
|
|
442
|
+
const buildDir = path3.join(aaiDir, "build");
|
|
443
|
+
const clientDir = path3.join(aaiDir, "client");
|
|
444
|
+
const devMode = isDevMode();
|
|
445
|
+
const devResolve = devMode ? { conditions: ["source"] } : {};
|
|
360
446
|
try {
|
|
361
447
|
await build({
|
|
362
448
|
configFile: false,
|
|
363
449
|
root: agent.dir,
|
|
364
450
|
logLevel: "warn",
|
|
451
|
+
plugins: [workerEntryPlugin()],
|
|
452
|
+
resolve: devResolve,
|
|
365
453
|
build: {
|
|
454
|
+
rollupOptions: {
|
|
455
|
+
input: "virtual:worker-entry",
|
|
456
|
+
output: { format: "es", entryFileNames: "worker.js" }
|
|
457
|
+
},
|
|
366
458
|
outDir: buildDir,
|
|
367
459
|
emptyOutDir: true,
|
|
368
460
|
minify: true,
|
|
369
|
-
target: "es2022"
|
|
370
|
-
rollupOptions: {
|
|
371
|
-
input: workerEntry,
|
|
372
|
-
output: {
|
|
373
|
-
format: "es",
|
|
374
|
-
entryFileNames: "worker.js",
|
|
375
|
-
inlineDynamicImports: true
|
|
376
|
-
}
|
|
377
|
-
}
|
|
461
|
+
target: "es2022"
|
|
378
462
|
}
|
|
379
463
|
});
|
|
380
464
|
} catch (err) {
|
|
381
|
-
throw new BundleError(
|
|
465
|
+
throw new BundleError(errorMessage(err));
|
|
382
466
|
}
|
|
383
467
|
const skipClient = opts?.skipClient || !agent.clientEntry;
|
|
384
468
|
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
469
|
try {
|
|
397
470
|
await build({
|
|
398
471
|
root: agent.dir,
|
|
399
472
|
base: "./",
|
|
400
473
|
logLevel: "warn",
|
|
401
474
|
plugins: [preact(), tailwindcss()],
|
|
402
|
-
|
|
475
|
+
resolve: {
|
|
476
|
+
...devResolve,
|
|
477
|
+
...devMode && { dedupe: ["preact", "@preact/signals"] }
|
|
478
|
+
},
|
|
403
479
|
build: {
|
|
404
480
|
outDir: clientDir,
|
|
405
481
|
emptyOutDir: true,
|
|
@@ -408,11 +484,11 @@ async function bundleAgent(agent, opts) {
|
|
|
408
484
|
}
|
|
409
485
|
});
|
|
410
486
|
} catch (err) {
|
|
411
|
-
throw new BundleError(
|
|
487
|
+
throw new BundleError(errorMessage(err));
|
|
412
488
|
}
|
|
413
489
|
}
|
|
414
|
-
const worker = await
|
|
415
|
-
const clientFiles = await
|
|
490
|
+
const worker = await fs3.readFile(path3.join(buildDir, "worker.js"), "utf-8");
|
|
491
|
+
const clientFiles = await readDirFiles(clientDir);
|
|
416
492
|
return {
|
|
417
493
|
worker,
|
|
418
494
|
clientFiles,
|
|
@@ -424,6 +500,7 @@ var BundleError;
|
|
|
424
500
|
var init_bundler = __esm({
|
|
425
501
|
"cli/_bundler.ts"() {
|
|
426
502
|
"use strict";
|
|
503
|
+
init_utils();
|
|
427
504
|
init_discover();
|
|
428
505
|
BundleError = class extends Error {
|
|
429
506
|
constructor(message) {
|
|
@@ -434,280 +511,68 @@ var init_bundler = __esm({
|
|
|
434
511
|
}
|
|
435
512
|
});
|
|
436
513
|
|
|
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
|
-
}
|
|
514
|
+
// cli/_build.tsx
|
|
515
|
+
var build_exports = {};
|
|
516
|
+
__export(build_exports, {
|
|
517
|
+
buildAgentBundle: () => buildAgentBundle,
|
|
518
|
+
runBuildCommand: () => runBuildCommand
|
|
571
519
|
});
|
|
572
|
-
|
|
573
|
-
// cli/_build.ts
|
|
574
|
-
import React2 from "react";
|
|
520
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
575
521
|
async function buildAgentBundle(cwd, log, opts) {
|
|
576
522
|
const agent = await loadAgent(cwd);
|
|
577
523
|
if (!agent) {
|
|
578
524
|
throw new Error("No agent found \u2014 run `aai init` first");
|
|
579
525
|
}
|
|
580
|
-
log(
|
|
526
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Bundle", msg: agent.slug }));
|
|
581
527
|
let bundle;
|
|
582
528
|
try {
|
|
583
529
|
bundle = await bundleAgent(agent);
|
|
584
530
|
} catch (err) {
|
|
585
531
|
if (err instanceof BundleError) {
|
|
586
532
|
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);
|
|
533
|
+
}
|
|
534
|
+
throw err;
|
|
698
535
|
}
|
|
699
|
-
|
|
536
|
+
const kb = (bundle.workerBytes / 1024).toFixed(1);
|
|
537
|
+
const clientCount = Object.keys(bundle.clientFiles).length;
|
|
538
|
+
log(/* @__PURE__ */ jsx3(Info, { msg: `worker: ${kb} KB, client: ${clientCount} file(s)` }));
|
|
539
|
+
if (agent.clientEntry && !opts?.skipRenderCheck) {
|
|
540
|
+
const renderCheckPath = "../sdk/_render_check.ts";
|
|
541
|
+
const mod = await import(
|
|
542
|
+
/* @vite-ignore */
|
|
543
|
+
renderCheckPath
|
|
544
|
+
).catch(() => null);
|
|
545
|
+
if (mod) {
|
|
546
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Render", msg: "check" }));
|
|
547
|
+
try {
|
|
548
|
+
await mod.renderCheck(agent.clientEntry, cwd);
|
|
549
|
+
} catch (err) {
|
|
550
|
+
throw new Error(`Render check failed: ${errorMessage(err)}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return bundle;
|
|
700
555
|
}
|
|
701
|
-
|
|
702
|
-
|
|
556
|
+
async function runBuildCommand(cwd) {
|
|
557
|
+
await runWithInk(async ({ log }) => {
|
|
558
|
+
await buildAgentBundle(cwd, log);
|
|
559
|
+
log(/* @__PURE__ */ jsx3(Step, { action: "Build", msg: "ok" }));
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
var init_build = __esm({
|
|
563
|
+
"cli/_build.tsx"() {
|
|
703
564
|
"use strict";
|
|
565
|
+
init_utils();
|
|
566
|
+
init_bundler();
|
|
567
|
+
init_discover();
|
|
568
|
+
init_ink();
|
|
704
569
|
}
|
|
705
570
|
});
|
|
706
571
|
|
|
707
572
|
// cli/_deploy.ts
|
|
708
|
-
async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
573
|
+
async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
|
|
709
574
|
try {
|
|
710
|
-
return await
|
|
575
|
+
return await fetchFn(`${url}/${slug}/deploy`, {
|
|
711
576
|
method: "POST",
|
|
712
577
|
headers: {
|
|
713
578
|
"Content-Type": "application/json",
|
|
@@ -724,37 +589,36 @@ async function attemptDeploy(url, slug, apiKey, env, worker, clientFiles) {
|
|
|
724
589
|
}
|
|
725
590
|
}
|
|
726
591
|
async function runDeploy(opts) {
|
|
727
|
-
const worker = opts.bundle
|
|
728
|
-
const
|
|
592
|
+
const { worker, clientFiles } = opts.bundle;
|
|
593
|
+
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
729
594
|
let slug = opts.slug;
|
|
730
|
-
if (opts.dryRun) {
|
|
731
|
-
return { slug };
|
|
732
|
-
}
|
|
733
595
|
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
734
|
-
const resp = await attemptDeploy(
|
|
596
|
+
const resp = await attemptDeploy(
|
|
597
|
+
fetchFn,
|
|
598
|
+
opts.url,
|
|
599
|
+
slug,
|
|
600
|
+
opts.apiKey,
|
|
601
|
+
opts.env,
|
|
602
|
+
worker,
|
|
603
|
+
clientFiles
|
|
604
|
+
);
|
|
735
605
|
if (resp.ok) {
|
|
736
606
|
return { slug };
|
|
737
607
|
}
|
|
738
|
-
if (resp.status === 403) {
|
|
739
|
-
const text2 = await resp.text();
|
|
740
|
-
if (text2.includes("Slug")) {
|
|
741
|
-
slug = generateSlug();
|
|
742
|
-
continue;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
608
|
const text = await resp.text();
|
|
609
|
+
if (resp.status === 403 && text.includes("Slug")) {
|
|
610
|
+
slug = generateSlug();
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
746
613
|
throw new Error(`deploy failed (${resp.status}): ${text}`);
|
|
747
614
|
}
|
|
748
615
|
throw new Error(`deploy failed: could not find available slug after ${MAX_RETRIES} attempts`);
|
|
749
616
|
}
|
|
750
|
-
var
|
|
617
|
+
var MAX_RETRIES;
|
|
751
618
|
var init_deploy = __esm({
|
|
752
619
|
"cli/_deploy.ts"() {
|
|
753
620
|
"use strict";
|
|
754
621
|
init_discover();
|
|
755
|
-
_internals = {
|
|
756
|
-
fetch: globalThis.fetch.bind(globalThis)
|
|
757
|
-
};
|
|
758
622
|
MAX_RETRIES = 20;
|
|
759
623
|
}
|
|
760
624
|
});
|
|
@@ -764,103 +628,66 @@ var deploy_exports = {};
|
|
|
764
628
|
__export(deploy_exports, {
|
|
765
629
|
runDeployCommand: () => runDeployCommand
|
|
766
630
|
});
|
|
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
|
-
}
|
|
631
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
773
632
|
async function deployBundle(opts) {
|
|
774
633
|
const { bundle, serverUrl, apiKey, cwd, log } = opts;
|
|
775
634
|
let { slug } = opts;
|
|
776
|
-
log(/* @__PURE__ */
|
|
635
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Deploy", msg: slug }));
|
|
777
636
|
const deployed = await runDeploy({
|
|
778
637
|
url: serverUrl,
|
|
779
638
|
bundle,
|
|
780
639
|
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
781
640
|
slug,
|
|
782
|
-
dryRun: false,
|
|
783
641
|
apiKey
|
|
784
642
|
});
|
|
785
643
|
slug = deployed.slug;
|
|
786
644
|
await writeProjectConfig(cwd, { slug, serverUrl });
|
|
787
645
|
const agentUrl = `${serverUrl}/${slug}`;
|
|
788
|
-
log(/* @__PURE__ */
|
|
646
|
+
log(/* @__PURE__ */ jsx4(Step, { action: "Ready", msg: agentUrl }));
|
|
789
647
|
return agentUrl;
|
|
790
648
|
}
|
|
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;
|
|
649
|
+
async function runDeployCommand(opts) {
|
|
650
|
+
const { cwd } = opts;
|
|
651
|
+
const dryRun = opts.dryRun ?? false;
|
|
807
652
|
const apiKey = dryRun ? "" : await getApiKey();
|
|
808
653
|
const projectConfig = await readProjectConfig(cwd);
|
|
654
|
+
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
809
655
|
const slug = projectConfig?.slug ?? generateSlug();
|
|
810
|
-
|
|
811
|
-
await runWithInk(async (log) => {
|
|
656
|
+
await runWithInk(async ({ log }) => {
|
|
812
657
|
const bundle = await buildAgentBundle(cwd, log);
|
|
813
658
|
if (dryRun) {
|
|
814
|
-
log(/* @__PURE__ */
|
|
659
|
+
log(/* @__PURE__ */ jsx4(StepInfo, { action: "Dry run", msg: `would deploy as ${slug}` }));
|
|
815
660
|
return;
|
|
816
661
|
}
|
|
817
|
-
|
|
662
|
+
await deployBundle({ bundle, serverUrl, apiKey, slug, cwd, log });
|
|
818
663
|
});
|
|
819
|
-
if (agentUrl && !dryRun) {
|
|
820
|
-
await askEnter("Press enter to open in browser");
|
|
821
|
-
const { exec } = await import("node:child_process");
|
|
822
|
-
exec(`open "${agentUrl}"`);
|
|
823
|
-
}
|
|
824
664
|
}
|
|
825
|
-
var deployCommandDef;
|
|
826
665
|
var init_deploy2 = __esm({
|
|
827
666
|
"cli/deploy.tsx"() {
|
|
828
667
|
"use strict";
|
|
829
668
|
init_build();
|
|
830
669
|
init_deploy();
|
|
831
670
|
init_discover();
|
|
832
|
-
init_help();
|
|
833
671
|
init_ink();
|
|
834
|
-
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
672
|
}
|
|
849
673
|
});
|
|
850
674
|
|
|
851
675
|
// cli/init.tsx
|
|
676
|
+
var init_exports2 = {};
|
|
677
|
+
__export(init_exports2, {
|
|
678
|
+
runInitCommand: () => runInitCommand
|
|
679
|
+
});
|
|
852
680
|
import { execFile } from "node:child_process";
|
|
853
681
|
import fs4 from "node:fs/promises";
|
|
854
|
-
import
|
|
682
|
+
import path4 from "node:path";
|
|
855
683
|
import { fileURLToPath } from "node:url";
|
|
856
684
|
import { promisify } from "node:util";
|
|
857
|
-
import
|
|
858
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
685
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
859
686
|
async function rewriteDevDeps(cwd, cliDir2) {
|
|
860
|
-
const monorepoRoot =
|
|
861
|
-
const pkgJsonPath2 =
|
|
687
|
+
const monorepoRoot = path4.join(cliDir2, "..");
|
|
688
|
+
const pkgJsonPath2 = path4.join(cwd, "package.json");
|
|
862
689
|
const pkgJson2 = JSON.parse(await fs4.readFile(pkgJsonPath2, "utf-8"));
|
|
863
|
-
const rootPkg = JSON.parse(await fs4.readFile(
|
|
690
|
+
const rootPkg = JSON.parse(await fs4.readFile(path4.join(monorepoRoot, "package.json"), "utf-8"));
|
|
864
691
|
const rootPkgName = rootPkg.name;
|
|
865
692
|
if (pkgJson2.dependencies[rootPkgName]) {
|
|
866
693
|
pkgJson2.dependencies[rootPkgName] = `file:${monorepoRoot}`;
|
|
@@ -869,56 +696,45 @@ async function rewriteDevDeps(cwd, cliDir2) {
|
|
|
869
696
|
`);
|
|
870
697
|
}
|
|
871
698
|
async function installDeps(cwd, log) {
|
|
872
|
-
if (await fileExists(
|
|
699
|
+
if (await fileExists(path4.join(cwd, "node_modules"))) return;
|
|
873
700
|
let pkgJson2;
|
|
874
701
|
try {
|
|
875
|
-
pkgJson2 = JSON.parse(await fs4.readFile(
|
|
702
|
+
pkgJson2 = JSON.parse(await fs4.readFile(path4.join(cwd, "package.json"), "utf-8"));
|
|
876
703
|
} catch {
|
|
877
704
|
pkgJson2 = {};
|
|
878
705
|
}
|
|
879
706
|
const deps = Object.keys(pkgJson2.dependencies ?? {});
|
|
880
707
|
const devDeps = Object.keys(pkgJson2.devDependencies ?? {});
|
|
881
708
|
if (deps.length > 0) {
|
|
882
|
-
log(/* @__PURE__ */
|
|
709
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: deps.join(", ") }));
|
|
883
710
|
}
|
|
884
711
|
if (devDeps.length > 0) {
|
|
885
|
-
log(/* @__PURE__ */
|
|
712
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Install", msg: `dev: ${devDeps.join(", ")}` }));
|
|
886
713
|
}
|
|
887
714
|
try {
|
|
888
715
|
await execFileAsync("npm", ["install"], { cwd });
|
|
889
716
|
} catch {
|
|
890
|
-
log(/* @__PURE__ */
|
|
717
|
+
log(/* @__PURE__ */ jsx5(Warn, { msg: "npm install failed" }));
|
|
891
718
|
}
|
|
892
719
|
}
|
|
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];
|
|
720
|
+
async function runInitCommand(opts, extra) {
|
|
721
|
+
await getApiKey();
|
|
722
|
+
let dir = opts.dir;
|
|
906
723
|
if (!dir) {
|
|
907
724
|
dir = await askText("What is your project named?", "my-voice-agent");
|
|
908
725
|
}
|
|
909
|
-
const cwd =
|
|
910
|
-
if (!
|
|
911
|
-
|
|
726
|
+
const cwd = path4.resolve(resolveCwd(), dir);
|
|
727
|
+
if (!opts.force && await fileExists(path4.join(cwd, "agent.ts"))) {
|
|
728
|
+
throw new Error(
|
|
912
729
|
`agent.ts already exists in this directory. Use ${interactive("--force")} to overwrite.`
|
|
913
730
|
);
|
|
914
|
-
process.exit(1);
|
|
915
731
|
}
|
|
916
|
-
const cliDir2 =
|
|
917
|
-
const templatesDir =
|
|
732
|
+
const cliDir2 = path4.dirname(fileURLToPath(import.meta.url));
|
|
733
|
+
const templatesDir = path4.join(cliDir2, "..", "templates");
|
|
918
734
|
const { runInit: runInit2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
919
|
-
const template =
|
|
920
|
-
await runWithInk(async (log) => {
|
|
921
|
-
log(/* @__PURE__ */
|
|
735
|
+
const template = opts.template || "simple";
|
|
736
|
+
await runWithInk(async ({ log }) => {
|
|
737
|
+
log(/* @__PURE__ */ jsx5(Step, { action: "Create", msg: dir }));
|
|
922
738
|
await runInit2({ targetDir: cwd, template, templatesDir });
|
|
923
739
|
if (isDevMode()) {
|
|
924
740
|
await rewriteDevDeps(cwd, cliDir2);
|
|
@@ -927,60 +743,32 @@ async function runInitCommand(args, version, opts) {
|
|
|
927
743
|
});
|
|
928
744
|
process.chdir(cwd);
|
|
929
745
|
delete process.env.INIT_CWD;
|
|
930
|
-
if (!
|
|
746
|
+
if (!extra?.quiet) {
|
|
931
747
|
const { runDeployCommand: runDeployCommand2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
|
|
932
|
-
await runDeployCommand2(
|
|
748
|
+
await runDeployCommand2({ cwd });
|
|
933
749
|
}
|
|
934
750
|
return cwd;
|
|
935
751
|
}
|
|
936
|
-
var execFileAsync
|
|
752
|
+
var execFileAsync;
|
|
937
753
|
var init_init2 = __esm({
|
|
938
754
|
"cli/init.tsx"() {
|
|
939
755
|
"use strict";
|
|
940
|
-
init_colors();
|
|
941
756
|
init_discover();
|
|
942
|
-
init_help();
|
|
943
757
|
init_ink();
|
|
944
758
|
init_prompts();
|
|
945
759
|
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
760
|
}
|
|
959
761
|
});
|
|
960
762
|
|
|
961
763
|
// sdk/protocol.ts
|
|
962
764
|
import { z } from "zod";
|
|
963
|
-
var DEFAULT_TTS_SAMPLE_RATE, AUDIO_FORMAT,
|
|
765
|
+
var DEFAULT_TTS_SAMPLE_RATE, AUDIO_FORMAT, KvRequestSchema, VectorRequestSchema, HOOK_TIMEOUT_MS, TOOL_EXECUTION_TIMEOUT_MS, SessionErrorCodeSchema, ev, textEv, turnOrder, ClientEventSchema, ClientMessageSchema;
|
|
964
766
|
var init_protocol = __esm({
|
|
965
767
|
"sdk/protocol.ts"() {
|
|
966
768
|
"use strict";
|
|
967
769
|
DEFAULT_TTS_SAMPLE_RATE = 24e3;
|
|
968
770
|
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", [
|
|
771
|
+
KvRequestSchema = z.discriminatedUnion("op", [
|
|
984
772
|
z.object({ op: z.literal("get"), key: z.string().min(1) }),
|
|
985
773
|
z.object({
|
|
986
774
|
op: z.literal("set"),
|
|
@@ -994,9 +782,29 @@ var init_protocol = __esm({
|
|
|
994
782
|
prefix: z.string(),
|
|
995
783
|
limit: z.number().int().positive().optional(),
|
|
996
784
|
reverse: z.boolean().optional()
|
|
785
|
+
}),
|
|
786
|
+
z.object({ op: z.literal("keys"), pattern: z.string().optional() })
|
|
787
|
+
]);
|
|
788
|
+
VectorRequestSchema = z.discriminatedUnion("op", [
|
|
789
|
+
z.object({
|
|
790
|
+
op: z.literal("upsert"),
|
|
791
|
+
id: z.string().min(1),
|
|
792
|
+
data: z.string().min(1),
|
|
793
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
794
|
+
}),
|
|
795
|
+
z.object({
|
|
796
|
+
op: z.literal("query"),
|
|
797
|
+
text: z.string().min(1),
|
|
798
|
+
topK: z.number().int().positive().max(100).optional(),
|
|
799
|
+
filter: z.string().optional()
|
|
800
|
+
}),
|
|
801
|
+
z.object({
|
|
802
|
+
op: z.literal("remove"),
|
|
803
|
+
ids: z.array(z.string().min(1)).min(1)
|
|
997
804
|
})
|
|
998
805
|
]);
|
|
999
806
|
HOOK_TIMEOUT_MS = 5e3;
|
|
807
|
+
TOOL_EXECUTION_TIMEOUT_MS = 3e4;
|
|
1000
808
|
SessionErrorCodeSchema = z.enum([
|
|
1001
809
|
"stt",
|
|
1002
810
|
"llm",
|
|
@@ -1007,23 +815,16 @@ var init_protocol = __esm({
|
|
|
1007
815
|
"audio",
|
|
1008
816
|
"internal"
|
|
1009
817
|
]);
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
isFinal: z.boolean(),
|
|
1014
|
-
turnOrder: z.number().int().nonnegative().optional()
|
|
1015
|
-
});
|
|
818
|
+
ev = (t) => z.object({ type: z.literal(t) });
|
|
819
|
+
textEv = (t) => z.object({ type: z.literal(t), text: z.string() });
|
|
820
|
+
turnOrder = z.number().int().nonnegative().optional();
|
|
1016
821
|
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() }),
|
|
822
|
+
ev("speech_started"),
|
|
823
|
+
ev("speech_stopped"),
|
|
824
|
+
z.object({ type: z.literal("transcript"), text: z.string(), isFinal: z.boolean(), turnOrder }),
|
|
825
|
+
textEv("turn").extend({ turnOrder }),
|
|
826
|
+
textEv("chat"),
|
|
827
|
+
textEv("chat_delta"),
|
|
1027
828
|
z.object({
|
|
1028
829
|
type: z.literal("tool_call_start"),
|
|
1029
830
|
toolCallId: z.string(),
|
|
@@ -1035,55 +836,35 @@ var init_protocol = __esm({
|
|
|
1035
836
|
toolCallId: z.string(),
|
|
1036
837
|
result: z.string().max(4e3)
|
|
1037
838
|
}),
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
z.object({
|
|
1042
|
-
type: z.literal("error"),
|
|
1043
|
-
code: SessionErrorCodeSchema,
|
|
1044
|
-
message: z.string()
|
|
1045
|
-
})
|
|
839
|
+
ev("tts_done"),
|
|
840
|
+
ev("cancelled"),
|
|
841
|
+
ev("reset"),
|
|
842
|
+
z.object({ type: z.literal("error"), code: SessionErrorCodeSchema, message: z.string() })
|
|
1046
843
|
]);
|
|
1047
844
|
ClientMessageSchema = z.discriminatedUnion("type", [
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
845
|
+
ev("audio_ready"),
|
|
846
|
+
ev("cancel"),
|
|
847
|
+
ev("reset"),
|
|
1051
848
|
z.object({
|
|
1052
849
|
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)
|
|
850
|
+
messages: z.array(z.object({ role: z.enum(["user", "assistant"]), text: z.string().max(1e5) })).max(200)
|
|
1059
851
|
})
|
|
1060
852
|
]);
|
|
1061
853
|
}
|
|
1062
854
|
});
|
|
1063
855
|
|
|
1064
856
|
// sdk/runtime.ts
|
|
1065
|
-
var consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
857
|
+
var _log, consoleLogger, noopMetrics, DEFAULT_S2S_CONFIG;
|
|
1066
858
|
var init_runtime = __esm({
|
|
1067
859
|
"sdk/runtime.ts"() {
|
|
1068
860
|
"use strict";
|
|
1069
861
|
init_protocol();
|
|
862
|
+
_log = (m) => (msg, ctx) => console[m](msg, ...ctx ? [ctx] : []);
|
|
1070
863
|
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
|
-
}
|
|
864
|
+
info: _log("log"),
|
|
865
|
+
warn: _log("warn"),
|
|
866
|
+
error: _log("error"),
|
|
867
|
+
debug: _log("debug")
|
|
1087
868
|
};
|
|
1088
869
|
noopMetrics = {
|
|
1089
870
|
sessionsTotal: { inc() {
|
|
@@ -1100,20 +881,230 @@ var init_runtime = __esm({
|
|
|
1100
881
|
}
|
|
1101
882
|
});
|
|
1102
883
|
|
|
1103
|
-
// sdk/
|
|
884
|
+
// sdk/s2s.ts
|
|
885
|
+
var s2s_exports = {};
|
|
886
|
+
__export(s2s_exports, {
|
|
887
|
+
connectS2s: () => connectS2s,
|
|
888
|
+
wrapOnStyleWebSocket: () => wrapOnStyleWebSocket
|
|
889
|
+
});
|
|
1104
890
|
import { z as z2 } from "zod";
|
|
891
|
+
function uint8ToBase64(bytes) {
|
|
892
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
893
|
+
}
|
|
894
|
+
function base64ToUint8(base64) {
|
|
895
|
+
const buf = Buffer.from(base64, "base64");
|
|
896
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
897
|
+
}
|
|
898
|
+
function wrapOnStyleWebSocket(ws) {
|
|
899
|
+
const target = new EventTarget();
|
|
900
|
+
ws.on("open", () => target.dispatchEvent(new Event("open")));
|
|
901
|
+
ws.on("message", (data) => target.dispatchEvent(new MessageEvent("message", { data })));
|
|
902
|
+
ws.on("close", (code, reason) => {
|
|
903
|
+
const init = { reason: String(reason ?? "") };
|
|
904
|
+
if (typeof code === "number") init.code = code;
|
|
905
|
+
target.dispatchEvent(new CloseEvent("close", init));
|
|
906
|
+
});
|
|
907
|
+
ws.on(
|
|
908
|
+
"error",
|
|
909
|
+
(err) => target.dispatchEvent(
|
|
910
|
+
new ErrorEvent("error", {
|
|
911
|
+
message: errorMessage(err)
|
|
912
|
+
})
|
|
913
|
+
)
|
|
914
|
+
);
|
|
915
|
+
Object.defineProperties(target, {
|
|
916
|
+
readyState: { get: () => ws.readyState, enumerable: true },
|
|
917
|
+
send: { value: (data) => ws.send(data), enumerable: true },
|
|
918
|
+
close: { value: () => ws.close(), enumerable: true }
|
|
919
|
+
});
|
|
920
|
+
return target;
|
|
921
|
+
}
|
|
922
|
+
function dispatchS2sMessage(target, msg) {
|
|
923
|
+
const entry = S2S_DISPATCH[msg.type]?.(msg);
|
|
924
|
+
if (entry) target.dispatchEvent(new CustomEvent(entry[0], { detail: entry[1] }));
|
|
925
|
+
}
|
|
926
|
+
function connectS2s(opts) {
|
|
927
|
+
const { apiKey, config, createWebSocket, logger: log = consoleLogger } = opts;
|
|
928
|
+
return new Promise((resolve, reject) => {
|
|
929
|
+
log.info("S2S connecting", { url: config.wssUrl });
|
|
930
|
+
const ws = createWebSocket(config.wssUrl, {
|
|
931
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
932
|
+
});
|
|
933
|
+
const target = new EventTarget();
|
|
934
|
+
let opened = false;
|
|
935
|
+
function send(msg) {
|
|
936
|
+
if (ws.readyState !== WS_OPEN) return;
|
|
937
|
+
const json = JSON.stringify(msg);
|
|
938
|
+
if (msg.type !== "input.audio") {
|
|
939
|
+
log.info(
|
|
940
|
+
`S2S >> ${msg.type}`,
|
|
941
|
+
msg.type === "session.update" ? { payload: json } : void 0
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
ws.send(json);
|
|
945
|
+
}
|
|
946
|
+
const handle = Object.assign(target, {
|
|
947
|
+
sendAudio(audio) {
|
|
948
|
+
if (ws.readyState !== WS_OPEN) return;
|
|
949
|
+
ws.send(`{"type":"input.audio","audio":"${uint8ToBase64(audio)}"}`);
|
|
950
|
+
},
|
|
951
|
+
sendToolResult(callId, result) {
|
|
952
|
+
const msg = { type: "tool.result", call_id: callId, result };
|
|
953
|
+
log.info("S2S >> tool.result", { call_id: callId, resultLength: result.length });
|
|
954
|
+
send(msg);
|
|
955
|
+
},
|
|
956
|
+
updateSession(sessionConfig) {
|
|
957
|
+
send({ type: "session.update", session: sessionConfig });
|
|
958
|
+
},
|
|
959
|
+
resumeSession(sessionId) {
|
|
960
|
+
send({ type: "session.resume", session_id: sessionId });
|
|
961
|
+
},
|
|
962
|
+
close() {
|
|
963
|
+
log.info("S2S closing");
|
|
964
|
+
ws.close();
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
ws.addEventListener("open", () => {
|
|
968
|
+
opened = true;
|
|
969
|
+
log.info("S2S WebSocket open");
|
|
970
|
+
resolve(handle);
|
|
971
|
+
});
|
|
972
|
+
function handleS2sMessage(ev2) {
|
|
973
|
+
const data = ev2.data;
|
|
974
|
+
let raw;
|
|
975
|
+
try {
|
|
976
|
+
raw = JSON.parse(String(data));
|
|
977
|
+
} catch {
|
|
978
|
+
log.warn("S2S << invalid JSON", { data: String(data).slice(0, 200) });
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const obj = raw;
|
|
982
|
+
if (obj.type !== "reply.audio" && obj.type !== "input.audio") {
|
|
983
|
+
log.info(
|
|
984
|
+
`S2S << ${obj.type}`,
|
|
985
|
+
obj.type === "transcript.agent.delta" ? { delta: obj.delta } : void 0
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
if (obj.type === "reply.audio" && typeof obj.data === "string") {
|
|
989
|
+
const audioBytes = base64ToUint8(obj.data);
|
|
990
|
+
target.dispatchEvent(new CustomEvent("audio", { detail: { audio: audioBytes } }));
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
const parsed = S2sServerMessageSchema.safeParse(raw);
|
|
994
|
+
if (!parsed.success) {
|
|
995
|
+
log.warn(
|
|
996
|
+
`S2S << unrecognised message type: ${obj.type ?? JSON.stringify(raw).slice(0, 200)}`
|
|
997
|
+
);
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
dispatchS2sMessage(target, parsed.data);
|
|
1001
|
+
}
|
|
1002
|
+
ws.addEventListener("message", handleS2sMessage);
|
|
1003
|
+
ws.addEventListener("close", ((ev2) => {
|
|
1004
|
+
log.info("S2S WebSocket closed", {
|
|
1005
|
+
code: ev2.code ?? 0,
|
|
1006
|
+
reason: ev2.reason ?? ""
|
|
1007
|
+
});
|
|
1008
|
+
target.dispatchEvent(new CustomEvent("close"));
|
|
1009
|
+
}));
|
|
1010
|
+
ws.addEventListener("error", ((ev2) => {
|
|
1011
|
+
const message = ev2 instanceof ErrorEvent ? ev2.message : "WebSocket error";
|
|
1012
|
+
const errObj = new Error(message);
|
|
1013
|
+
log.error("S2S WebSocket error", { error: errObj.message });
|
|
1014
|
+
if (!opened) {
|
|
1015
|
+
reject(errObj);
|
|
1016
|
+
} else {
|
|
1017
|
+
target.dispatchEvent(
|
|
1018
|
+
new CustomEvent("error", {
|
|
1019
|
+
detail: { code: "ws_error", message: errObj.message }
|
|
1020
|
+
})
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
}));
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
var WS_OPEN, S2sServerMessageSchema, S2S_DISPATCH;
|
|
1027
|
+
var init_s2s = __esm({
|
|
1028
|
+
"sdk/s2s.ts"() {
|
|
1029
|
+
"use strict";
|
|
1030
|
+
init_utils();
|
|
1031
|
+
init_runtime();
|
|
1032
|
+
WS_OPEN = 1;
|
|
1033
|
+
S2sServerMessageSchema = z2.discriminatedUnion("type", [
|
|
1034
|
+
z2.object({ type: z2.literal("session.ready"), session_id: z2.string() }),
|
|
1035
|
+
z2.object({ type: z2.literal("session.updated") }).passthrough(),
|
|
1036
|
+
z2.object({ type: z2.literal("input.speech.started") }),
|
|
1037
|
+
z2.object({ type: z2.literal("input.speech.stopped") }),
|
|
1038
|
+
z2.object({ type: z2.literal("transcript.user.delta"), text: z2.string() }),
|
|
1039
|
+
z2.object({
|
|
1040
|
+
type: z2.literal("transcript.user"),
|
|
1041
|
+
item_id: z2.string(),
|
|
1042
|
+
text: z2.string()
|
|
1043
|
+
}),
|
|
1044
|
+
z2.object({ type: z2.literal("reply.started"), reply_id: z2.string() }),
|
|
1045
|
+
// reply.audio is handled on the fast path before Zod.
|
|
1046
|
+
z2.object({ type: z2.literal("transcript.agent.delta"), delta: z2.string() }).passthrough(),
|
|
1047
|
+
z2.object({ type: z2.literal("transcript.agent"), text: z2.string() }),
|
|
1048
|
+
z2.object({ type: z2.literal("reply.content_part.started") }).passthrough(),
|
|
1049
|
+
z2.object({ type: z2.literal("reply.content_part.done") }).passthrough(),
|
|
1050
|
+
z2.object({
|
|
1051
|
+
type: z2.literal("tool.call"),
|
|
1052
|
+
call_id: z2.string(),
|
|
1053
|
+
name: z2.string(),
|
|
1054
|
+
args: z2.record(z2.string(), z2.unknown()).optional().default({})
|
|
1055
|
+
}),
|
|
1056
|
+
z2.object({
|
|
1057
|
+
type: z2.literal("reply.done"),
|
|
1058
|
+
status: z2.string().optional()
|
|
1059
|
+
}),
|
|
1060
|
+
z2.object({
|
|
1061
|
+
type: z2.literal("session.error"),
|
|
1062
|
+
code: z2.string(),
|
|
1063
|
+
message: z2.string()
|
|
1064
|
+
}),
|
|
1065
|
+
// Connection-level error (bare "error" without "session." prefix).
|
|
1066
|
+
z2.object({
|
|
1067
|
+
type: z2.literal("error"),
|
|
1068
|
+
message: z2.string()
|
|
1069
|
+
})
|
|
1070
|
+
]);
|
|
1071
|
+
S2S_DISPATCH = {
|
|
1072
|
+
"session.ready": (m) => ["ready", { session_id: m.session_id }],
|
|
1073
|
+
"session.updated": (m) => ["session_updated", m],
|
|
1074
|
+
"input.speech.started": () => ["speech_started", void 0],
|
|
1075
|
+
"input.speech.stopped": () => ["speech_stopped", void 0],
|
|
1076
|
+
"transcript.user.delta": (m) => ["user_transcript_delta", { text: m.text }],
|
|
1077
|
+
"transcript.user": (m) => ["user_transcript", { item_id: m.item_id, text: m.text }],
|
|
1078
|
+
"reply.started": (m) => ["reply_started", { reply_id: m.reply_id }],
|
|
1079
|
+
"transcript.agent.delta": (m) => ["agent_transcript_delta", { text: m.delta }],
|
|
1080
|
+
"transcript.agent": (m) => ["agent_transcript", { text: m.text }],
|
|
1081
|
+
"tool.call": (m) => ["tool_call", { call_id: m.call_id, name: m.name, args: m.args }],
|
|
1082
|
+
"reply.done": (m) => ["reply_done", { status: m.status }],
|
|
1083
|
+
"session.error": (m) => [
|
|
1084
|
+
m.code === "session_not_found" || m.code === "session_forbidden" ? "session_expired" : "error",
|
|
1085
|
+
{ code: m.code, message: m.message }
|
|
1086
|
+
],
|
|
1087
|
+
error: (m) => ["error", { code: "connection", message: m.message }],
|
|
1088
|
+
"reply.content_part.started": () => void 0,
|
|
1089
|
+
"reply.content_part.done": () => void 0
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// sdk/_internal_types.ts
|
|
1095
|
+
import { z as z3 } from "zod";
|
|
1105
1096
|
function agentToolsToSchemas(tools) {
|
|
1106
1097
|
return Object.entries(tools).map(([name, def]) => ({
|
|
1107
1098
|
name,
|
|
1108
1099
|
description: def.description,
|
|
1109
|
-
parameters:
|
|
1100
|
+
parameters: z3.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1110
1101
|
}));
|
|
1111
1102
|
}
|
|
1112
1103
|
var EMPTY_PARAMS;
|
|
1113
1104
|
var init_internal_types = __esm({
|
|
1114
1105
|
"sdk/_internal_types.ts"() {
|
|
1115
1106
|
"use strict";
|
|
1116
|
-
EMPTY_PARAMS =
|
|
1107
|
+
EMPTY_PARAMS = z3.object({});
|
|
1117
1108
|
}
|
|
1118
1109
|
});
|
|
1119
1110
|
|
|
@@ -1139,68 +1130,16 @@ Voice-First Rules:
|
|
|
1139
1130
|
}
|
|
1140
1131
|
});
|
|
1141
1132
|
|
|
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
1133
|
// sdk/builtin_tools.ts
|
|
1198
1134
|
import { convert } from "html-to-text";
|
|
1199
1135
|
import { z as z4 } from "zod";
|
|
1136
|
+
function fetchSignal(toolSignal) {
|
|
1137
|
+
return AbortSignal.any([toolSignal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]);
|
|
1138
|
+
}
|
|
1200
1139
|
function htmlToText(html) {
|
|
1201
1140
|
return convert(html, { wordwrap: false });
|
|
1202
1141
|
}
|
|
1203
|
-
function createWebSearch() {
|
|
1142
|
+
function createWebSearch(fetchFn = globalThis.fetch) {
|
|
1204
1143
|
return {
|
|
1205
1144
|
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
1145
|
parameters: webSearchParams,
|
|
@@ -1215,9 +1154,9 @@ function createWebSearch() {
|
|
|
1215
1154
|
count: String(maxResults),
|
|
1216
1155
|
text_decorations: "false"
|
|
1217
1156
|
})}`;
|
|
1218
|
-
const resp = await
|
|
1157
|
+
const resp = await fetchFn(url, {
|
|
1219
1158
|
headers: { "X-Subscription-Token": apiKey },
|
|
1220
|
-
signal: ctx.abortSignal
|
|
1159
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1221
1160
|
});
|
|
1222
1161
|
if (!resp.ok) return [];
|
|
1223
1162
|
const raw = await resp.json();
|
|
@@ -1231,19 +1170,19 @@ function createWebSearch() {
|
|
|
1231
1170
|
}
|
|
1232
1171
|
};
|
|
1233
1172
|
}
|
|
1234
|
-
function createVisitWebpage() {
|
|
1173
|
+
function createVisitWebpage(fetchFn = globalThis.fetch) {
|
|
1235
1174
|
return {
|
|
1236
1175
|
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
1176
|
parameters: visitWebpageParams,
|
|
1238
1177
|
async execute(args, ctx) {
|
|
1239
1178
|
const { url } = args;
|
|
1240
|
-
const resp = await
|
|
1179
|
+
const resp = await fetchFn(url, {
|
|
1241
1180
|
headers: {
|
|
1242
1181
|
"User-Agent": "Mozilla/5.0 (compatible; VoiceAgent/1.0; +https://github.com/AssemblyAI/aai)",
|
|
1243
1182
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
1244
1183
|
},
|
|
1245
1184
|
redirect: "follow",
|
|
1246
|
-
signal: ctx.abortSignal
|
|
1185
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1247
1186
|
});
|
|
1248
1187
|
if (!resp.ok) {
|
|
1249
1188
|
return { error: `Failed to fetch: ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1261,15 +1200,15 @@ function createVisitWebpage() {
|
|
|
1261
1200
|
}
|
|
1262
1201
|
};
|
|
1263
1202
|
}
|
|
1264
|
-
function createFetchJson() {
|
|
1203
|
+
function createFetchJson(fetchFn = globalThis.fetch) {
|
|
1265
1204
|
return {
|
|
1266
1205
|
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
1206
|
parameters: fetchJsonParams,
|
|
1268
1207
|
async execute(args, ctx) {
|
|
1269
1208
|
const { url, headers } = args;
|
|
1270
|
-
const resp = await
|
|
1209
|
+
const resp = await fetchFn(url, {
|
|
1271
1210
|
...headers && { headers },
|
|
1272
|
-
signal: ctx.abortSignal
|
|
1211
|
+
signal: fetchSignal(ctx.abortSignal)
|
|
1273
1212
|
});
|
|
1274
1213
|
if (!resp.ok) {
|
|
1275
1214
|
return { error: `HTTP ${resp.status} ${resp.statusText}`, url };
|
|
@@ -1299,7 +1238,6 @@ function createRunCode() {
|
|
|
1299
1238
|
error: capture,
|
|
1300
1239
|
debug: capture
|
|
1301
1240
|
};
|
|
1302
|
-
const RUN_CODE_TIMEOUT = 5e3;
|
|
1303
1241
|
const AsyncFunction = Object.getPrototypeOf(async () => {
|
|
1304
1242
|
}).constructor;
|
|
1305
1243
|
try {
|
|
@@ -1313,7 +1251,7 @@ function createRunCode() {
|
|
|
1313
1251
|
const result = output.join("\n").trim();
|
|
1314
1252
|
return result || "Code ran successfully (no output)";
|
|
1315
1253
|
} catch (err) {
|
|
1316
|
-
return { error:
|
|
1254
|
+
return { error: errorMessage(err) };
|
|
1317
1255
|
}
|
|
1318
1256
|
}
|
|
1319
1257
|
};
|
|
@@ -1328,66 +1266,84 @@ function createVectorSearch(vectorSearchFn) {
|
|
|
1328
1266
|
}
|
|
1329
1267
|
};
|
|
1330
1268
|
}
|
|
1269
|
+
function resolveBuiltin(name, opts) {
|
|
1270
|
+
const entry = TOOL_REGISTRY[name];
|
|
1271
|
+
if (!entry) return [];
|
|
1272
|
+
if ("multi" in entry) return Object.entries(entry.multi());
|
|
1273
|
+
if (name === "vector_search" && !opts?.vectorSearch) return [];
|
|
1274
|
+
return [[name, entry.create(opts)]];
|
|
1275
|
+
}
|
|
1331
1276
|
function getBuiltinToolDefs(names, opts) {
|
|
1332
1277
|
const defs = {};
|
|
1333
1278
|
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
|
-
|
|
1279
|
+
for (const [k, v] of resolveBuiltin(name, opts)) defs[k] = v;
|
|
1280
|
+
}
|
|
1281
|
+
return defs;
|
|
1282
|
+
}
|
|
1283
|
+
function getBuiltinToolSchemas(names) {
|
|
1284
|
+
return names.flatMap(
|
|
1285
|
+
(name) => resolveBuiltin(name, { vectorSearch: async () => "" }).map(([toolName, def]) => ({
|
|
1286
|
+
name: toolName,
|
|
1287
|
+
description: def.description,
|
|
1288
|
+
parameters: z4.toJSONSchema(def.parameters ?? EMPTY_PARAMS)
|
|
1289
|
+
}))
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
function memoryTools() {
|
|
1293
|
+
return {
|
|
1294
|
+
save_memory: tool({
|
|
1295
|
+
description: "Save a piece of information to persistent memory. Use a descriptive key like 'user:name' or 'project:status'.",
|
|
1296
|
+
parameters: z4.object({
|
|
1297
|
+
key: z4.string().describe("A descriptive key for this memory (e.g. 'user:name', 'preference:color')"),
|
|
1298
|
+
value: z4.string().describe("The information to remember")
|
|
1299
|
+
}),
|
|
1300
|
+
execute: async ({ key, value }, ctx) => {
|
|
1301
|
+
await ctx.kv.set(key, value);
|
|
1302
|
+
return { saved: key };
|
|
1303
|
+
}
|
|
1304
|
+
}),
|
|
1305
|
+
recall_memory: tool({
|
|
1306
|
+
description: "Retrieve a previously saved memory by its key.",
|
|
1307
|
+
parameters: z4.object({
|
|
1308
|
+
key: z4.string().describe("The key to look up")
|
|
1309
|
+
}),
|
|
1310
|
+
execute: async ({ key }, ctx) => {
|
|
1311
|
+
const value = await ctx.kv.get(key);
|
|
1312
|
+
if (value === null) return { found: false, key };
|
|
1313
|
+
return { found: true, key, value };
|
|
1314
|
+
}
|
|
1315
|
+
}),
|
|
1316
|
+
list_memories: tool({
|
|
1317
|
+
description: "List all saved memory keys, optionally filtered by a prefix (e.g. 'user:').",
|
|
1318
|
+
parameters: z4.object({
|
|
1319
|
+
prefix: z4.string().describe("Prefix to filter keys (e.g. 'user:'). Use empty string for all.").optional()
|
|
1320
|
+
}),
|
|
1321
|
+
execute: async ({ prefix }, ctx) => {
|
|
1322
|
+
const entries = await ctx.kv.list(prefix ?? "");
|
|
1323
|
+
return { count: entries.length, keys: entries.map((e) => e.key) };
|
|
1358
1324
|
}
|
|
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)
|
|
1325
|
+
}),
|
|
1326
|
+
forget_memory: tool({
|
|
1327
|
+
description: "Delete a previously saved memory by its key.",
|
|
1328
|
+
parameters: z4.object({
|
|
1329
|
+
key: z4.string().describe("The key to delete")
|
|
1330
|
+
}),
|
|
1331
|
+
execute: async ({ key }, ctx) => {
|
|
1332
|
+
await ctx.kv.delete(key);
|
|
1333
|
+
return { deleted: key };
|
|
1381
1334
|
}
|
|
1382
|
-
|
|
1383
|
-
}
|
|
1335
|
+
})
|
|
1336
|
+
};
|
|
1384
1337
|
}
|
|
1385
|
-
var webSearchParams, BRAVE_SEARCH_URL, BraveSearchResponseSchema, MAX_PAGE_CHARS, MAX_HTML_BYTES, visitWebpageParams, fetchJsonParams, runCodeParams, vectorSearchParams,
|
|
1338
|
+
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
1339
|
var init_builtin_tools = __esm({
|
|
1387
1340
|
"sdk/builtin_tools.ts"() {
|
|
1388
1341
|
"use strict";
|
|
1389
1342
|
init_internal_types();
|
|
1390
|
-
|
|
1343
|
+
init_utils();
|
|
1344
|
+
init_types();
|
|
1345
|
+
FETCH_TIMEOUT_MS = 15e3;
|
|
1346
|
+
RUN_CODE_TIMEOUT = 5e3;
|
|
1391
1347
|
webSearchParams = z4.object({
|
|
1392
1348
|
query: z4.string().describe("The search query"),
|
|
1393
1349
|
max_results: z4.number().describe("Maximum number of results to return (default 5)").optional()
|
|
@@ -1422,16 +1378,13 @@ var init_builtin_tools = __esm({
|
|
|
1422
1378
|
),
|
|
1423
1379
|
topK: z4.number().describe("Maximum results to return (default: 5)").optional()
|
|
1424
1380
|
});
|
|
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
|
|
1381
|
+
TOOL_REGISTRY = {
|
|
1382
|
+
web_search: { create: (opts) => createWebSearch(opts?.fetch) },
|
|
1383
|
+
visit_webpage: { create: (opts) => createVisitWebpage(opts?.fetch) },
|
|
1384
|
+
fetch_json: { create: (opts) => createFetchJson(opts?.fetch) },
|
|
1385
|
+
run_code: { create: createRunCode },
|
|
1386
|
+
vector_search: { create: (opts) => createVectorSearch(opts?.vectorSearch ?? (async () => "")) },
|
|
1387
|
+
memory: { multi: memoryTools }
|
|
1435
1388
|
};
|
|
1436
1389
|
}
|
|
1437
1390
|
});
|
|
@@ -1502,291 +1455,6 @@ var init_kv = __esm({
|
|
|
1502
1455
|
}
|
|
1503
1456
|
});
|
|
1504
1457
|
|
|
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
1458
|
// sdk/session.ts
|
|
1791
1459
|
function createS2sSession(opts) {
|
|
1792
1460
|
const {
|
|
@@ -1817,7 +1485,6 @@ function createS2sSession(opts) {
|
|
|
1817
1485
|
}));
|
|
1818
1486
|
let s2s = null;
|
|
1819
1487
|
const sessionAbort = new AbortController();
|
|
1820
|
-
let audioReady = false;
|
|
1821
1488
|
let toolCallCount = 0;
|
|
1822
1489
|
let turnPromise = null;
|
|
1823
1490
|
let conversationMessages = [];
|
|
@@ -1829,36 +1496,21 @@ function createS2sSession(opts) {
|
|
|
1829
1496
|
if (!hookInvoker) return null;
|
|
1830
1497
|
try {
|
|
1831
1498
|
return await hookInvoker.resolveTurnConfig(id, HOOK_TIMEOUT_MS);
|
|
1832
|
-
} catch {
|
|
1499
|
+
} catch (err) {
|
|
1500
|
+
log.warn("resolveTurnConfig hook failed", { err: errorMessage(err) });
|
|
1833
1501
|
return null;
|
|
1834
1502
|
}
|
|
1835
1503
|
}
|
|
1836
1504
|
function invokeHook(hook, arg) {
|
|
1837
1505
|
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)
|
|
1506
|
+
try {
|
|
1507
|
+
const h = hookInvoker[hook];
|
|
1508
|
+
Promise.resolve(h.call(hookInvoker, id, arg, HOOK_TIMEOUT_MS)).catch((err) => {
|
|
1509
|
+
log.warn(`${hook} hook failed`, { err: errorMessage(err) });
|
|
1860
1510
|
});
|
|
1861
|
-
})
|
|
1511
|
+
} catch (err) {
|
|
1512
|
+
log.warn(`${hook} hook failed`, { err: errorMessage(err) });
|
|
1513
|
+
}
|
|
1862
1514
|
}
|
|
1863
1515
|
function checkTurnLimits(turnConfig, name) {
|
|
1864
1516
|
const maxSteps = turnConfig?.maxSteps ?? agentConfig.maxSteps;
|
|
@@ -1898,7 +1550,7 @@ function createS2sSession(opts) {
|
|
|
1898
1550
|
try {
|
|
1899
1551
|
result = await executeTool(name, parsedArgs, id, conversationMessages);
|
|
1900
1552
|
} catch (err) {
|
|
1901
|
-
const msg =
|
|
1553
|
+
const msg = errorMessage(err);
|
|
1902
1554
|
log.error("Tool execution failed", { tool: name, error: msg });
|
|
1903
1555
|
result = JSON.stringify({ error: msg });
|
|
1904
1556
|
}
|
|
@@ -1913,6 +1565,79 @@ function createS2sSession(opts) {
|
|
|
1913
1565
|
function on(target, event, handler) {
|
|
1914
1566
|
target.addEventListener(event, handler);
|
|
1915
1567
|
}
|
|
1568
|
+
function setupListeners(handle) {
|
|
1569
|
+
on(handle, "ready", (e) => {
|
|
1570
|
+
s2sSessionId = e.detail.session_id;
|
|
1571
|
+
log.info("S2S session ready", { session_id: s2sSessionId });
|
|
1572
|
+
});
|
|
1573
|
+
on(handle, "session_expired", () => {
|
|
1574
|
+
log.info("S2S session expired, reconnecting fresh");
|
|
1575
|
+
s2sSessionId = null;
|
|
1576
|
+
handle.close();
|
|
1577
|
+
});
|
|
1578
|
+
for (const type of ["speech_started", "speech_stopped"]) {
|
|
1579
|
+
handle.addEventListener(type, () => client.event({ type }));
|
|
1580
|
+
}
|
|
1581
|
+
on(handle, "user_transcript_delta", (e) => {
|
|
1582
|
+
client.event({ type: "transcript", text: e.detail.text, isFinal: false });
|
|
1583
|
+
});
|
|
1584
|
+
on(handle, "user_transcript", (e) => {
|
|
1585
|
+
const { text } = e.detail;
|
|
1586
|
+
log.info("S2S user transcript", { text });
|
|
1587
|
+
client.event({ type: "transcript", text, isFinal: true });
|
|
1588
|
+
client.event({ type: "turn", text });
|
|
1589
|
+
conversationMessages.push({ role: "user", content: text });
|
|
1590
|
+
invokeHook("onTurn", text);
|
|
1591
|
+
});
|
|
1592
|
+
handle.addEventListener("reply_started", () => {
|
|
1593
|
+
toolCallCount = 0;
|
|
1594
|
+
});
|
|
1595
|
+
on(handle, "audio", (e) => {
|
|
1596
|
+
client.playAudioChunk(e.detail.audio);
|
|
1597
|
+
});
|
|
1598
|
+
on(handle, "agent_transcript_delta", (e) => {
|
|
1599
|
+
client.event({ type: "chat_delta", text: e.detail.text });
|
|
1600
|
+
});
|
|
1601
|
+
on(handle, "agent_transcript", (e) => {
|
|
1602
|
+
const { text } = e.detail;
|
|
1603
|
+
client.event({ type: "chat", text });
|
|
1604
|
+
conversationMessages.push({ role: "assistant", content: text });
|
|
1605
|
+
});
|
|
1606
|
+
on(handle, "tool_call", (e) => {
|
|
1607
|
+
const p = handleToolCall(e.detail).catch((err) => {
|
|
1608
|
+
log.error("Tool call handler failed", { err: errorMessage(err) });
|
|
1609
|
+
});
|
|
1610
|
+
turnPromise = (turnPromise ?? Promise.resolve()).then(() => p);
|
|
1611
|
+
});
|
|
1612
|
+
on(handle, "reply_done", (e) => {
|
|
1613
|
+
if (e.detail.status === "interrupted") {
|
|
1614
|
+
log.info("S2S reply interrupted (barge-in)");
|
|
1615
|
+
pendingTools = [];
|
|
1616
|
+
client.event({ type: "cancelled" });
|
|
1617
|
+
} else if (pendingTools.length > 0) {
|
|
1618
|
+
for (const tool2 of pendingTools) s2s?.sendToolResult(tool2.call_id, tool2.result);
|
|
1619
|
+
pendingTools = [];
|
|
1620
|
+
} else {
|
|
1621
|
+
client.playAudioDone();
|
|
1622
|
+
client.event({ type: "tts_done" });
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
on(handle, "error", (e) => {
|
|
1626
|
+
log.error("S2S error", { code: e.detail.code, message: e.detail.message });
|
|
1627
|
+
client.event({ type: "error", code: "internal", message: e.detail.message });
|
|
1628
|
+
handle.close();
|
|
1629
|
+
});
|
|
1630
|
+
handle.addEventListener("close", () => {
|
|
1631
|
+
log.info("S2S closed");
|
|
1632
|
+
s2s = null;
|
|
1633
|
+
if (!sessionAbort.signal.aborted) {
|
|
1634
|
+
log.info("Attempting S2S reconnect");
|
|
1635
|
+
connectAndSetup().catch((err) => {
|
|
1636
|
+
log.error("S2S reconnect failed", { error: errorMessage(err) });
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1916
1641
|
async function connectAndSetup() {
|
|
1917
1642
|
if (connecting) {
|
|
1918
1643
|
pendingReconnect = true;
|
|
@@ -1920,106 +1645,15 @@ function createS2sSession(opts) {
|
|
|
1920
1645
|
}
|
|
1921
1646
|
connecting = true;
|
|
1922
1647
|
try {
|
|
1923
|
-
const handle = await
|
|
1648
|
+
const handle = await _internals.connectS2s({
|
|
1924
1649
|
apiKey,
|
|
1925
1650
|
config: s2sConfig,
|
|
1926
1651
|
createWebSocket,
|
|
1927
1652
|
logger: log
|
|
1928
1653
|
});
|
|
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
|
-
});
|
|
1654
|
+
setupListeners(handle);
|
|
2019
1655
|
if (s2sSessionId) {
|
|
2020
|
-
log.info("Attempting S2S session resume", {
|
|
2021
|
-
session_id: s2sSessionId
|
|
2022
|
-
});
|
|
1656
|
+
log.info("Attempting S2S session resume", { session_id: s2sSessionId });
|
|
2023
1657
|
handle.resumeSession(s2sSessionId);
|
|
2024
1658
|
} else {
|
|
2025
1659
|
handle.updateSession({
|
|
@@ -2030,7 +1664,7 @@ function createS2sSession(opts) {
|
|
|
2030
1664
|
}
|
|
2031
1665
|
s2s = handle;
|
|
2032
1666
|
} catch (err) {
|
|
2033
|
-
const msg =
|
|
1667
|
+
const msg = errorMessage(err);
|
|
2034
1668
|
log.error("S2S connect failed", { error: msg });
|
|
2035
1669
|
client.event({ type: "error", code: "internal", message: msg });
|
|
2036
1670
|
} finally {
|
|
@@ -2038,8 +1672,7 @@ function createS2sSession(opts) {
|
|
|
2038
1672
|
if (pendingReconnect && !sessionAbort.signal.aborted) {
|
|
2039
1673
|
pendingReconnect = false;
|
|
2040
1674
|
connectAndSetup().catch((err) => {
|
|
2041
|
-
|
|
2042
|
-
log.error("S2S deferred reconnect failed", { error: msg });
|
|
1675
|
+
log.error("S2S deferred reconnect failed", { error: errorMessage(err) });
|
|
2043
1676
|
});
|
|
2044
1677
|
}
|
|
2045
1678
|
}
|
|
@@ -2063,8 +1696,6 @@ function createS2sSession(opts) {
|
|
|
2063
1696
|
s2s?.sendAudio(data);
|
|
2064
1697
|
},
|
|
2065
1698
|
onAudioReady() {
|
|
2066
|
-
if (audioReady) return;
|
|
2067
|
-
audioReady = true;
|
|
2068
1699
|
},
|
|
2069
1700
|
onCancel() {
|
|
2070
1701
|
client.event({ type: "cancelled" });
|
|
@@ -2088,17 +1719,36 @@ function createS2sSession(opts) {
|
|
|
2088
1719
|
}
|
|
2089
1720
|
};
|
|
2090
1721
|
}
|
|
2091
|
-
|
|
1722
|
+
function buildSystemPrompt(config, opts) {
|
|
1723
|
+
const { hasTools } = opts;
|
|
1724
|
+
const agentInstructions = config.instructions && config.instructions !== DEFAULT_INSTRUCTIONS ? `
|
|
1725
|
+
|
|
1726
|
+
Agent-Specific Instructions:
|
|
1727
|
+
${config.instructions}` : "";
|
|
1728
|
+
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.' : "";
|
|
1729
|
+
const today = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
1730
|
+
weekday: "long",
|
|
1731
|
+
year: "numeric",
|
|
1732
|
+
month: "long",
|
|
1733
|
+
day: "numeric"
|
|
1734
|
+
});
|
|
1735
|
+
return DEFAULT_INSTRUCTIONS + `
|
|
1736
|
+
|
|
1737
|
+
Today's date is ${today}.` + agentInstructions + toolPreamble + (opts.voice ? VOICE_RULES : "");
|
|
1738
|
+
}
|
|
1739
|
+
var _internals, VOICE_RULES;
|
|
2092
1740
|
var init_session = __esm({
|
|
2093
1741
|
"sdk/session.ts"() {
|
|
2094
1742
|
"use strict";
|
|
1743
|
+
init_utils();
|
|
2095
1744
|
init_protocol();
|
|
2096
1745
|
init_runtime();
|
|
2097
1746
|
init_s2s();
|
|
2098
|
-
|
|
2099
|
-
|
|
1747
|
+
init_types();
|
|
1748
|
+
_internals = {
|
|
2100
1749
|
connectS2s
|
|
2101
1750
|
};
|
|
1751
|
+
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
1752
|
}
|
|
2103
1753
|
});
|
|
2104
1754
|
|
|
@@ -2149,11 +1799,10 @@ var init_vector = __esm({
|
|
|
2149
1799
|
|
|
2150
1800
|
// sdk/worker_entry.ts
|
|
2151
1801
|
function buildToolContext(opts) {
|
|
2152
|
-
const { env,
|
|
1802
|
+
const { env, state, kv, vector, messages } = opts;
|
|
2153
1803
|
return {
|
|
2154
|
-
sessionId: sessionId ?? "",
|
|
2155
1804
|
env: { ...env },
|
|
2156
|
-
abortSignal: AbortSignal.timeout(
|
|
1805
|
+
abortSignal: AbortSignal.timeout(TOOL_EXECUTION_TIMEOUT_MS),
|
|
2157
1806
|
state: state ?? {},
|
|
2158
1807
|
get kv() {
|
|
2159
1808
|
if (!kv) throw new Error("KV not available");
|
|
@@ -2182,21 +1831,18 @@ async function executeToolCall(name, args, options) {
|
|
|
2182
1831
|
if (result == null) return "null";
|
|
2183
1832
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
2184
1833
|
} 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
1834
|
console.warn(`[tool-executor] Tool execution failed: ${name}`, err);
|
|
2190
|
-
return `Error: ${
|
|
1835
|
+
return `Error: ${errorMessage(err)}`;
|
|
2191
1836
|
}
|
|
2192
1837
|
}
|
|
2193
|
-
var yieldTick
|
|
1838
|
+
var yieldTick;
|
|
2194
1839
|
var init_worker_entry = __esm({
|
|
2195
1840
|
"sdk/worker_entry.ts"() {
|
|
2196
1841
|
"use strict";
|
|
2197
1842
|
init_internal_types();
|
|
1843
|
+
init_utils();
|
|
1844
|
+
init_protocol();
|
|
2198
1845
|
yieldTick = () => new Promise((r) => setTimeout(r, 0));
|
|
2199
|
-
TOOL_HANDLER_TIMEOUT = 3e4;
|
|
2200
1846
|
}
|
|
2201
1847
|
});
|
|
2202
1848
|
|
|
@@ -2248,7 +1894,6 @@ function createDirectExecutor(opts) {
|
|
|
2248
1894
|
}
|
|
2249
1895
|
function makeHookContext(sessionId) {
|
|
2250
1896
|
return {
|
|
2251
|
-
sessionId,
|
|
2252
1897
|
env: frozenEnv,
|
|
2253
1898
|
state: getState(sessionId),
|
|
2254
1899
|
get kv() {
|
|
@@ -2265,7 +1910,6 @@ function createDirectExecutor(opts) {
|
|
|
2265
1910
|
return executeToolCall(name, args, {
|
|
2266
1911
|
tool: tool2,
|
|
2267
1912
|
env: frozenEnv,
|
|
2268
|
-
sessionId,
|
|
2269
1913
|
state: getState(sessionId ?? ""),
|
|
2270
1914
|
kv,
|
|
2271
1915
|
vector,
|
|
@@ -2344,9 +1988,6 @@ var init_direct_executor = __esm({
|
|
|
2344
1988
|
});
|
|
2345
1989
|
|
|
2346
1990
|
// 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
1991
|
function createClientSink(ws) {
|
|
2351
1992
|
function safeSend(data) {
|
|
2352
1993
|
try {
|
|
@@ -2378,19 +2019,9 @@ function toUint8Array(data) {
|
|
|
2378
2019
|
const buf = data;
|
|
2379
2020
|
return new Uint8Array(buf.buffer ?? data, buf.byteOffset ?? 0, buf.byteLength);
|
|
2380
2021
|
}
|
|
2381
|
-
function handleBinaryAudio(data, session
|
|
2022
|
+
function handleBinaryAudio(data, session) {
|
|
2382
2023
|
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);
|
|
2024
|
+
session.onAudio(toUint8Array(data));
|
|
2394
2025
|
return true;
|
|
2395
2026
|
}
|
|
2396
2027
|
function handleTextMessage(data, session, log, ctx, sid) {
|
|
@@ -2425,7 +2056,7 @@ function handleTextMessage(data, session, log, ctx, sid) {
|
|
|
2425
2056
|
}
|
|
2426
2057
|
function wireSessionSocket(ws, opts) {
|
|
2427
2058
|
const { sessions, logger: log = consoleLogger } = opts;
|
|
2428
|
-
const sessionId =
|
|
2059
|
+
const sessionId = crypto.randomUUID();
|
|
2429
2060
|
const sid = sessionId.slice(0, 8);
|
|
2430
2061
|
const ctx = opts.logContext ?? {};
|
|
2431
2062
|
let session = null;
|
|
@@ -2436,8 +2067,11 @@ function wireSessionSocket(ws, opts) {
|
|
|
2436
2067
|
session = opts.createSession(sessionId, client);
|
|
2437
2068
|
sessions.set(sessionId, session);
|
|
2438
2069
|
ws.send(JSON.stringify({ type: "config", ...opts.readyConfig }));
|
|
2439
|
-
|
|
2440
|
-
|
|
2070
|
+
session.start().then(() => {
|
|
2071
|
+
log.info("Session ready", { ...ctx, sid });
|
|
2072
|
+
}).catch((err) => {
|
|
2073
|
+
log.error("Session start failed", { ...ctx, sid, error: errorMessage(err) });
|
|
2074
|
+
});
|
|
2441
2075
|
}
|
|
2442
2076
|
if (ws.readyState === 1) {
|
|
2443
2077
|
onOpen();
|
|
@@ -2447,7 +2081,7 @@ function wireSessionSocket(ws, opts) {
|
|
|
2447
2081
|
ws.addEventListener("message", (event) => {
|
|
2448
2082
|
if (!session) return;
|
|
2449
2083
|
const { data } = event;
|
|
2450
|
-
if (handleBinaryAudio(data, session
|
|
2084
|
+
if (handleBinaryAudio(data, session)) return;
|
|
2451
2085
|
handleTextMessage(data, session, log, ctx, sid);
|
|
2452
2086
|
});
|
|
2453
2087
|
ws.addEventListener("close", () => {
|
|
@@ -2464,13 +2098,12 @@ function wireSessionSocket(ws, opts) {
|
|
|
2464
2098
|
log.error("WebSocket error", { ...ctx, sid, error: msg });
|
|
2465
2099
|
});
|
|
2466
2100
|
}
|
|
2467
|
-
var MAX_AUDIO_CHUNK_BYTES;
|
|
2468
2101
|
var init_ws_handler = __esm({
|
|
2469
2102
|
"sdk/ws_handler.ts"() {
|
|
2470
2103
|
"use strict";
|
|
2104
|
+
init_utils();
|
|
2471
2105
|
init_protocol();
|
|
2472
2106
|
init_runtime();
|
|
2473
|
-
MAX_AUDIO_CHUNK_BYTES = 1048576;
|
|
2474
2107
|
}
|
|
2475
2108
|
});
|
|
2476
2109
|
|
|
@@ -2529,8 +2162,7 @@ function createWintercServer(options) {
|
|
|
2529
2162
|
skipGreeting: wsOpts?.skipGreeting ?? false
|
|
2530
2163
|
}),
|
|
2531
2164
|
readyConfig,
|
|
2532
|
-
logger
|
|
2533
|
-
uid: wsOpts?.uid
|
|
2165
|
+
logger
|
|
2534
2166
|
});
|
|
2535
2167
|
},
|
|
2536
2168
|
async close() {
|
|
@@ -2565,7 +2197,7 @@ async function loadWsFactory() {
|
|
|
2565
2197
|
try {
|
|
2566
2198
|
const mod = await import("ws");
|
|
2567
2199
|
const WS = mod.default ?? mod;
|
|
2568
|
-
return (url, opts) => new WS(url, { headers: opts.headers });
|
|
2200
|
+
return (url, opts) => wrapOnStyleWebSocket(new WS(url, { headers: opts.headers }));
|
|
2569
2201
|
} catch {
|
|
2570
2202
|
throw new Error(
|
|
2571
2203
|
"WebSocket factory not provided and `ws` package not found. Install `ws` (`npm install ws`) or pass `createWebSocket` option."
|
|
@@ -2573,11 +2205,7 @@ async function loadWsFactory() {
|
|
|
2573
2205
|
}
|
|
2574
2206
|
}
|
|
2575
2207
|
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;
|
|
2208
|
+
return Object.fromEntries(Object.entries(env).filter(([, v]) => v !== void 0));
|
|
2581
2209
|
}
|
|
2582
2210
|
function createServer(options) {
|
|
2583
2211
|
const {
|
|
@@ -2624,6 +2252,23 @@ function createServer(options) {
|
|
|
2624
2252
|
await getWsFactory();
|
|
2625
2253
|
const wintercServer = getWinterc();
|
|
2626
2254
|
const app = new Hono2();
|
|
2255
|
+
app.onError((err, c) => {
|
|
2256
|
+
logger.error(`${c.req.method} ${new URL(c.req.url).pathname} error: ${err.message}`);
|
|
2257
|
+
return c.json({ error: "Internal Server Error" }, 500);
|
|
2258
|
+
});
|
|
2259
|
+
app.use("/*", async (c, next) => {
|
|
2260
|
+
const start = Date.now();
|
|
2261
|
+
await next();
|
|
2262
|
+
const ms = Date.now() - start;
|
|
2263
|
+
const status = c.res.status;
|
|
2264
|
+
const method = c.req.method;
|
|
2265
|
+
const path8 = new URL(c.req.url).pathname;
|
|
2266
|
+
if (status >= 400) {
|
|
2267
|
+
logger.error(`${method} ${path8} ${status} ${ms}ms`);
|
|
2268
|
+
} else {
|
|
2269
|
+
logger.info(`${method} ${path8} ${status} ${ms}ms`);
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2627
2272
|
if (clientDir) {
|
|
2628
2273
|
app.use("/*", serveStatic({ root: clientDir }));
|
|
2629
2274
|
}
|
|
@@ -2636,11 +2281,12 @@ function createServer(options) {
|
|
|
2636
2281
|
const wsMod = await import("ws");
|
|
2637
2282
|
const wss = new wsMod.WebSocketServer({ noServer: true });
|
|
2638
2283
|
nodeServer.on("upgrade", (req, socket, head) => {
|
|
2284
|
+
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2285
|
+
const resume = reqUrl.searchParams.has("resume");
|
|
2286
|
+
logger.info(`WS upgrade ${reqUrl.pathname}${resume ? " (resume)" : ""}`);
|
|
2639
2287
|
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
2640
|
-
const reqUrl = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2641
2288
|
wintercServer.handleWebSocket(ws, {
|
|
2642
|
-
skipGreeting:
|
|
2643
|
-
uid: reqUrl.searchParams.get("uid") ?? void 0
|
|
2289
|
+
skipGreeting: resume
|
|
2644
2290
|
});
|
|
2645
2291
|
});
|
|
2646
2292
|
});
|
|
@@ -2665,88 +2311,30 @@ var init_server = __esm({
|
|
|
2665
2311
|
"sdk/server.ts"() {
|
|
2666
2312
|
"use strict";
|
|
2667
2313
|
init_runtime();
|
|
2314
|
+
init_s2s();
|
|
2668
2315
|
init_winterc_server();
|
|
2669
2316
|
}
|
|
2670
2317
|
});
|
|
2671
2318
|
|
|
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
2319
|
// cli/_server_common.ts
|
|
2725
|
-
init_discover();
|
|
2726
2320
|
import fs5 from "node:fs/promises";
|
|
2727
|
-
import
|
|
2728
|
-
import {
|
|
2321
|
+
import path5 from "node:path";
|
|
2322
|
+
import { tsImport } from "tsx/esm/api";
|
|
2729
2323
|
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();
|
|
2324
|
+
const agentPath = path5.resolve(cwd, "agent.ts");
|
|
2325
|
+
const agentModule = await tsImport(agentPath, cwd);
|
|
2326
|
+
let agentDef = agentModule.default;
|
|
2327
|
+
if (agentDef?.__esModule && agentDef.default) {
|
|
2328
|
+
agentDef = agentDef.default;
|
|
2329
|
+
}
|
|
2330
|
+
if (!agentDef || typeof agentDef !== "object" || !agentDef.name) {
|
|
2331
|
+
throw new Error("agent.ts must export a default agent definition (from defineAgent())");
|
|
2745
2332
|
}
|
|
2333
|
+
return agentDef;
|
|
2746
2334
|
}
|
|
2747
|
-
async function resolveServerEnv() {
|
|
2335
|
+
async function resolveServerEnv(baseEnv) {
|
|
2748
2336
|
const env = Object.fromEntries(
|
|
2749
|
-
Object.entries(process.env).filter((e) => e[1] !== void 0)
|
|
2337
|
+
Object.entries(baseEnv ?? process.env).filter((e) => e[1] !== void 0)
|
|
2750
2338
|
);
|
|
2751
2339
|
if (!env.ASSEMBLYAI_API_KEY) {
|
|
2752
2340
|
env.ASSEMBLYAI_API_KEY = await getApiKey();
|
|
@@ -2754,10 +2342,11 @@ async function resolveServerEnv() {
|
|
|
2754
2342
|
return env;
|
|
2755
2343
|
}
|
|
2756
2344
|
async function bootServer(agentDef, clientDir, env, port) {
|
|
2345
|
+
const { wrapOnStyleWebSocket: wrapOnStyleWebSocket2 } = await Promise.resolve().then(() => (init_s2s(), s2s_exports));
|
|
2757
2346
|
const wsMod = await import("ws");
|
|
2758
2347
|
const WS = wsMod.default ?? wsMod;
|
|
2759
|
-
const createWebSocket = (url, opts) => new WS(url, { headers: opts.headers });
|
|
2760
|
-
const clientHtml = await fs5.readFile(
|
|
2348
|
+
const createWebSocket = (url, opts) => wrapOnStyleWebSocket2(new WS(url, { headers: opts.headers }));
|
|
2349
|
+
const clientHtml = await fs5.readFile(path5.join(clientDir, "index.html"), "utf-8");
|
|
2761
2350
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
2762
2351
|
const server = createServer2({
|
|
2763
2352
|
agent: agentDef,
|
|
@@ -2768,155 +2357,186 @@ async function bootServer(agentDef, clientDir, env, port) {
|
|
|
2768
2357
|
});
|
|
2769
2358
|
await server.listen(port);
|
|
2770
2359
|
}
|
|
2360
|
+
var init_server_common = __esm({
|
|
2361
|
+
"cli/_server_common.ts"() {
|
|
2362
|
+
"use strict";
|
|
2363
|
+
init_discover();
|
|
2364
|
+
}
|
|
2365
|
+
});
|
|
2771
2366
|
|
|
2772
|
-
// cli/
|
|
2367
|
+
// cli/dev.tsx
|
|
2368
|
+
var dev_exports = {};
|
|
2369
|
+
__export(dev_exports, {
|
|
2370
|
+
_startDevServer: () => _startDevServer,
|
|
2371
|
+
runDevCommand: () => runDevCommand
|
|
2372
|
+
});
|
|
2373
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2773
2374
|
async function _startDevServer(cwd, port, log) {
|
|
2774
2375
|
const bundle = await buildAgentBundle(cwd, log, { skipRenderCheck: true });
|
|
2775
2376
|
const agentDef = await loadAgentDef(cwd);
|
|
2776
2377
|
const env = await resolveServerEnv();
|
|
2777
2378
|
await bootServer(agentDef, bundle.clientDir, env, port);
|
|
2778
|
-
log(
|
|
2379
|
+
log(/* @__PURE__ */ jsx6(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
2779
2380
|
}
|
|
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" }
|
|
2381
|
+
async function runDevCommand(opts) {
|
|
2382
|
+
const port = Number.parseInt(opts.port, 10);
|
|
2383
|
+
await runWithInk(async ({ log }) => {
|
|
2384
|
+
await _startDevServer(opts.cwd, port, log);
|
|
2802
2385
|
});
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2386
|
+
}
|
|
2387
|
+
var init_dev = __esm({
|
|
2388
|
+
"cli/dev.tsx"() {
|
|
2389
|
+
"use strict";
|
|
2390
|
+
init_build();
|
|
2391
|
+
init_ink();
|
|
2392
|
+
init_server_common();
|
|
2806
2393
|
}
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2394
|
+
});
|
|
2395
|
+
|
|
2396
|
+
// cli/start.tsx
|
|
2397
|
+
var start_exports = {};
|
|
2398
|
+
__export(start_exports, {
|
|
2399
|
+
_startProductionServer: () => _startProductionServer,
|
|
2400
|
+
runStartCommand: () => runStartCommand
|
|
2401
|
+
});
|
|
2402
|
+
import path6 from "node:path";
|
|
2403
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2404
|
+
async function _startProductionServer(cwd, port, log) {
|
|
2405
|
+
const clientDir = path6.join(cwd, ".aai", "client");
|
|
2406
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Start", msg: "loading agent" }));
|
|
2407
|
+
const agentDef = await loadAgentDef(cwd);
|
|
2408
|
+
const env = await resolveServerEnv();
|
|
2409
|
+
await bootServer(agentDef, clientDir, env, port);
|
|
2410
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Ready", msg: `http://localhost:${port}` }));
|
|
2411
|
+
}
|
|
2412
|
+
async function runStartCommand(opts) {
|
|
2413
|
+
const port = Number.parseInt(opts.port, 10);
|
|
2414
|
+
const buildDir = path6.join(opts.cwd, ".aai", "build");
|
|
2415
|
+
if (!await fileExists(path6.join(buildDir, "worker.js"))) {
|
|
2416
|
+
throw new Error("No build found \u2014 run `aai build` first");
|
|
2811
2417
|
}
|
|
2812
|
-
await
|
|
2813
|
-
|
|
2814
|
-
await
|
|
2418
|
+
await runWithInk(async ({ log }) => {
|
|
2419
|
+
log(/* @__PURE__ */ jsx7(Step, { action: "Start", msg: `production server on port ${port}` }));
|
|
2420
|
+
await _startProductionServer(opts.cwd, port, log);
|
|
2815
2421
|
});
|
|
2816
2422
|
}
|
|
2423
|
+
var init_start = __esm({
|
|
2424
|
+
"cli/start.tsx"() {
|
|
2425
|
+
"use strict";
|
|
2426
|
+
init_discover();
|
|
2427
|
+
init_ink();
|
|
2428
|
+
init_server_common();
|
|
2429
|
+
}
|
|
2430
|
+
});
|
|
2817
2431
|
|
|
2818
|
-
// cli/
|
|
2819
|
-
|
|
2432
|
+
// cli/secret.tsx
|
|
2433
|
+
var secret_exports = {};
|
|
2434
|
+
__export(secret_exports, {
|
|
2435
|
+
runSecretDelete: () => runSecretDelete,
|
|
2436
|
+
runSecretList: () => runSecretList,
|
|
2437
|
+
runSecretPut: () => runSecretPut
|
|
2438
|
+
});
|
|
2439
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
2440
|
+
async function apiFetch(cwd, pathSuffix, init) {
|
|
2441
|
+
const { serverUrl, slug, apiKey } = await getServerInfo(cwd);
|
|
2442
|
+
const resp = await fetch(`${serverUrl}/${slug}/secret${pathSuffix}`, {
|
|
2443
|
+
...init,
|
|
2444
|
+
headers: { Authorization: `Bearer ${apiKey}`, ...init?.headers }
|
|
2445
|
+
});
|
|
2446
|
+
if (!resp.ok) {
|
|
2447
|
+
const text = await resp.text();
|
|
2448
|
+
throw new Error(`Secret operation failed: ${text}`);
|
|
2449
|
+
}
|
|
2450
|
+
return { resp, slug };
|
|
2451
|
+
}
|
|
2452
|
+
async function runSecretPut(cwd, name) {
|
|
2453
|
+
const value = await askPassword(`Enter value for ${name}`);
|
|
2454
|
+
if (!value) throw new Error("No value provided");
|
|
2455
|
+
await runWithInk(async ({ log }) => {
|
|
2456
|
+
const { slug } = await apiFetch(cwd, "", {
|
|
2457
|
+
method: "PUT",
|
|
2458
|
+
headers: { "Content-Type": "application/json" },
|
|
2459
|
+
body: JSON.stringify({ [name]: value })
|
|
2460
|
+
});
|
|
2461
|
+
log(/* @__PURE__ */ jsx8(Step, { action: "Set", msg: `${name} for ${slug}` }));
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
async function runSecretDelete(cwd, name) {
|
|
2465
|
+
await runWithInk(async ({ log }) => {
|
|
2466
|
+
const { slug } = await apiFetch(cwd, `/${name}`, { method: "DELETE" });
|
|
2467
|
+
log(/* @__PURE__ */ jsx8(Step, { action: "Deleted", msg: `${name} from ${slug}` }));
|
|
2468
|
+
});
|
|
2469
|
+
}
|
|
2470
|
+
async function runSecretList(cwd) {
|
|
2471
|
+
await runWithInk(async ({ log }) => {
|
|
2472
|
+
const { resp } = await apiFetch(cwd, "");
|
|
2473
|
+
const { vars } = await resp.json();
|
|
2474
|
+
if (vars.length === 0) {
|
|
2475
|
+
log(/* @__PURE__ */ jsx8(StepInfo, { action: "Secrets", msg: "none set" }));
|
|
2476
|
+
} else {
|
|
2477
|
+
for (const name of vars) {
|
|
2478
|
+
log(/* @__PURE__ */ jsx8(Detail, { msg: name }));
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
2482
|
+
}
|
|
2483
|
+
var init_secret = __esm({
|
|
2484
|
+
"cli/secret.tsx"() {
|
|
2485
|
+
"use strict";
|
|
2486
|
+
init_discover();
|
|
2487
|
+
init_ink();
|
|
2488
|
+
init_prompts();
|
|
2489
|
+
}
|
|
2490
|
+
});
|
|
2820
2491
|
|
|
2821
2492
|
// cli/rag.tsx
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2493
|
+
var rag_exports = {};
|
|
2494
|
+
__export(rag_exports, {
|
|
2495
|
+
chunkPages: () => chunkPages,
|
|
2496
|
+
parsePage: () => parsePage,
|
|
2497
|
+
runRagCommand: () => runRagCommand,
|
|
2498
|
+
slugify: () => slugify,
|
|
2499
|
+
splitPages: () => splitPages,
|
|
2500
|
+
stripNoise: () => stripNoise,
|
|
2501
|
+
upsertChunks: () => upsertChunks
|
|
2502
|
+
});
|
|
2503
|
+
import { Text as Text3 } from "ink";
|
|
2827
2504
|
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
|
-
}
|
|
2505
|
+
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2886
2506
|
async function runRag(opts) {
|
|
2887
|
-
const { url, apiKey, serverUrl, slug, chunkSize, log,
|
|
2888
|
-
log(/* @__PURE__ */
|
|
2507
|
+
const { url, apiKey, serverUrl, slug, chunkSize, log, setStatus } = opts;
|
|
2508
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Fetch", msg: url }));
|
|
2889
2509
|
const resp = await fetch(url, {
|
|
2890
2510
|
headers: { "User-Agent": "aai-cli/1.0" },
|
|
2891
2511
|
redirect: "follow",
|
|
2892
|
-
signal: AbortSignal.timeout(
|
|
2512
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
2893
2513
|
});
|
|
2894
2514
|
if (!resp.ok) {
|
|
2895
2515
|
throw new Error(`Failed to fetch: ${resp.status} ${resp.statusText}`);
|
|
2896
2516
|
}
|
|
2897
2517
|
const content = await resp.text();
|
|
2898
2518
|
if (content.length === 0) {
|
|
2899
|
-
log(/* @__PURE__ */
|
|
2519
|
+
log(/* @__PURE__ */ jsx9(Warn, { msg: "File is empty" }));
|
|
2900
2520
|
return;
|
|
2901
2521
|
}
|
|
2902
|
-
log(/* @__PURE__ */
|
|
2522
|
+
log(/* @__PURE__ */ jsx9(Info, { msg: `${(content.length / 1024).toFixed(0)} KB` }));
|
|
2903
2523
|
const origin = new URL(url).origin;
|
|
2904
2524
|
const pages = splitPages(content);
|
|
2905
|
-
log(/* @__PURE__ */
|
|
2525
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Parse", msg: `${pages.length} pages` }));
|
|
2906
2526
|
const { RecursiveChunker } = await import("@chonkiejs/core");
|
|
2907
2527
|
const chunker = await RecursiveChunker.create({ chunkSize });
|
|
2908
2528
|
const siteSlug = slugify(origin);
|
|
2909
2529
|
const allChunks = await chunkPages(pages, chunker, origin, siteSlug);
|
|
2910
|
-
log(/* @__PURE__ */
|
|
2530
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Chunk", msg: `${allChunks.length} chunks` }));
|
|
2911
2531
|
const vectorUrl = `${serverUrl}/${slug}/vector`;
|
|
2912
|
-
log(/* @__PURE__ */
|
|
2913
|
-
const result = await upsertChunks(allChunks, vectorUrl, apiKey,
|
|
2914
|
-
log(/* @__PURE__ */
|
|
2532
|
+
log(/* @__PURE__ */ jsx9(Info, { msg: `target: ${vectorUrl}` }));
|
|
2533
|
+
const result = await upsertChunks(allChunks, vectorUrl, apiKey, setStatus);
|
|
2534
|
+
log(/* @__PURE__ */ jsx9(Step, { action: "Done", msg: `${result.upserted} chunks upserted` }));
|
|
2915
2535
|
if (result.errors > 0) {
|
|
2916
|
-
log(/* @__PURE__ */
|
|
2917
|
-
if (result.lastError) log(/* @__PURE__ */
|
|
2536
|
+
log(/* @__PURE__ */ jsx9(Warn, { msg: `${result.errors} failed` }));
|
|
2537
|
+
if (result.lastError) log(/* @__PURE__ */ jsx9(Info, { msg: `last error: ${result.lastError}` }));
|
|
2918
2538
|
}
|
|
2919
|
-
log(/* @__PURE__ */
|
|
2539
|
+
log(/* @__PURE__ */ jsx9(Detail, { msg: `Agent: ${slug}` }));
|
|
2920
2540
|
}
|
|
2921
2541
|
async function chunkPages(pages, chunker, origin, siteSlug) {
|
|
2922
2542
|
const allChunks = [];
|
|
@@ -2942,19 +2562,34 @@ ${c.text}` : c.text;
|
|
|
2942
2562
|
}
|
|
2943
2563
|
return allChunks;
|
|
2944
2564
|
}
|
|
2945
|
-
async function upsertChunks(chunks, vectorUrl, apiKey,
|
|
2565
|
+
async function upsertChunks(chunks, vectorUrl, apiKey, setStatus, fetchFn = globalThis.fetch) {
|
|
2946
2566
|
const total = chunks.length;
|
|
2947
2567
|
let completed = 0;
|
|
2948
2568
|
let upserted = 0;
|
|
2949
2569
|
let errors = 0;
|
|
2950
2570
|
let lastError = "";
|
|
2951
|
-
|
|
2571
|
+
const updateStatus = () => {
|
|
2572
|
+
const pct = Math.round(completed / total * 100);
|
|
2573
|
+
setStatus(
|
|
2574
|
+
/* @__PURE__ */ jsxs3(Text3, { children: [
|
|
2575
|
+
" ",
|
|
2576
|
+
"Upsert ",
|
|
2577
|
+
completed,
|
|
2578
|
+
"/",
|
|
2579
|
+
total,
|
|
2580
|
+
" (",
|
|
2581
|
+
pct,
|
|
2582
|
+
"%)"
|
|
2583
|
+
] })
|
|
2584
|
+
);
|
|
2585
|
+
};
|
|
2586
|
+
updateStatus();
|
|
2952
2587
|
const limit = pLimit(5);
|
|
2953
2588
|
await Promise.all(
|
|
2954
2589
|
chunks.map(
|
|
2955
2590
|
(chunk) => limit(async () => {
|
|
2956
2591
|
try {
|
|
2957
|
-
const r = await
|
|
2592
|
+
const r = await fetchFn(vectorUrl, {
|
|
2958
2593
|
method: "POST",
|
|
2959
2594
|
headers: {
|
|
2960
2595
|
"Content-Type": "application/json",
|
|
@@ -2974,65 +2609,29 @@ async function upsertChunks(chunks, vectorUrl, apiKey, setProgress) {
|
|
|
2974
2609
|
upserted++;
|
|
2975
2610
|
}
|
|
2976
2611
|
} catch (err) {
|
|
2977
|
-
lastError =
|
|
2612
|
+
lastError = errorMessage(err);
|
|
2978
2613
|
errors++;
|
|
2979
2614
|
}
|
|
2980
2615
|
completed++;
|
|
2981
|
-
|
|
2616
|
+
updateStatus();
|
|
2982
2617
|
})
|
|
2983
2618
|
)
|
|
2984
2619
|
);
|
|
2620
|
+
setStatus(null);
|
|
2985
2621
|
return { upserted, errors, lastError };
|
|
2986
2622
|
}
|
|
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
|
-
}
|
|
2623
|
+
async function runRagCommand(opts) {
|
|
2624
|
+
const { url, cwd } = opts;
|
|
3004
2625
|
try {
|
|
3005
2626
|
new URL(url);
|
|
3006
2627
|
} catch {
|
|
3007
2628
|
throw new Error(`Invalid URL: ${url}`);
|
|
3008
2629
|
}
|
|
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;
|
|
2630
|
+
const { apiKey, serverUrl, slug } = await getServerInfo(cwd, opts.server);
|
|
2631
|
+
const chunkSize = Number.parseInt(opts.chunkSize ?? "512", 10);
|
|
2632
|
+
await runWithInk(async ({ log, setStatus }) => {
|
|
2633
|
+
await runRag({ url, apiKey, serverUrl, slug, chunkSize, log, setStatus });
|
|
2634
|
+
});
|
|
3036
2635
|
}
|
|
3037
2636
|
function splitPages(content) {
|
|
3038
2637
|
const raw = content.split(/^\*{3,}$/m);
|
|
@@ -3079,243 +2678,153 @@ function stripNoise(text) {
|
|
|
3079
2678
|
function slugify(s) {
|
|
3080
2679
|
return s.replace(/^https?:\/\//, "").replace(/^#+\s*/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase().slice(0, 80);
|
|
3081
2680
|
}
|
|
2681
|
+
var FETCH_TIMEOUT_MS2;
|
|
2682
|
+
var init_rag = __esm({
|
|
2683
|
+
"cli/rag.tsx"() {
|
|
2684
|
+
"use strict";
|
|
2685
|
+
init_utils();
|
|
2686
|
+
init_discover();
|
|
2687
|
+
init_ink();
|
|
2688
|
+
FETCH_TIMEOUT_MS2 = 6e4;
|
|
2689
|
+
}
|
|
2690
|
+
});
|
|
3082
2691
|
|
|
3083
|
-
// cli/
|
|
2692
|
+
// cli/cli.ts
|
|
2693
|
+
init_utils();
|
|
3084
2694
|
init_discover();
|
|
3085
|
-
init_help();
|
|
3086
2695
|
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
|
-
|
|
2696
|
+
import { readFileSync } from "node:fs";
|
|
2697
|
+
import path7 from "node:path";
|
|
2698
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2699
|
+
import chalk2 from "chalk";
|
|
2700
|
+
import { Command } from "commander";
|
|
2701
|
+
var cliDir = path7.dirname(fileURLToPath2(import.meta.url));
|
|
2702
|
+
var pkgJsonPath = path7.join(cliDir, "..", "package.json");
|
|
2703
|
+
var pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
2704
|
+
var VERSION = pkgJson.version;
|
|
2705
|
+
var banner = [
|
|
2706
|
+
"",
|
|
2707
|
+
` ${primary(chalk2.bold(" \u2584\u2580\u2588 \u2584\u2580\u2588 \u2588"))} ${chalk2.dim("Voice agent development kit")}`,
|
|
2708
|
+
` ${primary(chalk2.bold(" \u2588\u2580\u2588 \u2588\u2580\u2588 \u2588"))} ${primary(`v${VERSION}`)}`,
|
|
2709
|
+
""
|
|
2710
|
+
].join("\n");
|
|
2711
|
+
var gettingStarted = [
|
|
2712
|
+
"",
|
|
2713
|
+
` ${chalk2.bold(interactive("Getting started"))}`,
|
|
2714
|
+
"",
|
|
2715
|
+
` ${chalk2.dim("$")} ${primary("aai init")} ${interactive("my-agent")}`,
|
|
2716
|
+
` ${chalk2.dim("$")} ${primary("cd")} ${interactive("my-agent")}`,
|
|
2717
|
+
` ${chalk2.dim("$")} ${primary("aai dev")}`,
|
|
2718
|
+
""
|
|
2719
|
+
].join("\n");
|
|
2720
|
+
async function ensureAgent(cwd, yes) {
|
|
2721
|
+
if (!await fileExists(path7.join(cwd, "agent.ts"))) {
|
|
2722
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2723
|
+
await runInitCommand2({ yes }, { quiet: true });
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
function withCwd(cmd) {
|
|
2727
|
+
return cmd.hook("preAction", (thisCmd) => {
|
|
2728
|
+
thisCmd.setOptionValue("cwd", resolveCwd());
|
|
3111
2729
|
});
|
|
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
2730
|
}
|
|
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}` }));
|
|
2731
|
+
function withAgentGuard(cmd) {
|
|
2732
|
+
return cmd.hook("preAction", async (thisCmd) => {
|
|
2733
|
+
await ensureAgent(thisCmd.getOptionValue("cwd"), thisCmd.opts().yes);
|
|
3163
2734
|
});
|
|
3164
2735
|
}
|
|
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}` }));
|
|
2736
|
+
function withApiKey(cmd) {
|
|
2737
|
+
return cmd.hook("preAction", async () => {
|
|
2738
|
+
await getApiKey();
|
|
3178
2739
|
});
|
|
3179
2740
|
}
|
|
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
|
-
}
|
|
2741
|
+
function createProgram() {
|
|
2742
|
+
const program = new Command();
|
|
2743
|
+
program.name("aai").version(VERSION, "-V, --version").addHelpText("before", banner).addHelpText("after", gettingStarted);
|
|
2744
|
+
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(
|
|
2745
|
+
async (dir, opts) => {
|
|
2746
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2747
|
+
await runInitCommand2({ dir, ...opts });
|
|
3197
2748
|
}
|
|
2749
|
+
);
|
|
2750
|
+
withApiKey(
|
|
2751
|
+
withAgentGuard(
|
|
2752
|
+
withCwd(
|
|
2753
|
+
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) => {
|
|
2754
|
+
const { runDevCommand: runDevCommand2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
|
|
2755
|
+
await runDevCommand2(opts);
|
|
2756
|
+
})
|
|
2757
|
+
)
|
|
2758
|
+
)
|
|
2759
|
+
);
|
|
2760
|
+
withAgentGuard(
|
|
2761
|
+
withCwd(
|
|
2762
|
+
program.command("build").description("Bundle and validate (no server or deploy)").option("-y, --yes", "Accept defaults (no prompts)").action(async (opts) => {
|
|
2763
|
+
const { runBuildCommand: runBuildCommand2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
2764
|
+
await runBuildCommand2(opts.cwd);
|
|
2765
|
+
})
|
|
2766
|
+
)
|
|
2767
|
+
);
|
|
2768
|
+
withAgentGuard(
|
|
2769
|
+
withCwd(
|
|
2770
|
+
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) => {
|
|
2771
|
+
const { runDeployCommand: runDeployCommand2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
|
|
2772
|
+
await runDeployCommand2(opts);
|
|
2773
|
+
})
|
|
2774
|
+
)
|
|
2775
|
+
);
|
|
2776
|
+
withApiKey(
|
|
2777
|
+
withCwd(
|
|
2778
|
+
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) => {
|
|
2779
|
+
const { runStartCommand: runStartCommand2 } = await Promise.resolve().then(() => (init_start(), start_exports));
|
|
2780
|
+
await runStartCommand2(opts);
|
|
2781
|
+
})
|
|
2782
|
+
)
|
|
2783
|
+
);
|
|
2784
|
+
const secret = program.command("secret").description("Manage secrets").action(() => secret.help());
|
|
2785
|
+
withApiKey(withCwd(secret));
|
|
2786
|
+
secret.command("put").description("Create or update a secret").argument("<name>", "Secret name").action(async (name, _opts, cmd) => {
|
|
2787
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2788
|
+
const { runSecretPut: runSecretPut2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2789
|
+
await runSecretPut2(cwd, name);
|
|
3198
2790
|
});
|
|
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" }
|
|
2791
|
+
secret.command("delete").description("Delete a secret").argument("<name>", "Secret name").action(async (name, _opts, cmd) => {
|
|
2792
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2793
|
+
const { runSecretDelete: runSecretDelete2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2794
|
+
await runSecretDelete2(cwd, name);
|
|
3239
2795
|
});
|
|
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);
|
|
2796
|
+
secret.command("list").description("List secret names").action(async (_opts, cmd) => {
|
|
2797
|
+
const cwd = cmd.parent?.getOptionValue("cwd");
|
|
2798
|
+
const { runSecretList: runSecretList2 } = await Promise.resolve().then(() => (init_secret(), secret_exports));
|
|
2799
|
+
await runSecretList2(cwd);
|
|
3254
2800
|
});
|
|
2801
|
+
withApiKey(
|
|
2802
|
+
withCwd(
|
|
2803
|
+
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) => {
|
|
2804
|
+
const { runRagCommand: runRagCommand2 } = await Promise.resolve().then(() => (init_rag(), rag_exports));
|
|
2805
|
+
await runRagCommand2({ url, ...opts });
|
|
2806
|
+
})
|
|
2807
|
+
)
|
|
2808
|
+
);
|
|
2809
|
+
return program;
|
|
3255
2810
|
}
|
|
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
2811
|
async function main(args) {
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
stopEarly: true
|
|
3267
|
-
});
|
|
3268
|
-
if (parsed.version) {
|
|
3269
|
-
console.log(VERSION);
|
|
2812
|
+
if (args.length === 0) {
|
|
2813
|
+
const { runInitCommand: runInitCommand2 } = await Promise.resolve().then(() => (init_init2(), init_exports2));
|
|
2814
|
+
await runInitCommand2({});
|
|
3270
2815
|
return;
|
|
3271
2816
|
}
|
|
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
|
-
}
|
|
2817
|
+
const program = createProgram();
|
|
2818
|
+
await program.parseAsync(args, { from: "user" });
|
|
3311
2819
|
}
|
|
3312
2820
|
if (process.env.VITEST !== "true") {
|
|
3313
2821
|
process.on("SIGINT", () => process.exit(0));
|
|
3314
2822
|
main(process.argv.slice(2)).catch((err) => {
|
|
3315
|
-
console.error(
|
|
2823
|
+
console.error(errorMessage(err));
|
|
3316
2824
|
process.exit(1);
|
|
3317
2825
|
});
|
|
3318
2826
|
}
|
|
3319
2827
|
export {
|
|
2828
|
+
createProgram,
|
|
3320
2829
|
main
|
|
3321
2830
|
};
|