@openlucaskaka/kagent 0.1.7
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 +353 -0
- package/npm/bin/kagent-serve.js +6 -0
- package/npm/bin/kagent.js +6 -0
- package/npm/lib/App.js +524 -0
- package/npm/lib/app-state.js +224 -0
- package/npm/lib/approval-choice.js +25 -0
- package/npm/lib/commands.js +59 -0
- package/npm/lib/editor.js +188 -0
- package/npm/lib/ink-runner.js +41 -0
- package/npm/lib/kagent-home.js +39 -0
- package/npm/lib/launcher.js +221 -0
- package/npm/lib/protocol.js +33 -0
- package/npm/lib/provider-setup.js +139 -0
- package/npm/lib/python-runner.js +892 -0
- package/npm/lib/runtime-client.js +390 -0
- package/npm/lib/terminal-input.js +127 -0
- package/npm/lib/terminal-text.js +19 -0
- package/npm/lib/terminal-width.js +14 -0
- package/npm/lib/transcript.js +227 -0
- package/npm/lib/ui-components.js +247 -0
- package/npm/lib/update-manager.js +334 -0
- package/package.json +39 -0
- package/pyproject.toml +55 -0
- package/src/kagent/__init__.py +90 -0
- package/src/kagent/cli/__init__.py +5 -0
- package/src/kagent/cli/__main__.py +6 -0
- package/src/kagent/cli/commands.py +112 -0
- package/src/kagent/cli/conversation.py +127 -0
- package/src/kagent/cli/interactive.py +841 -0
- package/src/kagent/cli/main.py +685 -0
- package/src/kagent/cli/memory.py +460 -0
- package/src/kagent/cli/pending_approval.py +169 -0
- package/src/kagent/cli/provider.py +27 -0
- package/src/kagent/cli/session_commands.py +401 -0
- package/src/kagent/cli/stdio_runtime.py +784 -0
- package/src/kagent/cli/trace.py +67 -0
- package/src/kagent/cli/ui.py +931 -0
- package/src/kagent/core/__init__.py +0 -0
- package/src/kagent/core/agent.py +296 -0
- package/src/kagent/core/faults.py +11 -0
- package/src/kagent/core/invariants.py +47 -0
- package/src/kagent/core/normalization.py +81 -0
- package/src/kagent/core/planning.py +48 -0
- package/src/kagent/core/state.py +73 -0
- package/src/kagent/core/summary.py +64 -0
- package/src/kagent/core/tools.py +196 -0
- package/src/kagent/core/trace.py +57 -0
- package/src/kagent/eval/__init__.py +11 -0
- package/src/kagent/eval/cases.py +229 -0
- package/src/kagent/eval/evaluator.py +216 -0
- package/src/kagent/integrations/__init__.py +3 -0
- package/src/kagent/integrations/audit.py +95 -0
- package/src/kagent/integrations/backends.py +131 -0
- package/src/kagent/integrations/memory.py +301 -0
- package/src/kagent/ops/__init__.py +0 -0
- package/src/kagent/ops/batch.py +156 -0
- package/src/kagent/ops/doctor.py +255 -0
- package/src/kagent/ops/metrics.py +214 -0
- package/src/kagent/ops/release_evidence.py +877 -0
- package/src/kagent/ops/release_manifest.py +142 -0
- package/src/kagent/ops/trace_replay.py +285 -0
- package/src/kagent/providers/__init__.py +7 -0
- package/src/kagent/providers/embeddings.py +187 -0
- package/src/kagent/providers/llm.py +770 -0
- package/src/kagent/py.typed +1 -0
- package/src/kagent/runtime/__init__.py +28 -0
- package/src/kagent/runtime/action_graph.py +543 -0
- package/src/kagent/runtime/agent.py +2089 -0
- package/src/kagent/runtime/approval.py +64 -0
- package/src/kagent/runtime/cancellation.py +64 -0
- package/src/kagent/runtime/checkpoint_state.py +146 -0
- package/src/kagent/runtime/checkpoint_storage.py +270 -0
- package/src/kagent/runtime/context.py +65 -0
- package/src/kagent/runtime/file_transaction.py +195 -0
- package/src/kagent/runtime/hooks.py +74 -0
- package/src/kagent/runtime/metadata.py +116 -0
- package/src/kagent/runtime/patch_checkpoints.py +385 -0
- package/src/kagent/runtime/policy.py +50 -0
- package/src/kagent/runtime/presentation.py +205 -0
- package/src/kagent/runtime/redaction.py +130 -0
- package/src/kagent/runtime/sandbox.py +331 -0
- package/src/kagent/runtime/skills.py +66 -0
- package/src/kagent/runtime/steering.py +56 -0
- package/src/kagent/runtime/steps.py +255 -0
- package/src/kagent/runtime/task_state.py +40 -0
- package/src/kagent/runtime/tools.py +3532 -0
- package/src/kagent/runtime/types.py +240 -0
- package/src/kagent/runtime/workspace.py +597 -0
- package/src/kagent/service/__init__.py +26 -0
- package/src/kagent/service/__main__.py +6 -0
- package/src/kagent/service/active_runs.py +178 -0
- package/src/kagent/service/cli.py +737 -0
- package/src/kagent/service/contract.py +2571 -0
- package/src/kagent/service/errors.py +71 -0
- package/src/kagent/service/idempotency.py +584 -0
- package/src/kagent/service/router.py +884 -0
- package/src/kagent/service/run.py +150 -0
- package/src/kagent/service/runtime.py +1915 -0
- package/src/kagent/service/runtime_approval.py +20 -0
- package/src/kagent/service/runtime_cancel.py +192 -0
- package/src/kagent/service/runtime_lifecycle.py +229 -0
- package/src/kagent/service/runtime_metadata.py +21 -0
- package/src/kagent/service/runtime_policy.py +115 -0
- package/src/kagent/service/runtime_recovery.py +573 -0
- package/src/kagent/service/runtime_resume.py +382 -0
- package/src/kagent/service/runtime_resume_claim.py +116 -0
- package/src/kagent/service/runtime_run.py +350 -0
- package/src/kagent/service/runtime_status.py +2007 -0
- package/src/kagent/service/safety.py +139 -0
- package/src/kagent/service/server.py +114 -0
- package/src/kagent/service/status.py +233 -0
- package/src/kagent/service/trace_store.py +322 -0
- package/src/kagent/service/transport.py +24 -0
- package/src/kagent/utils/__init__.py +0 -0
- package/src/kagent/utils/config_validation.py +21 -0
- package/src/kagent/utils/json_output.py +23 -0
- package/src/kagent/utils/paths.py +473 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTranscriptState = createTranscriptState;
|
|
4
|
+
exports.transcriptReducer = transcriptReducer;
|
|
5
|
+
exports.progressTranscriptAction = progressTranscriptAction;
|
|
6
|
+
exports.selectTranscriptViewport = selectTranscriptViewport;
|
|
7
|
+
exports.moveTranscriptViewport = moveTranscriptViewport;
|
|
8
|
+
exports.clampTranscriptOffset = clampTranscriptOffset;
|
|
9
|
+
const terminal_width_1 = require("./terminal-width");
|
|
10
|
+
function createTranscriptState(maxEntries = 100) {
|
|
11
|
+
return {
|
|
12
|
+
entries: [],
|
|
13
|
+
activeAssistantId: null,
|
|
14
|
+
nextId: 1,
|
|
15
|
+
maxEntries: Math.max(1, maxEntries),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function transcriptReducer(state, action) {
|
|
19
|
+
if (action.type === "user_submitted") {
|
|
20
|
+
return appendEntry(state, "user", action.text, "complete");
|
|
21
|
+
}
|
|
22
|
+
if (action.type === "command_completed") {
|
|
23
|
+
const base = action.clear ? { ...state, entries: [], activeAssistantId: null } : state;
|
|
24
|
+
return appendEntry(base, "command", action.text, "complete", action.title);
|
|
25
|
+
}
|
|
26
|
+
if (action.type === "assistant_started") {
|
|
27
|
+
if (state.activeAssistantId) {
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
const next = appendEntry(state, "assistant", "", "streaming");
|
|
31
|
+
return { ...next, activeAssistantId: next.entries.at(-1)?.id || null };
|
|
32
|
+
}
|
|
33
|
+
if (action.type === "assistant_delta") {
|
|
34
|
+
const started = state.activeAssistantId
|
|
35
|
+
? state
|
|
36
|
+
: transcriptReducer(state, { type: "assistant_started" });
|
|
37
|
+
return updateActiveAssistant(started, (entry) => ({
|
|
38
|
+
...entry,
|
|
39
|
+
text: entry.text + action.text,
|
|
40
|
+
status: "streaming",
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
if (action.type === "assistant_completed") {
|
|
44
|
+
const status = action.outcome === "cancelled" ? "cancelled" : "complete";
|
|
45
|
+
if (state.activeAssistantId) {
|
|
46
|
+
const completed = updateActiveAssistant(state, (entry) => ({
|
|
47
|
+
...entry,
|
|
48
|
+
text: action.text || entry.text,
|
|
49
|
+
status,
|
|
50
|
+
}));
|
|
51
|
+
return { ...completed, activeAssistantId: null };
|
|
52
|
+
}
|
|
53
|
+
const last = state.entries.at(-1);
|
|
54
|
+
if (last?.role === "assistant" && last.text === action.text && last.status === status) {
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
57
|
+
return appendEntry(state, "assistant", action.text, status);
|
|
58
|
+
}
|
|
59
|
+
if (action.type === "result_completed") {
|
|
60
|
+
const entry = {
|
|
61
|
+
id: `m-${state.nextId}`,
|
|
62
|
+
role: "command",
|
|
63
|
+
status: "complete",
|
|
64
|
+
text: "",
|
|
65
|
+
title: action.title,
|
|
66
|
+
...(action.detail ? { detail: action.detail } : {}),
|
|
67
|
+
...(action.content ? { content: action.content, expanded: false } : {}),
|
|
68
|
+
};
|
|
69
|
+
return retain({
|
|
70
|
+
...state,
|
|
71
|
+
entries: state.entries.concat(entry),
|
|
72
|
+
nextId: state.nextId + 1,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (action.type === "toggle_latest_result") {
|
|
76
|
+
let index = -1;
|
|
77
|
+
for (let candidate = state.entries.length - 1; candidate >= 0; candidate -= 1) {
|
|
78
|
+
if (state.entries[candidate].content) {
|
|
79
|
+
index = candidate;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (index < 0) {
|
|
84
|
+
return state;
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
...state,
|
|
88
|
+
entries: state.entries.map((entry, entryIndex) => entryIndex === index ? { ...entry, expanded: !entry.expanded } : entry),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return appendEntry(state, "system", action.text, "error");
|
|
92
|
+
}
|
|
93
|
+
function progressTranscriptAction(event) {
|
|
94
|
+
const type = String(event.type || "");
|
|
95
|
+
if (type === "answer_started") {
|
|
96
|
+
return { type: "assistant_started" };
|
|
97
|
+
}
|
|
98
|
+
if (type === "answer_delta") {
|
|
99
|
+
return { type: "assistant_delta", text: String(event.delta ?? event.text ?? "") };
|
|
100
|
+
}
|
|
101
|
+
if (type === "answer_completed") {
|
|
102
|
+
return {
|
|
103
|
+
type: "assistant_completed",
|
|
104
|
+
text: String(event.answer ?? event.text ?? ""),
|
|
105
|
+
outcome: "complete",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (type === "tool_completed") {
|
|
109
|
+
const presentation = event.presentation;
|
|
110
|
+
if (!presentation || typeof presentation !== "object") {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const payload = presentation;
|
|
114
|
+
const title = String(payload.title || "").trim();
|
|
115
|
+
if (!title) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const detail = String(payload.detail || "").trim();
|
|
119
|
+
return {
|
|
120
|
+
type: "result_completed",
|
|
121
|
+
title,
|
|
122
|
+
detail: payload.truncated === true
|
|
123
|
+
? [detail, "truncated"].filter(Boolean).join(" · ")
|
|
124
|
+
: detail,
|
|
125
|
+
content: String(payload.content || "").trim(),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function selectTranscriptViewport(entries, viewport, offset = 0) {
|
|
131
|
+
if (entries.length === 0) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const availableRows = Math.max(1, viewport.rows - (viewport.reservedRows ?? 0));
|
|
135
|
+
const safeOffset = clampTranscriptOffset(entries, offset);
|
|
136
|
+
const end = entries.length - safeOffset;
|
|
137
|
+
let usedRows = 0;
|
|
138
|
+
let start = end - 1;
|
|
139
|
+
for (let index = end - 1; index >= 0; index -= 1) {
|
|
140
|
+
const rows = estimateEntryRows(entries[index], viewport.columns);
|
|
141
|
+
if (usedRows > 0 && usedRows + rows > availableRows) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
usedRows += rows;
|
|
145
|
+
start = index;
|
|
146
|
+
}
|
|
147
|
+
return entries.slice(start, end);
|
|
148
|
+
}
|
|
149
|
+
function moveTranscriptViewport(entries, viewport, offset, direction) {
|
|
150
|
+
if (entries.length === 0) {
|
|
151
|
+
return 0;
|
|
152
|
+
}
|
|
153
|
+
const safeOffset = clampTranscriptOffset(entries, offset);
|
|
154
|
+
const pageOffsets = transcriptPageOffsets(entries, viewport);
|
|
155
|
+
if (direction === "older") {
|
|
156
|
+
return pageOffsets.find((pageOffset) => pageOffset > safeOffset)
|
|
157
|
+
?? pageOffsets.at(-1)
|
|
158
|
+
?? 0;
|
|
159
|
+
}
|
|
160
|
+
for (let index = pageOffsets.length - 1; index >= 0; index -= 1) {
|
|
161
|
+
if (pageOffsets[index] < safeOffset) {
|
|
162
|
+
return pageOffsets[index];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
function clampTranscriptOffset(entries, offset) {
|
|
168
|
+
if (entries.length === 0) {
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
return Math.min(Math.max(Math.trunc(offset), 0), entries.length - 1);
|
|
172
|
+
}
|
|
173
|
+
function transcriptPageOffsets(entries, viewport) {
|
|
174
|
+
const offsets = [0];
|
|
175
|
+
while (offsets.at(-1) < entries.length - 1) {
|
|
176
|
+
const current = offsets.at(-1);
|
|
177
|
+
const visibleCount = Math.max(1, selectTranscriptViewport(entries, viewport, current).length);
|
|
178
|
+
const next = clampTranscriptOffset(entries, current + visibleCount);
|
|
179
|
+
if (next === current) {
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
offsets.push(next);
|
|
183
|
+
}
|
|
184
|
+
return offsets;
|
|
185
|
+
}
|
|
186
|
+
function appendEntry(state, role, text, status, title) {
|
|
187
|
+
const entry = {
|
|
188
|
+
id: `m-${state.nextId}`,
|
|
189
|
+
role,
|
|
190
|
+
status,
|
|
191
|
+
text,
|
|
192
|
+
...(title ? { title } : {}),
|
|
193
|
+
};
|
|
194
|
+
return retain({
|
|
195
|
+
...state,
|
|
196
|
+
entries: state.entries.concat(entry),
|
|
197
|
+
nextId: state.nextId + 1,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function updateActiveAssistant(state, update) {
|
|
201
|
+
if (!state.activeAssistantId) {
|
|
202
|
+
return state;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
...state,
|
|
206
|
+
entries: state.entries.map((entry) => entry.id === state.activeAssistantId ? update(entry) : entry),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function retain(state) {
|
|
210
|
+
if (state.entries.length <= state.maxEntries) {
|
|
211
|
+
return state;
|
|
212
|
+
}
|
|
213
|
+
const entries = state.entries.slice(-state.maxEntries);
|
|
214
|
+
const activeAssistantId = entries.some((entry) => entry.id === state.activeAssistantId)
|
|
215
|
+
? state.activeAssistantId
|
|
216
|
+
: null;
|
|
217
|
+
return { ...state, entries, activeAssistantId };
|
|
218
|
+
}
|
|
219
|
+
function estimateEntryRows(entry, columns) {
|
|
220
|
+
const contentColumns = Math.max(4, columns - 4);
|
|
221
|
+
const titleRows = entry.title ? (0, terminal_width_1.estimateTextRows)(entry.title, contentColumns) : 0;
|
|
222
|
+
const detailRows = entry.detail ? (0, terminal_width_1.estimateTextRows)(entry.detail, contentColumns) : 0;
|
|
223
|
+
const contentRows = entry.expanded && entry.content
|
|
224
|
+
? (0, terminal_width_1.estimateTextRows)(entry.content, contentColumns)
|
|
225
|
+
: 0;
|
|
226
|
+
return Math.max(1, titleRows + detailRows + contentRows + (0, terminal_width_1.estimateTextRows)(entry.text, contentColumns)) + 1;
|
|
227
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TERMINAL_SPINNER_FRAMES = void 0;
|
|
4
|
+
exports.createTerminalLayout = createTerminalLayout;
|
|
5
|
+
exports.NarrowTerminal = NarrowTerminal;
|
|
6
|
+
exports.createPromptViewport = createPromptViewport;
|
|
7
|
+
exports.Header = Header;
|
|
8
|
+
exports.ProviderSetupPanel = ProviderSetupPanel;
|
|
9
|
+
exports.MessageList = MessageList;
|
|
10
|
+
exports.TranscriptPosition = TranscriptPosition;
|
|
11
|
+
exports.ApprovalPanel = ApprovalPanel;
|
|
12
|
+
exports.CommandPalette = CommandPalette;
|
|
13
|
+
exports.StatusLine = StatusLine;
|
|
14
|
+
exports.PromptLine = PromptLine;
|
|
15
|
+
const editor_1 = require("./editor");
|
|
16
|
+
const provider_setup_1 = require("./provider-setup");
|
|
17
|
+
const terminal_text_1 = require("./terminal-text");
|
|
18
|
+
const terminal_width_1 = require("./terminal-width");
|
|
19
|
+
exports.TERMINAL_SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
20
|
+
function createTerminalLayout(columns, rows, overlays) {
|
|
21
|
+
const safeColumns = Math.max(1, columns || 80);
|
|
22
|
+
const safeRows = Math.max(10, rows || 24);
|
|
23
|
+
const tooNarrow = safeColumns < 20;
|
|
24
|
+
const compact = safeColumns < 56;
|
|
25
|
+
const horizontalPadding = compact ? 0 : 1;
|
|
26
|
+
const defaultCommandLimit = compact ? 4 : 6;
|
|
27
|
+
const headerRows = compact ? 2 : 3;
|
|
28
|
+
const promptChromeRows = 1;
|
|
29
|
+
const fixedBaseRows = headerRows + promptChromeRows;
|
|
30
|
+
const approvalColumns = Math.max(4, safeColumns - horizontalPadding * 2 - (compact ? 0 : 2));
|
|
31
|
+
const approvalRows = estimateApprovalRows(overlays.approval, approvalColumns);
|
|
32
|
+
const commandColumns = Math.max(4, safeColumns - horizontalPadding * 2 - (compact ? 0 : 2));
|
|
33
|
+
const commandExtraRows = estimateCommandExtraRows(overlays.commandMenu, compact, commandColumns);
|
|
34
|
+
const commandCapacity = Math.max(1, safeRows - 1 - fixedBaseRows - 1 - commandExtraRows - approvalRows);
|
|
35
|
+
const commandLimit = overlays.commandMenu
|
|
36
|
+
? Math.min(defaultCommandLimit, commandCapacity)
|
|
37
|
+
: defaultCommandLimit;
|
|
38
|
+
const promptColumns = Math.max(4, safeColumns - horizontalPadding * 2 - 2);
|
|
39
|
+
const visibleCommandRows = overlays.commandMenu && overlays.commandMenu !== true
|
|
40
|
+
? Math.min(commandLimit, overlays.commandMenu.options.length)
|
|
41
|
+
: commandLimit;
|
|
42
|
+
const commandRows = overlays.commandMenu
|
|
43
|
+
? visibleCommandRows + commandExtraRows
|
|
44
|
+
: 0;
|
|
45
|
+
const promptRowLimit = Math.max(1, Math.min(compact ? 4 : 6, safeRows - 1 - fixedBaseRows - approvalRows - commandRows));
|
|
46
|
+
const promptRows = overlays.prompt === undefined
|
|
47
|
+
? 1
|
|
48
|
+
: (0, terminal_width_1.estimateTextRows)(createPromptViewport(overlays.prompt, overlays.promptCursor ?? (0, editor_1.splitGraphemes)(overlays.prompt).length, promptColumns, promptRowLimit).rendered, promptColumns);
|
|
49
|
+
const baseRows = fixedBaseRows + promptRows;
|
|
50
|
+
return {
|
|
51
|
+
columns: safeColumns,
|
|
52
|
+
rows: safeRows,
|
|
53
|
+
compact,
|
|
54
|
+
tooNarrow,
|
|
55
|
+
horizontalPadding,
|
|
56
|
+
commandLimit,
|
|
57
|
+
promptColumns,
|
|
58
|
+
promptRowLimit,
|
|
59
|
+
reservedRows: Math.min(safeRows - 1, baseRows + approvalRows + commandRows),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function NarrowTerminal({ React, Box, Text, }) {
|
|
63
|
+
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, { bold: true, color: "cyan" }, "kagent"), React.createElement(Text, { color: "gray", wrap: "wrap" }, "widen terminal"));
|
|
64
|
+
}
|
|
65
|
+
function estimateApprovalRows(approval, columns) {
|
|
66
|
+
if (!approval) {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
if (approval === true) {
|
|
70
|
+
return 8;
|
|
71
|
+
}
|
|
72
|
+
const rows = (value) => value ? (0, terminal_width_1.estimateTextRows)(value, columns) : 0;
|
|
73
|
+
const detailRows = approval.showDetails
|
|
74
|
+
? (approval.details ?? []).reduce((total, detail) => total + rows(` ${detail}`), 0)
|
|
75
|
+
: 0;
|
|
76
|
+
const detailMarginRows = approval.showDetails && approval.details?.length ? 1 : 0;
|
|
77
|
+
const reasonRows = approval.showDetails ? rows(approval.reason) : 0;
|
|
78
|
+
return (5 +
|
|
79
|
+
rows(approval.title) +
|
|
80
|
+
rows(approval.target) +
|
|
81
|
+
rows("←→ select · enter confirm · d details") +
|
|
82
|
+
detailMarginRows +
|
|
83
|
+
detailRows +
|
|
84
|
+
reasonRows);
|
|
85
|
+
}
|
|
86
|
+
function estimateCommandExtraRows(menu, compact, columns) {
|
|
87
|
+
if (!menu) {
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (menu === true) {
|
|
91
|
+
return compact ? 3 : 2;
|
|
92
|
+
}
|
|
93
|
+
const helpRows = (0, terminal_width_1.estimateTextRows)("↑↓ choose · tab complete · enter run", columns);
|
|
94
|
+
const selected = menu.options[menu.selectedIndex];
|
|
95
|
+
const descriptionRows = compact && selected
|
|
96
|
+
? (0, terminal_width_1.estimateTextRows)(` ${selected.description}`, columns)
|
|
97
|
+
: 0;
|
|
98
|
+
return 1 + helpRows + descriptionRows;
|
|
99
|
+
}
|
|
100
|
+
function createPromptViewport(input, cursor, columns, maxRows) {
|
|
101
|
+
const characters = (0, editor_1.splitGraphemes)(input);
|
|
102
|
+
const safeCursor = Math.min(Math.max(cursor, 0), characters.length);
|
|
103
|
+
const safeColumns = Math.max(4, columns);
|
|
104
|
+
const safeRows = Math.max(1, maxRows);
|
|
105
|
+
const preserveActiveNewline = safeRows > 1;
|
|
106
|
+
let start = safeCursor;
|
|
107
|
+
let end = Math.min(characters.length, safeCursor + 1);
|
|
108
|
+
while (start > 0 &&
|
|
109
|
+
promptViewportRows(characters, safeCursor, start - 1, end, safeColumns, preserveActiveNewline) <= safeRows) {
|
|
110
|
+
start -= 1;
|
|
111
|
+
}
|
|
112
|
+
while (end < characters.length &&
|
|
113
|
+
promptViewportRows(characters, safeCursor, start, end + 1, safeColumns, preserveActiveNewline) <= safeRows) {
|
|
114
|
+
end += 1;
|
|
115
|
+
}
|
|
116
|
+
return promptViewportParts(characters, safeCursor, start, end, preserveActiveNewline);
|
|
117
|
+
}
|
|
118
|
+
function promptViewportRows(characters, cursor, start, end, columns, preserveActiveNewline) {
|
|
119
|
+
return (0, terminal_width_1.estimateTextRows)(promptViewportParts(characters, cursor, start, end, preserveActiveNewline).rendered, columns);
|
|
120
|
+
}
|
|
121
|
+
function promptViewportParts(characters, cursor, start, end, preserveActiveNewline) {
|
|
122
|
+
const prefixClipped = start > 0;
|
|
123
|
+
const suffixClipped = end < characters.length;
|
|
124
|
+
const rawActive = characters[cursor] || " ";
|
|
125
|
+
const active = rawActive === "\n" ? (preserveActiveNewline ? " " : "↵") : rawActive;
|
|
126
|
+
const before = `${prefixClipped ? "…" : ""}${characters
|
|
127
|
+
.slice(start, cursor)
|
|
128
|
+
.join("")}`;
|
|
129
|
+
const after = `${rawActive === "\n" && preserveActiveNewline ? "\n" : ""}${characters.slice(cursor + 1, end).join("")}${suffixClipped ? "…" : ""}`;
|
|
130
|
+
return {
|
|
131
|
+
before,
|
|
132
|
+
active,
|
|
133
|
+
after,
|
|
134
|
+
rendered: `${before}${active}${after}`,
|
|
135
|
+
prefixClipped,
|
|
136
|
+
suffixClipped,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function Header({ React, Box, Text, compact, provider, setup, workspace, }) {
|
|
140
|
+
const providerLabel = provider?.configured
|
|
141
|
+
? `${(0, terminal_text_1.terminalSafeText)(provider.display_name)}${provider.model ? ` · ${(0, terminal_text_1.terminalSafeText)(provider.model)}` : ""}`
|
|
142
|
+
: "";
|
|
143
|
+
const safeWorkspace = (0, terminal_text_1.terminalSafeText)(workspace);
|
|
144
|
+
if (compact) {
|
|
145
|
+
const compactContext = setup ? " setup" : ` · ${providerLabel || "local"}`;
|
|
146
|
+
return React.createElement(Box, { flexDirection: "row", marginBottom: 1, flexShrink: 1 }, React.createElement(Text, { bold: true, color: "cyan" }, "◆ kagent"), React.createElement(Text, { color: "gray", wrap: "truncate" }, compactContext));
|
|
147
|
+
}
|
|
148
|
+
const sessionLabel = [safeWorkspace, providerLabel].filter(Boolean).join(" · ") || "local session";
|
|
149
|
+
return React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, React.createElement(Box, { flexDirection: "row", flexShrink: 0 }, React.createElement(Text, { bold: true, color: "cyan" }, "◆ kagent"), React.createElement(Text, { color: "gray" }, setup ? " setup" : "")), React.createElement(Text, { color: "gray", wrap: "truncate" }, sessionLabel));
|
|
150
|
+
}
|
|
151
|
+
function ProviderSetupPanel({ React, Box, Text, frame, setup, }) {
|
|
152
|
+
const option = (0, provider_setup_1.selectedProvider)(setup);
|
|
153
|
+
if (setup.stage === "provider") {
|
|
154
|
+
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, { bold: true }, "Connect a model provider"), React.createElement(Box, { flexDirection: "column", marginTop: 1 }, ...setup.options.map((candidate, index) => React.createElement(Text, {
|
|
155
|
+
key: candidate.provider,
|
|
156
|
+
bold: index === setup.selectedIndex,
|
|
157
|
+
color: index === setup.selectedIndex ? "cyan" : undefined,
|
|
158
|
+
}, `${index === setup.selectedIndex ? "›" : " "} ${candidate.label}`))), React.createElement(Text, { color: "gray" }, "↑↓ choose enter continue esc quit"));
|
|
159
|
+
}
|
|
160
|
+
if (setup.stage === "saving") {
|
|
161
|
+
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, { bold: true }, `Connect ${option.label}`), React.createElement(Text, { color: "cyan" }, `${exports.TERMINAL_SPINNER_FRAMES[frame]} Saving settings`));
|
|
162
|
+
}
|
|
163
|
+
const field = setupField(setup);
|
|
164
|
+
const displayValue = setup.stage === "api_key" ? (0, provider_setup_1.maskSecret)(setup.editor.value) : setup.editor.value;
|
|
165
|
+
return React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, { bold: true }, `Connect ${option.label}`), React.createElement(Text, { color: "gray", bold: true }, field.label), React.createElement(PromptLine, {
|
|
166
|
+
React,
|
|
167
|
+
Box,
|
|
168
|
+
Text,
|
|
169
|
+
cursor: setup.editor.cursor,
|
|
170
|
+
input: displayValue,
|
|
171
|
+
disabled: false,
|
|
172
|
+
placeholder: field.placeholder,
|
|
173
|
+
compact: true,
|
|
174
|
+
}), setup.error ? React.createElement(Text, { color: "red", wrap: "wrap" }, setup.error) : null, React.createElement(Text, { color: "gray" }, "enter continue esc back"));
|
|
175
|
+
}
|
|
176
|
+
function MessageList({ React, Box, Text, messages, }) {
|
|
177
|
+
return React.createElement(Box, { flexDirection: "column" }, ...messages.map((message) => {
|
|
178
|
+
const marker = message.role === "user" ? "›" : message.role === "assistant" ? "•" : message.role === "command" ? "·" : "!";
|
|
179
|
+
const color = message.role === "user" ? "cyan" : message.role === "system" ? "red" : message.role === "command" ? "gray" : undefined;
|
|
180
|
+
return React.createElement(Box, { key: message.id, flexDirection: "row", marginBottom: 1 }, React.createElement(Text, { color, bold: message.role === "user" }, `${marker} `), React.createElement(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1 }, message.title ? React.createElement(Text, { bold: true, color }, message.title) : null, message.detail
|
|
181
|
+
? React.createElement(Text, { color: "gray", wrap: "wrap" }, message.detail)
|
|
182
|
+
: null, message.text
|
|
183
|
+
? React.createElement(Text, { color, wrap: "wrap" }, message.text)
|
|
184
|
+
: null, message.expanded && message.content
|
|
185
|
+
? React.createElement(Text, { color: "gray", wrap: "wrap" }, message.content)
|
|
186
|
+
: null));
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
function TranscriptPosition({ React, Text, newerCount, }) {
|
|
190
|
+
if (newerCount <= 0) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return React.createElement(Text, { color: "gray" }, `History · ${newerCount} newer`);
|
|
194
|
+
}
|
|
195
|
+
function ApprovalPanel({ React, Box, Text, approval, choice, compact, showDetails, }) {
|
|
196
|
+
return React.createElement(Box, { flexDirection: "column", marginY: 1, paddingLeft: compact ? 0 : 2 }, React.createElement(Text, { bold: true, color: "yellow" }, "Permission required"), React.createElement(Text, { wrap: "wrap" }, approval.title), approval.target ? React.createElement(Text, { color: "cyan", wrap: "wrap" }, approval.target) : null, showDetails && approval.details?.length
|
|
197
|
+
? React.createElement(Box, { flexDirection: "column", marginTop: 1 }, ...approval.details.map((detail, index) => React.createElement(Text, { key: `${index}-${detail}`, color: "cyan", wrap: "wrap" }, ` ${detail}`)))
|
|
198
|
+
: null, showDetails && approval.reason
|
|
199
|
+
? React.createElement(Text, { color: "gray", wrap: "wrap" }, approval.reason)
|
|
200
|
+
: null, React.createElement(Box, { flexDirection: "row", marginTop: 1 }, React.createElement(Text, { bold: choice === "allow", color: choice === "allow" ? "cyan" : "gray" }, `${choice === "allow" ? "›" : " "} Allow once`), React.createElement(Text, {
|
|
201
|
+
bold: choice === "deny",
|
|
202
|
+
color: choice === "deny" ? "yellow" : "gray",
|
|
203
|
+
}, `${compact ? " " : " "}${choice === "deny" ? "›" : " "} Deny`)), React.createElement(Text, { color: "gray" }, "←→ select · enter confirm · d details"));
|
|
204
|
+
}
|
|
205
|
+
function CommandPalette({ React, Box, Text, compact, limit, menu, }) {
|
|
206
|
+
const visibleStart = Math.min(Math.max(menu.selectedIndex - limit + 1, 0), Math.max(menu.options.length - limit, 0));
|
|
207
|
+
const visibleOptions = menu.options.slice(visibleStart, visibleStart + limit);
|
|
208
|
+
return React.createElement(Box, { flexDirection: "column", paddingLeft: compact ? 0 : 2, marginTop: 1 }, ...visibleOptions.map((option, index) => {
|
|
209
|
+
const selected = visibleStart + index === menu.selectedIndex;
|
|
210
|
+
return React.createElement(Box, { key: option.command, flexDirection: compact ? "column" : "row" }, React.createElement(Text, {
|
|
211
|
+
bold: selected,
|
|
212
|
+
color: selected ? "cyan" : "gray",
|
|
213
|
+
wrap: "truncate",
|
|
214
|
+
}, `${selected ? "›" : " "} ${option.command}`), compact
|
|
215
|
+
? selected
|
|
216
|
+
? React.createElement(Text, { color: "gray", wrap: "wrap" }, ` ${option.description}`)
|
|
217
|
+
: null
|
|
218
|
+
: React.createElement(Text, { color: "gray", wrap: "truncate" }, ` ${option.description}`));
|
|
219
|
+
}), React.createElement(Text, { color: "gray" }, "↑↓ choose · tab complete · enter run"));
|
|
220
|
+
}
|
|
221
|
+
function StatusLine({ React, Text, frame, elapsedSeconds, status, statusText, }) {
|
|
222
|
+
if (status !== "thinking" && status !== "cancelling" && status !== "starting") {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const label = status === "starting" ? "Starting runtime" : statusText;
|
|
226
|
+
const elapsed = elapsedSeconds > 0 ? ` · ${elapsedSeconds}s` : "";
|
|
227
|
+
return React.createElement(Text, { color: "cyan" }, `${exports.TERMINAL_SPINNER_FRAMES[frame]} ${label}${elapsed}`);
|
|
228
|
+
}
|
|
229
|
+
function PromptLine({ React, Box, Text, cursor, disabled, input, placeholder = "Ask kagent", compact = false, columns = 80, maxRows = 6, }) {
|
|
230
|
+
const viewport = createPromptViewport(input, cursor, columns, maxRows);
|
|
231
|
+
return React.createElement(Box, { flexDirection: "row", marginTop: compact ? 0 : 1, alignItems: "flex-start" }, React.createElement(Text, { color: disabled ? "gray" : "cyan" }, "› "), input
|
|
232
|
+
? React.createElement(Text, { wrap: "wrap" }, viewport.before, React.createElement(Text, { inverse: !disabled }, viewport.active), viewport.after)
|
|
233
|
+
: React.createElement(Text, { color: "gray" }, disabled ? "" : placeholder));
|
|
234
|
+
}
|
|
235
|
+
function setupField(setup) {
|
|
236
|
+
if (setup.stage === "base_url") {
|
|
237
|
+
return { label: "Base URL", placeholder: "https://api.example.com/v1" };
|
|
238
|
+
}
|
|
239
|
+
if (setup.stage === "model") {
|
|
240
|
+
return { label: "Model", placeholder: "model-id" };
|
|
241
|
+
}
|
|
242
|
+
const required = (0, provider_setup_1.selectedProvider)(setup).api_key_required;
|
|
243
|
+
return {
|
|
244
|
+
label: required ? "API key" : "API key (optional)",
|
|
245
|
+
placeholder: required ? "Paste API key" : "Leave empty for local providers",
|
|
246
|
+
};
|
|
247
|
+
}
|