@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,401 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shlex
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from difflib import get_close_matches
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from kagent.cli.commands import runtime_interactive_commands
|
|
10
|
+
from kagent.cli.conversation import compact_runtime_conversation_memory
|
|
11
|
+
from kagent.cli.memory import (
|
|
12
|
+
RuntimeSessionMemory,
|
|
13
|
+
clear_runtime_history,
|
|
14
|
+
default_runtime_history_path,
|
|
15
|
+
save_runtime_session_memory,
|
|
16
|
+
)
|
|
17
|
+
from kagent.providers.llm import (
|
|
18
|
+
LLMProviderConfig,
|
|
19
|
+
missing_provider_config_fields,
|
|
20
|
+
provider_display_name,
|
|
21
|
+
)
|
|
22
|
+
from kagent.runtime.tools import registered_runtime_tool_metadata
|
|
23
|
+
|
|
24
|
+
_SUPPORTED_COMMANDS = {
|
|
25
|
+
"/help",
|
|
26
|
+
"/pwd",
|
|
27
|
+
"/cd",
|
|
28
|
+
"/status",
|
|
29
|
+
"/config",
|
|
30
|
+
"/tools",
|
|
31
|
+
"/memory",
|
|
32
|
+
"/compact-memory",
|
|
33
|
+
"/clear",
|
|
34
|
+
"/reset",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_ACTION_GROUPS = (
|
|
38
|
+
(
|
|
39
|
+
"Workspace files",
|
|
40
|
+
{"apply_patch", "list_files", "read_file"},
|
|
41
|
+
"Read, browse, create, and update files in the active workspace.",
|
|
42
|
+
),
|
|
43
|
+
(
|
|
44
|
+
"Documents and planning",
|
|
45
|
+
{"artifact", "decision_matrix", "rubric_score", "task_list", "task_transition"},
|
|
46
|
+
"Create deliverables, compare options, score results, and track tasks.",
|
|
47
|
+
),
|
|
48
|
+
(
|
|
49
|
+
"Browser and applications",
|
|
50
|
+
{"open_app", "open_url"},
|
|
51
|
+
"Open approved websites and local macOS applications.",
|
|
52
|
+
),
|
|
53
|
+
(
|
|
54
|
+
"External web requests",
|
|
55
|
+
{"http_request"},
|
|
56
|
+
"Fetch public web content after approval.",
|
|
57
|
+
),
|
|
58
|
+
(
|
|
59
|
+
"Shell commands",
|
|
60
|
+
{"shell_command"},
|
|
61
|
+
"Run bounded non-interactive commands after approval.",
|
|
62
|
+
),
|
|
63
|
+
(
|
|
64
|
+
"Skills and delegation",
|
|
65
|
+
{"delegate_task", "skill_get", "skill_list"},
|
|
66
|
+
"Use installed skills and delegate bounded subtasks.",
|
|
67
|
+
),
|
|
68
|
+
(
|
|
69
|
+
"Connected memory",
|
|
70
|
+
{
|
|
71
|
+
"memory_get",
|
|
72
|
+
"memory_put",
|
|
73
|
+
"memory_recall",
|
|
74
|
+
"memory_remember",
|
|
75
|
+
"memory_search",
|
|
76
|
+
"memory_upsert",
|
|
77
|
+
},
|
|
78
|
+
"Read and write configured short-term or semantic memory stores.",
|
|
79
|
+
),
|
|
80
|
+
(
|
|
81
|
+
"Runtime workspace",
|
|
82
|
+
{
|
|
83
|
+
"workspace_diff",
|
|
84
|
+
"workspace_history",
|
|
85
|
+
"workspace_list",
|
|
86
|
+
"workspace_read",
|
|
87
|
+
"workspace_search",
|
|
88
|
+
"workspace_write",
|
|
89
|
+
},
|
|
90
|
+
"Manage versioned runtime assets, reports, logs, and policies.",
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass(frozen=True)
|
|
96
|
+
class SessionCommandResult:
|
|
97
|
+
command: str
|
|
98
|
+
title: str
|
|
99
|
+
message: str
|
|
100
|
+
data: dict[str, Any]
|
|
101
|
+
clear_messages: bool = False
|
|
102
|
+
|
|
103
|
+
def event(self) -> dict[str, Any]:
|
|
104
|
+
return {
|
|
105
|
+
"type": "session_command_completed",
|
|
106
|
+
"command": self.command,
|
|
107
|
+
"title": self.title,
|
|
108
|
+
"message": self.message,
|
|
109
|
+
"data": self.data,
|
|
110
|
+
"clear_messages": self.clear_messages,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class SessionCommandError(ValueError):
|
|
115
|
+
def __init__(self, error_code: str, message: str, *, command: str = "") -> None:
|
|
116
|
+
super().__init__(message)
|
|
117
|
+
self.error_code = error_code
|
|
118
|
+
self.command = command
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def execute_session_command(
|
|
122
|
+
raw_command: str,
|
|
123
|
+
*,
|
|
124
|
+
memory: RuntimeSessionMemory,
|
|
125
|
+
memory_path: str,
|
|
126
|
+
provider_config: LLMProviderConfig,
|
|
127
|
+
last_payload: dict[str, Any] | None = None,
|
|
128
|
+
history_path: str = "",
|
|
129
|
+
) -> SessionCommandResult:
|
|
130
|
+
command = str(raw_command).strip()
|
|
131
|
+
if not command:
|
|
132
|
+
raise SessionCommandError("missing_command", "command is required")
|
|
133
|
+
command_name = command.split(maxsplit=1)[0].lower()
|
|
134
|
+
canonical = _canonical_command(command_name)
|
|
135
|
+
if not canonical:
|
|
136
|
+
suggestions = _command_suggestions(command_name)
|
|
137
|
+
detail = f" Try {', '.join(suggestions)}." if suggestions else " Try /help."
|
|
138
|
+
raise SessionCommandError(
|
|
139
|
+
"unknown_command",
|
|
140
|
+
f"Unknown command: {command_name}.{detail}",
|
|
141
|
+
command=command_name,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if canonical == "/help":
|
|
145
|
+
return _help_result(canonical)
|
|
146
|
+
if canonical == "/pwd":
|
|
147
|
+
cwd = os.getcwd()
|
|
148
|
+
return SessionCommandResult(canonical, "Working directory", cwd, {"cwd": cwd})
|
|
149
|
+
if canonical == "/cd":
|
|
150
|
+
return _change_directory(command, canonical)
|
|
151
|
+
if canonical == "/status":
|
|
152
|
+
return _status_result(canonical, memory, provider_config, last_payload)
|
|
153
|
+
if canonical == "/config":
|
|
154
|
+
return _config_result(canonical, provider_config)
|
|
155
|
+
if canonical == "/tools":
|
|
156
|
+
return _tools_result(canonical)
|
|
157
|
+
if canonical == "/memory":
|
|
158
|
+
return _memory_result(canonical, memory)
|
|
159
|
+
if canonical == "/compact-memory":
|
|
160
|
+
compacted_now = compact_runtime_conversation_memory(memory)
|
|
161
|
+
save_runtime_session_memory(memory_path, memory)
|
|
162
|
+
detail = (
|
|
163
|
+
f"Compacted {compacted_now} remembered turn"
|
|
164
|
+
f"{'s' if compacted_now != 1 else ''}."
|
|
165
|
+
if compacted_now
|
|
166
|
+
else "Memory is already compact."
|
|
167
|
+
)
|
|
168
|
+
return SessionCommandResult(
|
|
169
|
+
canonical,
|
|
170
|
+
"Memory compacted",
|
|
171
|
+
detail,
|
|
172
|
+
_memory_snapshot(memory),
|
|
173
|
+
)
|
|
174
|
+
if canonical == "/clear":
|
|
175
|
+
memory.clear()
|
|
176
|
+
save_runtime_session_memory(memory_path, memory)
|
|
177
|
+
return SessionCommandResult(
|
|
178
|
+
canonical,
|
|
179
|
+
"Memory cleared",
|
|
180
|
+
"Remembered context was cleared.",
|
|
181
|
+
{},
|
|
182
|
+
)
|
|
183
|
+
if canonical == "/reset":
|
|
184
|
+
memory.clear()
|
|
185
|
+
save_runtime_session_memory(memory_path, memory)
|
|
186
|
+
clear_runtime_history(history_path or default_runtime_history_path())
|
|
187
|
+
return SessionCommandResult(
|
|
188
|
+
canonical,
|
|
189
|
+
"Session reset",
|
|
190
|
+
"Conversation memory and prompt history were cleared.",
|
|
191
|
+
{},
|
|
192
|
+
clear_messages=True,
|
|
193
|
+
)
|
|
194
|
+
raise AssertionError(f"unhandled session command: {canonical}")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def redacted_provider_snapshot(config: LLMProviderConfig) -> dict[str, Any]:
|
|
198
|
+
configured = not missing_provider_config_fields(config)
|
|
199
|
+
return {
|
|
200
|
+
"configured": configured,
|
|
201
|
+
"provider": config.provider.value if configured else "unconfigured",
|
|
202
|
+
"display_name": provider_display_name(config.provider) if configured else "Unconfigured",
|
|
203
|
+
"base_url_configured": bool(config.base_url),
|
|
204
|
+
"model": config.model,
|
|
205
|
+
"api_key_configured": bool(config.api_key),
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def runtime_session_command_catalog() -> list[dict[str, Any]]:
|
|
210
|
+
return [
|
|
211
|
+
{
|
|
212
|
+
"command": command.primary,
|
|
213
|
+
"description": command.description,
|
|
214
|
+
"aliases": list(command.aliases),
|
|
215
|
+
}
|
|
216
|
+
for command in runtime_interactive_commands()
|
|
217
|
+
if command.primary.split()[0] in _SUPPORTED_COMMANDS
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _canonical_command(command_name: str) -> str:
|
|
222
|
+
for command in runtime_interactive_commands():
|
|
223
|
+
primary = command.primary.split()[0]
|
|
224
|
+
if primary not in _SUPPORTED_COMMANDS:
|
|
225
|
+
continue
|
|
226
|
+
if command_name == primary or command_name in command.aliases:
|
|
227
|
+
return primary
|
|
228
|
+
return ""
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _command_suggestions(command_name: str) -> list[str]:
|
|
232
|
+
names = []
|
|
233
|
+
for command in runtime_interactive_commands():
|
|
234
|
+
primary = command.primary.split()[0]
|
|
235
|
+
if primary in _SUPPORTED_COMMANDS:
|
|
236
|
+
names.extend((primary, *command.aliases))
|
|
237
|
+
return get_close_matches(command_name, names, n=3, cutoff=0.55)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _help_result(command_name: str) -> SessionCommandResult:
|
|
241
|
+
commands = [
|
|
242
|
+
command
|
|
243
|
+
for command in runtime_interactive_commands()
|
|
244
|
+
if command.primary.split()[0] in _SUPPORTED_COMMANDS
|
|
245
|
+
]
|
|
246
|
+
width = max(len(command.primary) for command in commands)
|
|
247
|
+
lines = [f"{command.primary.ljust(width)} {command.description}" for command in commands]
|
|
248
|
+
data = {
|
|
249
|
+
"commands": [
|
|
250
|
+
{"command": command.primary, "description": command.description}
|
|
251
|
+
for command in commands
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
return SessionCommandResult(command_name, "Commands", "\n".join(lines), data)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _change_directory(raw_command: str, command_name: str) -> SessionCommandResult:
|
|
258
|
+
try:
|
|
259
|
+
parts = shlex.split(raw_command)
|
|
260
|
+
except ValueError as exc:
|
|
261
|
+
raise SessionCommandError("invalid_command", str(exc), command=command_name) from exc
|
|
262
|
+
target_text = " ".join(parts[1:]).strip() or "~"
|
|
263
|
+
target = os.path.abspath(os.path.expanduser(target_text))
|
|
264
|
+
if not os.path.isdir(target):
|
|
265
|
+
raise SessionCommandError(
|
|
266
|
+
"directory_not_found",
|
|
267
|
+
f"Directory not found: {target}",
|
|
268
|
+
command=command_name,
|
|
269
|
+
)
|
|
270
|
+
try:
|
|
271
|
+
os.chdir(target)
|
|
272
|
+
except OSError as exc:
|
|
273
|
+
raise SessionCommandError(
|
|
274
|
+
"directory_unavailable",
|
|
275
|
+
f"Cannot use directory: {exc}",
|
|
276
|
+
command=command_name,
|
|
277
|
+
) from exc
|
|
278
|
+
cwd = os.getcwd()
|
|
279
|
+
return SessionCommandResult(command_name, "Working directory", cwd, {"cwd": cwd})
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _status_result(
|
|
283
|
+
command_name: str,
|
|
284
|
+
memory: RuntimeSessionMemory,
|
|
285
|
+
provider_config: LLMProviderConfig,
|
|
286
|
+
last_payload: dict[str, Any] | None,
|
|
287
|
+
) -> SessionCommandResult:
|
|
288
|
+
provider = redacted_provider_snapshot(provider_config)
|
|
289
|
+
memory_snapshot = _memory_snapshot(memory)
|
|
290
|
+
last_status = str((last_payload or {}).get("status", "")).strip() or "none"
|
|
291
|
+
lines = [
|
|
292
|
+
f"Directory {os.getcwd()}",
|
|
293
|
+
f"Provider {provider['display_name']}",
|
|
294
|
+
f"Model {provider['model'] or '-'}",
|
|
295
|
+
f"Memory {memory_snapshot['recent_turns']} recent, "
|
|
296
|
+
f"{memory_snapshot['compacted_turns']} compacted",
|
|
297
|
+
f"Last run {last_status}",
|
|
298
|
+
]
|
|
299
|
+
return SessionCommandResult(
|
|
300
|
+
command_name,
|
|
301
|
+
"Session",
|
|
302
|
+
"\n".join(lines),
|
|
303
|
+
{
|
|
304
|
+
"cwd": os.getcwd(),
|
|
305
|
+
"provider": provider,
|
|
306
|
+
"memory": memory_snapshot,
|
|
307
|
+
"last_status": last_status,
|
|
308
|
+
},
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _config_result(
|
|
313
|
+
command_name: str,
|
|
314
|
+
provider_config: LLMProviderConfig,
|
|
315
|
+
) -> SessionCommandResult:
|
|
316
|
+
provider = {
|
|
317
|
+
**redacted_provider_snapshot(provider_config),
|
|
318
|
+
"timeout_seconds": provider_config.timeout_seconds,
|
|
319
|
+
"max_retries": provider_config.max_retries,
|
|
320
|
+
"retry_backoff_seconds": provider_config.retry_backoff_seconds,
|
|
321
|
+
}
|
|
322
|
+
lines = [
|
|
323
|
+
f"Provider {provider['display_name']}",
|
|
324
|
+
f"Model {provider['model'] or '-'}",
|
|
325
|
+
f"Endpoint {'configured' if provider['base_url_configured'] else 'not configured'}",
|
|
326
|
+
f"API key {'configured' if provider['api_key_configured'] else 'not configured'}",
|
|
327
|
+
f"Timeout {provider['timeout_seconds']}s",
|
|
328
|
+
f"Retries {provider['max_retries']}",
|
|
329
|
+
]
|
|
330
|
+
return SessionCommandResult(command_name, "Provider", "\n".join(lines), provider)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _tools_result(command_name: str) -> SessionCommandResult:
|
|
334
|
+
metadata = registered_runtime_tool_metadata()
|
|
335
|
+
by_name = {str(item.get("name", "")): item for item in metadata}
|
|
336
|
+
capabilities = []
|
|
337
|
+
for label, names, description in _ACTION_GROUPS:
|
|
338
|
+
available = [by_name[name] for name in names if name in by_name]
|
|
339
|
+
if not available:
|
|
340
|
+
continue
|
|
341
|
+
approval = any(
|
|
342
|
+
str(item.get("approval_required_by_default", "")).lower() == "true"
|
|
343
|
+
for item in available
|
|
344
|
+
)
|
|
345
|
+
capabilities.append(
|
|
346
|
+
{
|
|
347
|
+
"label": label,
|
|
348
|
+
"access": "approval required" if approval else "available",
|
|
349
|
+
"description": description,
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
width = max(len(item["label"]) for item in capabilities)
|
|
353
|
+
lines = [
|
|
354
|
+
f"{item['label'].ljust(width)} {item['access']}"
|
|
355
|
+
for item in capabilities
|
|
356
|
+
]
|
|
357
|
+
return SessionCommandResult(
|
|
358
|
+
command_name,
|
|
359
|
+
"Capabilities",
|
|
360
|
+
"\n".join(lines),
|
|
361
|
+
{"capabilities": capabilities},
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _memory_result(command_name: str, memory: RuntimeSessionMemory) -> SessionCommandResult:
|
|
366
|
+
snapshot = _memory_snapshot(memory)
|
|
367
|
+
if not memory:
|
|
368
|
+
return SessionCommandResult(command_name, "Memory", "Memory is empty.", snapshot)
|
|
369
|
+
lines = []
|
|
370
|
+
if memory.summary:
|
|
371
|
+
lines.extend(("Summary", memory.summary))
|
|
372
|
+
if memory.facts:
|
|
373
|
+
lines.append("Facts")
|
|
374
|
+
lines.extend(f"- {fact}" for fact in memory.facts)
|
|
375
|
+
if memory.open_items:
|
|
376
|
+
lines.append("Open items")
|
|
377
|
+
lines.extend(f"- {item}" for item in memory.open_items)
|
|
378
|
+
if memory.turns:
|
|
379
|
+
lines.append("Recent turns")
|
|
380
|
+
for turn in memory.turns:
|
|
381
|
+
lines.append(f"You: {turn.get('user', '')}")
|
|
382
|
+
if turn.get("assistant"):
|
|
383
|
+
lines.append(f"kagent: {turn['assistant']}")
|
|
384
|
+
return SessionCommandResult(command_name, "Memory", "\n".join(lines), snapshot)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _memory_snapshot(memory: RuntimeSessionMemory) -> dict[str, int]:
|
|
388
|
+
return {
|
|
389
|
+
"recent_turns": len(memory.turns),
|
|
390
|
+
"compacted_turns": memory.compacted_turn_count,
|
|
391
|
+
"facts": len(memory.facts),
|
|
392
|
+
"open_items": len(memory.open_items),
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
__all__ = [
|
|
397
|
+
"SessionCommandError",
|
|
398
|
+
"SessionCommandResult",
|
|
399
|
+
"execute_session_command",
|
|
400
|
+
"redacted_provider_snapshot",
|
|
401
|
+
]
|