praisonai-code 0.0.1__py3-none-any.whl

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 (309) hide show
  1. praisonai_code/__init__.py +17 -0
  2. praisonai_code/cli/__init__.py +12 -0
  3. praisonai_code/cli/_forward_shim.py +10 -0
  4. praisonai_code/cli/_paths.py +88 -0
  5. praisonai_code/cli/_warnings.py +58 -0
  6. praisonai_code/cli/app.py +757 -0
  7. praisonai_code/cli/approval_backend.py +272 -0
  8. praisonai_code/cli/branding.py +94 -0
  9. praisonai_code/cli/commands/__init__.py +114 -0
  10. praisonai_code/cli/commands/acp.py +80 -0
  11. praisonai_code/cli/commands/agent.py +116 -0
  12. praisonai_code/cli/commands/agents.py +80 -0
  13. praisonai_code/cli/commands/app.py +139 -0
  14. praisonai_code/cli/commands/attach.py +95 -0
  15. praisonai_code/cli/commands/audit.py +102 -0
  16. praisonai_code/cli/commands/auth.py +508 -0
  17. praisonai_code/cli/commands/batch.py +848 -0
  18. praisonai_code/cli/commands/benchmark.py +286 -0
  19. praisonai_code/cli/commands/browser.py +299 -0
  20. praisonai_code/cli/commands/call.py +45 -0
  21. praisonai_code/cli/commands/chat.py +332 -0
  22. praisonai_code/cli/commands/checkpoint.py +170 -0
  23. praisonai_code/cli/commands/code.py +276 -0
  24. praisonai_code/cli/commands/command.py +114 -0
  25. praisonai_code/cli/commands/commit.py +47 -0
  26. praisonai_code/cli/commands/completion.py +333 -0
  27. praisonai_code/cli/commands/config.py +681 -0
  28. praisonai_code/cli/commands/context.py +414 -0
  29. praisonai_code/cli/commands/daemon.py +203 -0
  30. praisonai_code/cli/commands/debug.py +142 -0
  31. praisonai_code/cli/commands/deploy.py +71 -0
  32. praisonai_code/cli/commands/diag.py +55 -0
  33. praisonai_code/cli/commands/docs.py +1575 -0
  34. praisonai_code/cli/commands/doctor.py +332 -0
  35. praisonai_code/cli/commands/endpoints.py +51 -0
  36. praisonai_code/cli/commands/environment.py +179 -0
  37. praisonai_code/cli/commands/eval.py +131 -0
  38. praisonai_code/cli/commands/examples.py +953 -0
  39. praisonai_code/cli/commands/flow.py +436 -0
  40. praisonai_code/cli/commands/github.py +752 -0
  41. praisonai_code/cli/commands/hooks.py +74 -0
  42. praisonai_code/cli/commands/init.py +174 -0
  43. praisonai_code/cli/commands/knowledge.py +440 -0
  44. praisonai_code/cli/commands/langextract.py +120 -0
  45. praisonai_code/cli/commands/langfuse.py +984 -0
  46. praisonai_code/cli/commands/loop.py +211 -0
  47. praisonai_code/cli/commands/lsp.py +112 -0
  48. praisonai_code/cli/commands/managed.py +659 -0
  49. praisonai_code/cli/commands/mcp.py +763 -0
  50. praisonai_code/cli/commands/memory.py +298 -0
  51. praisonai_code/cli/commands/models.py +264 -0
  52. praisonai_code/cli/commands/n8n.py +326 -0
  53. praisonai_code/cli/commands/obs.py +19 -0
  54. praisonai_code/cli/commands/package.py +76 -0
  55. praisonai_code/cli/commands/paths.py +106 -0
  56. praisonai_code/cli/commands/permissions.py +272 -0
  57. praisonai_code/cli/commands/plugins.py +609 -0
  58. praisonai_code/cli/commands/port.py +530 -0
  59. praisonai_code/cli/commands/profile.py +466 -0
  60. praisonai_code/cli/commands/publish.py +193 -0
  61. praisonai_code/cli/commands/rag.py +913 -0
  62. praisonai_code/cli/commands/realtime.py +52 -0
  63. praisonai_code/cli/commands/recipe.py +684 -0
  64. praisonai_code/cli/commands/registry.py +59 -0
  65. praisonai_code/cli/commands/replay.py +830 -0
  66. praisonai_code/cli/commands/research.py +49 -0
  67. praisonai_code/cli/commands/retrieval.py +377 -0
  68. praisonai_code/cli/commands/rules.py +71 -0
  69. praisonai_code/cli/commands/run.py +1573 -0
  70. praisonai_code/cli/commands/sandbox.py +371 -0
  71. praisonai_code/cli/commands/schedule.py +529 -0
  72. praisonai_code/cli/commands/serve.py +690 -0
  73. praisonai_code/cli/commands/session.py +450 -0
  74. praisonai_code/cli/commands/setup.py +174 -0
  75. praisonai_code/cli/commands/skills.py +545 -0
  76. praisonai_code/cli/commands/standardise.py +711 -0
  77. praisonai_code/cli/commands/templates.py +54 -0
  78. praisonai_code/cli/commands/test.py +558 -0
  79. praisonai_code/cli/commands/todo.py +74 -0
  80. praisonai_code/cli/commands/tools.py +205 -0
  81. praisonai_code/cli/commands/traces.py +145 -0
  82. praisonai_code/cli/commands/tracker.py +852 -0
  83. praisonai_code/cli/commands/train.py +613 -0
  84. praisonai_code/cli/commands/ui.py +172 -0
  85. praisonai_code/cli/commands/up.py +354 -0
  86. praisonai_code/cli/commands/validate.py +291 -0
  87. praisonai_code/cli/commands/version.py +101 -0
  88. praisonai_code/cli/commands/workflow.py +97 -0
  89. praisonai_code/cli/config_loader.py +437 -0
  90. praisonai_code/cli/configuration/__init__.py +27 -0
  91. praisonai_code/cli/configuration/config.schema.json +57 -0
  92. praisonai_code/cli/configuration/credentials.py +446 -0
  93. praisonai_code/cli/configuration/loader.py +364 -0
  94. praisonai_code/cli/configuration/model_resolver.py +161 -0
  95. praisonai_code/cli/configuration/oauth.py +389 -0
  96. praisonai_code/cli/configuration/paths.py +224 -0
  97. praisonai_code/cli/configuration/resolver.py +687 -0
  98. praisonai_code/cli/configuration/schema.py +317 -0
  99. praisonai_code/cli/execution/__init__.py +99 -0
  100. praisonai_code/cli/execution/core.py +208 -0
  101. praisonai_code/cli/execution/profiler.py +898 -0
  102. praisonai_code/cli/execution/request.py +85 -0
  103. praisonai_code/cli/execution/result.py +74 -0
  104. praisonai_code/cli/fallback_schema.py +416 -0
  105. praisonai_code/cli/features/__init__.py +278 -0
  106. praisonai_code/cli/features/_endpoint_registry.py +64 -0
  107. praisonai_code/cli/features/_search_registry.py +43 -0
  108. praisonai_code/cli/features/acp.py +236 -0
  109. praisonai_code/cli/features/action_orchestrator.py +576 -0
  110. praisonai_code/cli/features/agent_scheduler.py +773 -0
  111. praisonai_code/cli/features/agent_tools.py +603 -0
  112. praisonai_code/cli/features/agents.py +397 -0
  113. praisonai_code/cli/features/at_mentions.py +471 -0
  114. praisonai_code/cli/features/audit_cli.py +270 -0
  115. praisonai_code/cli/features/auto_memory.py +182 -0
  116. praisonai_code/cli/features/auto_mode.py +552 -0
  117. praisonai_code/cli/features/autonomy_mode.py +546 -0
  118. praisonai_code/cli/features/background.py +356 -0
  119. praisonai_code/cli/features/base.py +168 -0
  120. praisonai_code/cli/features/benchmark.py +1462 -0
  121. praisonai_code/cli/features/capabilities.py +1326 -0
  122. praisonai_code/cli/features/checkpoints.py +345 -0
  123. praisonai_code/cli/features/cli_profiler.py +335 -0
  124. praisonai_code/cli/features/code_intelligence.py +666 -0
  125. praisonai_code/cli/features/compaction.py +294 -0
  126. praisonai_code/cli/features/compare.py +534 -0
  127. praisonai_code/cli/features/config_hierarchy.py +366 -0
  128. praisonai_code/cli/features/context_manager.py +597 -0
  129. praisonai_code/cli/features/cost_tracker.py +514 -0
  130. praisonai_code/cli/features/csv_test_runner.py +736 -0
  131. praisonai_code/cli/features/custom_definitions.py +790 -0
  132. praisonai_code/cli/features/debug.py +810 -0
  133. praisonai_code/cli/features/deploy.py +605 -0
  134. praisonai_code/cli/features/diag.py +289 -0
  135. praisonai_code/cli/features/display_jsonl.py +173 -0
  136. praisonai_code/cli/features/doctor/__init__.py +63 -0
  137. praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
  138. praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
  139. praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
  140. praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
  141. praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
  142. praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
  143. praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
  144. praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
  145. praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
  146. praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
  147. praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
  148. praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
  149. praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
  150. praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
  151. praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
  152. praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
  153. praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
  154. praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
  155. praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
  156. praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
  157. praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
  158. praisonai_code/cli/features/doctor/engine.py +266 -0
  159. praisonai_code/cli/features/doctor/formatters.py +377 -0
  160. praisonai_code/cli/features/doctor/handler.py +564 -0
  161. praisonai_code/cli/features/doctor/models.py +276 -0
  162. praisonai_code/cli/features/doctor/registry.py +239 -0
  163. praisonai_code/cli/features/endpoints.py +1016 -0
  164. praisonai_code/cli/features/eval.py +559 -0
  165. praisonai_code/cli/features/examples.py +707 -0
  166. praisonai_code/cli/features/external_agents.py +231 -0
  167. praisonai_code/cli/features/fast_context.py +410 -0
  168. praisonai_code/cli/features/file_history.py +320 -0
  169. praisonai_code/cli/features/flow_display.py +566 -0
  170. praisonai_code/cli/features/git_attribution.py +159 -0
  171. praisonai_code/cli/features/git_integration.py +651 -0
  172. praisonai_code/cli/features/guardrail.py +171 -0
  173. praisonai_code/cli/features/handoff.py +252 -0
  174. praisonai_code/cli/features/hooks.py +583 -0
  175. praisonai_code/cli/features/hybrid_workflow.py +391 -0
  176. praisonai_code/cli/features/image.py +384 -0
  177. praisonai_code/cli/features/interactive_core_headless.py +450 -0
  178. praisonai_code/cli/features/interactive_runtime.py +600 -0
  179. praisonai_code/cli/features/interactive_test_harness.py +537 -0
  180. praisonai_code/cli/features/interactive_tools.py +428 -0
  181. praisonai_code/cli/features/interactive_tui.py +603 -0
  182. praisonai_code/cli/features/job_workflow.py +906 -0
  183. praisonai_code/cli/features/jobs.py +632 -0
  184. praisonai_code/cli/features/knowledge.py +531 -0
  185. praisonai_code/cli/features/knowledge_cli.py +438 -0
  186. praisonai_code/cli/features/lite.py +244 -0
  187. praisonai_code/cli/features/logs.py +200 -0
  188. praisonai_code/cli/features/lsp_cli.py +225 -0
  189. praisonai_code/cli/features/lsp_diagnostics.py +185 -0
  190. praisonai_code/cli/features/mcp.py +344 -0
  191. praisonai_code/cli/features/message_queue.py +587 -0
  192. praisonai_code/cli/features/metrics.py +210 -0
  193. praisonai_code/cli/features/migrate.py +1329 -0
  194. praisonai_code/cli/features/migration_flow.py +463 -0
  195. praisonai_code/cli/features/migration_spec.py +276 -0
  196. praisonai_code/cli/features/n8n.py +703 -0
  197. praisonai_code/cli/features/observability.py +293 -0
  198. praisonai_code/cli/features/ollama.py +361 -0
  199. praisonai_code/cli/features/output_modes.py +155 -0
  200. praisonai_code/cli/features/output_style.py +273 -0
  201. praisonai_code/cli/features/package.py +631 -0
  202. praisonai_code/cli/features/performance.py +308 -0
  203. praisonai_code/cli/features/persistence.py +636 -0
  204. praisonai_code/cli/features/profiler/__init__.py +81 -0
  205. praisonai_code/cli/features/profiler/core.py +558 -0
  206. praisonai_code/cli/features/profiler/optimizations.py +652 -0
  207. praisonai_code/cli/features/profiler/suite.py +386 -0
  208. praisonai_code/cli/features/queue/__init__.py +73 -0
  209. praisonai_code/cli/features/queue/manager.py +435 -0
  210. praisonai_code/cli/features/queue/models.py +289 -0
  211. praisonai_code/cli/features/queue/persistence.py +564 -0
  212. praisonai_code/cli/features/queue/scheduler.py +529 -0
  213. praisonai_code/cli/features/queue/worker.py +400 -0
  214. praisonai_code/cli/features/recipe.py +2187 -0
  215. praisonai_code/cli/features/recipe_creator.py +996 -0
  216. praisonai_code/cli/features/recipe_optimizer.py +1364 -0
  217. praisonai_code/cli/features/recipe_prompts.py +226 -0
  218. praisonai_code/cli/features/registry.py +229 -0
  219. praisonai_code/cli/features/repo_map.py +860 -0
  220. praisonai_code/cli/features/router.py +466 -0
  221. praisonai_code/cli/features/safe_shell.py +427 -0
  222. praisonai_code/cli/features/sandbox_cli.py +283 -0
  223. praisonai_code/cli/features/sandbox_executor.py +536 -0
  224. praisonai_code/cli/features/sdk_knowledge.py +500 -0
  225. praisonai_code/cli/features/session.py +222 -0
  226. praisonai_code/cli/features/session_checkpoints.py +208 -0
  227. praisonai_code/cli/features/setup/__init__.py +9 -0
  228. praisonai_code/cli/features/setup/handler.py +355 -0
  229. praisonai_code/cli/features/setup/templates.py +62 -0
  230. praisonai_code/cli/features/skills.py +940 -0
  231. praisonai_code/cli/features/slash_commands.py +692 -0
  232. praisonai_code/cli/features/telemetry.py +179 -0
  233. praisonai_code/cli/features/templates.py +1390 -0
  234. praisonai_code/cli/features/thinking.py +343 -0
  235. praisonai_code/cli/features/todo.py +334 -0
  236. praisonai_code/cli/features/tools.py +680 -0
  237. praisonai_code/cli/features/tui/__init__.py +83 -0
  238. praisonai_code/cli/features/tui/app.py +871 -0
  239. praisonai_code/cli/features/tui/cli.py +580 -0
  240. praisonai_code/cli/features/tui/config.py +150 -0
  241. praisonai_code/cli/features/tui/debug.py +526 -0
  242. praisonai_code/cli/features/tui/events.py +99 -0
  243. praisonai_code/cli/features/tui/mock_provider.py +328 -0
  244. praisonai_code/cli/features/tui/orchestrator.py +652 -0
  245. praisonai_code/cli/features/tui/screens/__init__.py +50 -0
  246. praisonai_code/cli/features/tui/screens/help.py +157 -0
  247. praisonai_code/cli/features/tui/screens/main.py +568 -0
  248. praisonai_code/cli/features/tui/screens/queue.py +174 -0
  249. praisonai_code/cli/features/tui/screens/session.py +124 -0
  250. praisonai_code/cli/features/tui/screens/settings.py +148 -0
  251. praisonai_code/cli/features/tui/session_store.py +198 -0
  252. praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
  253. praisonai_code/cli/features/tui/widgets/chat.py +263 -0
  254. praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
  255. praisonai_code/cli/features/tui/widgets/composer.py +292 -0
  256. praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
  257. praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
  258. praisonai_code/cli/features/tui/widgets/status.py +181 -0
  259. praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
  260. praisonai_code/cli/features/wizard.py +289 -0
  261. praisonai_code/cli/features/workflow.py +802 -0
  262. praisonai_code/cli/features/yaml_utils.py +321 -0
  263. praisonai_code/cli/interactive/__init__.py +48 -0
  264. praisonai_code/cli/interactive/async_tui.py +1218 -0
  265. praisonai_code/cli/interactive/config.py +139 -0
  266. praisonai_code/cli/interactive/core.py +618 -0
  267. praisonai_code/cli/interactive/events.py +131 -0
  268. praisonai_code/cli/interactive/frontends/__init__.py +31 -0
  269. praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
  270. praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
  271. praisonai_code/cli/interactive/praison_io.py +502 -0
  272. praisonai_code/cli/interactive/repl.py +297 -0
  273. praisonai_code/cli/interactive/split_tui.py +456 -0
  274. praisonai_code/cli/interactive/tui_app.py +457 -0
  275. praisonai_code/cli/langfuse_client.py +360 -0
  276. praisonai_code/cli/main.py +7421 -0
  277. praisonai_code/cli/output/__init__.py +25 -0
  278. praisonai_code/cli/output/console.py +456 -0
  279. praisonai_code/cli/output/event_bridge.py +191 -0
  280. praisonai_code/cli/schedule_cli.py +54 -0
  281. praisonai_code/cli/schema_provider.py +23 -0
  282. praisonai_code/cli/session/__init__.py +16 -0
  283. praisonai_code/cli/session/resume.py +148 -0
  284. praisonai_code/cli/session/unified.py +548 -0
  285. praisonai_code/cli/state/__init__.py +31 -0
  286. praisonai_code/cli/state/identifiers.py +161 -0
  287. praisonai_code/cli/state/project_sessions.py +383 -0
  288. praisonai_code/cli/state/sessions.py +390 -0
  289. praisonai_code/cli/ui/__init__.py +160 -0
  290. praisonai_code/cli/ui/config.py +46 -0
  291. praisonai_code/cli/ui/events.py +61 -0
  292. praisonai_code/cli/ui/mg_backend.py +342 -0
  293. praisonai_code/cli/ui/plain.py +133 -0
  294. praisonai_code/cli/ui/rich_backend.py +162 -0
  295. praisonai_code/cli/unified_schema.py +655 -0
  296. praisonai_code/cli/utils/env_utils.py +126 -0
  297. praisonai_code/cli/utils/project.py +131 -0
  298. praisonai_code/cli_backends/__init__.py +73 -0
  299. praisonai_code/cli_backends/claude.py +373 -0
  300. praisonai_code/cli_backends/registry.py +113 -0
  301. praisonai_code/runtime/__init__.py +36 -0
  302. praisonai_code/runtime/__main__.py +81 -0
  303. praisonai_code/runtime/client.py +131 -0
  304. praisonai_code/runtime/descriptor.py +209 -0
  305. praisonai_code/runtime/server.py +356 -0
  306. praisonai_code-0.0.1.dist-info/METADATA +80 -0
  307. praisonai_code-0.0.1.dist-info/RECORD +309 -0
  308. praisonai_code-0.0.1.dist-info/WHEEL +5 -0
  309. praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,597 @@
1
+ """
2
+ Context Management CLI Feature for PraisonAI.
3
+
4
+ Provides CLI commands and integration for context budgeting,
5
+ optimization, and monitoring.
6
+
7
+ This module uses the SDK ContextManager facade to ensure DRY
8
+ and CLI/SDK parity.
9
+ """
10
+
11
+ from typing import Dict, List, Any, Optional
12
+
13
+
14
+ # Lazy import SDK components to avoid import overhead
15
+ def _get_sdk_manager():
16
+ """Lazy import SDK ContextManager."""
17
+ from praisonaiagents.context import ContextManager
18
+ return ContextManager
19
+
20
+
21
+ def _get_sdk_config():
22
+ """Lazy import SDK ManagerConfig."""
23
+ from praisonaiagents.context import ManagerConfig
24
+ return ManagerConfig
25
+
26
+
27
+ def _get_create_manager():
28
+ """Lazy import create_context_manager factory."""
29
+ from praisonaiagents.context import create_context_manager
30
+ return create_context_manager
31
+
32
+
33
+ class ContextManagerHandler:
34
+ """
35
+ Handles context management for interactive CLI sessions.
36
+
37
+ This is a thin wrapper around the SDK ContextManager facade.
38
+ All core logic is in the SDK to ensure DRY and parity.
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ model: str = "gpt-4o-mini",
44
+ session_id: str = "",
45
+ agent_name: str = "Assistant",
46
+ config_file: Optional[str] = None,
47
+ cli_overrides: Optional[Dict[str, Any]] = None,
48
+ ):
49
+ """
50
+ Initialize context manager handler.
51
+
52
+ Args:
53
+ model: Model name for budget calculation
54
+ session_id: Session identifier
55
+ agent_name: Agent name for monitoring
56
+ config_file: Path to config.yaml
57
+ cli_overrides: CLI argument overrides
58
+ """
59
+ # Use SDK factory with proper precedence
60
+ create_manager = _get_create_manager()
61
+ self._manager = create_manager(
62
+ model=model,
63
+ session_id=session_id,
64
+ agent_name=agent_name,
65
+ config_file=config_file,
66
+ cli_overrides=cli_overrides,
67
+ )
68
+
69
+ # Expose model for compatibility
70
+ self.model = model
71
+ self.session_id = session_id
72
+ self.agent_name = agent_name
73
+
74
+ @property
75
+ def config(self):
76
+ """Get SDK config for compatibility."""
77
+ return self._manager.config
78
+
79
+ def set_model(self, model: str) -> None:
80
+ """Update model and reset manager."""
81
+ self.model = model
82
+ create_manager = _get_create_manager()
83
+ self._manager = create_manager(
84
+ model=model,
85
+ session_id=self.session_id,
86
+ agent_name=self.agent_name,
87
+ )
88
+
89
+ def get_stats(self) -> Dict[str, Any]:
90
+ """Get current context statistics."""
91
+ stats = self._manager.get_stats()
92
+ # Add CLI-specific fields for compatibility
93
+ stats["auto_compact"] = self._manager.config.auto_compact
94
+ stats["monitor_enabled"] = self._manager.config.monitor_enabled
95
+ return stats
96
+
97
+ def track_history(self, messages: List[Dict[str, Any]]) -> int:
98
+ """Track conversation history tokens."""
99
+ return self._manager._ledger.track_history(messages)
100
+
101
+ def track_system_prompt(self, content: str) -> int:
102
+ """Track system prompt tokens."""
103
+ return self._manager._ledger.track_system_prompt(content)
104
+
105
+ def track_tools(self, tools: List[Dict[str, Any]]) -> int:
106
+ """Track tool schema tokens."""
107
+ return self._manager._ledger.track_tools(tools)
108
+
109
+ def check_overflow(self) -> bool:
110
+ """Check if context is approaching limit."""
111
+ return self._manager._ledger.get_utilization() >= self._manager.config.compact_threshold
112
+
113
+ def should_auto_compact(self) -> bool:
114
+ """Check if auto-compaction should trigger."""
115
+ return self._manager.config.auto_compact and self.check_overflow()
116
+
117
+ def optimize(
118
+ self,
119
+ messages: List[Dict[str, Any]],
120
+ strategy: Optional[str] = None,
121
+ ) -> tuple:
122
+ """
123
+ Optimize messages using configured strategy.
124
+
125
+ Args:
126
+ messages: Messages to optimize
127
+ strategy: Override strategy
128
+
129
+ Returns:
130
+ Tuple of (optimized_messages, result)
131
+ """
132
+ from praisonaiagents.context import get_optimizer, OptimizerStrategy
133
+
134
+ strategy_name = strategy or self._manager.config.strategy.value
135
+ try:
136
+ strategy_enum = OptimizerStrategy(strategy_name)
137
+ except ValueError:
138
+ strategy_enum = OptimizerStrategy.SMART
139
+
140
+ optimizer = get_optimizer(strategy_enum)
141
+ target = int(self._manager._budget.usable * self._manager.config.compact_threshold)
142
+
143
+ return optimizer.optimize(messages, target, self._manager._ledger.get_ledger())
144
+
145
+ def process(
146
+ self,
147
+ messages: List[Dict[str, Any]],
148
+ system_prompt: str = "",
149
+ tools: Optional[List[Dict[str, Any]]] = None,
150
+ ) -> Dict[str, Any]:
151
+ """
152
+ Process messages through context pipeline.
153
+
154
+ Uses SDK ContextManager.process() for full pipeline.
155
+ """
156
+ return self._manager.process(
157
+ messages=messages,
158
+ system_prompt=system_prompt,
159
+ tools=tools,
160
+ )
161
+
162
+ def write_snapshot(
163
+ self,
164
+ messages: List[Dict[str, Any]],
165
+ trigger: str = "manual",
166
+ ) -> Optional[str]:
167
+ """Write context snapshot to disk."""
168
+ return self._manager._monitor.snapshot(
169
+ ledger=self._manager._ledger.get_ledger(),
170
+ budget=self._manager._budget,
171
+ messages=messages,
172
+ session_id=self.session_id,
173
+ agent_name=self.agent_name,
174
+ model_name=self.model,
175
+ trigger=trigger,
176
+ )
177
+
178
+ def enable_monitor(self) -> None:
179
+ """Enable context monitoring."""
180
+ self._manager.config.monitor_enabled = True
181
+ self._manager._monitor.enable()
182
+
183
+ def disable_monitor(self) -> None:
184
+ """Disable context monitoring."""
185
+ self._manager.config.monitor_enabled = False
186
+ self._manager._monitor.disable()
187
+
188
+ def set_monitor_path(self, path: str) -> None:
189
+ """Set monitor output path."""
190
+ self._manager.config.monitor_path = path
191
+ self._manager._monitor.set_path(path)
192
+
193
+ def set_monitor_format(self, format: str) -> None:
194
+ """Set monitor output format."""
195
+ self._manager.config.monitor_format = format
196
+ self._manager._monitor.set_format(format)
197
+
198
+ def set_monitor_frequency(self, frequency: str) -> None:
199
+ """Set monitor update frequency."""
200
+ self._manager.config.monitor_frequency = frequency
201
+ self._manager._monitor.set_frequency(frequency)
202
+
203
+ def get_history(self) -> List[Dict[str, Any]]:
204
+ """Get optimization history."""
205
+ return self._manager.get_history()
206
+
207
+ def get_resolved_config(self) -> Dict[str, Any]:
208
+ """Get resolved configuration with precedence info."""
209
+ return self._manager.get_resolved_config()
210
+
211
+ def capture_llm_boundary(
212
+ self,
213
+ messages: List[Dict[str, Any]],
214
+ tools: List[Dict[str, Any]],
215
+ ):
216
+ """Capture exact state at LLM call boundary."""
217
+ return self._manager.capture_llm_boundary(messages, tools)
218
+
219
+ # Compatibility properties for legacy code
220
+ @property
221
+ def budgeter(self):
222
+ """Get budgeter for compatibility."""
223
+ return self._manager._budgeter
224
+
225
+ @property
226
+ def ledger(self):
227
+ """Get ledger for compatibility."""
228
+ return self._manager._ledger
229
+
230
+ @property
231
+ def monitor(self):
232
+ """Get monitor for compatibility."""
233
+ return self._manager._monitor
234
+
235
+
236
+ def handle_context_command(
237
+ console,
238
+ args: str,
239
+ session_state: Dict[str, Any],
240
+ context_manager: Optional[ContextManagerHandler] = None,
241
+ ) -> None:
242
+ """
243
+ Handle /context command and subcommands.
244
+
245
+ Usage:
246
+ /context - Show context stats
247
+ /context show - Show summary + budgets
248
+ /context stats - Token ledger table
249
+ /context budget - Budget allocation details
250
+ /context dump - Write snapshot now
251
+ /context on - Enable monitoring
252
+ /context off - Disable monitoring
253
+ /context path <path> - Set snapshot path
254
+ /context format <fmt> - Set format (human/json)
255
+ /context frequency <f>- Set frequency
256
+ /context compact - Trigger optimization
257
+ /context history - Show optimization history
258
+ /context config - Show resolved configuration
259
+ """
260
+ args = args.strip().lower() if args else ""
261
+ parts = args.split(maxsplit=1)
262
+ subcommand = parts[0] if parts else ""
263
+ subargs = parts[1] if len(parts) > 1 else ""
264
+
265
+ # Get or create context manager
266
+ if context_manager is None:
267
+ context_manager = session_state.get("context_manager")
268
+ if context_manager is None:
269
+ context_manager = ContextManagerHandler(
270
+ model=session_state.get("current_model", "gpt-4o-mini"),
271
+ session_id=session_state.get("session_id", ""),
272
+ )
273
+ session_state["context_manager"] = context_manager
274
+
275
+ # Update history tracking
276
+ history = session_state.get("conversation_history", [])
277
+ context_manager.track_history(history)
278
+
279
+ if subcommand in ("", "show"):
280
+ _show_context_summary(console, context_manager)
281
+ elif subcommand == "stats":
282
+ _show_context_stats(console, context_manager)
283
+ elif subcommand == "budget":
284
+ _show_budget_details(console, context_manager)
285
+ elif subcommand == "dump":
286
+ _dump_context(console, context_manager, history)
287
+ elif subcommand == "on":
288
+ context_manager.enable_monitor()
289
+ console.print("[green]✓ Context monitoring enabled[/green]")
290
+ console.print(f"[dim]Output: {context_manager.config.monitor_path}[/dim]")
291
+ elif subcommand == "off":
292
+ context_manager.disable_monitor()
293
+ console.print("[yellow]Context monitoring disabled[/yellow]")
294
+ elif subcommand == "path":
295
+ if subargs:
296
+ context_manager.set_monitor_path(subargs)
297
+ console.print(f"[green]✓ Monitor path set to: {subargs}[/green]")
298
+ else:
299
+ console.print(f"[cyan]Current path: {context_manager.config.monitor_path}[/cyan]")
300
+ elif subcommand == "format":
301
+ if subargs in ("human", "json"):
302
+ context_manager.set_monitor_format(subargs)
303
+ console.print(f"[green]✓ Monitor format set to: {subargs}[/green]")
304
+ else:
305
+ console.print("[yellow]Format must be 'human' or 'json'[/yellow]")
306
+ elif subcommand == "frequency":
307
+ valid = ("turn", "tool_call", "manual", "overflow")
308
+ if subargs in valid:
309
+ context_manager.set_monitor_frequency(subargs)
310
+ console.print(f"[green]✓ Monitor frequency set to: {subargs}[/green]")
311
+ else:
312
+ console.print(f"[yellow]Frequency must be one of: {', '.join(valid)}[/yellow]")
313
+ elif subcommand == "compact":
314
+ _compact_context(console, context_manager, session_state)
315
+ elif subcommand == "history":
316
+ _show_optimization_history(console, context_manager)
317
+ elif subcommand == "config":
318
+ _show_resolved_config(console, context_manager)
319
+ else:
320
+ console.print("[yellow]Unknown subcommand. Use: show, stats, budget, dump, on, off, path, format, frequency, compact, history, config[/yellow]")
321
+
322
+
323
+ def _show_context_summary(console, manager: ContextManagerHandler) -> None:
324
+ """Show context summary."""
325
+ stats = manager.get_stats()
326
+
327
+ console.print("\n[bold cyan]Context Summary[/bold cyan]")
328
+ console.print(f" Model: {stats['model']}")
329
+ console.print(f" Model Limit: {stats['model_limit']:,} tokens")
330
+ console.print(f" Output Reserve: {stats['output_reserve']:,} tokens")
331
+ console.print(f" Usable Budget: {stats['usable']:,} tokens")
332
+ console.print(f" Current Usage: {stats['total_tokens']:,} tokens ({stats['utilization']*100:.1f}%)")
333
+ console.print(f" Turns: {stats['turn_count']}")
334
+ console.print(f" Messages: {stats['message_count']}")
335
+ console.print(f" Auto-Compact: {'enabled' if stats['auto_compact'] else 'disabled'}")
336
+ console.print(f" Monitoring: {'enabled' if stats['monitor_enabled'] else 'disabled'}")
337
+
338
+ if stats['warnings']:
339
+ console.print("\n[yellow]Warnings:[/yellow]")
340
+ for warning in stats['warnings']:
341
+ console.print(f" ⚠ {warning}")
342
+ console.print("")
343
+
344
+
345
+ def _show_context_stats(console, manager: ContextManagerHandler) -> None:
346
+ """Show detailed token stats."""
347
+ stats = manager.get_stats()
348
+ segments = stats.get("segments", {})
349
+
350
+ console.print("\n[bold cyan]Token Ledger[/bold cyan]")
351
+ console.print(f"{'Segment':<20} {'Tokens':>10} {'Budget':>10} {'Used':>8}")
352
+ console.print("-" * 50)
353
+
354
+ for name, data in segments.items():
355
+ tokens = data.get("tokens", 0)
356
+ budget = data.get("budget", 0)
357
+ util = data.get("utilization", 0) * 100
358
+ console.print(f"{name:<20} {tokens:>10,} {budget:>10,} {util:>7.1f}%")
359
+
360
+ console.print("-" * 50)
361
+ console.print(f"{'TOTAL':<20} {stats['total_tokens']:>10,} {stats['usable']:>10,} {stats['utilization']*100:>7.1f}%")
362
+ console.print("")
363
+
364
+
365
+ def _show_budget_details(console, manager: ContextManagerHandler) -> None:
366
+ """Show budget allocation details."""
367
+ budget = manager.budgeter.allocate()
368
+
369
+ console.print("\n[bold cyan]Budget Allocation[/bold cyan]")
370
+ console.print(f" Model Limit: {budget.model_limit:,}")
371
+ console.print(f" Output Reserve: {budget.output_reserve:,}")
372
+ console.print(f" Usable: {budget.usable:,}")
373
+ console.print("")
374
+ console.print(" Segment Budgets:")
375
+ console.print(f" System Prompt: {budget.system_prompt:,}")
376
+ console.print(f" Rules: {budget.rules:,}")
377
+ console.print(f" Skills: {budget.skills:,}")
378
+ console.print(f" Memory: {budget.memory:,}")
379
+ console.print(f" Tool Schemas: {budget.tools_schema:,}")
380
+ console.print(f" Tool Outputs: {budget.tool_outputs:,}")
381
+ console.print(f" History: {budget.history_budget:,}")
382
+ console.print(f" Buffer: {budget.buffer:,}")
383
+ console.print("")
384
+
385
+
386
+ def _dump_context(console, manager: ContextManagerHandler, messages: List[Dict[str, Any]]) -> None:
387
+ """Dump context snapshot to file."""
388
+ # Temporarily enable if needed
389
+ was_enabled = manager.config.monitor_enabled
390
+ if not was_enabled:
391
+ manager.enable_monitor()
392
+
393
+ path = manager.write_snapshot(messages, trigger="manual")
394
+
395
+ if not was_enabled:
396
+ manager.disable_monitor()
397
+
398
+ if path:
399
+ console.print(f"[green]✓ Context snapshot written to: {path}[/green]")
400
+ else:
401
+ console.print("[yellow]Failed to write context snapshot[/yellow]")
402
+
403
+
404
+ def _compact_context(console, manager: ContextManagerHandler, session_state: Dict[str, Any]) -> None:
405
+ """Trigger context compaction."""
406
+ history = session_state.get("conversation_history", [])
407
+
408
+ if len(history) < 4:
409
+ console.print("[yellow]Not enough history to compact (need at least 4 messages)[/yellow]")
410
+ return
411
+
412
+ console.print("[dim]Optimizing context...[/dim]")
413
+
414
+ optimized, result = manager.optimize(history)
415
+
416
+ if result.tokens_saved > 0:
417
+ session_state["conversation_history"] = optimized
418
+ console.print(f"[green]✓ Optimized: {result.original_tokens:,} → {result.optimized_tokens:,} tokens[/green]")
419
+ console.print(f"[dim]Saved {result.tokens_saved:,} tokens ({result.reduction_percent:.1f}%)[/dim]")
420
+ console.print(f"[dim]Strategy: {result.strategy_used.value}[/dim]")
421
+ else:
422
+ console.print("[yellow]No optimization needed[/yellow]")
423
+
424
+
425
+ def _show_optimization_history(console, manager: ContextManagerHandler) -> None:
426
+ """Show optimization history."""
427
+ history = manager.get_history()
428
+
429
+ if not history:
430
+ console.print("[dim]No optimization events recorded yet.[/dim]")
431
+ return
432
+
433
+ console.print("\n[bold cyan]Optimization History[/bold cyan]")
434
+ console.print(f"{'Time':<24} {'Event':<20} {'Tokens':>12} {'Saved':>10}")
435
+ console.print("-" * 70)
436
+
437
+ for event in history[-20:]: # Show last 20 events
438
+ timestamp = event.get("timestamp", "")[:19] # Trim to datetime
439
+ event_type = event.get("event_type", "unknown")
440
+ tokens_before = event.get("tokens_before", 0)
441
+ tokens_saved = event.get("tokens_saved", 0)
442
+
443
+ tokens_str = f"{tokens_before:,}" if tokens_before else "-"
444
+ saved_str = f"-{tokens_saved:,}" if tokens_saved else "-"
445
+
446
+ console.print(f"{timestamp:<24} {event_type:<20} {tokens_str:>12} {saved_str:>10}")
447
+
448
+ console.print("")
449
+ console.print(f"[dim]Showing last {min(20, len(history))} of {len(history)} events[/dim]")
450
+
451
+
452
+ def _show_resolved_config(console, manager: ContextManagerHandler) -> None:
453
+ """Show resolved configuration with precedence info."""
454
+ resolved = manager.get_resolved_config()
455
+ config = resolved.get("config", {})
456
+
457
+ console.print("\n[bold cyan]Resolved Configuration[/bold cyan]")
458
+ console.print(f"[dim]Precedence: {resolved.get('precedence', 'CLI > ENV > config.yaml > defaults')}[/dim]")
459
+ console.print(f"[dim]Source: {config.get('source', 'defaults')}[/dim]")
460
+ console.print("")
461
+
462
+ console.print("[bold]Auto-Compaction:[/bold]")
463
+ console.print(f" auto_compact: {config.get('auto_compact', True)}")
464
+ console.print(f" compact_threshold: {config.get('compact_threshold', 0.8)}")
465
+ console.print(f" strategy: {config.get('strategy', 'smart')}")
466
+ console.print(f" compression_min_gain: {config.get('compression_min_gain_pct', 5.0)}%")
467
+ console.print("")
468
+
469
+ console.print("[bold]Budget:[/bold]")
470
+ console.print(f" output_reserve: {config.get('output_reserve', 8000):,}")
471
+ console.print(f" default_tool_max: {config.get('default_tool_output_max', 10000):,}")
472
+ console.print("")
473
+
474
+ console.print("[bold]Estimation:[/bold]")
475
+ console.print(f" estimation_mode: {config.get('estimation_mode', 'heuristic')}")
476
+ console.print(f" log_mismatch: {config.get('log_estimation_mismatch', False)}")
477
+ console.print("")
478
+
479
+ console.print("[bold]Monitoring:[/bold]")
480
+ console.print(f" monitor_enabled: {config.get('monitor_enabled', False)}")
481
+ console.print(f" monitor_path: {config.get('monitor_path', './context.txt')}")
482
+ console.print(f" monitor_format: {config.get('monitor_format', 'human')}")
483
+ console.print(f" monitor_frequency: {config.get('monitor_frequency', 'turn')}")
484
+ console.print(f" monitor_write_mode: {config.get('monitor_write_mode', 'sync')}")
485
+ console.print(f" redact_sensitive: {config.get('redact_sensitive', True)}")
486
+ console.print("")
487
+
488
+ # Show effective budget
489
+ budget = resolved.get("effective_budget", {})
490
+ if budget:
491
+ console.print("[bold]Effective Budget:[/bold]")
492
+ console.print(f" model_limit: {budget.get('model_limit', 0):,}")
493
+ console.print(f" usable: {budget.get('usable', 0):,}")
494
+ console.print(f" history_budget: {budget.get('history_budget', 0):,}")
495
+ console.print("")
496
+
497
+
498
+ # CLI argument definitions for argparse integration
499
+ CONTEXT_CLI_ARGS = [
500
+ {
501
+ "flags": ["--context-auto-compact", "--no-context-auto-compact"],
502
+ "dest": "context_auto_compact",
503
+ "action": "store_true",
504
+ "default": None,
505
+ "help": "Enable/disable auto-compaction",
506
+ },
507
+ {
508
+ "flags": ["--context-strategy"],
509
+ "dest": "context_strategy",
510
+ "choices": ["smart", "truncate", "sliding_window", "summarize", "prune_tools"],
511
+ "default": None,
512
+ "help": "Context optimization strategy",
513
+ },
514
+ {
515
+ "flags": ["--context-threshold"],
516
+ "dest": "context_threshold",
517
+ "type": float,
518
+ "default": None,
519
+ "help": "Auto-compact threshold (0.0-1.0)",
520
+ },
521
+ {
522
+ "flags": ["--context-monitor"],
523
+ "dest": "context_monitor",
524
+ "action": "store_true",
525
+ "default": None,
526
+ "help": "Enable context monitoring",
527
+ },
528
+ {
529
+ "flags": ["--context-monitor-path"],
530
+ "dest": "context_monitor_path",
531
+ "default": None,
532
+ "help": "Context monitor output path",
533
+ },
534
+ {
535
+ "flags": ["--context-monitor-format"],
536
+ "dest": "context_monitor_format",
537
+ "choices": ["human", "json"],
538
+ "default": None,
539
+ "help": "Context monitor output format",
540
+ },
541
+ {
542
+ "flags": ["--context-monitor-frequency"],
543
+ "dest": "context_monitor_frequency",
544
+ "choices": ["turn", "tool_call", "manual", "overflow"],
545
+ "default": None,
546
+ "help": "Context monitor update frequency",
547
+ },
548
+ {
549
+ "flags": ["--context-redact", "--no-context-redact"],
550
+ "dest": "context_redact",
551
+ "action": "store_true",
552
+ "default": None,
553
+ "help": "Enable/disable sensitive data redaction",
554
+ },
555
+ {
556
+ "flags": ["--context-output-reserve"],
557
+ "dest": "context_output_reserve",
558
+ "type": int,
559
+ "default": None,
560
+ "help": "Output token reserve",
561
+ },
562
+ {
563
+ "flags": ["--context-estimation-mode"],
564
+ "dest": "context_estimation_mode",
565
+ "choices": ["heuristic", "accurate", "validated"],
566
+ "default": None,
567
+ "help": "Token estimation mode",
568
+ },
569
+ {
570
+ "flags": ["--context-log-mismatch"],
571
+ "dest": "context_log_mismatch",
572
+ "action": "store_true",
573
+ "default": None,
574
+ "help": "Log token estimation mismatches",
575
+ },
576
+ {
577
+ "flags": ["--context-snapshot-timing"],
578
+ "dest": "context_snapshot_timing",
579
+ "choices": ["pre_optimization", "post_optimization", "both"],
580
+ "default": None,
581
+ "help": "When to capture context snapshots",
582
+ },
583
+ {
584
+ "flags": ["--context-write-mode"],
585
+ "dest": "context_write_mode",
586
+ "choices": ["sync", "async"],
587
+ "default": None,
588
+ "help": "Monitor write mode (sync or async)",
589
+ },
590
+ {
591
+ "flags": ["--context-show-config"],
592
+ "dest": "context_show_config",
593
+ "action": "store_true",
594
+ "default": False,
595
+ "help": "Show resolved context configuration and exit",
596
+ },
597
+ ]