akernel-runtime 0.1.6__tar.gz → 0.1.8__tar.gz

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.
Files changed (98) hide show
  1. akernel_runtime-0.1.8/.github/release-notes/v0.1.7.md +32 -0
  2. akernel_runtime-0.1.8/.github/release-notes/v0.1.8.md +14 -0
  3. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/CHANGELOG.md +20 -0
  4. {akernel_runtime-0.1.6/src/akernel_runtime.egg-info → akernel_runtime-0.1.8}/PKG-INFO +2 -1
  5. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/packages/npm/akernel/package.json +1 -1
  6. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/pyproject.toml +2 -2
  7. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8/src/akernel_runtime.egg-info}/PKG-INFO +2 -1
  8. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/akernel_runtime.egg-info/SOURCES.txt +2 -0
  9. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/akernel_runtime.egg-info/requires.txt +1 -0
  10. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/__init__.py +1 -1
  11. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/cli.py +120 -23
  12. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/tests/test_runtime.py +15 -1
  13. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.env.example +0 -0
  14. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  15. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  16. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/pull_request_template.md +0 -0
  17. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.0.md +0 -0
  18. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.1.md +0 -0
  19. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.2.md +0 -0
  20. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.3.md +0 -0
  21. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.4.md +0 -0
  22. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.5.md +0 -0
  23. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/release-notes/v0.1.6.md +0 -0
  24. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/workflows/ci.yml +0 -0
  25. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/.github/workflows/release.yml +0 -0
  26. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/CODE_OF_CONDUCT.md +0 -0
  27. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/CONTRIBUTING.md +0 -0
  28. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/LICENSE +0 -0
  29. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/MANIFEST.in +0 -0
  30. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/NOTICE +0 -0
  31. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/README.md +0 -0
  32. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/SECURITY.md +0 -0
  33. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/00-vision.md +0 -0
  34. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/01-architecture.md +0 -0
  35. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/02-execution-plan.md +0 -0
  36. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/03-cli-mvp.md +0 -0
  37. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/04-evaluation.md +0 -0
  38. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/05-local-wake.md +0 -0
  39. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/06-skill-compiler.md +0 -0
  40. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/07-release-and-ci.md +0 -0
  41. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/08-open-source-plan.md +0 -0
  42. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/09-product-roadmap.md +0 -0
  43. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/10-benchmark-evidence.md +0 -0
  44. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/docs/11-publishing-setup.md +0 -0
  45. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/phase2/01-routing.json +0 -0
  46. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/phase2/02-memory.json +0 -0
  47. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/phase2/03-budget-profiles.json +0 -0
  48. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/scale/01-context-pressure.json +0 -0
  49. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/scale/02-agent-editing.json +0 -0
  50. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/benchmarks/scale/03-global-memory-marketplace.json +0 -0
  51. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/evals/phase2.json +0 -0
  52. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/marketplace/skills/index.json +0 -0
  53. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/skills/context_budget.json +0 -0
  54. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/skills/edit_file.json +0 -0
  55. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/examples/skills/markdown/context_budget.md +0 -0
  56. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/packages/npm/akernel/README.md +0 -0
  57. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/packages/npm/akernel/bin/akernel.js +0 -0
  58. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/scripts/install_remote.ps1 +0 -0
  59. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/scripts/release_check.ps1 +0 -0
  60. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/setup.cfg +0 -0
  61. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/setup.cmd +0 -0
  62. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/setup.ps1 +0 -0
  63. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/akernel_runtime.egg-info/dependency_links.txt +0 -0
  64. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/akernel_runtime.egg-info/entry_points.txt +0 -0
  65. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/akernel_runtime.egg-info/top_level.txt +0 -0
  66. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/__main__.py +0 -0
  67. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/agent_reports.py +0 -0
  68. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/benchmarks.py +0 -0
  69. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/budget.py +0 -0
  70. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/context.py +0 -0
  71. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/evals.py +0 -0
  72. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/global_memory.py +0 -0
  73. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/loop.py +0 -0
  74. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace.py +0 -0
  75. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/context_budget.json +0 -0
  76. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/context_compaction.json +0 -0
  77. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/edit_file.json +0 -0
  78. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/index.json +0 -0
  79. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/long_task_planning.json +0 -0
  80. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/marketplace_data/skills/multi_file_bugfix.json +0 -0
  81. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/memory.py +0 -0
  82. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/models.py +0 -0
  83. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/planner.py +0 -0
  84. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/policy.py +0 -0
  85. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/project.py +0 -0
  86. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/providers.py +0 -0
  87. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/report_costs.py +0 -0
  88. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/runner.py +0 -0
  89. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/skills.py +0 -0
  90. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/state_writer.py +0 -0
  91. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/storage.py +0 -0
  92. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/tasks.py +0 -0
  93. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/text.py +0 -0
  94. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/tokenizer.py +0 -0
  95. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/tools.py +0 -0
  96. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/src/context_kernel/verifier.py +0 -0
  97. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/wake.cmd +0 -0
  98. {akernel_runtime-0.1.6 → akernel_runtime-0.1.8}/wake.ps1 +0 -0
@@ -0,0 +1,32 @@
1
+ # Context Kernel v0.1.7
2
+
3
+ This release adds real-time interactive completions to `akernel`.
4
+
5
+ ## Install
6
+
7
+ Python:
8
+
9
+ ```powershell
10
+ python -m pip install --user --upgrade akernel-runtime
11
+ akernel setup
12
+ akernel
13
+ ```
14
+
15
+ npm launcher:
16
+
17
+ ```powershell
18
+ npm install -g @context-akernel/akernel
19
+ akernel setup
20
+ akernel
21
+ ```
22
+
23
+ ## Highlights
24
+
25
+ - Typing `/` now opens command completions such as `/help`, `/status`, `/model`, and `/cost`.
26
+ - Typing `@` now opens workspace file completions for attaching files.
27
+ - Non-interactive shells and scripts still fall back to standard `input()` behavior.
28
+
29
+ ## Verification
30
+
31
+ - Added completion unit coverage for slash commands and `@` file candidates.
32
+ - Ran the full Python test suite.
@@ -0,0 +1,14 @@
1
+ # Context Kernel v0.1.8
2
+
3
+ This patch fixes the default TUI rendering rhythm so chat turns no longer flood the terminal with repeated full-screen layouts.
4
+
5
+ ## Highlights
6
+
7
+ - The startup workspace view still appears once.
8
+ - Each normal user message now appends only the user turn, compact status, and assistant result.
9
+ - Full redraw remains available through `/clear` or `AKERNEL_ALT_SCREEN=1`.
10
+
11
+ ## Verification
12
+
13
+ - Added regression coverage to ensure normal TUI turns do not repeatedly print the full header.
14
+ - Ran the full Python test suite.
@@ -8,6 +8,26 @@ The project follows a pragmatic pre-1.0 changelog: breaking changes may occur, b
8
8
 
9
9
  No changes yet.
10
10
 
11
+ ## 0.1.8 - 2026-05-14
12
+
13
+ ### Changed
14
+
15
+ - Changed the default TUI loop to render the full workspace view once, then append only incremental user/status/assistant updates for each turn.
16
+
17
+ ### Fixed
18
+
19
+ - Prevented normal chat turns from repeatedly printing the full fixed UI layout and filling the terminal scrollback.
20
+
21
+ ## 0.1.7 - 2026-05-14
22
+
23
+ ### Added
24
+
25
+ - Added real-time chat input completions for slash commands and `@` workspace file search.
26
+
27
+ ### Changed
28
+
29
+ - Added `prompt_toolkit` as the interactive input dependency, with automatic fallback to native `input()` in non-interactive terminals.
30
+
11
31
  ## 0.1.6 - 2026-05-14
12
32
 
13
33
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akernel-runtime
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Agent Kernel: a CLI-first context-native agent runtime prototype.
5
5
  Author: Context Kernel contributors
6
6
  License-Expression: Apache-2.0
@@ -20,6 +20,7 @@ Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  License-File: NOTICE
23
+ Requires-Dist: prompt_toolkit>=3.0.43
23
24
  Provides-Extra: dev
24
25
  Requires-Dist: build>=1.2; extra == "dev"
25
26
  Requires-Dist: twine>=5.0; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-akernel/akernel",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "npm launcher wrapper for the Context Kernel akernel CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/huanxin0825-ctrl/context-akernel#readme",
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "akernel-runtime"
7
- version = "0.1.6"
7
+ version = "0.1.8"
8
8
  description = "Agent Kernel: a CLI-first context-native agent runtime prototype."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
11
11
  license-files = ["LICENSE", "NOTICE"]
12
12
  requires-python = ">=3.10"
13
- dependencies = []
13
+ dependencies = ["prompt_toolkit>=3.0.43"]
14
14
  keywords = ["agent", "cli", "context", "llm", "token-budget"]
15
15
  authors = [
16
16
  { name = "Context Kernel contributors" },
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: akernel-runtime
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Agent Kernel: a CLI-first context-native agent runtime prototype.
5
5
  Author: Context Kernel contributors
6
6
  License-Expression: Apache-2.0
@@ -20,6 +20,7 @@ Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  License-File: NOTICE
23
+ Requires-Dist: prompt_toolkit>=3.0.43
23
24
  Provides-Extra: dev
24
25
  Requires-Dist: build>=1.2; extra == "dev"
25
26
  Requires-Dist: twine>=5.0; extra == "dev"
@@ -22,6 +22,8 @@ wake.ps1
22
22
  .github/release-notes/v0.1.4.md
23
23
  .github/release-notes/v0.1.5.md
24
24
  .github/release-notes/v0.1.6.md
25
+ .github/release-notes/v0.1.7.md
26
+ .github/release-notes/v0.1.8.md
25
27
  .github/workflows/ci.yml
26
28
  .github/workflows/release.yml
27
29
  docs/00-vision.md
@@ -1,3 +1,4 @@
1
+ prompt_toolkit>=3.0.43
1
2
 
2
3
  [dev]
3
4
  build>=1.2
@@ -1,3 +1,3 @@
1
1
  """Context Kernel CLI-first agent runtime prototype."""
2
2
 
3
- __version__ = "0.1.6"
3
+ __version__ = "0.1.8"
@@ -43,6 +43,22 @@ from .verifier import verify_trace
43
43
 
44
44
  DEFAULT_PRIMARY_MODEL = "gpt-5.5"
45
45
  DEFAULT_AUXILIARY_MODEL = "gpt-5.3-codex"
46
+ CHAT_COMMANDS: list[tuple[str, str]] = [
47
+ ("/help", "show command palette"),
48
+ ("/status", "show workspace and runtime status"),
49
+ ("/model", "show primary and auxiliary model roles"),
50
+ ("/config", "show setup and environment guidance"),
51
+ ("/compact", "show compact task brief"),
52
+ ("/paste", "enter a multi-line task"),
53
+ ("/task", "print current task session JSON"),
54
+ ("/runs", "list recent agent runs"),
55
+ ("/cost", "print last run cost report"),
56
+ ("/up", "show older transcript lines"),
57
+ ("/down", "move back toward latest messages"),
58
+ ("/latest", "jump to latest messages"),
59
+ ("/clear", "clear transcript"),
60
+ ("/exit", "leave interactive session"),
61
+ ]
46
62
  OPENAI_ENV_KEYS = {
47
63
  "api_key": "AKERNEL_OPENAI_API_KEY",
48
64
  "base_url": "AKERNEL_OPENAI_BASE_URL",
@@ -1075,7 +1091,7 @@ def cmd_chat(args: argparse.Namespace) -> None:
1075
1091
  print_chat_header(workspace, task_id, args)
1076
1092
  while True:
1077
1093
  try:
1078
- request = input(chat_prompt(args)).strip()
1094
+ request = read_chat_input(chat_prompt(args), workspace).strip()
1079
1095
  except EOFError:
1080
1096
  print("")
1081
1097
  break
@@ -1236,15 +1252,15 @@ def run_chat_loop_tui(
1236
1252
  render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1237
1253
  while True:
1238
1254
  try:
1239
- request = input(tui_prompt(args)).strip()
1255
+ request = read_chat_input(tui_prompt(args), workspace).strip()
1240
1256
  except EOFError:
1241
1257
  break
1242
1258
  except KeyboardInterrupt:
1243
1259
  transcript.append({"role": "system", "title": "Interrupted", "text": "Keyboard interrupt received."})
1244
- render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="interrupted", state=state, clear=use_alt_screen)
1260
+ render_chat_tui_update(workspace, task_id, args, transcript, last_report, pending_context, status="interrupted", state=state, clear=use_alt_screen)
1245
1261
  break
1246
1262
  if not request:
1247
- render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1263
+ render_chat_tui_update(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1248
1264
  continue
1249
1265
  lowered = request.lower()
1250
1266
  if lowered in {"/exit", "/quit", "exit", "quit"}:
@@ -1267,14 +1283,15 @@ def run_chat_loop_tui(
1267
1283
  state=state,
1268
1284
  ):
1269
1285
  last_report = state.get("last_report")
1270
- render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1286
+ render_chat_tui_update(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1271
1287
  continue
1272
1288
 
1273
1289
  request_for_agent = merge_pending_context(request, pending_context)
1274
1290
  pending_context.clear()
1275
1291
  state["scroll_offset"] = 0
1276
1292
  transcript.append({"role": "user", "title": "You", "text": request_for_agent})
1277
- render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="running", state=state, clear=use_alt_screen)
1293
+ render_chat_tui_message({"role": "user", "title": "You", "text": request_for_agent})
1294
+ render_chat_tui_status("running", args, pending_context)
1278
1295
  last_report = AgentLoop(workspace).run(
1279
1296
  request_for_agent,
1280
1297
  provider_name=args.provider,
@@ -1292,7 +1309,8 @@ def run_chat_loop_tui(
1292
1309
  expect_json=args.expect_json,
1293
1310
  )
1294
1311
  transcript.append({"role": "assistant", "title": "Assistant", "text": format_tui_report(last_report)})
1295
- render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status="ready", state=state, clear=use_alt_screen)
1312
+ render_chat_tui_message({"role": "assistant", "title": "Assistant", "text": format_tui_report(last_report)})
1313
+ render_chat_tui_status("ready", args, pending_context, last_report=last_report)
1296
1314
  finally:
1297
1315
  if use_alt_screen:
1298
1316
  print("\033[?1049l", end="")
@@ -1392,27 +1410,62 @@ def capture_chat_output(func: Any) -> str:
1392
1410
 
1393
1411
  def format_chat_help_text() -> str:
1394
1412
  rows = [
1395
- ("/help", "show this command palette"),
1396
- ("/status", "show workspace and runtime status"),
1397
- ("/model", "show primary and auxiliary model roles"),
1398
- ("/config", "show setup and environment guidance"),
1399
- ("/compact", "show the compact task brief used for resume context"),
1400
- ("/paste", "enter a multi-line task; finish with /end"),
1401
- ("@path", "attach a workspace file to the next task"),
1402
- ("!command", "run a policy-checked command and attach its summary"),
1403
- ("/task", "print the current task session JSON"),
1404
- ("/runs", "list recent agent runs"),
1405
- ("/cost", "print the last agent run cost report"),
1406
- ("/up", "show older transcript lines in the viewport"),
1407
- ("/down", "move the viewport back toward latest messages"),
1408
- ("/latest", "jump to the newest transcript lines"),
1409
- ("/clear", "clear the transcript"),
1410
- ("/exit", "leave the interactive session"),
1413
+ *CHAT_COMMANDS,
1411
1414
  ("@query", "search current workspace files; use @1, @2... to attach a listed match"),
1415
+ ("!command", "run a policy-checked command and attach its summary"),
1412
1416
  ]
1413
1417
  return "\n".join(f"{name:<10} {description}" for name, description in rows)
1414
1418
 
1415
1419
 
1420
+ def read_chat_input(prompt: str, workspace: Workspace) -> str:
1421
+ if not should_use_prompt_toolkit():
1422
+ return input(prompt)
1423
+ try:
1424
+ from prompt_toolkit import PromptSession
1425
+ from prompt_toolkit.completion import Completer, Completion
1426
+ from prompt_toolkit.formatted_text import ANSI
1427
+ from prompt_toolkit.shortcuts import CompleteStyle
1428
+ except ImportError:
1429
+ return input(prompt)
1430
+
1431
+ class ChatCompleter(Completer):
1432
+ def get_completions(self, document: Any, complete_event: Any) -> Any:
1433
+ text = document.text_before_cursor
1434
+ for value, description in chat_completion_items(workspace.root, text):
1435
+ yield Completion(value, start_position=-len(text), display=value, display_meta=description)
1436
+
1437
+ session = PromptSession(
1438
+ completer=ChatCompleter(),
1439
+ complete_while_typing=True,
1440
+ complete_in_thread=True,
1441
+ complete_style=CompleteStyle.MULTI_COLUMN,
1442
+ reserve_space_for_menu=6,
1443
+ )
1444
+ return session.prompt(ANSI(prompt))
1445
+
1446
+
1447
+ def should_use_prompt_toolkit() -> bool:
1448
+ if os.environ.get("AKERNEL_NO_COMPLETION"):
1449
+ return False
1450
+ return bool(sys.stdin.isatty() and sys.stdout.isatty())
1451
+
1452
+
1453
+ def chat_completion_items(root: Path, text: str, *, limit: int = 12) -> list[tuple[str, str]]:
1454
+ value = text.strip()
1455
+ if value.startswith("/"):
1456
+ query = value.casefold()
1457
+ return [
1458
+ (command, description)
1459
+ for command, description in CHAT_COMMANDS
1460
+ if command.casefold().startswith(query)
1461
+ ][:limit]
1462
+ if value.startswith("@"):
1463
+ query = value[1:].strip()
1464
+ matches = find_workspace_files(root, query, limit=limit)
1465
+ return [(f"@{path}", "attach file") for path in matches]
1466
+ return []
1467
+
1468
+
1416
1469
  def tui_prompt(args: argparse.Namespace) -> str:
1417
1470
  return chat_color("\nakernel", "cyan", bold=True) + chat_color(f" [{primary_model(args)}]", "dim") + "> "
1418
1471
 
@@ -1434,6 +1487,50 @@ def render_chat_tui_screen(
1434
1487
  print(prefix + screen + ("\n" if not clear else ""), end="")
1435
1488
 
1436
1489
 
1490
+ def render_chat_tui_update(
1491
+ workspace: Workspace,
1492
+ task_id: str,
1493
+ args: argparse.Namespace,
1494
+ transcript: list[dict[str, str]],
1495
+ last_report: dict[str, Any] | None,
1496
+ pending_context: list[str],
1497
+ *,
1498
+ status: str,
1499
+ state: dict[str, Any] | None = None,
1500
+ clear: bool = True,
1501
+ ) -> None:
1502
+ if clear:
1503
+ render_chat_tui_screen(workspace, task_id, args, transcript, last_report, pending_context, status=status, state=state, clear=True)
1504
+ return
1505
+ if transcript:
1506
+ render_chat_tui_message(transcript[-1])
1507
+ render_chat_tui_status(status, args, pending_context, last_report=last_report)
1508
+
1509
+
1510
+ def render_chat_tui_message(item: dict[str, str]) -> None:
1511
+ width = chat_width()
1512
+ role = item.get("role", "system")
1513
+ title = item.get("title", role)
1514
+ label = tui_role_label(role, title)
1515
+ prefix = " " if role != "user" else "> "
1516
+ print("")
1517
+ print(chat_color(truncate_line(label, width), "cyan" if role == "system" else "green" if role == "assistant" else "yellow", bold=True))
1518
+ for line in wrap_plain(item.get("text", ""), width=max(20, width - len(prefix))).splitlines():
1519
+ print(truncate_line(prefix + line, width))
1520
+
1521
+
1522
+ def render_chat_tui_status(
1523
+ status: str,
1524
+ args: argparse.Namespace,
1525
+ pending_context: list[str],
1526
+ *,
1527
+ last_report: dict[str, Any] | None = None,
1528
+ ) -> None:
1529
+ tokens = 0 if not last_report else last_report.get("totals", {}).get("total_tokens", 0)
1530
+ summary = f"{status} | provider {args.provider} | primary {primary_model(args)} | attached {len(pending_context)} | tokens {tokens}"
1531
+ print(chat_color(truncate_line(summary, chat_width()), "dim"))
1532
+
1533
+
1437
1534
  def build_chat_tui_screen(
1438
1535
  workspace: Workspace,
1439
1536
  task_id: str,
@@ -10,7 +10,7 @@ from unittest.mock import patch
10
10
  from context_kernel.agent_reports import build_agent_cost_report, render_agent_cost_report
11
11
  from context_kernel.benchmarks import BenchmarkRunner, render_benchmark_evidence_markdown, render_benchmark_markdown
12
12
  from context_kernel.budget import allocate_budget
13
- from context_kernel.cli import build_chat_tui_screen, load_batch_patch_specs, main, print_agent_report
13
+ from context_kernel.cli import build_chat_tui_screen, chat_completion_items, load_batch_patch_specs, main, print_agent_report
14
14
  from context_kernel.context import ContextBuilder
15
15
  from context_kernel.evals import EvalRunner
16
16
  from context_kernel.global_memory import pull_global_memories, push_global_memories
@@ -1357,6 +1357,7 @@ class RuntimeTests(unittest.TestCase):
1357
1357
  self.assertIn("Assistant", output)
1358
1358
  self.assertIn("Mock agent response", output)
1359
1359
  self.assertIn("bye", output)
1360
+ self.assertEqual(output.count("AKERNEL // READY"), 1)
1360
1361
 
1361
1362
  def test_tui_screen_can_render_older_history_window(self) -> None:
1362
1363
  with tempfile.TemporaryDirectory() as tmp:
@@ -1417,6 +1418,19 @@ class RuntimeTests(unittest.TestCase):
1417
1418
  self.assertIn("Attached File", output)
1418
1419
  self.assertIn("Mock agent response", output)
1419
1420
 
1421
+ def test_chat_completion_items_include_commands_and_files(self) -> None:
1422
+ with tempfile.TemporaryDirectory() as tmp:
1423
+ root = Path(tmp)
1424
+ (root / "README.md").write_text("demo", encoding="utf-8")
1425
+ (root / "src").mkdir()
1426
+ (root / "src" / "runtime.py").write_text("print('ok')", encoding="utf-8")
1427
+
1428
+ command_items = chat_completion_items(root, "/mo")
1429
+ file_items = chat_completion_items(root, "@run")
1430
+
1431
+ self.assertIn(("/model", "show primary and auxiliary model roles"), command_items)
1432
+ self.assertIn(("@src/runtime.py", "attach file"), file_items)
1433
+
1420
1434
  def test_tui_screen_surfaces_task_plan_and_command_strip(self) -> None:
1421
1435
  with tempfile.TemporaryDirectory() as tmp:
1422
1436
  workspace = Workspace(Path(tmp))
File without changes
File without changes