@markusylisiurunen/tau 0.2.37 → 0.2.39
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/README.md +72 -4
- package/dist/core/async/cli.js +505 -0
- package/dist/core/async/cli.js.map +1 -0
- package/dist/core/async/http_protocol.js +60 -0
- package/dist/core/async/http_protocol.js.map +1 -0
- package/dist/core/async/http_server.js +260 -0
- package/dist/core/async/http_server.js.map +1 -0
- package/dist/core/async/index.js +8 -0
- package/dist/core/async/index.js.map +1 -0
- package/dist/core/async/server_config.js +282 -0
- package/dist/core/async/server_config.js.map +1 -0
- package/dist/core/async/session_manager.js +373 -0
- package/dist/core/async/session_manager.js.map +1 -0
- package/dist/core/async/telegram.js +462 -0
- package/dist/core/async/telegram.js.map +1 -0
- package/dist/core/async/workspace.js +90 -0
- package/dist/core/async/workspace.js.map +1 -0
- package/dist/core/cli.js +2 -0
- package/dist/core/cli.js.map +1 -1
- package/dist/core/config/content_loader.js +55 -3
- package/dist/core/config/content_loader.js.map +1 -1
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.js +235 -0
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/platform_support.js +7 -0
- package/dist/core/platform_support.js.map +1 -0
- package/dist/core/subagents/launch_model.js +89 -0
- package/dist/core/subagents/launch_model.js.map +1 -0
- package/dist/core/subagents/registry.js +18 -11
- package/dist/core/subagents/registry.js.map +1 -1
- package/dist/core/tools/spawn_agent.js +46 -2
- package/dist/core/tools/spawn_agent.js.map +1 -1
- package/dist/core/utils/type_guards.js +4 -0
- package/dist/core/utils/type_guards.js.map +1 -0
- package/dist/core/version.js +1 -1
- package/dist/main.js +30 -1
- package/dist/main.js.map +1 -1
- package/dist/tui/clipboard.js +81 -8
- package/dist/tui/clipboard.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -88,10 +88,35 @@ tau can run without the TUI via NDJSON RPC over stdin/stdout:
|
|
|
88
88
|
tau rpc --persona gpt-5.2-coder --risk read-only
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
RPC mode reuses the same startup config/persona/risk/sandbox loading as interactive mode. stdin/stdout are reserved for protocol traffic in this mode (piped stdin is **not** treated as an initial user message).
|
|
91
|
+
RPC mode reuses the same startup config/persona/risk/sandbox loading as interactive mode. stdin/stdout are reserved for protocol traffic in this mode (piped stdin is **not** treated as an initial user message). `--caffeinated` is a macOS-only TUI flag and is rejected in RPC mode.
|
|
92
92
|
|
|
93
93
|
for protocol details and examples, see [docs/rpc.md](docs/rpc.md).
|
|
94
94
|
|
|
95
|
+
## async daemon (http + telegram)
|
|
96
|
+
|
|
97
|
+
tau also supports an async daemon for queued/background sessions:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
tau async daemon --config-file <path>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
client command surface:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
tau async --project <id> <prompt...>
|
|
107
|
+
tau async -- <prompt...>
|
|
108
|
+
tau async list
|
|
109
|
+
tau async status <id>
|
|
110
|
+
tau async logs <id>
|
|
111
|
+
tau async send <id> <text...>
|
|
112
|
+
tau async cancel <id>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
use `tau async -- <prompt...>` when prompt text starts with a reserved command word (for example,
|
|
116
|
+
`list`).
|
|
117
|
+
|
|
118
|
+
for daemon/api/telegram details, see [docs/async.md](docs/async.md).
|
|
119
|
+
|
|
95
120
|
## sdk usage (node)
|
|
96
121
|
|
|
97
122
|
tau also ships a Node SDK at `@markusylisiurunen/tau/sdk` that talks to the same rpc subprocess (`tau rpc`) behind the scenes.
|
|
@@ -146,7 +171,7 @@ note that there is no confirmation step before tool execution. the model runs co
|
|
|
146
171
|
|
|
147
172
|
## getting started
|
|
148
173
|
|
|
149
|
-
tau requires Node.js 24.x and runs on macOS.
|
|
174
|
+
tau requires Node.js 24.x and runs on macOS and Linux (Windows is unsupported).
|
|
150
175
|
|
|
151
176
|
for development from source:
|
|
152
177
|
|
|
@@ -278,6 +303,8 @@ some personas can run isolated sub-agents via the `spawn_agent`, `send_input_to_
|
|
|
278
303
|
|
|
279
304
|
the built-in `default` sub-agent is available unless disabled. it inherits the main persona's model, settings, tool access (minus sub-agent management tools), and the session risk level. custom sub-agents can override model, reasoning, tools, and risk level. a sub-agent configured with `riskLevel: read-write` can perform writes even when the main session is `read-only`.
|
|
280
305
|
|
|
306
|
+
`spawn_agent` also supports an optional launch override string: `model: "<provider>/<model>:<effort>"`. overrides are allowlisted per subagent. custom subagents can define `launchModels` in persona frontmatter, and the built-in `default` sub-agent uses `subagents.defaultLaunchModels` from config.
|
|
307
|
+
|
|
281
308
|
sub-agent progress appears in a sticky panel. use `alt+down` to cycle active subagents and `ctrl+g` to terminate the selected one. tau caps active subagents at 8.
|
|
282
309
|
|
|
283
310
|
to use `web_search`/`web_fetch` in a sub-agent, set `apiKeys.parallel` in `~/.config/tau/config.json` (see above) or export `PARALLEL_API_KEY`. tau will only make web calls when you explicitly ask for web research.
|
|
@@ -417,7 +444,13 @@ settings merge from least-specific to most-specific.
|
|
|
417
444
|
"defaultRisk": "read-write",
|
|
418
445
|
"disableBuiltinPersonas": false,
|
|
419
446
|
"disableBuiltinThemes": false,
|
|
420
|
-
"defaultTheme": "solarized"
|
|
447
|
+
"defaultTheme": "solarized",
|
|
448
|
+
"subagents": {
|
|
449
|
+
"defaultLaunchModels": [
|
|
450
|
+
"openai/gpt-5.2:high",
|
|
451
|
+
"anthropic/claude-haiku-4-5:low"
|
|
452
|
+
]
|
|
453
|
+
}
|
|
421
454
|
}
|
|
422
455
|
```
|
|
423
456
|
|
|
@@ -427,10 +460,42 @@ the `defaultRisk` field sets the initial risk level (`read-only` or `read-write`
|
|
|
427
460
|
|
|
428
461
|
the `defaultTheme` field sets the theme id to load at startup. if not specified, it defaults to `gold`.
|
|
429
462
|
|
|
463
|
+
the `subagents.defaultLaunchModels` field configures allowed `spawn_agent` launch overrides for the built-in `default` sub-agent. values must use `<provider>/<model>:<effort>`.
|
|
464
|
+
|
|
430
465
|
if `disableBuiltinPersonas` is set to `true`, tau will not load built-in personas. if `disableBuiltinThemes` is set to `true`, tau will not load built-in themes. only entries from `~/.config/tau/` and `.tau/` will be available for those categories. you can also set these flags in any `.tau/config.json`; the most specific value wins.
|
|
431
466
|
|
|
432
467
|
the `sandbox` field configures docker sandboxing. `sandbox.image` is required when you start tau with `--sandbox`. `sandbox.mountPath` defaults to `/workspace`. `sandbox.pruneAfterHours` controls when old containers are auto-pruned (default `72`). `sandbox.extraDockerArgs` lets you pass additional `docker run` flags. `sandbox.environmentInfo` (optional) is injected into the system prompt to describe the container environment to the model.
|
|
433
468
|
|
|
469
|
+
the `async` field in normal tau config is client-side only:
|
|
470
|
+
|
|
471
|
+
- `async.client.defaultTarget` + `async.client.targets`: client-side URL/token target definitions for `tau async ...` commands.
|
|
472
|
+
|
|
473
|
+
example (`~/.config/tau/config.json` or `.tau/config.json`):
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
{
|
|
477
|
+
"async": {
|
|
478
|
+
"client": {
|
|
479
|
+
"defaultTarget": "local",
|
|
480
|
+
"targets": {
|
|
481
|
+
"local": {
|
|
482
|
+
"url": "http://127.0.0.1:7788",
|
|
483
|
+
"token": "replace-me"
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
daemon-side async settings are in a separate config file passed to:
|
|
492
|
+
|
|
493
|
+
```sh
|
|
494
|
+
tau async daemon --config-file <path>
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
see [docs/async.md](docs/async.md) for daemon config schema (`host`, `port`, `authToken`, `telegram`, `projects`, `workspaceRoot`) and GitHub repo requirements (`owner/repo`, cloned via `gh repo clone`).
|
|
498
|
+
|
|
434
499
|
### project bash commands
|
|
435
500
|
|
|
436
501
|
define shortcuts for common shell commands in any in-scope config file (`~/.config/tau/config.json` when cwd is under home, or `.tau/config.json` in the cwd ancestry). entries merge by `id` with the most specific level winning:
|
|
@@ -497,7 +562,7 @@ optional frontmatter fields:
|
|
|
497
562
|
- `reasoning`: one of `none`, `minimal`, `low`, `medium`, `high`, `xhigh`
|
|
498
563
|
- `allowedReasoningLevels`: list of reasoning levels shown in the ui
|
|
499
564
|
- `skills`: list of enabled skill names (matched by `name` in skill frontmatter), or `"*"` to enable all discovered skills
|
|
500
|
-
- `subagents`: optional map of subagent definitions. the built-in `default` sub-agent is implicit unless `default: false` is provided. custom subagents must include `systemPrompt` and may include `description`, `provider`+`model`, `reasoning`, `tools`, and `
|
|
565
|
+
- `subagents`: optional map of subagent definitions. the built-in `default` sub-agent is implicit unless `default: false` is provided. custom subagents must include `systemPrompt` and may include `description`, `provider`+`model`, `reasoning`, `tools`, `riskLevel`, and `launchModels` (when specifying a model, `provider` and `model` must be provided together). names must be lowercase with dashes (max 64 chars). `launchModels` entries must use `<provider>/<model>:<effort>` and are used to allowlist launch-time `spawn_agent` overrides. example:
|
|
501
566
|
```yaml
|
|
502
567
|
subagents:
|
|
503
568
|
default: false
|
|
@@ -510,6 +575,9 @@ optional frontmatter fields:
|
|
|
510
575
|
reasoning: medium
|
|
511
576
|
tools: [web_search, web_fetch, bash]
|
|
512
577
|
riskLevel: read-only
|
|
578
|
+
launchModels:
|
|
579
|
+
- openai/gpt-5.2:high
|
|
580
|
+
- anthropic/claude-haiku-4-5:medium
|
|
513
581
|
```
|
|
514
582
|
- `tools`: list of tool names to enable for this persona. allowed: `bash`, `write`, `edit`, `view_image`, `spawn_agent`, `send_input_to_agent`, `wait_for_agent`, `terminate_agent`. if omitted, defaults to `bash`, `write`, `edit`, `view_image` (and subagent tools when subagents are enabled). risk levels still apply.
|
|
515
583
|
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import { loadConfig } from "../config/schema.js";
|
|
2
|
+
import { startAsyncHttpServer } from "./http_server.js";
|
|
3
|
+
import { AsyncDaemonConfigError, loadAsyncDaemonConfig } from "./server_config.js";
|
|
4
|
+
import { createAsyncSessionManager } from "./session_manager.js";
|
|
5
|
+
import { startAsyncTelegramAdapter } from "./telegram.js";
|
|
6
|
+
export class AsyncCliError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "AsyncCliError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function parseValue(arg, argv, index) {
|
|
13
|
+
const eqIndex = arg.indexOf("=");
|
|
14
|
+
if (eqIndex !== -1) {
|
|
15
|
+
const value = arg.slice(eqIndex + 1).trim();
|
|
16
|
+
if (!value) {
|
|
17
|
+
throw new AsyncCliError(`missing value for ${arg.slice(0, eqIndex)}`);
|
|
18
|
+
}
|
|
19
|
+
return { value, nextIndex: index };
|
|
20
|
+
}
|
|
21
|
+
const next = argv[index + 1];
|
|
22
|
+
if (!next || next.startsWith("-")) {
|
|
23
|
+
throw new AsyncCliError(`missing value for ${arg}`);
|
|
24
|
+
}
|
|
25
|
+
const value = next.trim();
|
|
26
|
+
if (!value) {
|
|
27
|
+
throw new AsyncCliError(`missing value for ${arg}`);
|
|
28
|
+
}
|
|
29
|
+
return { value, nextIndex: index + 1 };
|
|
30
|
+
}
|
|
31
|
+
function parseAsyncArgs(argv) {
|
|
32
|
+
let help = false;
|
|
33
|
+
let projectId;
|
|
34
|
+
let targetId;
|
|
35
|
+
let url;
|
|
36
|
+
let token;
|
|
37
|
+
let configFilePath;
|
|
38
|
+
let forcePrompt = false;
|
|
39
|
+
const positional = [];
|
|
40
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
41
|
+
const arg = argv[i];
|
|
42
|
+
if (forcePrompt) {
|
|
43
|
+
positional.push(arg);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (arg === "--") {
|
|
47
|
+
forcePrompt = true;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (arg === "--help" || arg === "-h") {
|
|
51
|
+
help = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (arg === "--project" || arg.startsWith("--project=")) {
|
|
55
|
+
const parsed = parseValue(arg, argv, i);
|
|
56
|
+
i = parsed.nextIndex;
|
|
57
|
+
projectId = parsed.value;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg === "--target" || arg.startsWith("--target=")) {
|
|
61
|
+
const parsed = parseValue(arg, argv, i);
|
|
62
|
+
i = parsed.nextIndex;
|
|
63
|
+
targetId = parsed.value;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (arg === "--url" || arg.startsWith("--url=")) {
|
|
67
|
+
const parsed = parseValue(arg, argv, i);
|
|
68
|
+
i = parsed.nextIndex;
|
|
69
|
+
url = parsed.value;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (arg === "--token" || arg.startsWith("--token=")) {
|
|
73
|
+
const parsed = parseValue(arg, argv, i);
|
|
74
|
+
i = parsed.nextIndex;
|
|
75
|
+
token = parsed.value;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (arg === "--config-file" || arg.startsWith("--config-file=")) {
|
|
79
|
+
const parsed = parseValue(arg, argv, i);
|
|
80
|
+
i = parsed.nextIndex;
|
|
81
|
+
configFilePath = parsed.value;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (arg.startsWith("-")) {
|
|
85
|
+
throw new AsyncCliError(`unknown option: ${arg}`);
|
|
86
|
+
}
|
|
87
|
+
positional.push(arg);
|
|
88
|
+
}
|
|
89
|
+
const toCreateArgs = () => {
|
|
90
|
+
const prompt = positional.join(" ").trim();
|
|
91
|
+
if (!prompt) {
|
|
92
|
+
throw new AsyncCliError("missing prompt text");
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
help,
|
|
96
|
+
command: "create",
|
|
97
|
+
prompt,
|
|
98
|
+
projectId,
|
|
99
|
+
targetId,
|
|
100
|
+
url,
|
|
101
|
+
token,
|
|
102
|
+
configFilePath,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const first = positional[0];
|
|
106
|
+
if (!first) {
|
|
107
|
+
if (help) {
|
|
108
|
+
return { help: true, command: "list", projectId, targetId, url, token, configFilePath };
|
|
109
|
+
}
|
|
110
|
+
throw new AsyncCliError("missing async command or prompt");
|
|
111
|
+
}
|
|
112
|
+
if (forcePrompt) {
|
|
113
|
+
return toCreateArgs();
|
|
114
|
+
}
|
|
115
|
+
if (first === "daemon") {
|
|
116
|
+
if (positional.length === 1) {
|
|
117
|
+
return { help, command: "daemon", projectId, targetId, url, token, configFilePath };
|
|
118
|
+
}
|
|
119
|
+
return toCreateArgs();
|
|
120
|
+
}
|
|
121
|
+
if (first === "list") {
|
|
122
|
+
if (positional.length === 1) {
|
|
123
|
+
return { help, command: "list", projectId, targetId, url, token, configFilePath };
|
|
124
|
+
}
|
|
125
|
+
return toCreateArgs();
|
|
126
|
+
}
|
|
127
|
+
if (first === "status") {
|
|
128
|
+
if (positional.length === 1) {
|
|
129
|
+
throw new AsyncCliError("missing session id for status");
|
|
130
|
+
}
|
|
131
|
+
if (positional.length === 2) {
|
|
132
|
+
const sessionId = positional[1]?.trim();
|
|
133
|
+
if (!sessionId) {
|
|
134
|
+
throw new AsyncCliError("missing session id for status");
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
help,
|
|
138
|
+
command: "status",
|
|
139
|
+
sessionId,
|
|
140
|
+
projectId,
|
|
141
|
+
targetId,
|
|
142
|
+
url,
|
|
143
|
+
token,
|
|
144
|
+
configFilePath,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return toCreateArgs();
|
|
148
|
+
}
|
|
149
|
+
if (first === "logs") {
|
|
150
|
+
if (positional.length === 1) {
|
|
151
|
+
throw new AsyncCliError("missing session id for logs");
|
|
152
|
+
}
|
|
153
|
+
if (positional.length === 2) {
|
|
154
|
+
const sessionId = positional[1]?.trim();
|
|
155
|
+
if (!sessionId) {
|
|
156
|
+
throw new AsyncCliError("missing session id for logs");
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
help,
|
|
160
|
+
command: "logs",
|
|
161
|
+
sessionId,
|
|
162
|
+
projectId,
|
|
163
|
+
targetId,
|
|
164
|
+
url,
|
|
165
|
+
token,
|
|
166
|
+
configFilePath,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return toCreateArgs();
|
|
170
|
+
}
|
|
171
|
+
if (first === "send") {
|
|
172
|
+
if (positional.length === 1) {
|
|
173
|
+
throw new AsyncCliError("missing session id for send");
|
|
174
|
+
}
|
|
175
|
+
const sessionId = positional[1]?.trim();
|
|
176
|
+
if (!sessionId) {
|
|
177
|
+
throw new AsyncCliError("missing session id for send");
|
|
178
|
+
}
|
|
179
|
+
if (positional.length === 2) {
|
|
180
|
+
throw new AsyncCliError("missing message text for send");
|
|
181
|
+
}
|
|
182
|
+
const text = positional.slice(2).join(" ").trim();
|
|
183
|
+
if (!text) {
|
|
184
|
+
throw new AsyncCliError("missing message text for send");
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
help,
|
|
188
|
+
command: "send",
|
|
189
|
+
sessionId,
|
|
190
|
+
text,
|
|
191
|
+
projectId,
|
|
192
|
+
targetId,
|
|
193
|
+
url,
|
|
194
|
+
token,
|
|
195
|
+
configFilePath,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (first === "cancel") {
|
|
199
|
+
if (positional.length === 1) {
|
|
200
|
+
throw new AsyncCliError("missing session id for cancel");
|
|
201
|
+
}
|
|
202
|
+
if (positional.length === 2) {
|
|
203
|
+
const sessionId = positional[1]?.trim();
|
|
204
|
+
if (!sessionId) {
|
|
205
|
+
throw new AsyncCliError("missing session id for cancel");
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
help,
|
|
209
|
+
command: "cancel",
|
|
210
|
+
sessionId,
|
|
211
|
+
projectId,
|
|
212
|
+
targetId,
|
|
213
|
+
url,
|
|
214
|
+
token,
|
|
215
|
+
configFilePath,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return toCreateArgs();
|
|
219
|
+
}
|
|
220
|
+
return toCreateArgs();
|
|
221
|
+
}
|
|
222
|
+
function getTrimmedEnvValue(key, env) {
|
|
223
|
+
const value = env[key];
|
|
224
|
+
if (typeof value !== "string") {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
const trimmed = value.trim();
|
|
228
|
+
return trimmed || undefined;
|
|
229
|
+
}
|
|
230
|
+
function requireProjectId(projectId) {
|
|
231
|
+
if (!projectId?.trim()) {
|
|
232
|
+
throw new AsyncCliError("missing project id. use --project <id>");
|
|
233
|
+
}
|
|
234
|
+
return projectId.trim();
|
|
235
|
+
}
|
|
236
|
+
function resolveTarget(config, args) {
|
|
237
|
+
const targets = config.async?.client?.targets ?? {};
|
|
238
|
+
const configuredDefault = config.async?.client?.defaultTarget;
|
|
239
|
+
const targetIds = Object.keys(targets);
|
|
240
|
+
let selectedTargetId = args.targetId;
|
|
241
|
+
if (!selectedTargetId && (args.url === undefined || args.token === undefined)) {
|
|
242
|
+
selectedTargetId = configuredDefault ?? (targetIds.length === 1 ? targetIds[0] : undefined);
|
|
243
|
+
}
|
|
244
|
+
const selectedTarget = selectedTargetId ? targets[selectedTargetId] : undefined;
|
|
245
|
+
if (selectedTargetId && !selectedTarget) {
|
|
246
|
+
throw new AsyncCliError(`unknown async target '${selectedTargetId}'`);
|
|
247
|
+
}
|
|
248
|
+
const url = args.url ?? selectedTarget?.url;
|
|
249
|
+
const token = args.token ?? selectedTarget?.token;
|
|
250
|
+
const timeoutMs = selectedTarget?.timeoutMs;
|
|
251
|
+
if (!url) {
|
|
252
|
+
throw new AsyncCliError("missing async target url. set --url or config.async.client.targets");
|
|
253
|
+
}
|
|
254
|
+
if (!token) {
|
|
255
|
+
throw new AsyncCliError("missing async target token. set --token or config.async.client.targets");
|
|
256
|
+
}
|
|
257
|
+
return { url, token, timeoutMs };
|
|
258
|
+
}
|
|
259
|
+
function buildUrl(baseUrl, path) {
|
|
260
|
+
const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
261
|
+
return new URL(path.startsWith("/") ? path.slice(1) : path, base).toString();
|
|
262
|
+
}
|
|
263
|
+
async function requestJson(args) {
|
|
264
|
+
const controller = new AbortController();
|
|
265
|
+
const timeoutMs = args.target.timeoutMs ?? 30_000;
|
|
266
|
+
const timeout = setTimeout(() => {
|
|
267
|
+
controller.abort();
|
|
268
|
+
}, timeoutMs);
|
|
269
|
+
timeout.unref?.();
|
|
270
|
+
try {
|
|
271
|
+
const response = await args.fetchImpl(buildUrl(args.target.url, args.path), {
|
|
272
|
+
method: args.method,
|
|
273
|
+
headers: {
|
|
274
|
+
authorization: `Bearer ${args.target.token}`,
|
|
275
|
+
accept: "application/json",
|
|
276
|
+
...(args.body === undefined
|
|
277
|
+
? {}
|
|
278
|
+
: {
|
|
279
|
+
"content-type": "application/json",
|
|
280
|
+
}),
|
|
281
|
+
},
|
|
282
|
+
...(args.body === undefined ? {} : { body: JSON.stringify(args.body) }),
|
|
283
|
+
signal: controller.signal,
|
|
284
|
+
});
|
|
285
|
+
const text = await response.text();
|
|
286
|
+
let payload;
|
|
287
|
+
if (text.trim()) {
|
|
288
|
+
try {
|
|
289
|
+
payload = JSON.parse(text);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
payload = text;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (!response.ok) {
|
|
296
|
+
if (payload && typeof payload === "object" && payload !== null && "error" in payload) {
|
|
297
|
+
throw new AsyncCliError(`request failed (${response.status}): ${String(payload.error)}`);
|
|
298
|
+
}
|
|
299
|
+
throw new AsyncCliError(`request failed (${response.status})`);
|
|
300
|
+
}
|
|
301
|
+
return payload;
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (error instanceof AsyncCliError) {
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
if (error.name === "AbortError") {
|
|
308
|
+
throw new AsyncCliError(`request timed out after ${timeoutMs}ms`);
|
|
309
|
+
}
|
|
310
|
+
throw new AsyncCliError(`request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
clearTimeout(timeout);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function toJsonLine(value) {
|
|
317
|
+
return JSON.stringify(value, null, 2);
|
|
318
|
+
}
|
|
319
|
+
export function printAsyncHelp(log = console.log) {
|
|
320
|
+
log([
|
|
321
|
+
"usage:",
|
|
322
|
+
" tau async daemon --config-file <path>",
|
|
323
|
+
" tau async --project <id> <prompt...>",
|
|
324
|
+
" tau async list",
|
|
325
|
+
" tau async status <id>",
|
|
326
|
+
" tau async logs <id>",
|
|
327
|
+
" tau async send <id> <text...>",
|
|
328
|
+
" tau async cancel <id>",
|
|
329
|
+
"",
|
|
330
|
+
"options:",
|
|
331
|
+
" --project <id> project id for session creation.",
|
|
332
|
+
" --config-file <path> daemon config file path (daemon mode only).",
|
|
333
|
+
" --target <id> target id from config.async.client.targets.",
|
|
334
|
+
" --url <url> override async target base URL.",
|
|
335
|
+
" --token <token> override async bearer token.",
|
|
336
|
+
" -- treat remaining args as prompt text.",
|
|
337
|
+
" --help show this help and exit.",
|
|
338
|
+
].join("\n"));
|
|
339
|
+
}
|
|
340
|
+
async function runDaemon(args) {
|
|
341
|
+
let daemonConfig;
|
|
342
|
+
try {
|
|
343
|
+
daemonConfig = loadAsyncDaemonConfig(args.configFilePath);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
if (error instanceof AsyncDaemonConfigError) {
|
|
347
|
+
throw new AsyncCliError(error.message);
|
|
348
|
+
}
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
const authToken = getTrimmedEnvValue("TAU_ASYNC_AUTH_TOKEN", args.env) ?? daemonConfig.authToken;
|
|
352
|
+
if (!authToken) {
|
|
353
|
+
throw new AsyncCliError("missing async auth token. set authToken in daemon config or TAU_ASYNC_AUTH_TOKEN");
|
|
354
|
+
}
|
|
355
|
+
const sessionManager = createAsyncSessionManager({
|
|
356
|
+
projects: daemonConfig.projects,
|
|
357
|
+
workspaceRoot: daemonConfig.workspaceRoot,
|
|
358
|
+
maxSessions: daemonConfig.maxSessions,
|
|
359
|
+
});
|
|
360
|
+
const handle = await startAsyncHttpServer({
|
|
361
|
+
host: daemonConfig.host,
|
|
362
|
+
port: daemonConfig.port,
|
|
363
|
+
authToken,
|
|
364
|
+
sessionManager,
|
|
365
|
+
});
|
|
366
|
+
const telegramConfig = daemonConfig.telegram;
|
|
367
|
+
let telegramHandle;
|
|
368
|
+
try {
|
|
369
|
+
if (telegramConfig?.botToken) {
|
|
370
|
+
telegramHandle = await startAsyncTelegramAdapter({
|
|
371
|
+
botToken: telegramConfig.botToken,
|
|
372
|
+
projects: daemonConfig.projects,
|
|
373
|
+
defaultProjectId: telegramConfig.defaultProjectId,
|
|
374
|
+
allowedUserIds: telegramConfig.allowedUserIds,
|
|
375
|
+
allowedChatIds: telegramConfig.allowedChatIds,
|
|
376
|
+
pollIntervalMs: telegramConfig.pollIntervalMs,
|
|
377
|
+
requestTimeoutSeconds: telegramConfig.requestTimeoutSeconds,
|
|
378
|
+
sessionManager,
|
|
379
|
+
onLog: (entry) => {
|
|
380
|
+
args.stdout(`[telegram:${entry.level}] ${entry.message}`);
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
args.stdout("tau async telegram adapter enabled");
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
await Promise.allSettled([handle.close(), sessionManager.close()]);
|
|
388
|
+
throw new AsyncCliError(`failed to start telegram adapter: ${error instanceof Error ? error.message : String(error)}`);
|
|
389
|
+
}
|
|
390
|
+
args.stdout(`tau async daemon listening on ${handle.baseUrl}`);
|
|
391
|
+
await new Promise((resolvePromise) => {
|
|
392
|
+
let shuttingDown = false;
|
|
393
|
+
const onSignal = () => {
|
|
394
|
+
if (shuttingDown) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
shuttingDown = true;
|
|
398
|
+
process.off("SIGINT", onSignal);
|
|
399
|
+
process.off("SIGTERM", onSignal);
|
|
400
|
+
void Promise.allSettled([
|
|
401
|
+
handle.close(),
|
|
402
|
+
...(telegramHandle ? [telegramHandle.close()] : []),
|
|
403
|
+
sessionManager.close(),
|
|
404
|
+
]).then(() => {
|
|
405
|
+
resolvePromise();
|
|
406
|
+
});
|
|
407
|
+
};
|
|
408
|
+
process.on("SIGINT", onSignal);
|
|
409
|
+
process.on("SIGTERM", onSignal);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
export async function runAsyncCommand(argv, options = {}) {
|
|
413
|
+
const parsed = parseAsyncArgs(argv);
|
|
414
|
+
const stdout = options.stdout ?? console.log;
|
|
415
|
+
if (parsed.help) {
|
|
416
|
+
printAsyncHelp(stdout);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const cwd = options.cwd ?? process.cwd();
|
|
420
|
+
const env = options.env ?? process.env;
|
|
421
|
+
const config = options.config ?? loadConfig(cwd);
|
|
422
|
+
if (parsed.command === "daemon") {
|
|
423
|
+
if (!parsed.configFilePath) {
|
|
424
|
+
throw new AsyncCliError("missing --config-file <path> for daemon mode");
|
|
425
|
+
}
|
|
426
|
+
await runDaemon({ configFilePath: parsed.configFilePath, env, stdout });
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (parsed.configFilePath) {
|
|
430
|
+
throw new AsyncCliError("--config-file can only be used with 'tau async daemon'");
|
|
431
|
+
}
|
|
432
|
+
const target = resolveTarget(config, parsed);
|
|
433
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
434
|
+
if (parsed.command === "create") {
|
|
435
|
+
const projectId = requireProjectId(parsed.projectId);
|
|
436
|
+
const payload = await requestJson({
|
|
437
|
+
target,
|
|
438
|
+
method: "POST",
|
|
439
|
+
path: "/v1/sessions",
|
|
440
|
+
body: {
|
|
441
|
+
projectId,
|
|
442
|
+
prompt: parsed.prompt,
|
|
443
|
+
},
|
|
444
|
+
fetchImpl,
|
|
445
|
+
});
|
|
446
|
+
stdout(toJsonLine(payload));
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
if (parsed.command === "list") {
|
|
450
|
+
const payload = await requestJson({
|
|
451
|
+
target,
|
|
452
|
+
method: "GET",
|
|
453
|
+
path: "/v1/sessions",
|
|
454
|
+
fetchImpl,
|
|
455
|
+
});
|
|
456
|
+
stdout(toJsonLine(payload));
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (parsed.command === "status") {
|
|
460
|
+
const payload = await requestJson({
|
|
461
|
+
target,
|
|
462
|
+
method: "GET",
|
|
463
|
+
path: `/v1/sessions/${encodeURIComponent(parsed.sessionId ?? "")}`,
|
|
464
|
+
fetchImpl,
|
|
465
|
+
});
|
|
466
|
+
stdout(toJsonLine(payload));
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (parsed.command === "logs") {
|
|
470
|
+
const payload = await requestJson({
|
|
471
|
+
target,
|
|
472
|
+
method: "GET",
|
|
473
|
+
path: `/v1/sessions/${encodeURIComponent(parsed.sessionId ?? "")}/logs`,
|
|
474
|
+
fetchImpl,
|
|
475
|
+
});
|
|
476
|
+
stdout(toJsonLine(payload));
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (parsed.command === "send") {
|
|
480
|
+
const payload = await requestJson({
|
|
481
|
+
target,
|
|
482
|
+
method: "POST",
|
|
483
|
+
path: `/v1/sessions/${encodeURIComponent(parsed.sessionId ?? "")}/messages`,
|
|
484
|
+
body: {
|
|
485
|
+
text: parsed.text,
|
|
486
|
+
},
|
|
487
|
+
fetchImpl,
|
|
488
|
+
});
|
|
489
|
+
stdout(toJsonLine(payload));
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (parsed.command === "cancel") {
|
|
493
|
+
const payload = await requestJson({
|
|
494
|
+
target,
|
|
495
|
+
method: "POST",
|
|
496
|
+
path: `/v1/sessions/${encodeURIComponent(parsed.sessionId ?? "")}/cancel`,
|
|
497
|
+
body: {},
|
|
498
|
+
fetchImpl,
|
|
499
|
+
});
|
|
500
|
+
stdout(toJsonLine(payload));
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
throw new AsyncCliError("unsupported async command");
|
|
504
|
+
}
|
|
505
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/core/async/cli.ts"],"names":[],"mappings":"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"}
|