camelagi 0.5.50 → 0.5.51
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/core/version.js +1 -1
- package/package.json +5 -2
- package/tui/package.json +23 -0
- package/tui/src/App.tsx +161 -0
- package/tui/src/agent/parse.ts +184 -0
- package/tui/src/agent/types.ts +75 -0
- package/tui/src/commands/registry.ts +301 -0
- package/tui/src/components/ActivityIndicator.tsx +148 -0
- package/tui/src/components/ApprovalPrompt.tsx +58 -0
- package/tui/src/components/BottomBar.tsx +74 -0
- package/tui/src/components/Chat.tsx +98 -0
- package/tui/src/components/Divider.tsx +12 -0
- package/tui/src/components/HorizontalRule.tsx +12 -0
- package/tui/src/components/Input.tsx +126 -0
- package/tui/src/components/Markdown.tsx +290 -0
- package/tui/src/components/Message.tsx +77 -0
- package/tui/src/components/PermissionBanner.tsx +30 -0
- package/tui/src/components/Picker.tsx +127 -0
- package/tui/src/components/SlashMenu.tsx +46 -0
- package/tui/src/components/SubagentBlock.tsx +16 -0
- package/tui/src/components/ToolBlock.tsx +24 -0
- package/tui/src/components/Welcome.tsx +75 -0
- package/tui/src/components/tools/BashTool.tsx +27 -0
- package/tui/src/components/tools/DefaultTool.tsx +38 -0
- package/tui/src/components/tools/DiffView.tsx +91 -0
- package/tui/src/components/tools/EditGroup.tsx +97 -0
- package/tui/src/components/tools/EditTool.tsx +41 -0
- package/tui/src/components/tools/ReadTool.tsx +41 -0
- package/tui/src/components/tools/SearchTool.tsx +27 -0
- package/tui/src/components/tools/ToolHeader.tsx +48 -0
- package/tui/src/components/tools/WriteTool.tsx +54 -0
- package/tui/src/config.ts +6 -0
- package/tui/src/hooks/useAgent.ts +202 -0
- package/tui/src/main.tsx +12 -0
- package/tui/src/models.ts +26 -0
- package/tui/src/state/reducer.ts +290 -0
- package/tui/src/theme.ts +28 -0
- package/tui/src/util/nativeNotify.ts +47 -0
- package/tui/src/util/spinner.ts +11 -0
- package/tui/tsconfig.json +19 -0
package/dist/core/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "camelagi",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.51",
|
|
4
4
|
"description": "Personal AI agent powered by Claude Agent SDK — manage everything from Telegram",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"lint": "tsc --noEmit",
|
|
16
16
|
"bundle:gateway": "node esbuild.gateway.mjs",
|
|
17
17
|
"build:all": "npm run build && npm run bundle:gateway",
|
|
18
|
-
"postinstall": "echo '\n \\033[36mCamelAGI\\033[0m installed!\\n\\n Get started:\\n camel setup # First-time setup\\n camel serve # Start server\\n camel chat # Terminal UI\\n'",
|
|
18
|
+
"postinstall": "echo '\n \\033[36mCamelAGI\\033[0m installed!\\n\\n Get started:\\n camel setup # First-time setup\\n camel serve # Start server\\n camel chat # Terminal UI\\n' && (command -v bun >/dev/null 2>&1 && cd tui && bun install --silent 2>/dev/null || true)",
|
|
19
19
|
"prepublishOnly": "npm run build"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
@@ -58,6 +58,9 @@
|
|
|
58
58
|
"files": [
|
|
59
59
|
"dist/",
|
|
60
60
|
"dashboard/",
|
|
61
|
+
"tui/src/",
|
|
62
|
+
"tui/package.json",
|
|
63
|
+
"tui/tsconfig.json",
|
|
61
64
|
"camelagi.mjs",
|
|
62
65
|
"config.example.yaml",
|
|
63
66
|
"README.md",
|
package/tui/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "camelagi-tui",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "CamelAGI terminal UI (OpenTUI + Bun). Connects to the CamelAGI gateway via WebSocket.",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "bun src/main.tsx",
|
|
9
|
+
"lint": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@opentui/core": "^0.1.27",
|
|
13
|
+
"@opentui/react": "^0.1.27",
|
|
14
|
+
"diff": "^7.0.0",
|
|
15
|
+
"react": "^19.0.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/diff": "^7.0.0",
|
|
19
|
+
"@types/node": "^22.0.0",
|
|
20
|
+
"@types/react": "^19.0.0",
|
|
21
|
+
"typescript": "^5.6.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/tui/src/App.tsx
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Root component. Owns settings state (model/effort/cwd) and the optional
|
|
2
|
+
// picker overlay; wires everything to useAgent (WebSocket to gateway).
|
|
3
|
+
|
|
4
|
+
import { useCallback, useState } from "react"
|
|
5
|
+
import { useKeyboard } from "@opentui/react"
|
|
6
|
+
import { useAgent } from "./hooks/useAgent.js"
|
|
7
|
+
import { Chat } from "./components/Chat.js"
|
|
8
|
+
import { Input } from "./components/Input.js"
|
|
9
|
+
import { ApprovalPrompt } from "./components/ApprovalPrompt.js"
|
|
10
|
+
import { Welcome } from "./components/Welcome.js"
|
|
11
|
+
import { nextMode } from "./components/PermissionBanner.js"
|
|
12
|
+
import { ActivityIndicator } from "./components/ActivityIndicator.js"
|
|
13
|
+
import { HorizontalRule } from "./components/HorizontalRule.js"
|
|
14
|
+
import { BottomBar } from "./components/BottomBar.js"
|
|
15
|
+
import { SlashMenu } from "./components/SlashMenu.js"
|
|
16
|
+
import { Picker, type PickerItem } from "./components/Picker.js"
|
|
17
|
+
import { findCommand, type CommandContext, type Settings } from "./commands/registry.js"
|
|
18
|
+
import { DEFAULT_MODEL } from "./config.js"
|
|
19
|
+
import type { SlashCommand } from "./commands/registry.js"
|
|
20
|
+
|
|
21
|
+
const VERSION = "0.5.49"
|
|
22
|
+
|
|
23
|
+
export interface AppProps {
|
|
24
|
+
model: string
|
|
25
|
+
cwd: string
|
|
26
|
+
wsUrl?: string
|
|
27
|
+
token?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface PickerState {
|
|
31
|
+
title: string
|
|
32
|
+
items: PickerItem[]
|
|
33
|
+
initialIndex?: number
|
|
34
|
+
onSelect: (value: string) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function App(props: AppProps) {
|
|
38
|
+
const [settings, setSettingsState] = useState<Settings>({
|
|
39
|
+
model: props.model || DEFAULT_MODEL,
|
|
40
|
+
effort: "high",
|
|
41
|
+
cwd: props.cwd,
|
|
42
|
+
})
|
|
43
|
+
const setSettings = useCallback(
|
|
44
|
+
(patch: Partial<Settings>) => setSettingsState(s => ({ ...s, ...patch })),
|
|
45
|
+
[],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const agent = useAgent({
|
|
49
|
+
model: settings.model,
|
|
50
|
+
effort: settings.effort,
|
|
51
|
+
cwd: settings.cwd,
|
|
52
|
+
wsUrl: props.wsUrl,
|
|
53
|
+
token: props.token,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const [slashState, setSlashState] = useState<{ matches: SlashCommand[]; selectedIndex: number; argMode?: boolean } | null>(null)
|
|
57
|
+
const [picker, setPicker] = useState<PickerState | null>(null)
|
|
58
|
+
|
|
59
|
+
const cmdCtx: CommandContext = {
|
|
60
|
+
pushSystem: (text, tone) => agent.pushSystem(text, tone),
|
|
61
|
+
agent: {
|
|
62
|
+
state: agent.state,
|
|
63
|
+
clear: agent.clear,
|
|
64
|
+
abort: agent.abort,
|
|
65
|
+
setPermissionMode: agent.setPermissionMode,
|
|
66
|
+
switchModel: agent.switchModel,
|
|
67
|
+
wsSend: agent.wsSend,
|
|
68
|
+
sessionId: agent.sessionId,
|
|
69
|
+
},
|
|
70
|
+
settings,
|
|
71
|
+
setSettings,
|
|
72
|
+
openPicker: opts => setPicker(opts),
|
|
73
|
+
exit: () => process.exit(0),
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const handleSlash = useCallback((name: string, args: string[]) => {
|
|
77
|
+
const cmd = findCommand(name)
|
|
78
|
+
if (!cmd) {
|
|
79
|
+
agent.pushSystem(`Unknown command: /${name}`, "warn")
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
void cmd.run(cmdCtx, args)
|
|
83
|
+
}, [cmdCtx, agent])
|
|
84
|
+
|
|
85
|
+
const handleCyclePermission = useCallback(() => {
|
|
86
|
+
const next = nextMode(agent.state.permissionMode)
|
|
87
|
+
agent.setPermissionMode(next)
|
|
88
|
+
}, [agent])
|
|
89
|
+
|
|
90
|
+
useKeyboard(key => {
|
|
91
|
+
if (key.ctrl && key.name === "c") {
|
|
92
|
+
if (agent.state.status !== "idle") agent.abort()
|
|
93
|
+
else process.exit(0)
|
|
94
|
+
}
|
|
95
|
+
if (key.ctrl && key.name === "l") {
|
|
96
|
+
agent.clear()
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const busy = agent.state.status !== "idle" && agent.state.status !== "error"
|
|
101
|
+
|
|
102
|
+
const welcome = (
|
|
103
|
+
<Welcome
|
|
104
|
+
cwd={settings.cwd}
|
|
105
|
+
model={settings.model}
|
|
106
|
+
version={VERSION}
|
|
107
|
+
/>
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
const overlayOpen = picker !== null || agent.state.pendingApproval !== null
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<box flexDirection="column" width="100%" height="100%">
|
|
114
|
+
<Chat entries={agent.state.entries} header={welcome} />
|
|
115
|
+
{picker ? (
|
|
116
|
+
<Picker
|
|
117
|
+
title={picker.title}
|
|
118
|
+
items={picker.items}
|
|
119
|
+
initialIndex={picker.initialIndex}
|
|
120
|
+
onSelect={value => {
|
|
121
|
+
const cb = picker.onSelect
|
|
122
|
+
setPicker(null)
|
|
123
|
+
cb(value)
|
|
124
|
+
}}
|
|
125
|
+
onCancel={() => setPicker(null)}
|
|
126
|
+
/>
|
|
127
|
+
) : null}
|
|
128
|
+
{agent.state.pendingApproval ? (
|
|
129
|
+
<ApprovalPrompt
|
|
130
|
+
request={agent.state.pendingApproval}
|
|
131
|
+
onResolve={behavior => agent.respondToApproval(behavior)}
|
|
132
|
+
/>
|
|
133
|
+
) : null}
|
|
134
|
+
{!overlayOpen ? (
|
|
135
|
+
<>
|
|
136
|
+
<ActivityIndicator
|
|
137
|
+
active={busy}
|
|
138
|
+
startedAt={agent.state.runStartedAt}
|
|
139
|
+
label={agent.state.activityLabel}
|
|
140
|
+
liveTokens={agent.state.liveTokens}
|
|
141
|
+
/>
|
|
142
|
+
<HorizontalRule />
|
|
143
|
+
<Input
|
|
144
|
+
disabled={busy}
|
|
145
|
+
onSubmit={agent.submit}
|
|
146
|
+
onSlash={handleSlash}
|
|
147
|
+
onAbort={agent.abort}
|
|
148
|
+
onCyclePermission={handleCyclePermission}
|
|
149
|
+
onSlashState={setSlashState}
|
|
150
|
+
/>
|
|
151
|
+
<HorizontalRule />
|
|
152
|
+
{slashState && slashState.matches.length > 0 ? (
|
|
153
|
+
<SlashMenu commands={slashState.matches} selectedIndex={slashState.selectedIndex} argMode={slashState.argMode} />
|
|
154
|
+
) : (
|
|
155
|
+
<BottomBar state={agent.state} />
|
|
156
|
+
)}
|
|
157
|
+
</>
|
|
158
|
+
) : null}
|
|
159
|
+
</box>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Normalize raw stream-json events from node-host/host.mjs into the typed
|
|
2
|
+
// AgentEvent union. Direct port of liquidagente-desktop/src/lib/localAgent.ts:58-188.
|
|
3
|
+
// Keep these two in lockstep — divergence here means the TUI silently
|
|
4
|
+
// misses events the React app handles.
|
|
5
|
+
|
|
6
|
+
import type { AgentEvent, UsageInfo } from "./types.js"
|
|
7
|
+
|
|
8
|
+
type Raw = Record<string, unknown>
|
|
9
|
+
|
|
10
|
+
const PERMISSION_DENIAL_MARKERS = [
|
|
11
|
+
"requested permissions",
|
|
12
|
+
"requires approval",
|
|
13
|
+
"haven't granted",
|
|
14
|
+
"multiple operations",
|
|
15
|
+
"permission denied",
|
|
16
|
+
"not allowed",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
export function parseEvent(raw: Raw): AgentEvent[] {
|
|
20
|
+
const out: AgentEvent[] = []
|
|
21
|
+
const type = raw.type as string
|
|
22
|
+
|
|
23
|
+
if (type === "error" || type === "host_error") {
|
|
24
|
+
out.push({ type: "error", message: String(raw.message ?? "unknown error") })
|
|
25
|
+
return out
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (type === "approval-request") {
|
|
29
|
+
out.push({
|
|
30
|
+
type: "approval_request",
|
|
31
|
+
request: {
|
|
32
|
+
id: String(raw.id ?? ""),
|
|
33
|
+
tool: String(raw.tool ?? ""),
|
|
34
|
+
input: (raw.input as Record<string, unknown>) ?? {},
|
|
35
|
+
blockedPath: raw.blockedPath as string | undefined,
|
|
36
|
+
decisionReason: raw.decisionReason as string | undefined,
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
return out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (type === "system") {
|
|
43
|
+
const subtype = raw.subtype as string
|
|
44
|
+
if (subtype === "init") {
|
|
45
|
+
out.push({ type: "init", sessionId: String(raw.session_id ?? "") })
|
|
46
|
+
} else if (subtype === "task_started") {
|
|
47
|
+
out.push({
|
|
48
|
+
type: "subagent_start",
|
|
49
|
+
agentId: String(raw.agent_id ?? "subagent"),
|
|
50
|
+
taskId: raw.task_id as string | undefined,
|
|
51
|
+
})
|
|
52
|
+
} else if (subtype === "task_progress") {
|
|
53
|
+
const ms = raw.duration_ms as number | undefined
|
|
54
|
+
out.push({
|
|
55
|
+
type: "subagent_progress",
|
|
56
|
+
agentId: String(raw.agent_id ?? "subagent"),
|
|
57
|
+
toolCount: raw.tool_count as number | undefined,
|
|
58
|
+
duration: ms ? Math.round(ms / 1000) : undefined,
|
|
59
|
+
})
|
|
60
|
+
} else if (subtype === "task_notification") {
|
|
61
|
+
out.push({
|
|
62
|
+
type: "subagent_done",
|
|
63
|
+
agentId: String(raw.agent_id ?? "subagent"),
|
|
64
|
+
toolUseId: raw.tool_use_id as string | undefined,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
return out
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (type === "assistant") {
|
|
71
|
+
const msg = raw.message as Raw | undefined
|
|
72
|
+
const content = msg?.content as Array<Raw> | undefined
|
|
73
|
+
if (!content) return out
|
|
74
|
+
for (const block of content) {
|
|
75
|
+
if (block.type === "text" && block.text) {
|
|
76
|
+
out.push({ type: "stream_text", text: String(block.text) })
|
|
77
|
+
} else if (block.type === "tool_use") {
|
|
78
|
+
out.push({
|
|
79
|
+
type: "tool_call",
|
|
80
|
+
id: String(block.id ?? ""),
|
|
81
|
+
name: String(block.name ?? ""),
|
|
82
|
+
args: (block.input as Record<string, unknown>) ?? {},
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (type === "user") {
|
|
90
|
+
const msg = raw.message as Raw | undefined
|
|
91
|
+
const content = msg?.content as Array<Raw> | undefined
|
|
92
|
+
if (!content) return out
|
|
93
|
+
for (const block of content) {
|
|
94
|
+
if (block.type !== "tool_result") continue
|
|
95
|
+
const resultContent = block.content
|
|
96
|
+
let preview = ""
|
|
97
|
+
if (typeof resultContent === "string") {
|
|
98
|
+
preview = resultContent
|
|
99
|
+
} else if (Array.isArray(resultContent)) {
|
|
100
|
+
preview = (resultContent as Array<Raw>)
|
|
101
|
+
.filter(b => b.type === "text")
|
|
102
|
+
.map(b => String(b.text ?? ""))
|
|
103
|
+
.join("\n")
|
|
104
|
+
}
|
|
105
|
+
const isError = block.is_error === true
|
|
106
|
+
const isPermissionDenial = isError && PERMISSION_DENIAL_MARKERS.some(m => preview.includes(m))
|
|
107
|
+
if (isPermissionDenial) {
|
|
108
|
+
out.push({
|
|
109
|
+
type: "permission_denied",
|
|
110
|
+
id: String(block.tool_use_id ?? ""),
|
|
111
|
+
message: preview,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
out.push({
|
|
115
|
+
type: "tool_result",
|
|
116
|
+
id: String(block.tool_use_id ?? ""),
|
|
117
|
+
preview: preview.slice(0, 2000),
|
|
118
|
+
isError,
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
return out
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (type === "result") {
|
|
125
|
+
const usage = parseUsage(raw.usage as Raw | undefined)
|
|
126
|
+
if (usage) out.push({ type: "usage", usage })
|
|
127
|
+
out.push({
|
|
128
|
+
type: "done",
|
|
129
|
+
response: String(raw.result ?? ""),
|
|
130
|
+
subtype: raw.subtype as string | undefined,
|
|
131
|
+
usage,
|
|
132
|
+
})
|
|
133
|
+
return out
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (type === "tool_use") {
|
|
137
|
+
out.push({
|
|
138
|
+
type: "tool_call",
|
|
139
|
+
id: String(raw.tool_use_id ?? ""),
|
|
140
|
+
name: String(raw.name ?? ""),
|
|
141
|
+
args: (raw.input as Record<string, unknown>) ?? {},
|
|
142
|
+
})
|
|
143
|
+
return out
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (type === "tool_result") {
|
|
147
|
+
out.push({
|
|
148
|
+
type: "tool_result",
|
|
149
|
+
id: String(raw.tool_use_id ?? ""),
|
|
150
|
+
preview: String(raw.content ?? ""),
|
|
151
|
+
})
|
|
152
|
+
return out
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (type === "stream_event") {
|
|
156
|
+
const event = raw.event as Raw | undefined
|
|
157
|
+
if (!event) return out
|
|
158
|
+
if (event.type === "content_block_start" && (event.content_block as Raw)?.type === "thinking") {
|
|
159
|
+
out.push({ type: "thinking", state: "start" })
|
|
160
|
+
} else if (event.type === "content_block_delta") {
|
|
161
|
+
const delta = event.delta as Raw | undefined
|
|
162
|
+
if (delta?.type === "text_delta" && delta.text) {
|
|
163
|
+
out.push({ type: "stream_text", text: String(delta.text) })
|
|
164
|
+
} else if (delta?.type === "thinking_delta" && delta.thinking) {
|
|
165
|
+
out.push({ type: "thinking_delta", text: String(delta.thinking) })
|
|
166
|
+
}
|
|
167
|
+
} else if (event.type === "content_block_stop") {
|
|
168
|
+
out.push({ type: "thinking", state: "end" })
|
|
169
|
+
}
|
|
170
|
+
return out
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return out
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function parseUsage(u: Raw | undefined): UsageInfo | undefined {
|
|
177
|
+
if (!u) return undefined
|
|
178
|
+
return {
|
|
179
|
+
inputTokens: Number(u.input_tokens ?? 0),
|
|
180
|
+
outputTokens: Number(u.output_tokens ?? 0),
|
|
181
|
+
cacheReadTokens: Number(u.cache_read_input_tokens ?? 0),
|
|
182
|
+
cacheWriteTokens: Number(u.cache_creation_input_tokens ?? 0),
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Agent protocol types. Mirrors node-host/host.mjs in/out shapes and the
|
|
2
|
+
// normalized event shape produced by parse.ts (which is itself a port of
|
|
3
|
+
// liquidagente-desktop/src/lib/localAgent.ts:58-188).
|
|
4
|
+
|
|
5
|
+
export type PermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan"
|
|
6
|
+
|
|
7
|
+
/** Which agent runtime to spawn.
|
|
8
|
+
* - cli: the `claude` binary directly. Auth via claude-cli login. Same path
|
|
9
|
+
* the desktop uses by default. Best for users who already ran
|
|
10
|
+
* `claude login`.
|
|
11
|
+
* - sdk: node-host/host.mjs (the Node sidecar that wraps the Agent SDK).
|
|
12
|
+
* Needed for direct API key usage or gateway-proxied auth. */
|
|
13
|
+
export type AgentRuntime = "cli" | "sdk"
|
|
14
|
+
|
|
15
|
+
/** Config passed to host.mjs via LIQUIDAGENTE_CONFIG env var (sdk mode) or
|
|
16
|
+
* translated to CLI args (cli mode). */
|
|
17
|
+
export interface AgentConfig {
|
|
18
|
+
prompt: string
|
|
19
|
+
model: string
|
|
20
|
+
cwd: string
|
|
21
|
+
runtime?: AgentRuntime
|
|
22
|
+
baseUrl?: string
|
|
23
|
+
authToken?: string
|
|
24
|
+
systemPrompt?: string
|
|
25
|
+
permissionMode?: PermissionMode
|
|
26
|
+
maxTurns?: number
|
|
27
|
+
effort?: string
|
|
28
|
+
sessionId?: string
|
|
29
|
+
resume?: boolean
|
|
30
|
+
allowedTools?: string[]
|
|
31
|
+
disallowedTools?: string[]
|
|
32
|
+
tools?: string[]
|
|
33
|
+
agentId?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ApprovalRequest {
|
|
37
|
+
id: string
|
|
38
|
+
tool: string
|
|
39
|
+
input: Record<string, unknown>
|
|
40
|
+
blockedPath?: string
|
|
41
|
+
decisionReason?: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface UsageInfo {
|
|
45
|
+
inputTokens: number
|
|
46
|
+
outputTokens: number
|
|
47
|
+
cacheReadTokens: number
|
|
48
|
+
cacheWriteTokens: number
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type AgentEvent =
|
|
52
|
+
| { type: "init"; sessionId: string }
|
|
53
|
+
| { type: "stream_text"; text: string }
|
|
54
|
+
| { type: "thinking"; state: "start" | "end" }
|
|
55
|
+
| { type: "thinking_delta"; text: string }
|
|
56
|
+
| { type: "tool_call"; id: string; name: string; args: Record<string, unknown> }
|
|
57
|
+
| { type: "tool_result"; id: string; preview: string; isError?: boolean }
|
|
58
|
+
| { type: "approval_request"; request: ApprovalRequest }
|
|
59
|
+
| { type: "permission_denied"; id: string; message: string }
|
|
60
|
+
| { type: "subagent_start"; agentId: string; taskId?: string }
|
|
61
|
+
| { type: "subagent_progress"; agentId: string; toolCount?: number; duration?: number }
|
|
62
|
+
| { type: "subagent_done"; agentId: string; toolUseId?: string }
|
|
63
|
+
| { type: "usage"; usage: UsageInfo }
|
|
64
|
+
| { type: "done"; response: string; subtype?: string; usage?: UsageInfo }
|
|
65
|
+
| { type: "error"; message: string }
|
|
66
|
+
|
|
67
|
+
export type ApprovalBehavior = "allow" | "deny"
|
|
68
|
+
|
|
69
|
+
/** Sent on host.mjs stdin in response to an approval-request. */
|
|
70
|
+
export interface ApprovalResponse {
|
|
71
|
+
type: "approval-response"
|
|
72
|
+
id: string
|
|
73
|
+
behavior: ApprovalBehavior
|
|
74
|
+
message?: string
|
|
75
|
+
}
|