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
@@ -0,0 +1,532 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import sys
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from agents.task.agent.views import ActionResult, AgentBrain, AgentOutput, AgentStepInfo
8
+ from modules.llm.messages import (
9
+ AIMessage,
10
+ BaseMessage,
11
+ HumanMessage,
12
+ SystemMessage,
13
+ ToolMessage,
14
+ )
15
+ from modules.llm.adapters import BaseChatModel
16
+
17
+ # LLM module availability flag + token counters (mirrors service.py module-level setup)
18
+ try:
19
+ from modules.llm.model_registry import get_model_config
20
+ from modules.llm import count_tokens, count_messages_tokens
21
+ LLM_MODULE_AVAILABLE = True
22
+ except ImportError:
23
+ LLM_MODULE_AVAILABLE = False
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ class TokenCounterMixin:
29
+ # Empty slots so the composed MessageManager keeps its own __slots__ (no __dict__).
30
+ __slots__ = ()
31
+
32
+ def _calculate_token_limits(self, llm: BaseChatModel,
33
+ max_input_override: Optional[int]) -> tuple:
34
+ """Calculate token limits from model config (SINGLE SOURCE OF TRUTH).
35
+
36
+ Args:
37
+ llm: Language model instance
38
+ max_input_override: Optional explicit limit (None = auto-calculate)
39
+
40
+ Returns:
41
+ (max_input_tokens, safe_input_tokens, completion_reserve)
42
+ """
43
+ from modules.llm.model_registry import get_model_config
44
+ from agents.task.robust_parse_config import RobustParseConfig
45
+
46
+ # Env override (operational knob): cap the effective input budget regardless of
47
+ # the model's native window. An explicit constructor override still wins.
48
+ if max_input_override is None:
49
+ import os
50
+ _env_cap = os.getenv("TASK_MAX_INPUT_TOKENS")
51
+ if _env_cap and _env_cap.strip().isdigit():
52
+ max_input_override = int(_env_cap)
53
+ self.logger.info(f"TASK_MAX_INPUT_TOKENS override: max_input={max_input_override}")
54
+
55
+ # Use override if provided
56
+ if max_input_override is not None:
57
+ max_input = max_input_override
58
+ safe_input = int(max_input * (1 - RobustParseConfig.SAFETY_MARGIN_PERCENT))
59
+ self.logger.info(f"Using explicit token limit: max={max_input}, safe={safe_input}")
60
+ return max_input, safe_input, 4096 # Default completion reserve
61
+
62
+ # Auto-calculate from model
63
+ model_name = self._model_name
64
+ model_config = get_model_config(model_name)
65
+
66
+ if model_config and model_config.context_window:
67
+ # 95% of context window minus completion reserve
68
+ context_95pct = int(model_config.context_window * 0.95)
69
+ completion_reserve = model_config.max_completion_tokens
70
+ max_input = max(1000, context_95pct - completion_reserve)
71
+
72
+ # Apply safety margin (default 5%)
73
+ safe_input = int(max_input * (1 - RobustParseConfig.SAFETY_MARGIN_PERCENT))
74
+
75
+ self.logger.info(
76
+ f"Calculated token limits for {model_name}: "
77
+ f"context={model_config.context_window}, "
78
+ f"max_input={max_input}, safe_input={safe_input}, "
79
+ f"completion_reserve={completion_reserve}"
80
+ )
81
+
82
+ return max_input, safe_input, completion_reserve
83
+ else:
84
+ # Fallback defaults
85
+ self.logger.warning(f"No model config found for {model_name}, using fallback limits")
86
+ max_input = 120000
87
+ safe_input = int(max_input * 0.95)
88
+ return max_input, safe_input, 4096
89
+
90
+ def _count_message_tokens(self, message: BaseMessage) -> int:
91
+ """Count tokens for a single message using modules.llm.
92
+
93
+ Args:
94
+ message: BaseMessage to count tokens for
95
+
96
+ Returns:
97
+ Token count
98
+ """
99
+ if not LLM_MODULE_AVAILABLE:
100
+ text = str(message.content if hasattr(message, 'content') else message)
101
+ return max(1, len(text) // 4) if text else 0
102
+
103
+ try:
104
+ # Convert to dict format for modules.llm
105
+ message_dict = {
106
+ "role": message.type,
107
+ "content": message.content
108
+ }
109
+ # CX-H4: tool-call arguments are real prompt bytes — the downstream
110
+ # counter supports them; omitting them makes compaction fire late.
111
+ tool_calls = getattr(message, "tool_calls", None)
112
+ if tool_calls:
113
+ message_dict["tool_calls"] = tool_calls
114
+ return count_messages_tokens([message_dict], self.model_name)
115
+ except Exception as e:
116
+ self.logger.debug(f"Token counting failed: {e}, using fallback")
117
+ text = str(message.content if hasattr(message, 'content') else message)
118
+ fallback_len = len(text)
119
+ tool_calls = getattr(message, "tool_calls", None)
120
+ if tool_calls:
121
+ import json
122
+ fallback_len += len(json.dumps(tool_calls))
123
+ return max(1, fallback_len // 4) if fallback_len else 0
124
+
125
+ def _increment_token_count(self, delta: int) -> None:
126
+ """Increment the total token count by delta.
127
+
128
+ This method provides efficient token counting without recalculation.
129
+ Token counts are now trusted from centralized modules.llm - no periodic recalibration needed.
130
+
131
+ Args:
132
+ delta: The number of tokens to add (positive) or remove (negative)
133
+ """
134
+ previous_count = self.history.total_tokens
135
+ self.history.total_tokens = max(0, self.history.total_tokens + delta)
136
+
137
+ if delta != 0:
138
+ self.logger.debug(
139
+ f"Token count incremented: {previous_count} → {self.history.total_tokens} (Δ{delta:+})"
140
+ )
141
+
142
+ # Check if we need to trim after increment
143
+ if self.history.total_tokens > self.max_input_tokens:
144
+ self.logger.debug(
145
+ f"Token count {self.history.total_tokens} exceeds limit {self.max_input_tokens} "
146
+ f"(trimming disabled - using full context)"
147
+ )
148
+
149
+ def get_total_tokens(self) -> int:
150
+ """Get total tokens including all foundation messages.
151
+
152
+ FIX #4: Single source of truth for total token count.
153
+ Includes system message, initial task, and conversation history.
154
+
155
+ Returns:
156
+ Total token count across all message storage
157
+ """
158
+ return (
159
+ self.history.total_tokens +
160
+ self._system_message_tokens +
161
+ self._initial_task_tokens +
162
+ getattr(self, '_skill_message_tokens', 0) +
163
+ getattr(self, '_self_context_tokens', 0) +
164
+ getattr(self, '_project_context_tokens', 0) +
165
+ getattr(self, '_runtime_identity_tokens', 0)
166
+ )
167
+
168
+ def estimate_tokens(self, messages: List[BaseMessage]) -> int:
169
+ """Estimate total tokens for a list of messages using modules.llm.
170
+
171
+ Args:
172
+ messages: List of BaseMessage objects to count tokens for
173
+
174
+ Returns:
175
+ Total estimated token count for all messages
176
+ """
177
+ if not LLM_MODULE_AVAILABLE:
178
+ # Fallback: estimate 4 chars per token
179
+ total_chars = sum(len(str(m.content)) for m in messages if hasattr(m, 'content'))
180
+ return max(1, total_chars // 4)
181
+
182
+ try:
183
+ # Convert to message dicts for modules.llm
184
+ message_dicts = []
185
+ for msg in messages:
186
+ message_dict = {"role": msg.type, "content": msg.content}
187
+ # CX-H4: mirror _count_message_tokens — include tool-call args.
188
+ tool_calls = getattr(msg, "tool_calls", None)
189
+ if tool_calls:
190
+ message_dict["tool_calls"] = tool_calls
191
+ message_dicts.append(message_dict)
192
+ return count_messages_tokens(message_dicts, self.model_name)
193
+ except Exception as e:
194
+ self.logger.debug(f"Token counting failed: {e}, using fallback")
195
+ import json
196
+ total_chars = 0
197
+ for m in messages:
198
+ if hasattr(m, 'content'):
199
+ total_chars += len(str(m.content))
200
+ tool_calls = getattr(m, "tool_calls", None)
201
+ if tool_calls:
202
+ total_chars += len(json.dumps(tool_calls))
203
+ return max(1, total_chars // 4)
204
+
205
+ def _get_model_token_limits(self) -> tuple[int, int]:
206
+ """Get token limits from model registry.
207
+
208
+ Returns:
209
+ Tuple of (context_window, max_completion_tokens)
210
+ """
211
+ from modules.llm.model_registry import get_model_config
212
+ model_name = self.model_name
213
+
214
+ # Use centralized model registry
215
+ config = get_model_config(model_name)
216
+ if config:
217
+ context_window = config.context_window
218
+ completion_tokens = config.max_completion_tokens
219
+ else:
220
+ # Conservative fallback
221
+ context_window = 128000
222
+ completion_tokens = 16384
223
+ self.logger.info(f"Got limits for {model_name}: context={context_window}, completion={completion_tokens}")
224
+ return context_window, completion_tokens
225
+
226
+ def get_memory_usage_estimate(self) -> int:
227
+ """Estimate memory usage of message history in bytes.
228
+
229
+ Returns:
230
+ Estimated memory usage in bytes
231
+ """
232
+ import sys
233
+
234
+ total_size = 0
235
+ for managed_msg in self.history.messages:
236
+ msg = managed_msg.message
237
+
238
+ # Estimate size of message content
239
+ if hasattr(msg, 'content') and msg.content:
240
+ total_size += sys.getsizeof(str(msg.content))
241
+
242
+ # Add size of metadata
243
+ if hasattr(managed_msg, 'metadata'):
244
+ total_size += sys.getsizeof(managed_msg.metadata)
245
+
246
+ # Add overhead for message object itself
247
+ total_size += sys.getsizeof(msg)
248
+
249
+ return total_size
250
+
251
+ def recalibrate_token_counts(self, force: bool = False) -> None:
252
+ """Recalculate token counts using unified counting method.
253
+
254
+ This is now only called when explicitly requested or when model changes.
255
+
256
+ Args:
257
+ force: If True, always recalibrate even if not necessary
258
+ """
259
+ self.logger.info("Recalibrating token counts for all messages")
260
+
261
+ # Check if model limits have changed (e.g. a fallback to a smaller-context
262
+ # model). Recompute the input budget the SAME way _calculate_token_limits does
263
+ # — 95% of the window MINUS the completion reserve — instead of using the raw
264
+ # context window (which leaves zero room for the response). Update BOTH
265
+ # max_input_tokens AND safe_input_tokens so check_token_safety stays consistent.
266
+ context_window, completion_tokens = self._get_model_token_limits()
267
+
268
+ if context_window > 0:
269
+ from agents.task.robust_parse_config import RobustParseConfig
270
+ new_max_input = max(1000, int(context_window * 0.95) - completion_tokens)
271
+ if new_max_input < self.max_input_tokens:
272
+ old_limit = self.max_input_tokens
273
+ self.max_input_tokens = new_max_input
274
+ self.safe_input_tokens = int(new_max_input * (1 - RobustParseConfig.SAFETY_MARGIN_PERCENT))
275
+ self.logger.info(
276
+ f"Updated token limits after model change: max_input={new_max_input}, "
277
+ f"safe_input={self.safe_input_tokens} (was max_input={old_limit})"
278
+ )
279
+
280
+ # Store the original total
281
+ original_total = self.history.total_tokens
282
+
283
+ # Reset total
284
+ self.history.total_tokens = 0
285
+
286
+ # Recalculate for each message
287
+ for managed_msg in self.history.messages:
288
+ old_count = managed_msg.metadata.input_tokens
289
+ new_count = self._count_message_tokens(managed_msg.message)
290
+ managed_msg.metadata.input_tokens = new_count
291
+ self.history.total_tokens += new_count
292
+
293
+ # Log the change (only if significant to reduce spam)
294
+ diff = self.history.total_tokens - original_total
295
+ if abs(diff) > 100: # Only log if significant change
296
+ self.logger.info(f"Token count recalibration: {original_total} → {self.history.total_tokens} (Δ{diff:+})")
297
+ elif diff != 0:
298
+ self.logger.debug(f"Token count recalibration: {original_total} → {self.history.total_tokens} (Δ{diff:+})")
299
+ # else: no logging for unchanged recalibration
300
+
301
+ # Capture telemetry for token count changes if significant
302
+ if abs(diff) > 100: # Only capture if change is significant
303
+ try:
304
+ from agents.task import capture_llm_request
305
+
306
+ capture_llm_request(
307
+ component="MessageManager",
308
+ purpose="token_recalibration",
309
+ model_name=self.model_name,
310
+ duration_seconds=0.0, # No actual LLM call
311
+ success=True,
312
+ token_count=self.history.total_tokens,
313
+ session_id=self.session_id
314
+ )
315
+
316
+ self.logger.debug("Captured telemetry for token count recalibration")
317
+
318
+ except Exception as e:
319
+ self.logger.debug(f"Failed to capture telemetry for token recalibration: {e}")
320
+
321
+ # Log if token count exceeds max (trimming disabled)
322
+ if self.history.total_tokens > self.max_input_tokens:
323
+ self.logger.debug(f"Token count {self.history.total_tokens} exceeds limit {self.max_input_tokens} (trimming disabled)")
324
+
325
+ def get_token_count(self) -> int:
326
+ """Get the current total token count including all separately stored messages.
327
+
328
+ NOTE: This does NOT include H-MEM or ephemeral messages.
329
+ Use get_actual_token_count() for the true count that will be sent to LLM.
330
+ """
331
+ return (self.history.total_tokens + self._system_message_tokens
332
+ + self._initial_task_tokens + getattr(self, '_skill_message_tokens', 0)
333
+ + getattr(self, '_self_context_tokens', 0)
334
+ + getattr(self, '_project_context_tokens', 0)
335
+ + getattr(self, '_runtime_identity_tokens', 0))
336
+
337
+ def get_actual_token_count(self) -> int:
338
+ """Get the ACTUAL token count including H-MEM and ephemeral messages.
339
+
340
+ This returns the true token count that will be sent to the LLM,
341
+ including dynamically injected hierarchical memory and ephemeral messages.
342
+
343
+ Use this for accurate context usage calculations before LLM calls.
344
+
345
+ NOTE: H-MEM tokens are cached per-step to avoid duplicate hierarchical searches.
346
+ Cache is invalidated when invalidate_hmem_cache() is called (typically at step start).
347
+ """
348
+ # Start with base count (system + task + history)
349
+ base_count = self.get_token_count()
350
+
351
+ # Add ephemeral messages if any
352
+ ephemeral_tokens = 0
353
+ if hasattr(self, '_ephemeral_messages') and self._ephemeral_messages:
354
+ ephemeral_tokens = self.estimate_tokens(self._ephemeral_messages)
355
+
356
+ # Estimate H-MEM tokens if available
357
+ hmem_tokens = 0
358
+ if self.task_context_manager and self.session_id:
359
+ try:
360
+ context = self.task_context_manager.get_context_injection(self.session_id)
361
+ if context:
362
+ # Rough estimate: words * 1.3 tokens per word
363
+ hmem_tokens = int(len(context.split()) * 1.3)
364
+ except Exception:
365
+ pass
366
+
367
+ total = base_count + ephemeral_tokens + hmem_tokens
368
+
369
+ # Log if there's a significant difference from base count
370
+ if ephemeral_tokens + hmem_tokens > 1000:
371
+ self.logger.debug(
372
+ f"Token count: base={base_count}, ephemeral={ephemeral_tokens}, "
373
+ f"hmem={hmem_tokens}, total={total}"
374
+ )
375
+
376
+ return total
377
+
378
+ def get_estimated_context_usage(self) -> float:
379
+ """Get estimated context usage as a ratio (0.0 to 1.0).
380
+
381
+ Uses actual token count including H-MEM and ephemeral messages.
382
+ """
383
+ if self.max_input_tokens <= 0:
384
+ return 0.0
385
+ total_tokens = self.get_actual_token_count()
386
+ return min(1.0, total_tokens / self.max_input_tokens)
387
+
388
+ def check_token_safety(self,
389
+ additional_messages: Optional[List[BaseMessage]] = None,
390
+ raise_on_overflow: bool = False) -> Dict[str, Any]:
391
+ """Check if current or projected token usage is safe.
392
+
393
+ Uses actual token count including H-MEM and ephemeral messages.
394
+
395
+ Args:
396
+ additional_messages: Optional messages to add (for projection)
397
+ raise_on_overflow: Raise LLMResponseError if unsafe
398
+
399
+ Returns:
400
+ {
401
+ 'safe': bool,
402
+ 'current_tokens': int,
403
+ 'estimated_tokens': int,
404
+ 'safe_limit': int,
405
+ 'max_limit': int,
406
+ 'would_overflow': bool,
407
+ 'usage_percent': float
408
+ }
409
+
410
+ Raises:
411
+ LLMResponseError: If raise_on_overflow=True and unsafe
412
+ """
413
+ from agents.task.robust_parse_config import RobustParseConfig
414
+ from core.exceptions import LLMResponseError
415
+
416
+ current = self.get_actual_token_count()
417
+
418
+ # Estimate with additional messages
419
+ if additional_messages:
420
+ additional_tokens = self.estimate_tokens(additional_messages)
421
+ estimated = current + additional_tokens
422
+ else:
423
+ estimated = current
424
+
425
+ # Check against safe limit
426
+ safe = estimated <= self.safe_input_tokens
427
+
428
+ # Check context overflow (hard limit)
429
+ would_overflow = RobustParseConfig.should_abort_context_overflow(
430
+ estimated,
431
+ self._model_name
432
+ )
433
+
434
+ if would_overflow:
435
+ safe = False
436
+
437
+ usage_percent = (estimated / self.max_input_tokens * 100) if self.max_input_tokens > 0 else 0
438
+
439
+ result = {
440
+ 'safe': safe,
441
+ 'current_tokens': current,
442
+ 'estimated_tokens': estimated,
443
+ 'safe_limit': self.safe_input_tokens,
444
+ 'max_limit': self.max_input_tokens,
445
+ 'would_overflow': would_overflow,
446
+ 'usage_percent': usage_percent
447
+ }
448
+
449
+ # Optionally raise
450
+ if raise_on_overflow and not safe:
451
+ raise LLMResponseError(
452
+ f"Token overflow: {estimated} tokens exceeds safe limit {self.safe_input_tokens} "
453
+ f"({usage_percent:.1f}% of max {self.max_input_tokens})"
454
+ )
455
+
456
+ return result
457
+
458
+ def get_token_stats(self) -> Dict[str, Any]:
459
+ """Get current token statistics.
460
+
461
+ Uses actual token count including H-MEM and ephemeral messages.
462
+
463
+ Returns:
464
+ {
465
+ 'current': int,
466
+ 'base': int (without H-MEM/ephemeral),
467
+ 'max': int,
468
+ 'safe': int,
469
+ 'remaining': int,
470
+ 'usage_percent': float
471
+ }
472
+ """
473
+ base_count = (self.history.total_tokens + self._system_message_tokens
474
+ + self._initial_task_tokens + getattr(self, '_skill_message_tokens', 0)
475
+ + getattr(self, '_self_context_tokens', 0)
476
+ + getattr(self, '_project_context_tokens', 0)
477
+ + getattr(self, '_runtime_identity_tokens', 0))
478
+ current = self.get_actual_token_count()
479
+ remaining = self.safe_input_tokens - current
480
+ usage_percent = (current / self.max_input_tokens * 100) if self.max_input_tokens > 0 else 0
481
+
482
+ return {
483
+ 'current': current,
484
+ 'base': base_count,
485
+ 'max': self.max_input_tokens,
486
+ 'safe': self.safe_input_tokens,
487
+ 'remaining': remaining,
488
+ 'usage_percent': usage_percent
489
+ }
490
+
491
+ def _get_min_safe_tokens(self, model_name: str) -> int:
492
+ """Get minimum safe token limit for a model.
493
+
494
+ This ensures we don't reduce tokens below a reasonable threshold for each model.
495
+ """
496
+ # Try to get config from the centralized LLM module
497
+ if LLM_MODULE_AVAILABLE:
498
+ try:
499
+ config = get_model_config(model_name)
500
+ if config:
501
+ return config.min_safe_tokens
502
+ except Exception as e:
503
+ self.logger.debug(f"Error getting min safe tokens from LLM module: {e}")
504
+
505
+ # Fallback to hardcoded logic
506
+ # For high-context models, use a larger minimum
507
+ if any(name in model_name for name in ["gpt-4", "claude", "o1"]):
508
+ # These models work well with at least 16k tokens
509
+ return 16000
510
+ elif "gpt-3.5" in model_name:
511
+ # GPT-3.5 can handle at least 8k
512
+ return 8000
513
+ elif "llama" in model_name:
514
+ # Llama models typically have smaller contexts
515
+ return 4000
516
+ else:
517
+ # Conservative default for unknown models
518
+ return 4000
519
+
520
+ def get_context_usage_percent(self) -> float:
521
+ """Get current context usage as a percentage.
522
+
523
+ Returns:
524
+ Percentage of context window used (0-100)
525
+ """
526
+ if self.max_input_tokens <= 0:
527
+ return 0.0
528
+
529
+ # Use get_actual_token_count for complete picture including H-MEM
530
+ total_tokens = self.get_actual_token_count()
531
+ usage_pct = (total_tokens / self.max_input_tokens) * 100
532
+ return min(usage_pct, 100.0)