polyrob 0.5.0__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 (745) hide show
  1. agents/README.md +453 -0
  2. agents/__init__.py +164 -0
  3. agents/base_agent.py +743 -0
  4. agents/personality/character.py +119 -0
  5. agents/personality/character_manager.py +309 -0
  6. agents/personality/characters/rob.character.json +56 -0
  7. agents/personality/characters/trump.character.json +63 -0
  8. agents/personality/persona_render.py +78 -0
  9. agents/personality/persona_resolver.py +115 -0
  10. agents/prompt/__init__.py +58 -0
  11. agents/prompt/base_prompt.py +92 -0
  12. agents/prompt/system.py +417 -0
  13. agents/task/README_PATH_MANAGEMENT.md +141 -0
  14. agents/task/__init__.py +162 -0
  15. agents/task/agent/__init__.py +70 -0
  16. agents/task/agent/agent_state.py +408 -0
  17. agents/task/agent/async_delegation.py +274 -0
  18. agents/task/agent/autonomy_state.py +275 -0
  19. agents/task/agent/conversation.py +75 -0
  20. agents/task/agent/core/__init__.py +6 -0
  21. agents/task/agent/core/aux_metering.py +61 -0
  22. agents/task/agent/core/background_review.py +157 -0
  23. agents/task/agent/core/construction.py +1179 -0
  24. agents/task/agent/core/conversational_exit.py +49 -0
  25. agents/task/agent/core/correspondent_gate.py +227 -0
  26. agents/task/agent/core/curator.py +246 -0
  27. agents/task/agent/core/episodic_digest.py +103 -0
  28. agents/task/agent/core/error_recovery.py +480 -0
  29. agents/task/agent/core/history_io.py +257 -0
  30. agents/task/agent/core/llm_provisioning.py +287 -0
  31. agents/task/agent/core/llm_runner.py +547 -0
  32. agents/task/agent/core/logging_io.py +276 -0
  33. agents/task/agent/core/loop_detection.py +262 -0
  34. agents/task/agent/core/memory_prefetch.py +325 -0
  35. agents/task/agent/core/memory_writer.py +667 -0
  36. agents/task/agent/core/model_introspection.py +82 -0
  37. agents/task/agent/core/model_swap.py +177 -0
  38. agents/task/agent/core/next_action_internal.py +1331 -0
  39. agents/task/agent/core/output_validation.py +303 -0
  40. agents/task/agent/core/project_context.py +272 -0
  41. agents/task/agent/core/resources.py +93 -0
  42. agents/task/agent/core/result_processing.py +389 -0
  43. agents/task/agent/core/run_loop.py +661 -0
  44. agents/task/agent/core/safety_lifecycle.py +228 -0
  45. agents/task/agent/core/secret_guard.py +293 -0
  46. agents/task/agent/core/self_wake.py +280 -0
  47. agents/task/agent/core/session_metadata.py +104 -0
  48. agents/task/agent/core/step.py +781 -0
  49. agents/task/agent/core/step_execution.py +398 -0
  50. agents/task/agent/core/step_telemetry.py +222 -0
  51. agents/task/agent/core/test_aux_metering.py +50 -0
  52. agents/task/agent/core/test_billing_failover.py +68 -0
  53. agents/task/agent/core/test_fatal_error_classifier.py +38 -0
  54. agents/task/agent/core/test_judge_validation.py +275 -0
  55. agents/task/agent/core/test_model_swap.py +190 -0
  56. agents/task/agent/core/test_reflection_offload.py +54 -0
  57. agents/task/agent/core/turn_input.py +8 -0
  58. agents/task/agent/core/untrusted_wrap.py +103 -0
  59. agents/task/agent/core/user_ingress.py +228 -0
  60. agents/task/agent/hitl_manager.py +396 -0
  61. agents/task/agent/log_sanitize.py +36 -0
  62. agents/task/agent/message_manager/config.py +97 -0
  63. agents/task/agent/message_manager/service.py +758 -0
  64. agents/task/agent/message_manager/tests.py +305 -0
  65. agents/task/agent/message_manager/tool_call_builder.py +539 -0
  66. agents/task/agent/message_manager/tool_message_repair.py +364 -0
  67. agents/task/agent/message_manager/views.py +143 -0
  68. agents/task/agent/messages/__init__.py +8 -0
  69. agents/task/agent/messages/builders.py +309 -0
  70. agents/task/agent/messages/compactor.py +611 -0
  71. agents/task/agent/messages/context_references.py +271 -0
  72. agents/task/agent/messages/filters.py +333 -0
  73. agents/task/agent/messages/guidance.py +328 -0
  74. agents/task/agent/messages/persistence.py +448 -0
  75. agents/task/agent/messages/retrieval.py +506 -0
  76. agents/task/agent/messages/sqlite_persistence.py +85 -0
  77. agents/task/agent/messages/test_compaction_upgrade.py +349 -0
  78. agents/task/agent/messages/test_persistence_subdir_fix.py +28 -0
  79. agents/task/agent/messages/test_sqlite_persistence.py +54 -0
  80. agents/task/agent/messages/token_counter.py +532 -0
  81. agents/task/agent/orchestrator.py +776 -0
  82. agents/task/agent/profile_manager.py +105 -0
  83. agents/task/agent/profile_registry.py +173 -0
  84. agents/task/agent/prompts.py +1090 -0
  85. agents/task/agent/scenario_registry.py +226 -0
  86. agents/task/agent/service.py +509 -0
  87. agents/task/agent/session.py +984 -0
  88. agents/task/agent/skill_discovery.py +110 -0
  89. agents/task/agent/skill_frontmatter.py +94 -0
  90. agents/task/agent/skill_manager.py +1201 -0
  91. agents/task/agent/skill_store.py +627 -0
  92. agents/task/agent/skill_validation.py +56 -0
  93. agents/task/agent/skill_writer.py +492 -0
  94. agents/task/agent/sub_agent_manager.py +1137 -0
  95. agents/task/agent/test_session_disk_recovery.py +34 -0
  96. agents/task/agent/tests.py +513 -0
  97. agents/task/agent/tool_call_tracker.py +511 -0
  98. agents/task/agent/views.py +469 -0
  99. agents/task/config.py +432 -0
  100. agents/task/constants.py +1384 -0
  101. agents/task/flag_defaults.py +63 -0
  102. agents/task/goals/__init__.py +1 -0
  103. agents/task/goals/autonomy_marker.py +28 -0
  104. agents/task/goals/board.py +690 -0
  105. agents/task/goals/completion_judge.py +247 -0
  106. agents/task/goals/context.py +62 -0
  107. agents/task/goals/dispatcher.py +848 -0
  108. agents/task/goals/escalation.py +102 -0
  109. agents/task/goals/planner.py +114 -0
  110. agents/task/logging_config.py +155 -0
  111. agents/task/path.py +991 -0
  112. agents/task/robust_parse_config.py +400 -0
  113. agents/task/runtime/__init__.py +0 -0
  114. agents/task/runtime/run_as_session.py +130 -0
  115. agents/task/runtime_safety.py +308 -0
  116. agents/task/session/__init__.py +5 -0
  117. agents/task/session/browser_pool.py +130 -0
  118. agents/task/session/cleanup.py +612 -0
  119. agents/task/session/execution.py +397 -0
  120. agents/task/session/feed.py +200 -0
  121. agents/task/session/hitl_ingress.py +201 -0
  122. agents/task/session/hooks.py +83 -0
  123. agents/task/session/multi_agent.py +243 -0
  124. agents/task/session/workspace.py +91 -0
  125. agents/task/session_registry.py +91 -0
  126. agents/task/session_route.py +35 -0
  127. agents/task/sqlite_session_registry.py +261 -0
  128. agents/task/surface_config.py +185 -0
  129. agents/task/telemetry/__init__.py +58 -0
  130. agents/task/telemetry/event_log.py +180 -0
  131. agents/task/telemetry/formatters.py +642 -0
  132. agents/task/telemetry/manager.py +571 -0
  133. agents/task/telemetry/memory_events.py +66 -0
  134. agents/task/telemetry/self_events.py +53 -0
  135. agents/task/telemetry/sequence.py +160 -0
  136. agents/task/telemetry/service.py +1265 -0
  137. agents/task/telemetry/views.py +882 -0
  138. agents/task/templates.py +98 -0
  139. agents/task/test_aux_chain.py +151 -0
  140. agents/task/test_aux_router.py +41 -0
  141. agents/task/tests/test_parse_robustness.py +170 -0
  142. agents/task/tool_defaults.py +110 -0
  143. agents/task/utils.py +762 -0
  144. agents/task/utils_json.py +768 -0
  145. agents/task/utils_webview.py +86 -0
  146. agents/task/workspace_context.py +229 -0
  147. agents/task_agent_lite.py +2398 -0
  148. api/README.md +683 -0
  149. api/TASK_API_DOCS.md +151 -0
  150. api/__init__.py +0 -0
  151. api/a2a/__init__.py +37 -0
  152. api/a2a/agent_card.py +337 -0
  153. api/a2a/client.py +657 -0
  154. api/a2a/endpoints.py +375 -0
  155. api/a2a/models.py +268 -0
  156. api/a2a/streaming.py +419 -0
  157. api/a2a/task_handler.py +929 -0
  158. api/admin_endpoints.py +1584 -0
  159. api/app.py +923 -0
  160. api/auth_constants.py +28 -0
  161. api/auth_endpoints.py +402 -0
  162. api/auth_state.py +36 -0
  163. api/chat_via_task.py +42 -0
  164. api/conversation_manager.py +231 -0
  165. api/dependencies.py +186 -0
  166. api/eip8004_endpoints.py +452 -0
  167. api/hyperliquid_models.py +174 -0
  168. api/hyperliquid_routes.py +450 -0
  169. api/interfaces.py +207 -0
  170. api/jwt_middleware.py +83 -0
  171. api/kb/__init__.py +1 -0
  172. api/kb/endpoints.py +314 -0
  173. api/mcp_models.py +279 -0
  174. api/mcp_routes.py +438 -0
  175. api/middleware.py +526 -0
  176. api/models.py +176 -0
  177. api/openai_compat/__init__.py +0 -0
  178. api/openai_compat/model_map.py +25 -0
  179. api/openai_compat/models.py +59 -0
  180. api/openai_compat/router.py +140 -0
  181. api/payment_endpoints.py +444 -0
  182. api/payment_verification.py +138 -0
  183. api/polymarket_models.py +155 -0
  184. api/polymarket_routes.py +501 -0
  185. api/pricing_endpoints.py +89 -0
  186. api/session_routing.py +54 -0
  187. api/skill_endpoints.py +453 -0
  188. api/task_http_api.py +1856 -0
  189. api/webhooks.py +52 -0
  190. api/x402_endpoints.py +280 -0
  191. avatar/README.md +44 -0
  192. avatar/__init__.py +1 -0
  193. avatar/config/rob.json +7 -0
  194. avatar/mindprint.js +395 -0
  195. avatar/renders/rob.meta.json +20 -0
  196. avatar/renders/rob.png +0 -0
  197. avatar/studio.html +373 -0
  198. avatar/webview/avatar-live.js +44 -0
  199. cli/README.md +89 -0
  200. cli/__init__.py +0 -0
  201. cli/cli_surface.py +67 -0
  202. cli/commands/__init__.py +0 -0
  203. cli/commands/_bootstrap.py +49 -0
  204. cli/commands/_errors.py +53 -0
  205. cli/commands/chat.py +973 -0
  206. cli/commands/config.py +100 -0
  207. cli/commands/dashboard.py +103 -0
  208. cli/commands/doctor.py +222 -0
  209. cli/commands/email.py +174 -0
  210. cli/commands/gateway.py +346 -0
  211. cli/commands/goals.py +509 -0
  212. cli/commands/init.py +276 -0
  213. cli/commands/journey.py +30 -0
  214. cli/commands/kb.py +280 -0
  215. cli/commands/model.py +107 -0
  216. cli/commands/owner.py +431 -0
  217. cli/commands/pfp.py +232 -0
  218. cli/commands/run.py +414 -0
  219. cli/commands/serve.py +41 -0
  220. cli/commands/session.py +684 -0
  221. cli/commands/skill_install.py +786 -0
  222. cli/commands/skills.py +128 -0
  223. cli/commands/subagents.py +100 -0
  224. cli/commands/surface.py +81 -0
  225. cli/commands/telegram.py +185 -0
  226. cli/commands/todos.py +209 -0
  227. cli/commands/tools.py +102 -0
  228. cli/commands/update.py +316 -0
  229. cli/commands/whatsapp.py +175 -0
  230. cli/config_store.py +276 -0
  231. cli/gitignore.py +43 -0
  232. cli/inventory.py +46 -0
  233. cli/keys.py +101 -0
  234. cli/persona.py +17 -0
  235. cli/polyrob.py +137 -0
  236. cli/ui/__init__.py +64 -0
  237. cli/ui/activity.py +141 -0
  238. cli/ui/app.py +538 -0
  239. cli/ui/banner.py +233 -0
  240. cli/ui/blocks.py +534 -0
  241. cli/ui/bootstrap_notice.py +47 -0
  242. cli/ui/commands/__init__.py +41 -0
  243. cli/ui/commands/h_cron.py +64 -0
  244. cli/ui/commands/h_journey.py +164 -0
  245. cli/ui/commands/h_kb.py +121 -0
  246. cli/ui/commands/h_learn.py +100 -0
  247. cli/ui/commands/h_mcp.py +215 -0
  248. cli/ui/commands/h_self.py +113 -0
  249. cli/ui/commands/h_skills.py +314 -0
  250. cli/ui/commands/handlers.py +1672 -0
  251. cli/ui/commands/registry.py +426 -0
  252. cli/ui/dialog.py +425 -0
  253. cli/ui/event_registry.py +110 -0
  254. cli/ui/event_specs.py +45 -0
  255. cli/ui/events.py +433 -0
  256. cli/ui/identity.py +15 -0
  257. cli/ui/lifecycle.py +159 -0
  258. cli/ui/live_hooks.py +43 -0
  259. cli/ui/model_selector.py +532 -0
  260. cli/ui/persistent_loop.py +181 -0
  261. cli/ui/pick.py +113 -0
  262. cli/ui/plain_renderer.py +351 -0
  263. cli/ui/renderer.py +384 -0
  264. cli/ui/rich_renderer.py +533 -0
  265. cli/ui/secrets.py +115 -0
  266. cli/ui/state.py +376 -0
  267. cli/ui/statusbar.py +231 -0
  268. cli/ui/streaming.py +254 -0
  269. cli/ui/terminal_render.py +105 -0
  270. cli/ui/theme.py +132 -0
  271. cli/update/__init__.py +6 -0
  272. cli/update/context.py +121 -0
  273. cli/update/detect.py +176 -0
  274. cli/update/engine.py +95 -0
  275. cli/update/migrate_guarded.py +55 -0
  276. cli/update/process_guard.py +215 -0
  277. cli/update/runners.py +78 -0
  278. cli/update/snapshot.py +270 -0
  279. cli/update/versions.py +205 -0
  280. core/README.md +377 -0
  281. core/__init__.py +174 -0
  282. core/assets.py +87 -0
  283. core/async_bridge.py +76 -0
  284. core/autonomy_runtime.py +259 -0
  285. core/base_component.py +302 -0
  286. core/bootstrap.py +681 -0
  287. core/bot.py +310 -0
  288. core/config.py +833 -0
  289. core/constants.py +126 -0
  290. core/container.py +462 -0
  291. core/db_manifest.py +101 -0
  292. core/embedding.py +57 -0
  293. core/env.py +39 -0
  294. core/exceptions.py +287 -0
  295. core/flags.py +144 -0
  296. core/flags_catalog.py +345 -0
  297. core/home_migration.py +62 -0
  298. core/identity.py +118 -0
  299. core/initialization.py +1004 -0
  300. core/instance.py +537 -0
  301. core/interactive_gate.py +96 -0
  302. core/logging.py +436 -0
  303. core/owner_doc_writer.py +176 -0
  304. core/pairing.py +193 -0
  305. core/path_safety.py +20 -0
  306. core/paths.py +27 -0
  307. core/payment_config.py +21 -0
  308. core/permissions.py +322 -0
  309. core/runtime_config.py +96 -0
  310. core/runtime_paths.py +135 -0
  311. core/seams.py +35 -0
  312. core/secret_scan.py +25 -0
  313. core/secret_scrub.py +71 -0
  314. core/secrets.py +35 -0
  315. core/security_logging_filter.py +148 -0
  316. core/self_context_writer.py +333 -0
  317. core/self_evolution.py +294 -0
  318. core/session_context.py +47 -0
  319. core/sqlite_util.py +59 -0
  320. core/surfaces/__init__.py +16 -0
  321. core/surfaces/access.py +118 -0
  322. core/surfaces/binding.py +88 -0
  323. core/surfaces/bootstrap.py +78 -0
  324. core/surfaces/circuit.py +168 -0
  325. core/surfaces/continuity.py +77 -0
  326. core/surfaces/correspondents.py +228 -0
  327. core/surfaces/dispatcher.py +216 -0
  328. core/surfaces/envelopes.py +75 -0
  329. core/surfaces/gc.py +30 -0
  330. core/surfaces/idempotency.py +57 -0
  331. core/surfaces/inbound_webhook.py +124 -0
  332. core/surfaces/media.py +32 -0
  333. core/surfaces/message_router.py +91 -0
  334. core/surfaces/outbound_allowlist.py +80 -0
  335. core/surfaces/outbound_dispatcher.py +110 -0
  336. core/surfaces/outbound_mirror.py +37 -0
  337. core/surfaces/outbound_queue.py +107 -0
  338. core/surfaces/outbound_target.py +12 -0
  339. core/surfaces/owner_admin.py +29 -0
  340. core/surfaces/proactive.py +78 -0
  341. core/surfaces/progress.py +108 -0
  342. core/surfaces/rate_bucket.py +21 -0
  343. core/surfaces/registry.py +51 -0
  344. core/surfaces/rendering.py +53 -0
  345. core/surfaces/send_policy.py +14 -0
  346. core/surfaces/serialize.py +24 -0
  347. core/surfaces/session_chat_registry.py +112 -0
  348. core/surfaces/session_policy.py +60 -0
  349. core/surfaces/surface.py +288 -0
  350. core/surfaces/transcription.py +88 -0
  351. core/surfaces/voice_echo.py +26 -0
  352. core/surfaces/voice_guard.py +23 -0
  353. core/tickers.py +174 -0
  354. core/tool_catalog.py +192 -0
  355. core/version.py +75 -0
  356. core/wallet/__init__.py +5 -0
  357. core/wallet/agent_wallet.py +59 -0
  358. core/wallet/audit_sink.py +61 -0
  359. core/wallet/config.py +70 -0
  360. core/wallet/factory.py +87 -0
  361. core/wallet/policy.py +104 -0
  362. core/wallet/signer.py +51 -0
  363. cron/README.md +65 -0
  364. cron/__init__.py +0 -0
  365. cron/delivery.py +277 -0
  366. cron/digest.py +124 -0
  367. cron/jobs.py +207 -0
  368. cron/runner.py +297 -0
  369. cron/schedule.py +194 -0
  370. cron/scheduler.py +201 -0
  371. cron/service.py +57 -0
  372. cron/wake_gate.py +223 -0
  373. data/__init__.py +1 -0
  374. data/prompts/autov2_prompts.json +87 -0
  375. data/prompts/skills/browser-automation/SKILL.md +43 -0
  376. data/prompts/skills/coding-workflow/SKILL.md +36 -0
  377. data/prompts/skills/crypto-trading-safety/SKILL.md +53 -0
  378. data/prompts/skills/document-writing/SKILL.md +33 -0
  379. data/prompts/skills/email-comms/SKILL.md +33 -0
  380. data/prompts/skills/file-data-ops/SKILL.md +35 -0
  381. data/prompts/skills/hyperliquid-account-review/SKILL.md +48 -0
  382. data/prompts/skills/hyperliquid-market-data/SKILL.md +52 -0
  383. data/prompts/skills/hyperliquid-trading/SKILL.md +59 -0
  384. data/prompts/skills/lead-research/SKILL.md +86 -0
  385. data/prompts/skills/market-research-brief/SKILL.md +104 -0
  386. data/prompts/skills/person-analyzer/SKILL.md +124 -0
  387. data/prompts/skills/polymarket-market-research/SKILL.md +54 -0
  388. data/prompts/skills/polymarket-portfolio-review/SKILL.md +50 -0
  389. data/prompts/skills/polymarket-trading/SKILL.md +55 -0
  390. data/prompts/skills/presentation-creator/SKILL.md +36 -0
  391. data/prompts/skills/project-analyzer/SKILL.md +169 -0
  392. data/prompts/skills/rules.json +268 -0
  393. data/prompts/skills/secret-handling/SKILL.md +20 -0
  394. data/prompts/skills/skill-authoring/SKILL.md +31 -0
  395. data/prompts/skills/skill-security-review/SKILL.md +27 -0
  396. data/prompts/skills/social-discovery/SKILL.md +57 -0
  397. data/prompts/skills/task-planning/SKILL.md +33 -0
  398. data/prompts/skills/web-research/SKILL.md +39 -0
  399. data/prompts/skills/web-scraping/SKILL.md +73 -0
  400. data/prompts/skills/x-engagement/SKILL.md +69 -0
  401. data/prompts/system_prompts.json +4 -0
  402. data/subscription_channels.json +5 -0
  403. modules/README.md +503 -0
  404. modules/__init__.py +124 -0
  405. modules/auth/__init__.py +13 -0
  406. modules/auth/api_key_manager.py +157 -0
  407. modules/auth/identity_mapper.py +380 -0
  408. modules/auth/siwe_auth.py +273 -0
  409. modules/auth/tier_manager.py +173 -0
  410. modules/base_module.py +190 -0
  411. modules/credits/__init__.py +29 -0
  412. modules/credits/balance_manager.py +237 -0
  413. modules/credits/cost_utils.py +129 -0
  414. modules/credits/pricing.py +139 -0
  415. modules/credits/unified_ledger.py +148 -0
  416. modules/credits/usage_meter.py +310 -0
  417. modules/credits/usage_tracker.py +674 -0
  418. modules/database/__init__.py +33 -0
  419. modules/database/audit_log.py +322 -0
  420. modules/database/auth_tables.py +276 -0
  421. modules/database/connection.py +644 -0
  422. modules/database/connection_pool.py +305 -0
  423. modules/database/conversation_contexts.py +446 -0
  424. modules/database/database_manager.py +237 -0
  425. modules/database/hyperliquid.py +375 -0
  426. modules/database/polymarket.py +574 -0
  427. modules/database/user_mcp_servers.py +728 -0
  428. modules/database/user_profiles.py +562 -0
  429. modules/database/utils.py +107 -0
  430. modules/database/x402_tables.py +92 -0
  431. modules/eip8004/README.md +1069 -0
  432. modules/eip8004/__init__.py +65 -0
  433. modules/eip8004/contracts.py +498 -0
  434. modules/eip8004/models.py +271 -0
  435. modules/eip8004/registration.py +148 -0
  436. modules/eip8004/reputation.py +367 -0
  437. modules/eip8004/validation.py +277 -0
  438. modules/llm/__init__.py +97 -0
  439. modules/llm/adapters.py +963 -0
  440. modules/llm/anthropic_client.py +831 -0
  441. modules/llm/available_models.py +106 -0
  442. modules/llm/brain_scrubber.py +137 -0
  443. modules/llm/cache_hints.py +162 -0
  444. modules/llm/deepseek_client.py +562 -0
  445. modules/llm/gemini_client.py +1367 -0
  446. modules/llm/llm_client.py +1139 -0
  447. modules/llm/llm_client_registry.py +188 -0
  448. modules/llm/llm_factory.py +237 -0
  449. modules/llm/llm_manager.py +1036 -0
  450. modules/llm/messages.py +374 -0
  451. modules/llm/model_registry.py +1935 -0
  452. modules/llm/nvidia_client.py +125 -0
  453. modules/llm/openai_client.py +800 -0
  454. modules/llm/openrouter_client.py +969 -0
  455. modules/llm/profiles.py +178 -0
  456. modules/llm/test_anthropic_cache_capture.py +35 -0
  457. modules/llm/test_cached_pricing_derivation.py +24 -0
  458. modules/llm/think_scrubber.py +444 -0
  459. modules/llm/token_counter.py +268 -0
  460. modules/memory/__init__.py +35 -0
  461. modules/memory/backend_factory.py +83 -0
  462. modules/memory/cache_manager.py +186 -0
  463. modules/memory/episodic.py +108 -0
  464. modules/memory/local_vector_memory_provider.py +552 -0
  465. modules/memory/memory_manager.py +225 -0
  466. modules/memory/models.py +312 -0
  467. modules/memory/provider.py +210 -0
  468. modules/memory/registry.py +205 -0
  469. modules/memory/sqlite_memory_provider.py +767 -0
  470. modules/memory/task/__init__.py +52 -0
  471. modules/memory/task/compaction_manager.py +157 -0
  472. modules/memory/task/context_retriever.py +809 -0
  473. modules/memory/task/hierarchical_memory.py +1002 -0
  474. modules/memory/task/lexical_retriever.py +71 -0
  475. modules/memory/task/null_context_manager.py +213 -0
  476. modules/memory/task/phase_manager.py +625 -0
  477. modules/memory/task/reflection_service.py +157 -0
  478. modules/memory/task/semantic_retriever.py +218 -0
  479. modules/memory/task/task_context_manager.py +1165 -0
  480. modules/memory/task/test_forgetting_engages.py +24 -0
  481. modules/memory/task/test_reflection_llm.py +39 -0
  482. modules/memory/task/test_threat_scan.py +53 -0
  483. modules/memory/task/threat_scan.py +90 -0
  484. modules/memory/test_sqlite_memory_provider.py +106 -0
  485. modules/memory/user_profile_manager.py +527 -0
  486. modules/payments/__init__.py +11 -0
  487. modules/payments/deposit_monitor.py +478 -0
  488. modules/payments/price_oracle.py +70 -0
  489. modules/payments/treasury_sweeper.py +401 -0
  490. modules/payments/wallet_generator.py +145 -0
  491. modules/pfp/__init__.py +1 -0
  492. modules/pfp/config.py +92 -0
  493. modules/pfp/mesh.py +565 -0
  494. modules/pfp/push.py +69 -0
  495. modules/pfp/renderer.py +85 -0
  496. modules/pfp/store.py +82 -0
  497. modules/skills/__init__.py +1 -0
  498. modules/skills/skill_usage.py +248 -0
  499. modules/transcription/__init__.py +24 -0
  500. modules/transcription/base.py +20 -0
  501. modules/transcription/faster_whisper_transcriber.py +55 -0
  502. modules/x402/README.md +249 -0
  503. modules/x402/__init__.py +22 -0
  504. modules/x402/invoicing.py +416 -0
  505. modules/x402/middleware.py +364 -0
  506. modules/x402/settlement_watcher.py +145 -0
  507. modules/x402/x402_integration.py +344 -0
  508. polyrob-0.5.0.dist-info/METADATA +482 -0
  509. polyrob-0.5.0.dist-info/RECORD +745 -0
  510. polyrob-0.5.0.dist-info/WHEEL +5 -0
  511. polyrob-0.5.0.dist-info/entry_points.txt +2 -0
  512. polyrob-0.5.0.dist-info/licenses/LICENSE +21 -0
  513. polyrob-0.5.0.dist-info/top_level.txt +12 -0
  514. surfaces/README.md +70 -0
  515. surfaces/__init__.py +0 -0
  516. surfaces/email/__init__.py +0 -0
  517. surfaces/email/dedup.py +44 -0
  518. surfaces/email/harness.py +187 -0
  519. surfaces/email/inbound.py +159 -0
  520. surfaces/email/seed.py +60 -0
  521. surfaces/email/surface.py +105 -0
  522. surfaces/telegram/__init__.py +0 -0
  523. surfaces/telegram/dedup.py +83 -0
  524. surfaces/telegram/harness.py +886 -0
  525. surfaces/telegram/inbound.py +145 -0
  526. surfaces/telegram/interactive_tools.py +49 -0
  527. surfaces/telegram/markdown.py +347 -0
  528. surfaces/telegram/rate_limit.py +167 -0
  529. surfaces/telegram/surface.py +187 -0
  530. surfaces/telegram/voice.py +52 -0
  531. surfaces/whatsapp/__init__.py +0 -0
  532. surfaces/whatsapp/client.py +51 -0
  533. surfaces/whatsapp/harness.py +62 -0
  534. surfaces/whatsapp/inbound.py +132 -0
  535. surfaces/whatsapp/surface.py +64 -0
  536. surfaces/whatsapp/window.py +34 -0
  537. tools/README.md +578 -0
  538. tools/__init__.py +424 -0
  539. tools/alchemy/__init__.py +5 -0
  540. tools/alchemy/alchemy_tool.py +389 -0
  541. tools/anysite/__init__.py +17 -0
  542. tools/anysite/client.py +88 -0
  543. tools/anysite/tool.py +89 -0
  544. tools/base_tool.py +468 -0
  545. tools/browser/__init__.py +22 -0
  546. tools/browser/actions.py +118 -0
  547. tools/browser/browser.py +1457 -0
  548. tools/browser/browser_manager.py +690 -0
  549. tools/browser/context.py +1748 -0
  550. tools/browser/playwright_utils.py +137 -0
  551. tools/browser/views.py +56 -0
  552. tools/code_exec/SANDBOX_SECURITY.md +144 -0
  553. tools/code_exec/__init__.py +178 -0
  554. tools/code_exec/backend.py +73 -0
  555. tools/code_exec/backends/__init__.py +1 -0
  556. tools/code_exec/backends/docker.py +779 -0
  557. tools/code_exec/backends/local_subprocess.py +154 -0
  558. tools/code_exec/env_policy.py +45 -0
  559. tools/code_exec/result.py +42 -0
  560. tools/code_exec/sandbox_guard.py +59 -0
  561. tools/code_exec/tool.py +227 -0
  562. tools/coding/__init__.py +50 -0
  563. tools/coding/edit.py +107 -0
  564. tools/coding/search.py +113 -0
  565. tools/coding/tool.py +353 -0
  566. tools/collabland/__init__.py +5 -0
  567. tools/collabland/collabland_tool.py +471 -0
  568. tools/controller/__init__.py +0 -0
  569. tools/controller/_helpers.py +165 -0
  570. tools/controller/action_registration.py +1765 -0
  571. tools/controller/approval.py +244 -0
  572. tools/controller/approval_interactive.py +90 -0
  573. tools/controller/delegation.py +195 -0
  574. tools/controller/execution.py +797 -0
  575. tools/controller/execution_context.py +141 -0
  576. tools/controller/hooks.py +135 -0
  577. tools/controller/introspection.py +344 -0
  578. tools/controller/mcp_registrar.py +190 -0
  579. tools/controller/message_send.py +31 -0
  580. tools/controller/registry/__init__.py +4 -0
  581. tools/controller/registry/schema_generators.py +395 -0
  582. tools/controller/registry/schema_sanitizer.py +406 -0
  583. tools/controller/registry/service.py +1266 -0
  584. tools/controller/registry/views.py +151 -0
  585. tools/controller/service.py +409 -0
  586. tools/controller/tool_management.py +334 -0
  587. tools/controller/types.py +28 -0
  588. tools/controller/views.py +450 -0
  589. tools/cronjob_tools.py +166 -0
  590. tools/crypto_trade_gate.py +59 -0
  591. tools/descriptors.py +452 -0
  592. tools/dom/__init__.py +0 -0
  593. tools/dom/history_tree_processor/service.py +244 -0
  594. tools/dom/history_tree_processor/view.py +99 -0
  595. tools/dom/service.py +471 -0
  596. tools/dom/views.py +346 -0
  597. tools/email_tool.py +403 -0
  598. tools/exceptions.py +169 -0
  599. tools/filesystem.py +1038 -0
  600. tools/filesystem_docproc.py +331 -0
  601. tools/filesystem_pdf.py +755 -0
  602. tools/git/__init__.py +42 -0
  603. tools/git/tool.py +258 -0
  604. tools/github/__init__.py +33 -0
  605. tools/github/client.py +94 -0
  606. tools/github/tool.py +237 -0
  607. tools/goal_tools.py +309 -0
  608. tools/hyperliquid/__init__.py +56 -0
  609. tools/hyperliquid/models.py +233 -0
  610. tools/hyperliquid/service.py +1680 -0
  611. tools/knowledge_ingest.py +950 -0
  612. tools/mcp/README.md +535 -0
  613. tools/mcp/__init__.py +52 -0
  614. tools/mcp/catalog.py +115 -0
  615. tools/mcp/config.py +337 -0
  616. tools/mcp/mcp_tool.py +1415 -0
  617. tools/mcp/param_coercion.py +289 -0
  618. tools/mcp/protocol.py +1520 -0
  619. tools/mcp/rate_limit.py +50 -0
  620. tools/mcp/security.py +424 -0
  621. tools/mcp/self_install.py +111 -0
  622. tools/mcp/server_manager.py +829 -0
  623. tools/mcp/subscriptions.py +72 -0
  624. tools/mcp/user_mcp_service.py +899 -0
  625. tools/mcp/validation_tracker.py +89 -0
  626. tools/mcp/views.py +346 -0
  627. tools/oauth/__init__.py +17 -0
  628. tools/oauth/manager.py +75 -0
  629. tools/oauth/provider.py +69 -0
  630. tools/oauth/providers/__init__.py +1 -0
  631. tools/oauth/providers/generic_oauth2.py +96 -0
  632. tools/perplexity_tool.py +280 -0
  633. tools/polymarket/__init__.py +41 -0
  634. tools/polymarket/clob_adapter.py +76 -0
  635. tools/polymarket/models.py +182 -0
  636. tools/polymarket/service.py +2082 -0
  637. tools/self_env/__init__.py +61 -0
  638. tools/self_env/tool.py +274 -0
  639. tools/shell/__init__.py +80 -0
  640. tools/shell/backend_pool.py +118 -0
  641. tools/shell/discipline.py +62 -0
  642. tools/shell/executor.py +157 -0
  643. tools/shell/loopback_allow.py +87 -0
  644. tools/shell/process_registry.py +113 -0
  645. tools/shell/process_tool.py +131 -0
  646. tools/shell/state.py +129 -0
  647. tools/shell/tool.py +151 -0
  648. tools/task_tool.py +637 -0
  649. tools/twitter_tool.py +2086 -0
  650. tools/user_directory.py +179 -0
  651. tools/web_fetch/__init__.py +3 -0
  652. tools/web_fetch/fetcher.py +144 -0
  653. tools/web_fetch/render.py +44 -0
  654. tools/web_fetch/tool.py +60 -0
  655. tools/x402/__init__.py +60 -0
  656. tools/x402/client.py +47 -0
  657. tools/x402/invoice_tool.py +143 -0
  658. tools/x402/real_client.py +250 -0
  659. tools/x402/service.py +131 -0
  660. utils/README.md +498 -0
  661. utils/__init__.py +46 -0
  662. utils/auth_utils.py +114 -0
  663. utils/bounded_collections.py +162 -0
  664. utils/circuit_breaker.py +389 -0
  665. utils/gif_utils.py +435 -0
  666. utils/markdown_utils.py +291 -0
  667. utils/message_utils.py +147 -0
  668. utils/metrics.py +36 -0
  669. utils/path_validator.py +227 -0
  670. utils/rate_limit_manager.py +399 -0
  671. utils/result_size.py +296 -0
  672. utils/time_utils.py +206 -0
  673. utils/user_utils.py +188 -0
  674. webview/README.md +111 -0
  675. webview/RENAME_AND_ALIGN_HANDOFF.md +200 -0
  676. webview/__init__.py +8 -0
  677. webview/activity.py +636 -0
  678. webview/owner_auth.py +108 -0
  679. webview/pages.py +448 -0
  680. webview/repair_sessions.py +399 -0
  681. webview/server.py +4323 -0
  682. webview/server_launcher.py +112 -0
  683. webview/static/css/activity.css +89 -0
  684. webview/static/css/chat.css +1772 -0
  685. webview/static/css/components.css +1190 -0
  686. webview/static/css/config-panel.css +651 -0
  687. webview/static/css/pages/admin.css +766 -0
  688. webview/static/css/pages/profile.css +231 -0
  689. webview/static/css/pages/settings.css +297 -0
  690. webview/static/css/pages/signin.css +316 -0
  691. webview/static/css/style.css +4250 -0
  692. webview/static/css/variables.css +147 -0
  693. webview/static/css/workspace-fullwidth-fix.css +109 -0
  694. webview/static/img/favicon.ico +0 -0
  695. webview/static/js/activity.js +394 -0
  696. webview/static/js/admin/activity.js +186 -0
  697. webview/static/js/admin/dashboard.js +163 -0
  698. webview/static/js/admin/user_detail.js +400 -0
  699. webview/static/js/admin/users.js +174 -0
  700. webview/static/js/admin/utils.js +214 -0
  701. webview/static/js/chat.js +3178 -0
  702. webview/static/js/config-panel.js +522 -0
  703. webview/static/js/constants.js +20 -0
  704. webview/static/js/error-handler.js +226 -0
  705. webview/static/js/ethers.min.js +1 -0
  706. webview/static/js/event-filter.js +137 -0
  707. webview/static/js/event-store.js +351 -0
  708. webview/static/js/file-attachments.js +374 -0
  709. webview/static/js/file-loader.js +163 -0
  710. webview/static/js/index.js +103 -0
  711. webview/static/js/performance-utils.js +196 -0
  712. webview/static/js/profile.js +396 -0
  713. webview/static/js/screenshot.js +386 -0
  714. webview/static/js/session.js +1527 -0
  715. webview/static/js/settings.js +1288 -0
  716. webview/static/js/sidebar-data.js +766 -0
  717. webview/static/js/sidebar-toggle.js +296 -0
  718. webview/static/js/socket.io.min.js +7 -0
  719. webview/static/js/stats.js +355 -0
  720. webview/static/js/ui-utils.js +420 -0
  721. webview/static/js/workspace.js +966 -0
  722. webview/stats_service.py +613 -0
  723. webview/templates/__init__.py +1 -0
  724. webview/templates/__pycache__/__init__.cpython-311.pyc +0 -0
  725. webview/templates/activity.html +36 -0
  726. webview/templates/admin/activity.html +122 -0
  727. webview/templates/admin/dashboard.html +112 -0
  728. webview/templates/admin/user_detail.html +228 -0
  729. webview/templates/admin/users.html +105 -0
  730. webview/templates/autonomy.html +60 -0
  731. webview/templates/error.html +133 -0
  732. webview/templates/finance.html +90 -0
  733. webview/templates/identity.html +73 -0
  734. webview/templates/index.html +42 -0
  735. webview/templates/layout.html +125 -0
  736. webview/templates/memory.html +59 -0
  737. webview/templates/owner_login.html +15 -0
  738. webview/templates/profile.html +121 -0
  739. webview/templates/session.html +312 -0
  740. webview/templates/settings.html +534 -0
  741. webview/templates/sidebar.html +112 -0
  742. webview/templates/signin.html +213 -0
  743. webview/templates/status.html +14 -0
  744. webview/templates/system.html +45 -0
  745. webview/webgate.py +196 -0
cli/ui/events.py ADDED
@@ -0,0 +1,433 @@
1
+ """Typed feed-event model for the POLYROB CLI renderer (Phase 1).
2
+
3
+ Normalises the 14 real feed dicts emitted by
4
+ ``agents/task/telemetry/formatters.py`` into a small set of typed
5
+ ``RenderEvent`` dataclasses. The field names are taken DIRECTLY from the
6
+ formatter source — this file is the authoritative mapping so that wrong-key
7
+ bugs like the ``cost``/``cost_estimate`` or ``total_tokens``/``token_count``
8
+ mis-reads in the old ``_feed.py`` cannot silently recur.
9
+
10
+ Key mapping (formatters.py → RenderEvent field):
11
+ llm_request
12
+ data.model_name → LLMCall.model_name
13
+ data.provider → LLMCall.provider
14
+ data.prompt_tokens → LLMCall.prompt_tokens
15
+ data.completion_tokens→ LLMCall.completion_tokens
16
+ data.token_count → LLMCall.token_count
17
+ data.cost_estimate → LLMCall.cost_estimate (NOT "cost")
18
+ data.duration_seconds → LLMCall.duration_seconds
19
+ data.success → LLMCall.success
20
+
21
+ step
22
+ data.reasoning → Step.reasoning
23
+ data.context.outputs.memory → Step.memory
24
+ data.actions → Step.actions
25
+
26
+ session_start
27
+ data.task → SessionStart.task
28
+ data.model_name → SessionStart.model_name
29
+ data.agent_id → SessionStart.agent_id
30
+ data.use_vision → SessionStart.use_vision
31
+
32
+ tool_execution
33
+ data.tool_name → ToolExec.tool_name
34
+ data.action_name → ToolExec.action_name
35
+ data.success → ToolExec.success
36
+ data.duration_seconds → ToolExec.duration_seconds
37
+ data.error → ToolExec.error
38
+
39
+ iteration_complete
40
+ data.iteration → IterationDone.iteration
41
+ data.iteration_status → IterationDone.iteration_status
42
+ data.is_done → IterationDone.is_done
43
+
44
+ error
45
+ data.error_message → ErrorEvent.error_message
46
+ data.error_type → ErrorEvent.error_type
47
+
48
+ session_completion
49
+ data.success → SessionDone.success
50
+ data.total_steps → SessionDone.total_steps
51
+ data.metrics.final_result → SessionDone.final_result
52
+ data.error_message → SessionDone.error_message
53
+
54
+ agent_registration (live-emitted; §0 amendment 2)
55
+ data.agent_id / agent_name / agent_type / model_name / task → AgentRegistration
56
+
57
+ agent_end (live-emitted; §0 amendment 2)
58
+ data.agent_id / steps / max_steps_reached / success / errors → AgentEnd
59
+
60
+ All other types (status / user_message / queue_status /
61
+ multi_agent_relationship / multi_agent_relationship_detailed /
62
+ session_relationship / available_actions / session_paused /
63
+ session_resumed) become ``Info``. Unknown types also become ``Info``
64
+ (never crash).
65
+ """
66
+
67
+ from __future__ import annotations
68
+
69
+ import logging
70
+ from dataclasses import dataclass, field
71
+ from typing import Any, Dict, List, Optional
72
+
73
+ logger = logging.getLogger(__name__)
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Dataclasses
77
+ # ---------------------------------------------------------------------------
78
+
79
+
80
+ @dataclass
81
+ class SessionStart:
82
+ """Emitted when the agent session begins."""
83
+
84
+ type: str = "session_start"
85
+ task: str = ""
86
+ model_name: str = ""
87
+ agent_id: str = ""
88
+ use_vision: bool = False
89
+ raw: Dict[str, Any] = field(default_factory=dict)
90
+
91
+
92
+ @dataclass
93
+ class Step:
94
+ """One agent step: reasoning + memory + actions."""
95
+
96
+ type: str = "step"
97
+ step: int = 0
98
+ reasoning: str = ""
99
+ memory: str = ""
100
+ actions: List[Dict[str, Any]] = field(default_factory=list)
101
+ raw: Dict[str, Any] = field(default_factory=dict)
102
+
103
+
104
+ @dataclass
105
+ class LLMCall:
106
+ """Result of an LLM API call (real field names from LLMRequestFormatter)."""
107
+
108
+ type: str = "llm_request"
109
+ model_name: str = ""
110
+ provider: str = ""
111
+ prompt_tokens: Optional[int] = None
112
+ completion_tokens: Optional[int] = None
113
+ token_count: Optional[int] = None
114
+ cost_estimate: Optional[float] = None
115
+ duration_seconds: float = 0.0
116
+ success: bool = True
117
+ raw: Dict[str, Any] = field(default_factory=dict)
118
+
119
+
120
+ @dataclass
121
+ class ToolExec:
122
+ """Result of a single tool execution (real field names from ToolExecutionFormatter).
123
+
124
+ ``parameters``/``result_preview``/``result_truncated`` are carried so the CLI
125
+ can render a tool transcript (call args + result preview) BY DEFAULT, not just
126
+ under ``/verbose``. The feed dict has always carried them; they were previously
127
+ dropped on the floor here.
128
+ """
129
+
130
+ type: str = "tool_execution"
131
+ step: int = 0
132
+ tool_name: str = ""
133
+ action_name: str = ""
134
+ success: bool = True
135
+ duration_seconds: float = 0.0
136
+ error: Optional[str] = None
137
+ parameters: Dict[str, Any] = field(default_factory=dict)
138
+ result_preview: Optional[str] = None
139
+ result_truncated: bool = False
140
+ raw: Dict[str, Any] = field(default_factory=dict)
141
+
142
+
143
+ @dataclass
144
+ class IterationDone:
145
+ """Iteration boundary marker (IterationCompleteFormatter)."""
146
+
147
+ type: str = "iteration_complete"
148
+ iteration: int = 0
149
+ step: int = 0
150
+ iteration_status: str = ""
151
+ is_done: bool = False
152
+ raw: Dict[str, Any] = field(default_factory=dict)
153
+
154
+
155
+ @dataclass
156
+ class ErrorEvent:
157
+ """An agent error (ErrorFormatter)."""
158
+
159
+ type: str = "error"
160
+ step: int = 0
161
+ error_message: str = ""
162
+ error_type: str = ""
163
+ raw: Dict[str, Any] = field(default_factory=dict)
164
+
165
+
166
+ @dataclass
167
+ class SessionDone:
168
+ """Session completion (SessionCompletionFormatter)."""
169
+
170
+ type: str = "session_completion"
171
+ success: bool = True
172
+ total_steps: int = 0
173
+ final_result: str = ""
174
+ error_message: str = ""
175
+ duration_seconds: float = 0.0
176
+ raw: Dict[str, Any] = field(default_factory=dict)
177
+
178
+
179
+ @dataclass
180
+ class AgentRegistration:
181
+ """An agent (main or sub-agent) was registered (AgentRegistrationFormatter).
182
+
183
+ Real shape (captured live):
184
+ data.agent_id, data.agent_name, data.agent_type, data.model_name,
185
+ data.task, data.session_id
186
+ Used for sub-agent grouping: the first registration is the main agent;
187
+ subsequent registrations with different agent_ids are sub-agents.
188
+ """
189
+
190
+ type: str = "agent_registration"
191
+ agent_id: str = ""
192
+ agent_name: str = ""
193
+ agent_type: str = ""
194
+ model_name: str = ""
195
+ task: str = ""
196
+ raw: Dict[str, Any] = field(default_factory=dict)
197
+
198
+
199
+ @dataclass
200
+ class AgentEnd:
201
+ """An agent finished its run (AgentEndFormatter).
202
+
203
+ Real shape (captured live):
204
+ data.agent_id, data.steps, data.max_steps_reached, data.success,
205
+ data.errors[]
206
+ """
207
+
208
+ type: str = "agent_end"
209
+ agent_id: str = ""
210
+ steps: int = 0
211
+ max_steps_reached: bool = False
212
+ success: bool = True
213
+ errors: List[Any] = field(default_factory=list)
214
+ raw: Dict[str, Any] = field(default_factory=dict)
215
+
216
+
217
+ @dataclass
218
+ class Info:
219
+ """Passthrough wrapper for informational / status events.
220
+
221
+ Covers: status, user_message, queue_status, multi_agent_relationship,
222
+ multi_agent_relationship_detailed, session_relationship,
223
+ available_actions, session_paused, session_resumed, and any unknown types.
224
+ """
225
+
226
+ type: str = "info"
227
+ content: str = ""
228
+ raw: Dict[str, Any] = field(default_factory=dict)
229
+
230
+
231
+ from cli.ui.event_registry import RegisteredEvent # noqa: E402 (no top-level cli deps)
232
+ import cli.ui.event_specs # noqa: E402,F401 — registers built-in extension events (T4-02)
233
+
234
+ # Union alias for type annotations
235
+ RenderEvent = (
236
+ SessionStart
237
+ | Step
238
+ | LLMCall
239
+ | ToolExec
240
+ | IterationDone
241
+ | ErrorEvent
242
+ | SessionDone
243
+ | AgentRegistration
244
+ | AgentEnd
245
+ | RegisteredEvent
246
+ | Info
247
+ )
248
+
249
+ # ---------------------------------------------------------------------------
250
+ # Normalisation
251
+ # ---------------------------------------------------------------------------
252
+
253
+ #: Feed types that map to ``Info`` (pass-through, no rich extraction needed).
254
+ _INFO_TYPES = frozenset(
255
+ {
256
+ "status",
257
+ "user_message",
258
+ "queue_status",
259
+ "multi_agent_relationship",
260
+ "multi_agent_relationship_detailed",
261
+ "session_relationship",
262
+ "available_actions",
263
+ "session_paused",
264
+ "session_resumed",
265
+ }
266
+ )
267
+
268
+
269
+ def normalize(feed_dict: Dict[str, Any]) -> RenderEvent:
270
+ """Normalise a raw feed dict into a typed ``RenderEvent``.
271
+
272
+ Never raises; unknown types become ``Info``.
273
+
274
+ Args:
275
+ feed_dict: A sanitized update dict as emitted by
276
+ ``ProductTelemetry._on_feed_entry``.
277
+
278
+ Returns:
279
+ A typed ``RenderEvent`` dataclass.
280
+ """
281
+ try:
282
+ return _normalize_inner(feed_dict)
283
+ except Exception as exc: # pragma: no cover
284
+ logger.debug("events.normalize error for %r: %s", feed_dict.get("type"), exc)
285
+ return Info(
286
+ type=feed_dict.get("type", "unknown"),
287
+ raw=feed_dict,
288
+ )
289
+
290
+
291
+ def _normalize_inner(feed_dict: Dict[str, Any]) -> RenderEvent:
292
+ event_type = feed_dict.get("type", "unknown")
293
+ data = feed_dict.get("data", {}) or {}
294
+
295
+ # Extension seam (D2): a registered spec wins over the built-in fallback, so a
296
+ # new core event type surfaces without editing this function.
297
+ from cli.ui.event_registry import get_spec
298
+ spec = get_spec(event_type)
299
+ if spec is not None:
300
+ return spec.parse(feed_dict)
301
+
302
+ if event_type == "session_start":
303
+ return SessionStart(
304
+ task=data.get("task", ""),
305
+ model_name=data.get("model_name", ""),
306
+ agent_id=data.get("agent_id", ""),
307
+ use_vision=bool(data.get("use_vision", False)),
308
+ raw=feed_dict,
309
+ )
310
+
311
+ if event_type == "step":
312
+ # memory lives inside data.context.outputs.memory
313
+ ctx = data.get("context", {}) or {}
314
+ outputs = ctx.get("outputs", {}) or {}
315
+ memory = outputs.get("memory", "")
316
+ return Step(
317
+ step=int(feed_dict.get("step", data.get("step", data.get("iteration", 0)))),
318
+ reasoning=data.get("reasoning", ""),
319
+ memory=memory,
320
+ actions=list(data.get("actions", [])),
321
+ raw=feed_dict,
322
+ )
323
+
324
+ if event_type == "llm_request":
325
+ cost_raw = data.get("cost_estimate")
326
+ cost = float(cost_raw) if cost_raw is not None else None
327
+ return LLMCall(
328
+ model_name=data.get("model_name", ""),
329
+ provider=data.get("provider", ""),
330
+ prompt_tokens=_int_or_none(data.get("prompt_tokens")),
331
+ completion_tokens=_int_or_none(data.get("completion_tokens")),
332
+ token_count=_int_or_none(data.get("token_count")),
333
+ cost_estimate=cost,
334
+ duration_seconds=float(data.get("duration_seconds") or 0.0),
335
+ success=bool(data.get("success", True)),
336
+ raw=feed_dict,
337
+ )
338
+
339
+ if event_type == "tool_execution":
340
+ raw_params = data.get("parameters")
341
+ params = raw_params if isinstance(raw_params, dict) else {}
342
+ preview = data.get("result_preview")
343
+ return ToolExec(
344
+ step=int(feed_dict.get("step", 0)),
345
+ tool_name=data.get("tool_name", ""),
346
+ action_name=data.get("action_name", ""),
347
+ success=bool(data.get("success", True)),
348
+ duration_seconds=float(data.get("duration_seconds") or 0.0),
349
+ error=data.get("error"),
350
+ parameters=params,
351
+ result_preview=str(preview) if preview is not None else None,
352
+ result_truncated=bool(data.get("result_truncated", False)),
353
+ raw=feed_dict,
354
+ )
355
+
356
+ if event_type == "iteration_complete":
357
+ return IterationDone(
358
+ iteration=int(data.get("iteration", 0)),
359
+ step=int(data.get("step", 0)),
360
+ iteration_status=data.get("iteration_status", ""),
361
+ is_done=bool(data.get("is_done", False)),
362
+ raw=feed_dict,
363
+ )
364
+
365
+ if event_type == "error":
366
+ return ErrorEvent(
367
+ step=int(feed_dict.get("step", 0)),
368
+ error_message=data.get("error_message", ""),
369
+ error_type=data.get("error_type", ""),
370
+ raw=feed_dict,
371
+ )
372
+
373
+ if event_type == "session_completion":
374
+ metrics = data.get("metrics", {}) or {}
375
+ return SessionDone(
376
+ success=bool(data.get("success", True)),
377
+ total_steps=int(data.get("total_steps", 0)),
378
+ final_result=str(metrics.get("final_result", "") or ""),
379
+ error_message=str(data.get("error_message", "") or ""),
380
+ duration_seconds=float(data.get("duration_seconds") or 0.0),
381
+ raw=feed_dict,
382
+ )
383
+
384
+ if event_type == "agent_registration":
385
+ return AgentRegistration(
386
+ agent_id=data.get("agent_id", ""),
387
+ agent_name=data.get("agent_name", ""),
388
+ agent_type=data.get("agent_type", ""),
389
+ model_name=data.get("model_name", ""),
390
+ task=data.get("task", ""),
391
+ raw=feed_dict,
392
+ )
393
+
394
+ if event_type == "agent_end":
395
+ return AgentEnd(
396
+ agent_id=data.get("agent_id", ""),
397
+ steps=int(data.get("steps", 0)),
398
+ max_steps_reached=bool(data.get("max_steps_reached", False)),
399
+ success=bool(data.get("success", True)),
400
+ errors=list(data.get("errors", []) or []),
401
+ raw=feed_dict,
402
+ )
403
+
404
+ if event_type in _INFO_TYPES:
405
+ content = data.get("content", data.get("message", data.get("text", "")))
406
+ return Info(
407
+ type=event_type,
408
+ content=str(content) if content else "",
409
+ raw=feed_dict,
410
+ )
411
+
412
+ # Unknown type — log at debug, never crash.
413
+ logger.debug("events.normalize: unknown feed type %r — mapping to Info", event_type)
414
+ content = data.get("content", data.get("message", ""))
415
+ return Info(
416
+ type=event_type,
417
+ content=str(content) if content else "",
418
+ raw=feed_dict,
419
+ )
420
+
421
+
422
+ # ---------------------------------------------------------------------------
423
+ # Helpers
424
+ # ---------------------------------------------------------------------------
425
+
426
+
427
+ def _int_or_none(value: Any) -> Optional[int]:
428
+ if value is None:
429
+ return None
430
+ try:
431
+ return int(value)
432
+ except (TypeError, ValueError):
433
+ return None
cli/ui/identity.py ADDED
@@ -0,0 +1,15 @@
1
+ """The agent's display name for the chat UI — the resolved INSTANCE id.
2
+
3
+ Chat bubbles (``● rob`` / ``rob:``), the activity line (``rob · working…``), the
4
+ separator rule, and the streaming box all show the agent's OWN name. That name is
5
+ the INSTANCE id (default ``rob``, or ``POLYROB_INSTANCE_ID``), NOT the framework
6
+ name (``polyrob``): an operator who renames the instance should see the new name in
7
+ every bubble, matching the `polyrob run` banner — not a hardcoded ``rob``.
8
+ """
9
+ from __future__ import annotations
10
+
11
+
12
+ def agent_display_name() -> str:
13
+ """Return the agent's display name (resolved instance id; default ``rob``)."""
14
+ from core.instance import resolve_instance_id
15
+ return resolve_instance_id()
cli/ui/lifecycle.py ADDED
@@ -0,0 +1,159 @@
1
+ """lifecycle.py — the CLI's single source of truth for "is a turn active, and
2
+ for how long".
3
+
4
+ Before this object the CLI had four uncoordinated notions of session time/status
5
+ (session-age clock shown as "elapsed", an ad-hoc ``status`` string driven by feed
6
+ events, a correct-but-unused per-turn clock, and the agent-side ``SessionStatus``).
7
+ ``TurnLifecycle`` collapses them into one model the renderer/status-bar derive from.
8
+
9
+ Design (docs/plans/2026-06-26-session-runtime-lifecycle-PLAN.md §1, Fusion-validated):
10
+
11
+ **Two orthogonal lanes** — a background autonomy turn (cron/goal/self-wake) can run
12
+ *while* the user's foreground turn runs, so one scalar phase can't hold both:
13
+
14
+ - **foreground** — user turns. Owns the work clock (``active_elapsed``) and the
15
+ primary status word. Driven ONLY by the turn runner via ``begin_turn``/``end_turn``.
16
+ - **autonomy** — background turns. A simple in-flight counter that drives a muted
17
+ ``⟲ autonomy`` indicator. NEVER touches the work clock or the status word.
18
+
19
+ **Invariant:** feed events (``Step``/``LLMCall``/``ToolExec``/…) NEVER mutate this
20
+ object — only the turn seams do. That is what makes "running while idle" impossible
21
+ by construction (a stray/background feed event can't flip the foreground lane) and
22
+ makes a post-cancel straggler event harmless.
23
+
24
+ **Turn token** — ``begin_turn`` returns a monotonically-increasing token; ``end_turn``
25
+ is a no-op unless handed the *current* token. This defeats the Ctrl-C→immediate-resubmit
26
+ race where a cancelled task's late ``end_turn`` would otherwise settle the *new* turn.
27
+
28
+ The clock is injected so timing is deterministic in tests.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import time
34
+ from enum import Enum
35
+ from typing import Callable
36
+
37
+
38
+ class Phase(Enum):
39
+ """Foreground-lane phase."""
40
+
41
+ IDLE = "idle" # no user turn in flight (waiting for the user / follow-up)
42
+ ACTIVE = "active" # a user turn is running (between begin_turn and end_turn)
43
+
44
+
45
+ class TurnOutcome(Enum):
46
+ """How a foreground turn ended (sticky on the bar until the next turn)."""
47
+
48
+ NONE = "none" # no turn yet, or last turn succeeded
49
+ OK = "ok" # passed to end_turn for a clean finish (→ NONE on idle)
50
+ ERROR = "error" # the turn raised
51
+ CANCELLED = "cancelled" # the turn was interrupted (Ctrl-C)
52
+
53
+
54
+ #: Derived status words. ``working`` while ACTIVE; on IDLE the last outcome decides.
55
+ _OUTCOME_WORD = {
56
+ TurnOutcome.NONE: "ready",
57
+ TurnOutcome.OK: "ready",
58
+ TurnOutcome.ERROR: "error",
59
+ TurnOutcome.CANCELLED: "stopped",
60
+ }
61
+
62
+
63
+ class TurnLifecycle:
64
+ """Single source of truth for the CLI's active-turn + work-clock + status word.
65
+
66
+ Args:
67
+ clock: Monotonic clock (injectable for tests). Defaults to ``time.monotonic``.
68
+ """
69
+
70
+ def __init__(self, *, clock: Callable[[], float] = time.monotonic) -> None:
71
+ self._clock = clock
72
+ # Foreground lane.
73
+ self.phase: Phase = Phase.IDLE
74
+ self.active_started_at: float | None = None
75
+ self.last_outcome: TurnOutcome = TurnOutcome.NONE
76
+ self._token: int = 0
77
+ # Autonomy lane (orthogonal): count of in-flight background turns.
78
+ self._autonomy_active: int = 0
79
+
80
+ # ------------------------------------------------------------------
81
+ # Foreground lane — user turns (called from the turn runner ONLY)
82
+ # ------------------------------------------------------------------
83
+
84
+ def begin_turn(self) -> int:
85
+ """Start a user turn → ACTIVE; the work clock starts at 0 and runs.
86
+
87
+ Idempotent: calling it again while already ACTIVE is a no-op that returns
88
+ the SAME token and does NOT reset the clock (defends against a duplicate
89
+ submit/race). Clears any sticky error/cancel outcome.
90
+
91
+ Returns the turn token to hand back to ``end_turn``.
92
+ """
93
+ if self.phase is Phase.ACTIVE:
94
+ return self._token # already running — don't restart the clock
95
+ self._token += 1
96
+ self.phase = Phase.ACTIVE
97
+ self.active_started_at = self._clock()
98
+ self.last_outcome = TurnOutcome.NONE
99
+ return self._token
100
+
101
+ def end_turn(self, token: int, outcome: TurnOutcome = TurnOutcome.OK) -> None:
102
+ """End the user turn → IDLE; the work clock freezes (reads 0 on idle).
103
+
104
+ No-op unless *token* is the current turn's token AND a turn is active —
105
+ so a stale (cancelled-then-resubmitted) task's late settle can't touch the
106
+ new turn, and a double end_turn is harmless. ``OK`` settles to ``ready``;
107
+ ``ERROR``/``CANCELLED`` are sticky until the next ``begin_turn``.
108
+ """
109
+ if self.phase is not Phase.ACTIVE or token != self._token:
110
+ return
111
+ self.phase = Phase.IDLE
112
+ self.active_started_at = None
113
+ self.last_outcome = TurnOutcome.NONE if outcome is TurnOutcome.OK else outcome
114
+
115
+ # ------------------------------------------------------------------
116
+ # Autonomy lane — background turns (orthogonal to the foreground lane)
117
+ # ------------------------------------------------------------------
118
+
119
+ def begin_background(self) -> None:
120
+ """A background (cron/goal/self-wake) turn started. Lights the muted
121
+ autonomy indicator without touching the work clock or status word."""
122
+ self._autonomy_active += 1
123
+
124
+ def end_background(self) -> None:
125
+ """A background turn finished. Floored at 0 (underflow-safe)."""
126
+ self._autonomy_active = max(0, self._autonomy_active - 1)
127
+
128
+ def autonomy_busy(self) -> bool:
129
+ """True when one or more background turns are in flight."""
130
+ return self._autonomy_active > 0
131
+
132
+ # ------------------------------------------------------------------
133
+ # Derived reads (the renderer / status bar consume these)
134
+ # ------------------------------------------------------------------
135
+
136
+ def is_active(self) -> bool:
137
+ """True when a user turn is running (drives the spinner + cooking line)."""
138
+ return self.phase is Phase.ACTIVE
139
+
140
+ def active_elapsed(self) -> float:
141
+ """Work-clock seconds: ``now - active_started_at`` while ACTIVE, else 0.0.
142
+
143
+ Frozen (0.0) on idle — this is the fix for the bar showing session age
144
+ ("1h26m") while the user sits at the prompt.
145
+ """
146
+ if self.phase is Phase.ACTIVE and self.active_started_at is not None:
147
+ return max(0.0, self._clock() - self.active_started_at)
148
+ return 0.0
149
+
150
+ def status_word(self) -> str:
151
+ """The single derived status word: working / ready / error / stopped.
152
+
153
+ ``running``-while-idle is impossible by construction: the word is
154
+ ``working`` iff the foreground phase is ACTIVE, and the phase only goes
155
+ ACTIVE via ``begin_turn``.
156
+ """
157
+ if self.phase is Phase.ACTIVE:
158
+ return "working"
159
+ return _OUTCOME_WORD.get(self.last_outcome, "ready")
cli/ui/live_hooks.py ADDED
@@ -0,0 +1,43 @@
1
+ """live_hooks.py — bridge the orchestrator's lifecycle hooks into SessionState.
2
+
3
+ The orchestrator fires sub-agent start/end hooks (``_run_subagent_start_hooks`` /
4
+ ``_run_subagent_end_hooks`` in ``agents/task/session/hooks.py``, fired from
5
+ ``sub_agent_manager.py``) but nothing in the CLI subscribed — so a ``delegate_task``
6
+ spawn was invisible. ``make_subagent_hooks`` builds the two fail-open callbacks the
7
+ REPL registers on the orchestrator; they bump the live sub-agent counter on
8
+ ``SessionState`` (which the status line reads).
9
+
10
+ Hooks are called by the orchestrator with keyword args (``goal``, ``agent_id``,
11
+ ``parent_session_id`` and, on end, ``ok``). The callbacks accept arbitrary kwargs
12
+ and never raise — a UI-counter hook must never break the agent loop.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import Any, Callable, Tuple
18
+
19
+ from cli.ui.state import SessionState
20
+
21
+ Hook = Callable[..., None]
22
+
23
+
24
+ def make_subagent_hooks(state: SessionState) -> Tuple[Hook, Hook]:
25
+ """Return ``(start_hook, end_hook)`` that keep ``state.subagents_active`` live.
26
+
27
+ Both are fail-open (swallow any error) and accept arbitrary kwargs so a
28
+ change to the orchestrator's hook signature can't crash the REPL.
29
+ """
30
+
31
+ def _start(**_event: Any) -> None:
32
+ try:
33
+ state.note_subagent_start()
34
+ except Exception: # pragma: no cover - a UI counter must never break the loop
35
+ pass
36
+
37
+ def _end(**_event: Any) -> None:
38
+ try:
39
+ state.note_subagent_end()
40
+ except Exception: # pragma: no cover
41
+ pass
42
+
43
+ return _start, _end