aip-agents-binary 0.0.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 (447) hide show
  1. aip_agents/__init__.py +66 -0
  2. aip_agents/a2a/__init__.py +19 -0
  3. aip_agents/a2a/server/__init__.py +10 -0
  4. aip_agents/a2a/server/base_executor.py +1125 -0
  5. aip_agents/a2a/server/google_adk_executor.py +198 -0
  6. aip_agents/a2a/server/langflow_executor.py +180 -0
  7. aip_agents/a2a/server/langgraph_executor.py +270 -0
  8. aip_agents/a2a/types.py +232 -0
  9. aip_agents/a2ui/__init__.py +26 -0
  10. aip_agents/a2ui/catalog_provider.py +109 -0
  11. aip_agents/a2ui/examples/0.8/booking_form.json +1 -0
  12. aip_agents/a2ui/examples/0.8/confirmation.json +1 -0
  13. aip_agents/a2ui/examples/0.8/single_column_list.json +1 -0
  14. aip_agents/a2ui/examples/0.9/booking_form.json +1 -0
  15. aip_agents/a2ui/examples/0.9/confirmation.json +1 -0
  16. aip_agents/a2ui/examples/0.9/single_column_list.json +1 -0
  17. aip_agents/a2ui/middleware.py +754 -0
  18. aip_agents/a2ui/models.py +153 -0
  19. aip_agents/a2ui/public_url.py +138 -0
  20. aip_agents/a2ui/stream_filter.py +67 -0
  21. aip_agents/agent/__init__.py +72 -0
  22. aip_agents/agent/base_agent.py +1437 -0
  23. aip_agents/agent/base_langgraph_agent.py +4048 -0
  24. aip_agents/agent/google_adk_agent.py +932 -0
  25. aip_agents/agent/google_adk_constants.py +11 -0
  26. aip_agents/agent/graph_runtime.py +185 -0
  27. aip_agents/agent/hitl/__init__.py +24 -0
  28. aip_agents/agent/hitl/config.py +28 -0
  29. aip_agents/agent/hitl/langgraph_hitl_mixin.py +515 -0
  30. aip_agents/agent/hitl/manager.py +532 -0
  31. aip_agents/agent/hitl/models.py +18 -0
  32. aip_agents/agent/hitl/prompt/__init__.py +9 -0
  33. aip_agents/agent/hitl/prompt/base.py +42 -0
  34. aip_agents/agent/hitl/prompt/deferred.py +73 -0
  35. aip_agents/agent/hitl/registry.py +149 -0
  36. aip_agents/agent/interface.py +138 -0
  37. aip_agents/agent/interfaces.py +65 -0
  38. aip_agents/agent/langflow_agent.py +464 -0
  39. aip_agents/agent/langgraph_react_agent.py +3741 -0
  40. aip_agents/agent/model_invocation_adapter.py +346 -0
  41. aip_agents/agent/system_instruction_context.py +34 -0
  42. aip_agents/agent/tool_execution_engine.py +587 -0
  43. aip_agents/audio_interface/__init__.py +30 -0
  44. aip_agents/audio_interface/audio_agent_adapter.py +254 -0
  45. aip_agents/audio_interface/config.py +146 -0
  46. aip_agents/audio_interface/errors.py +15 -0
  47. aip_agents/audio_interface/livekit_audio_session.py +504 -0
  48. aip_agents/audio_interface/livekit_realtime_audio_session.py +142 -0
  49. aip_agents/audio_interface/session_factory.py +40 -0
  50. aip_agents/clients/__init__.py +10 -0
  51. aip_agents/clients/langflow/__init__.py +10 -0
  52. aip_agents/clients/langflow/client.py +477 -0
  53. aip_agents/clients/langflow/types.py +18 -0
  54. aip_agents/common/__init__.py +5 -0
  55. aip_agents/common/callable_introspection.py +17 -0
  56. aip_agents/constants.py +23 -0
  57. aip_agents/context/__init__.py +5 -0
  58. aip_agents/context/budget.py +237 -0
  59. aip_agents/context/compaction.py +339 -0
  60. aip_agents/context/metadata.py +169 -0
  61. aip_agents/context/offload.py +449 -0
  62. aip_agents/context/preparation.py +196 -0
  63. aip_agents/context/prompt.py +61 -0
  64. aip_agents/context/runtime.py +149 -0
  65. aip_agents/context/session_recall.py +69 -0
  66. aip_agents/context/state.py +48 -0
  67. aip_agents/context/utils.py +44 -0
  68. aip_agents/credentials/manager.py +132 -0
  69. aip_agents/examples/__init__.py +5 -0
  70. aip_agents/examples/audio_livekit_session.py +116 -0
  71. aip_agents/examples/compare_streaming_client.py +783 -0
  72. aip_agents/examples/compare_streaming_server.py +141 -0
  73. aip_agents/examples/gl_connectors_smoke.py +148 -0
  74. aip_agents/examples/hello_world_a2a_google_adk_client.py +49 -0
  75. aip_agents/examples/hello_world_a2a_google_adk_client_agent.py +48 -0
  76. aip_agents/examples/hello_world_a2a_google_adk_client_streaming.py +60 -0
  77. aip_agents/examples/hello_world_a2a_google_adk_server.py +78 -0
  78. aip_agents/examples/hello_world_a2a_langchain_client.py +39 -0
  79. aip_agents/examples/hello_world_a2a_langchain_client_agent.py +39 -0
  80. aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.py +37 -0
  81. aip_agents/examples/hello_world_a2a_langchain_client_streaming.py +41 -0
  82. aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.py +60 -0
  83. aip_agents/examples/hello_world_a2a_langchain_reference_server.py +104 -0
  84. aip_agents/examples/hello_world_a2a_langchain_server.py +78 -0
  85. aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.py +77 -0
  86. aip_agents/examples/hello_world_a2a_langflow_client.py +83 -0
  87. aip_agents/examples/hello_world_a2a_langflow_server.py +80 -0
  88. aip_agents/examples/hello_world_a2a_langgraph_artifact_client.py +73 -0
  89. aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.py +76 -0
  90. aip_agents/examples/hello_world_a2a_langgraph_artifact_server.py +91 -0
  91. aip_agents/examples/hello_world_a2a_langgraph_client.py +54 -0
  92. aip_agents/examples/hello_world_a2a_langgraph_client_agent.py +54 -0
  93. aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.py +32 -0
  94. aip_agents/examples/hello_world_a2a_langgraph_client_streaming.py +50 -0
  95. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.py +44 -0
  96. aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.py +92 -0
  97. aip_agents/examples/hello_world_a2a_langgraph_server.py +83 -0
  98. aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.py +78 -0
  99. aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.py +131 -0
  100. aip_agents/examples/hello_world_a2a_mcp_langgraph.py +196 -0
  101. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.py +244 -0
  102. aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.py +250 -0
  103. aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.py +57 -0
  104. aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.py +79 -0
  105. aip_agents/examples/hello_world_filesystem.py +162 -0
  106. aip_agents/examples/hello_world_google_adk.py +41 -0
  107. aip_agents/examples/hello_world_google_adk_mcp_http.py +34 -0
  108. aip_agents/examples/hello_world_google_adk_mcp_http_stream.py +40 -0
  109. aip_agents/examples/hello_world_google_adk_mcp_sse.py +44 -0
  110. aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py +48 -0
  111. aip_agents/examples/hello_world_google_adk_mcp_stdio.py +44 -0
  112. aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py +48 -0
  113. aip_agents/examples/hello_world_google_adk_stream.py +44 -0
  114. aip_agents/examples/hello_world_langchain.py +28 -0
  115. aip_agents/examples/hello_world_langchain_lm_invoker.py +15 -0
  116. aip_agents/examples/hello_world_langchain_mcp_http.py +34 -0
  117. aip_agents/examples/hello_world_langchain_mcp_http_interactive.py +130 -0
  118. aip_agents/examples/hello_world_langchain_mcp_http_stream.py +42 -0
  119. aip_agents/examples/hello_world_langchain_mcp_multi_server.py +155 -0
  120. aip_agents/examples/hello_world_langchain_mcp_sse.py +34 -0
  121. aip_agents/examples/hello_world_langchain_mcp_sse_stream.py +40 -0
  122. aip_agents/examples/hello_world_langchain_mcp_stdio.py +30 -0
  123. aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py +41 -0
  124. aip_agents/examples/hello_world_langchain_stream.py +36 -0
  125. aip_agents/examples/hello_world_langchain_stream_lm_invoker.py +39 -0
  126. aip_agents/examples/hello_world_langflow_agent.py +163 -0
  127. aip_agents/examples/hello_world_langgraph.py +39 -0
  128. aip_agents/examples/hello_world_langgraph_gl_connector_twitter.py +44 -0
  129. aip_agents/examples/hello_world_langgraph_mcp_http.py +31 -0
  130. aip_agents/examples/hello_world_langgraph_mcp_http_stream.py +34 -0
  131. aip_agents/examples/hello_world_langgraph_mcp_sse.py +35 -0
  132. aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py +50 -0
  133. aip_agents/examples/hello_world_langgraph_mcp_stdio.py +35 -0
  134. aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py +50 -0
  135. aip_agents/examples/hello_world_langgraph_skills.py +62 -0
  136. aip_agents/examples/hello_world_langgraph_stream.py +43 -0
  137. aip_agents/examples/hello_world_langgraph_stream_lm_invoker.py +37 -0
  138. aip_agents/examples/hello_world_model_switch_cli.py +210 -0
  139. aip_agents/examples/hello_world_multi_agent_adk.py +75 -0
  140. aip_agents/examples/hello_world_multi_agent_langchain.py +54 -0
  141. aip_agents/examples/hello_world_multi_agent_langgraph.py +66 -0
  142. aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.py +69 -0
  143. aip_agents/examples/hello_world_multi_agent_tool_output_client.py +57 -0
  144. aip_agents/examples/hello_world_multi_agent_tool_output_server.py +131 -0
  145. aip_agents/examples/hello_world_pii_logger.py +21 -0
  146. aip_agents/examples/hello_world_ptc.py +49 -0
  147. aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
  148. aip_agents/examples/hello_world_sentry.py +133 -0
  149. aip_agents/examples/hello_world_step_limits.py +273 -0
  150. aip_agents/examples/hello_world_stock_a2a_server.py +100 -0
  151. aip_agents/examples/hello_world_tool_output_client.py +55 -0
  152. aip_agents/examples/hello_world_tool_output_server.py +113 -0
  153. aip_agents/examples/hitl_demo.py +724 -0
  154. aip_agents/examples/mcp_configs/configs.py +63 -0
  155. aip_agents/examples/mcp_servers/common.py +76 -0
  156. aip_agents/examples/mcp_servers/mcp_name.py +29 -0
  157. aip_agents/examples/mcp_servers/mcp_server_http.py +19 -0
  158. aip_agents/examples/mcp_servers/mcp_server_sse.py +19 -0
  159. aip_agents/examples/mcp_servers/mcp_server_stdio.py +19 -0
  160. aip_agents/examples/mcp_servers/mcp_time.py +10 -0
  161. aip_agents/examples/pii_demo_langgraph_client.py +69 -0
  162. aip_agents/examples/pii_demo_langgraph_server.py +125 -0
  163. aip_agents/examples/pii_demo_multi_agent_client.py +80 -0
  164. aip_agents/examples/pii_demo_multi_agent_server.py +246 -0
  165. aip_agents/examples/todolist_planning_a2a_langchain_client.py +70 -0
  166. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +87 -0
  167. aip_agents/examples/tools/__init__.py +27 -0
  168. aip_agents/examples/tools/adk_arithmetic_tools.py +36 -0
  169. aip_agents/examples/tools/adk_weather_tool.py +60 -0
  170. aip_agents/examples/tools/data_generator_tool.py +103 -0
  171. aip_agents/examples/tools/data_visualization_tool.py +312 -0
  172. aip_agents/examples/tools/image_artifact_tool.py +136 -0
  173. aip_agents/examples/tools/langchain_arithmetic_tools.py +26 -0
  174. aip_agents/examples/tools/langchain_currency_exchange_tool.py +88 -0
  175. aip_agents/examples/tools/langchain_graph_artifact_tool.py +172 -0
  176. aip_agents/examples/tools/langchain_weather_tool.py +48 -0
  177. aip_agents/examples/tools/langgraph_streaming_tool.py +130 -0
  178. aip_agents/examples/tools/mock_retrieval_tool.py +56 -0
  179. aip_agents/examples/tools/multiply_tool.py +43 -0
  180. aip_agents/examples/tools/pii_demo_tools.py +189 -0
  181. aip_agents/examples/tools/random_chart_tool.py +142 -0
  182. aip_agents/examples/tools/serper_tool.py +202 -0
  183. aip_agents/examples/tools/stock_tools.py +82 -0
  184. aip_agents/examples/tools/table_generator_tool.py +167 -0
  185. aip_agents/examples/tools/time_tool.py +82 -0
  186. aip_agents/examples/tools/weather_forecast_tool.py +38 -0
  187. aip_agents/guardrails/__init__.py +83 -0
  188. aip_agents/guardrails/engines/__init__.py +69 -0
  189. aip_agents/guardrails/engines/base.py +90 -0
  190. aip_agents/guardrails/engines/nemo.py +101 -0
  191. aip_agents/guardrails/engines/phrase_matcher.py +113 -0
  192. aip_agents/guardrails/exceptions.py +39 -0
  193. aip_agents/guardrails/manager.py +163 -0
  194. aip_agents/guardrails/middleware.py +199 -0
  195. aip_agents/guardrails/schemas.py +63 -0
  196. aip_agents/guardrails/utils.py +45 -0
  197. aip_agents/integration/__init__.py +43 -0
  198. aip_agents/integration/agent.py +58 -0
  199. aip_agents/integration/guardrails.py +52 -0
  200. aip_agents/integration/hitl.py +71 -0
  201. aip_agents/integration/ptc.py +95 -0
  202. aip_agents/integration/skills.py +37 -0
  203. aip_agents/integration/storage.py +81 -0
  204. aip_agents/integration/version.py +103 -0
  205. aip_agents/mcp/__init__.py +1 -0
  206. aip_agents/mcp/client/__init__.py +60 -0
  207. aip_agents/mcp/client/base_mcp_client.py +377 -0
  208. aip_agents/mcp/client/connection_manager.py +231 -0
  209. aip_agents/mcp/client/errors.py +119 -0
  210. aip_agents/mcp/client/google_adk/__init__.py +45 -0
  211. aip_agents/mcp/client/google_adk/client.py +383 -0
  212. aip_agents/mcp/client/langchain/__init__.py +11 -0
  213. aip_agents/mcp/client/langchain/client.py +265 -0
  214. aip_agents/mcp/client/persistent_session.py +704 -0
  215. aip_agents/mcp/client/session_pool.py +358 -0
  216. aip_agents/mcp/client/transports.py +288 -0
  217. aip_agents/mcp/utils/__init__.py +7 -0
  218. aip_agents/mcp/utils/config_validator.py +139 -0
  219. aip_agents/memory/__init__.py +14 -0
  220. aip_agents/memory/adapters/__init__.py +10 -0
  221. aip_agents/memory/adapters/base_adapter.py +815 -0
  222. aip_agents/memory/adapters/mem0.py +286 -0
  223. aip_agents/memory/base.py +84 -0
  224. aip_agents/memory/constants.py +49 -0
  225. aip_agents/memory/factory.py +86 -0
  226. aip_agents/memory/guidance.py +20 -0
  227. aip_agents/memory/simple_memory.py +47 -0
  228. aip_agents/middleware/__init__.py +65 -0
  229. aip_agents/middleware/backends/__init__.py +72 -0
  230. aip_agents/middleware/backends/in_memory.py +578 -0
  231. aip_agents/middleware/backends/local_disk.py +1203 -0
  232. aip_agents/middleware/backends/protocol.py +353 -0
  233. aip_agents/middleware/backends/sandbox.py +1431 -0
  234. aip_agents/middleware/backends/sandbox_files.py +113 -0
  235. aip_agents/middleware/backends/utils.py +293 -0
  236. aip_agents/middleware/base.py +239 -0
  237. aip_agents/middleware/filesystem.py +690 -0
  238. aip_agents/middleware/manager.py +291 -0
  239. aip_agents/middleware/memory.py +532 -0
  240. aip_agents/middleware/pii_middleware.py +192 -0
  241. aip_agents/middleware/schema.py +19 -0
  242. aip_agents/middleware/skills.py +872 -0
  243. aip_agents/middleware/task_delegation.py +1656 -0
  244. aip_agents/middleware/todolist.py +276 -0
  245. aip_agents/middleware/tools/__init__.py +23 -0
  246. aip_agents/middleware/tools/edit_file.py +70 -0
  247. aip_agents/middleware/tools/execute.py +428 -0
  248. aip_agents/middleware/tools/grep_file.py +79 -0
  249. aip_agents/middleware/tools/ls.py +71 -0
  250. aip_agents/middleware/tools/read_file.py +239 -0
  251. aip_agents/middleware/tools/skill_load.py +193 -0
  252. aip_agents/middleware/tools/skill_resource.py +338 -0
  253. aip_agents/middleware/tools/write_file.py +114 -0
  254. aip_agents/middleware/vision.py +322 -0
  255. aip_agents/ptc/__init__.py +87 -0
  256. aip_agents/ptc/custom_tools.py +511 -0
  257. aip_agents/ptc/custom_tools_payload.py +499 -0
  258. aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
  259. aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +24 -0
  260. aip_agents/ptc/custom_tools_templates/custom_init.py.template +26 -0
  261. aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +149 -0
  262. aip_agents/ptc/custom_tools_templates/custom_registry.py.template +112 -0
  263. aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
  264. aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +87 -0
  265. aip_agents/ptc/doc_gen.py +122 -0
  266. aip_agents/ptc/exceptions.py +57 -0
  267. aip_agents/ptc/executor.py +627 -0
  268. aip_agents/ptc/mcp/__init__.py +45 -0
  269. aip_agents/ptc/mcp/sandbox_bridge.py +679 -0
  270. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  271. aip_agents/ptc/mcp/templates/mcp_client.py.template +240 -0
  272. aip_agents/ptc/naming.py +430 -0
  273. aip_agents/ptc/payload.py +26 -0
  274. aip_agents/ptc/prompt_builder.py +674 -0
  275. aip_agents/ptc/ptc_helper.py +16 -0
  276. aip_agents/ptc/sandbox_bridge.py +297 -0
  277. aip_agents/ptc/template_utils.py +33 -0
  278. aip_agents/ptc/templates/__init__.py +1 -0
  279. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  280. aip_agents/ptc/tool_def_helpers.py +101 -0
  281. aip_agents/ptc/tool_enrichment.py +163 -0
  282. aip_agents/resilience/__init__.py +10 -0
  283. aip_agents/resilience/base.py +46 -0
  284. aip_agents/resilience/tool.py +1661 -0
  285. aip_agents/sandbox/__init__.py +62 -0
  286. aip_agents/sandbox/defaults.py +220 -0
  287. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1-datasaur.Dockerfile +120 -0
  288. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-1.Dockerfile +100 -0
  289. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2-datasaur.Dockerfile +143 -0
  290. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-2.Dockerfile +119 -0
  291. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3-datasaur.Dockerfile +173 -0
  292. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-3.Dockerfile +130 -0
  293. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.Dockerfile +164 -0
  294. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.patch_js_context.py +41 -0
  295. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2-4-runner-managed.requirements.txt +29 -0
  296. aip_agents/sandbox/dockerfiles/aip-agents-sandbox-v2.Dockerfile +87 -0
  297. aip_agents/sandbox/e2b_runtime.py +27 -0
  298. aip_agents/sandbox/image_registry.py +98 -0
  299. aip_agents/sandbox/providers/__init__.py +76 -0
  300. aip_agents/sandbox/providers/base.py +392 -0
  301. aip_agents/sandbox/providers/bedrock.py +28 -0
  302. aip_agents/sandbox/providers/e2b.py +230 -0
  303. aip_agents/sandbox/providers/opensandbox.py +163 -0
  304. aip_agents/sandbox/sandbox_runtime.py +967 -0
  305. aip_agents/sandbox/template_builder.py +240 -0
  306. aip_agents/sandbox/types.py +141 -0
  307. aip_agents/sandbox/validation.py +50 -0
  308. aip_agents/schema/__init__.py +106 -0
  309. aip_agents/schema/a2a.py +58 -0
  310. aip_agents/schema/agent.py +117 -0
  311. aip_agents/schema/artifacts.py +75 -0
  312. aip_agents/schema/attachments.py +425 -0
  313. aip_agents/schema/hitl.py +157 -0
  314. aip_agents/schema/langgraph.py +47 -0
  315. aip_agents/schema/model_id.py +103 -0
  316. aip_agents/schema/model_usage.py +50 -0
  317. aip_agents/schema/runtime_metadata.py +78 -0
  318. aip_agents/schema/step_limit.py +108 -0
  319. aip_agents/schema/storage.py +40 -0
  320. aip_agents/schema/tool_payloads.py +68 -0
  321. aip_agents/sentry/__init__.py +11 -0
  322. aip_agents/sentry/sentry.py +267 -0
  323. aip_agents/skills/__init__.py +30 -0
  324. aip_agents/skills/errors.py +110 -0
  325. aip_agents/skills/installer.py +479 -0
  326. aip_agents/skills/models.py +769 -0
  327. aip_agents/skills/stager.py +224 -0
  328. aip_agents/skills/validation.py +53 -0
  329. aip_agents/storage/__init__.py +41 -0
  330. aip_agents/storage/base.py +85 -0
  331. aip_agents/storage/clients/__init__.py +12 -0
  332. aip_agents/storage/clients/minio_client.py +318 -0
  333. aip_agents/storage/config.py +62 -0
  334. aip_agents/storage/providers/__init__.py +15 -0
  335. aip_agents/storage/providers/base.py +106 -0
  336. aip_agents/storage/providers/memory.py +114 -0
  337. aip_agents/storage/providers/object_storage.py +214 -0
  338. aip_agents/tools/__init__.py +65 -0
  339. aip_agents/tools/agent_schedule_tool.py +392 -0
  340. aip_agents/tools/browser_use/__init__.py +83 -0
  341. aip_agents/tools/browser_use/action_parser.py +104 -0
  342. aip_agents/tools/browser_use/browser_use_tool.py +1118 -0
  343. aip_agents/tools/browser_use/llm_config.py +120 -0
  344. aip_agents/tools/browser_use/minio_storage.py +203 -0
  345. aip_agents/tools/browser_use/schemas.py +121 -0
  346. aip_agents/tools/browser_use/session.py +13 -0
  347. aip_agents/tools/browser_use/session_errors.py +132 -0
  348. aip_agents/tools/browser_use/steel_session_recording.py +321 -0
  349. aip_agents/tools/browser_use/streaming.py +263 -0
  350. aip_agents/tools/browser_use/structured_data_parser.py +257 -0
  351. aip_agents/tools/browser_use/structured_data_recovery.py +204 -0
  352. aip_agents/tools/browser_use/types.py +37 -0
  353. aip_agents/tools/code_sandbox/__init__.py +48 -0
  354. aip_agents/tools/code_sandbox/code_sandbox_tool.py +350 -0
  355. aip_agents/tools/code_sandbox/constant.py +13 -0
  356. aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +346 -0
  357. aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +65 -0
  358. aip_agents/tools/computer_use/__init__.py +75 -0
  359. aip_agents/tools/computer_use/computer_use_tool.py +910 -0
  360. aip_agents/tools/computer_use/schemas.py +78 -0
  361. aip_agents/tools/computer_use/streaming.py +198 -0
  362. aip_agents/tools/computer_use/types.py +32 -0
  363. aip_agents/tools/constants.py +177 -0
  364. aip_agents/tools/date_range_tool.py +554 -0
  365. aip_agents/tools/document_loader/__init__.py +44 -0
  366. aip_agents/tools/document_loader/base_reader.py +302 -0
  367. aip_agents/tools/document_loader/docx_reader_tool.py +68 -0
  368. aip_agents/tools/document_loader/excel_reader_tool.py +171 -0
  369. aip_agents/tools/document_loader/pdf_reader_tool.py +79 -0
  370. aip_agents/tools/document_loader/pdf_splitter.py +169 -0
  371. aip_agents/tools/execute_ptc_code.py +582 -0
  372. aip_agents/tools/gl_connector/__init__.py +5 -0
  373. aip_agents/tools/gl_connector/tool.py +518 -0
  374. aip_agents/tools/gl_connector_tools.py +170 -0
  375. aip_agents/tools/memory_search/__init__.py +29 -0
  376. aip_agents/tools/memory_search/base.py +213 -0
  377. aip_agents/tools/memory_search/mem0.py +424 -0
  378. aip_agents/tools/memory_search/schema.py +81 -0
  379. aip_agents/tools/memory_search_tool.py +34 -0
  380. aip_agents/tools/streaming_common.py +577 -0
  381. aip_agents/tools/time_tool.py +117 -0
  382. aip_agents/tools/tool_config_injector.py +300 -0
  383. aip_agents/tools/web_search/__init__.py +15 -0
  384. aip_agents/tools/web_search/serper_tool.py +187 -0
  385. aip_agents/types/__init__.py +73 -0
  386. aip_agents/types/a2a_events.py +13 -0
  387. aip_agents/utils/__init__.py +91 -0
  388. aip_agents/utils/a2a_connector.py +1758 -0
  389. aip_agents/utils/artifact_helpers.py +542 -0
  390. aip_agents/utils/artifacts/__init__.py +20 -0
  391. aip_agents/utils/artifacts/tracker.py +367 -0
  392. aip_agents/utils/attachment_helpers.py +178 -0
  393. aip_agents/utils/constants.py +22 -0
  394. aip_agents/utils/datetime/__init__.py +34 -0
  395. aip_agents/utils/datetime/normalization.py +231 -0
  396. aip_agents/utils/datetime/timezone.py +206 -0
  397. aip_agents/utils/env_loader.py +27 -0
  398. aip_agents/utils/event_handler_registry.py +58 -0
  399. aip_agents/utils/file_prompt_utils.py +276 -0
  400. aip_agents/utils/file_watchers/__init__.py +33 -0
  401. aip_agents/utils/file_watchers/base.py +46 -0
  402. aip_agents/utils/file_watchers/e2b.py +128 -0
  403. aip_agents/utils/file_watchers/factory.py +39 -0
  404. aip_agents/utils/file_watchers/ls_diff.py +88 -0
  405. aip_agents/utils/file_watchers/sandbox.py +66 -0
  406. aip_agents/utils/file_watchers/watchdog.py +97 -0
  407. aip_agents/utils/final_response_builder.py +211 -0
  408. aip_agents/utils/formatter_llm_client.py +258 -0
  409. aip_agents/utils/langgraph/__init__.py +19 -0
  410. aip_agents/utils/langgraph/converter.py +399 -0
  411. aip_agents/utils/langgraph/delegation_context.py +22 -0
  412. aip_agents/utils/langgraph/tool_managers/__init__.py +15 -0
  413. aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.py +99 -0
  414. aip_agents/utils/langgraph/tool_managers/base_tool_manager.py +66 -0
  415. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +1329 -0
  416. aip_agents/utils/langgraph/tool_output_management.py +1047 -0
  417. aip_agents/utils/logger.py +195 -0
  418. aip_agents/utils/metadata/__init__.py +27 -0
  419. aip_agents/utils/metadata/activity_metadata_helper.py +407 -0
  420. aip_agents/utils/metadata/activity_narrative/__init__.py +35 -0
  421. aip_agents/utils/metadata/activity_narrative/builder.py +822 -0
  422. aip_agents/utils/metadata/activity_narrative/constants.py +51 -0
  423. aip_agents/utils/metadata/activity_narrative/context.py +49 -0
  424. aip_agents/utils/metadata/activity_narrative/formatters.py +230 -0
  425. aip_agents/utils/metadata/activity_narrative/utils.py +35 -0
  426. aip_agents/utils/metadata/schemas/__init__.py +16 -0
  427. aip_agents/utils/metadata/schemas/activity_schema.py +29 -0
  428. aip_agents/utils/metadata/schemas/thinking_schema.py +31 -0
  429. aip_agents/utils/metadata/thinking_metadata_helper.py +38 -0
  430. aip_agents/utils/metadata_helper.py +363 -0
  431. aip_agents/utils/name_preprocessor/__init__.py +17 -0
  432. aip_agents/utils/name_preprocessor/base_name_preprocessor.py +73 -0
  433. aip_agents/utils/name_preprocessor/google_name_preprocessor.py +100 -0
  434. aip_agents/utils/name_preprocessor/name_preprocessor.py +87 -0
  435. aip_agents/utils/name_preprocessor/openai_name_preprocessor.py +48 -0
  436. aip_agents/utils/pii/__init__.py +29 -0
  437. aip_agents/utils/pii/pii_handler.py +555 -0
  438. aip_agents/utils/pii/pii_helper.py +225 -0
  439. aip_agents/utils/pii/uuid_deanonymizer_mapping.py +195 -0
  440. aip_agents/utils/reference_helper.py +273 -0
  441. aip_agents/utils/sse_chunk_transformer.py +836 -0
  442. aip_agents/utils/step_limit_manager.py +265 -0
  443. aip_agents/utils/token_usage_helper.py +531 -0
  444. aip_agents_binary-0.0.0.dist-info/METADATA +825 -0
  445. aip_agents_binary-0.0.0.dist-info/RECORD +447 -0
  446. aip_agents_binary-0.0.0.dist-info/WHEEL +5 -0
  447. aip_agents_binary-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,196 @@
1
+ """Context preparation facade that composes compaction primitives.
2
+
3
+ Composes #791 (budget/state), #792 (offload/prune/repair),
4
+ and #793 (compaction) into a single pipeline.
5
+
6
+ Authors:
7
+ Raymond Christopher (raymond.christopher@gdplabs.id)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from collections.abc import Sequence
13
+ from dataclasses import dataclass, field
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from aip_agents.context.budget import (
17
+ CompactionDecision,
18
+ ContextBudgetConfig,
19
+ decide_compaction,
20
+ estimate_message_token_counts,
21
+ )
22
+ from aip_agents.context.compaction import (
23
+ CompactionSummary,
24
+ CompressionResult,
25
+ ContextCompressor,
26
+ )
27
+ from aip_agents.context.offload import (
28
+ OffloadedPayloadRef,
29
+ offload_oversized_payloads,
30
+ prune_duplicate_tool_outputs,
31
+ repair_tool_result_pairing,
32
+ )
33
+ from aip_agents.context.state import CompactionState
34
+
35
+ if TYPE_CHECKING:
36
+ from aip_agents.context.prompt import PromptBuildContext
37
+
38
+
39
+ _SUMMARY_MESSAGE_ROLE = "assistant"
40
+
41
+ _ADMIN_TAG = "compact_summary"
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class ContextPreparationResult:
46
+ """Single output of the context preparation pipeline.
47
+
48
+ Composes all compaction primitives into one result object
49
+ so runtime code calls one facade instead of orchestrating
50
+ budget, offload, prune, repair, and summary individually.
51
+
52
+ Attributes:
53
+ messages: Provider-ready messages after context preparation.
54
+ prompt_context: Prompt assembly context used to build the system prompt.
55
+ decision: Budget decision that determined whether compaction was needed.
56
+ state: Safe compaction metadata for logging and observability.
57
+ offloaded_refs: Payload references produced by lossless offloading.
58
+ summary: Reference-only compaction summary inserted into context, if any.
59
+ """
60
+
61
+ messages: list[Any]
62
+ prompt_context: PromptBuildContext | None = None
63
+ decision: CompactionDecision | None = None
64
+ state: CompactionState | None = None
65
+ offloaded_refs: tuple[OffloadedPayloadRef, ...] = field(default_factory=tuple)
66
+ summary: CompactionSummary | None = None
67
+
68
+
69
+ def _build_summary_message(summary: CompactionSummary) -> dict[str, Any]:
70
+ """Build a replacement message from a compaction summary."""
71
+ return {
72
+ "role": _SUMMARY_MESSAGE_ROLE,
73
+ "content": f"[Previous conversation context summarized: {summary.body}]",
74
+ "type": _ADMIN_TAG,
75
+ "summary_id": summary.summary_id,
76
+ }
77
+
78
+
79
+ def prepare_context(
80
+ messages: Sequence[Any],
81
+ *,
82
+ config: ContextBudgetConfig | None = None,
83
+ backend: Any | None = None,
84
+ model_context_tokens: int | None = None,
85
+ summarizer: Any | None = None,
86
+ previous_summary: CompactionSummary | None = None,
87
+ focus_topic: str | None = None,
88
+ preserve_topic: str | None = None,
89
+ provider_overflow: bool = False,
90
+ ) -> ContextPreparationResult:
91
+ """Run the full context preparation pipeline.
92
+
93
+ Args:
94
+ messages: Full message sequence to prepare for model invocation.
95
+ config: Budget configuration for compaction decisions.
96
+ backend: Optional backend for offloading oversized payloads.
97
+ model_context_tokens: Provider model context window size, if known.
98
+ summarizer: Optional external summarizer client.
99
+ previous_summary: Previous compaction summary for incremental update.
100
+ focus_topic: Optional focus topic for manual/guided compaction.
101
+ preserve_topic: Alias for focus_topic (overrides focus_topic when set).
102
+ provider_overflow: If True, force compaction for provider-overflow retry
103
+ even when the local estimator is below the normal threshold.
104
+
105
+ Returns:
106
+ ContextPreparationResult with processed messages and metadata.
107
+
108
+ Order of operations:
109
+ 1. Budget decision (estimate tokens, decide if compaction needed)
110
+ 2. Lossless offload (oversized payloads to backend, if backend provided)
111
+ 3. Prune duplicate tool outputs
112
+ 4. Repair tool-result pairing
113
+ 5. Generate compaction summary (if should_compact)
114
+ 6. Assemble final messages (head + summary + tail)
115
+ """
116
+ cfg = config or ContextBudgetConfig()
117
+
118
+ effective_focus_topic = preserve_topic if preserve_topic is not None else focus_topic
119
+
120
+ # 1. Budget decision
121
+ token_counts = list(estimate_message_token_counts(messages))
122
+ estimated_prompt_tokens = sum(token_counts)
123
+
124
+ decision = decide_compaction(
125
+ messages,
126
+ config=cfg,
127
+ model_context_tokens=model_context_tokens,
128
+ provider_overflow=provider_overflow,
129
+ )
130
+
131
+ # 2-4: Always apply offload/prune/repair
132
+ transformed = list(messages)
133
+
134
+ offloaded_refs: tuple[OffloadedPayloadRef, ...] = ()
135
+ if backend is not None:
136
+ transformed, offloaded_refs = offload_oversized_payloads(
137
+ transformed,
138
+ backend=backend,
139
+ )
140
+
141
+ protected_tail_start = (
142
+ decision.summary_insertion_point.protected_tail_start_index
143
+ if decision.summary_insertion_point is not None
144
+ else len(transformed)
145
+ )
146
+ transformed = prune_duplicate_tool_outputs(
147
+ transformed,
148
+ protected_tail_start_index=protected_tail_start,
149
+ )
150
+ transformed = repair_tool_result_pairing(transformed)
151
+
152
+ # 5-6: Compaction summary + assembly
153
+ summary: CompactionSummary | None = None
154
+ state = CompactionState()
155
+
156
+ if decision.should_compact:
157
+ compressor = ContextCompressor(summarizer=summarizer)
158
+ try:
159
+ compression_result: CompressionResult = compressor.compress(
160
+ transformed,
161
+ focus_topic=decision.focus_topic or effective_focus_topic,
162
+ previous_summary=previous_summary,
163
+ )
164
+ summary = compression_result.summary
165
+
166
+ sip = decision.summary_insertion_point
167
+ if sip is not None:
168
+ summary_message = _build_summary_message(summary)
169
+ head = list(transformed[: sip.replace_start_index])
170
+ tail = list(transformed[sip.replace_end_index :])
171
+ transformed = head + [summary_message] + tail
172
+
173
+ post_compact_tokens = sum(estimate_message_token_counts(transformed))
174
+ state = CompactionState(
175
+ compaction_count=1,
176
+ last_summary_status="succeeded",
177
+ offloaded_ref_count=len(offloaded_refs),
178
+ estimated_token_savings=estimated_prompt_tokens - post_compact_tokens,
179
+ last_reason=decision.reason,
180
+ )
181
+ except Exception as exc:
182
+ state = CompactionState(
183
+ compaction_count=1,
184
+ last_summary_status="failed",
185
+ offloaded_ref_count=len(offloaded_refs),
186
+ last_reason=decision.reason,
187
+ last_error_code=str(type(exc).__name__),
188
+ )
189
+
190
+ return ContextPreparationResult(
191
+ messages=transformed,
192
+ decision=decision,
193
+ state=state,
194
+ offloaded_refs=offloaded_refs,
195
+ summary=summary,
196
+ )
@@ -0,0 +1,61 @@
1
+ """Prompt assembly utilities for agent system instructions.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class PromptBuildContext:
14
+ """Typed context for deterministic system prompt assembly.
15
+
16
+ The field order encodes the canonical layer order. Empty or None values are
17
+ skipped during rendering.
18
+ """
19
+
20
+ base_instruction: str
21
+ date_time_context: str | None = None
22
+ runtime_platform_hints: str | None = None
23
+ durable_memory_guidance: str | None = None
24
+ session_recall_guidance: str | None = None
25
+ project_context: str | None = None
26
+ compaction_summary: str | None = None
27
+ model_steering: str | None = None
28
+ middleware_prompts: tuple[str, ...] = ()
29
+
30
+
31
+ def build_system_prompt(context: PromptBuildContext) -> str:
32
+ """Build a system prompt from ordered context layers.
33
+
34
+ Args:
35
+ context: Prompt context containing ordered optional layers.
36
+
37
+ Returns:
38
+ Combined system prompt with non-empty layers joined by double newlines.
39
+ """
40
+ parts: list[str] = []
41
+
42
+ for layer in (
43
+ context.date_time_context,
44
+ context.base_instruction,
45
+ context.runtime_platform_hints,
46
+ context.durable_memory_guidance,
47
+ context.session_recall_guidance,
48
+ context.project_context,
49
+ context.compaction_summary,
50
+ context.model_steering,
51
+ ):
52
+ normalized = layer.strip() if isinstance(layer, str) else layer
53
+ if normalized:
54
+ parts.append(normalized)
55
+
56
+ for middleware_prompt in context.middleware_prompts:
57
+ normalized = middleware_prompt.strip() if isinstance(middleware_prompt, str) else middleware_prompt
58
+ if normalized:
59
+ parts.append(normalized)
60
+
61
+ return "\n\n".join(parts)
@@ -0,0 +1,149 @@
1
+ """Runtime integration helpers for context compaction.
2
+
3
+ Provides overflow detection, session recall derivation,
4
+ and compact-and-retry orchestration for the agent loop.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections.abc import Awaitable, Sequence
10
+ from typing import TYPE_CHECKING, Any, Protocol
11
+
12
+ from aip_agents.context.session_recall import (
13
+ SessionRecallSnapshot,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from aip_agents.context.preparation import ContextPreparationResult
18
+
19
+
20
+ class ModelInvoke(Protocol):
21
+ """Async model invocation callable used by compact_and_retry()."""
22
+
23
+ def __call__(self, messages: Sequence[Any]) -> Awaitable[Any]:
24
+ """Invoke a model with prepared messages."""
25
+
26
+
27
+ class PrepareContext(Protocol):
28
+ """Callable shape for context preparation."""
29
+
30
+ def __call__(
31
+ self,
32
+ messages: Sequence[Any],
33
+ *,
34
+ focus_topic: str | None = None,
35
+ provider_overflow: bool = False,
36
+ **kwargs: Any,
37
+ ) -> ContextPreparationResult:
38
+ """Prepare messages for model invocation."""
39
+
40
+
41
+ _OVERFLOW_KEYWORDS = [
42
+ "context_length_exceeded",
43
+ "maximum context length",
44
+ "max tokens exceeded",
45
+ "context window full",
46
+ "too many tokens",
47
+ "token limit reached",
48
+ ]
49
+
50
+
51
+ def detect_context_overflow(error: Exception | str) -> bool:
52
+ """Return True when an error appears to be a context-window overflow.
53
+
54
+ Args:
55
+ error: Exception or error message string to classify.
56
+
57
+ Returns:
58
+ True if the error matches known overflow patterns.
59
+ """
60
+ error_text = str(error).lower()
61
+ return any(keyword in error_text for keyword in _OVERFLOW_KEYWORDS)
62
+
63
+
64
+ def derive_session_recall(
65
+ messages: Sequence[dict[str, Any]],
66
+ tool_metadata: dict[str, Any] | None = None,
67
+ ) -> SessionRecallSnapshot:
68
+ """Derive a SessionRecallSnapshot from current loop state.
69
+
70
+ Args:
71
+ messages: Current message sequence in the agent loop.
72
+ tool_metadata: Optional metadata about recent tool activity.
73
+
74
+ Returns:
75
+ Populated SessionRecallSnapshot with supported fields derived from state.
76
+ """
77
+ active_task = _derive_active_task(messages)
78
+ changed_files = _derive_changed_files(tool_metadata)
79
+ return SessionRecallSnapshot(
80
+ active_task=active_task,
81
+ recent_decisions=(),
82
+ changed_files=changed_files,
83
+ blockers=(),
84
+ handoff_summary=None,
85
+ stale=False,
86
+ )
87
+
88
+
89
+ def _derive_active_task(messages: Sequence[dict[str, Any]]) -> str | None:
90
+ if not messages:
91
+ return None
92
+ for message in reversed(messages):
93
+ role = message.get("role", "")
94
+ if role not in ("user", "human"):
95
+ continue
96
+ content = message.get("content", "")
97
+ if isinstance(content, str) and content.strip():
98
+ return content.strip()[:200]
99
+ return None
100
+
101
+
102
+ def _derive_changed_files(
103
+ tool_metadata: dict[str, Any] | None,
104
+ ) -> tuple[str, ...]:
105
+ if not tool_metadata:
106
+ return ()
107
+ files = tool_metadata.get("changed_files")
108
+ if isinstance(files, list | tuple):
109
+ return tuple(str(f) for f in files if f)
110
+ return ()
111
+
112
+
113
+ async def compact_and_retry(
114
+ messages: Sequence[dict[str, Any]],
115
+ model_invoke: ModelInvoke,
116
+ *,
117
+ prepare_context: PrepareContext,
118
+ recall: SessionRecallSnapshot | None = None,
119
+ ) -> tuple[Any, ContextPreparationResult | None]:
120
+ """Run prepare_context and invoke the model, with one overflow retry.
121
+
122
+ Args:
123
+ messages: Current message sequence.
124
+ model_invoke: Async callable that invokes the model.
125
+ prepare_context: The prepare_context function from preparation module.
126
+ recall: Optional SessionRecallSnapshot for prompt context.
127
+
128
+ Returns:
129
+ Tuple of (model_output, preparation_result).
130
+ """
131
+ prep_result = prepare_context(
132
+ messages,
133
+ focus_topic=recall.active_task if recall else None,
134
+ )
135
+ first_messages = prep_result.messages if prep_result is not None else list(messages)
136
+
137
+ try:
138
+ output = await model_invoke(first_messages)
139
+ return output, prep_result
140
+ except Exception as exc:
141
+ if detect_context_overflow(exc):
142
+ retry_result = prepare_context(
143
+ first_messages,
144
+ focus_topic=recall.active_task if recall else None,
145
+ provider_overflow=True,
146
+ )
147
+ retry_output = await model_invoke(retry_result.messages)
148
+ return retry_output, retry_result
149
+ raise
@@ -0,0 +1,69 @@
1
+ """Session recall seam contracts.
2
+
3
+ This module defines lightweight contracts for short-lived session/task recall
4
+ without coupling them to durable memory persistence.
5
+
6
+ Authors:
7
+ Raymond Christopher (raymond.christopher@gdplabs.id)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass, field
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class SessionRecallSnapshot:
17
+ """Snapshot of short-lived task/session state.
18
+
19
+ This snapshot is intentionally scoped to active work context and should not
20
+ be treated as durable memory by default.
21
+ """
22
+
23
+ active_task: str | None = None
24
+ recent_decisions: tuple[str, ...] = field(default_factory=tuple)
25
+ changed_files: tuple[str, ...] = field(default_factory=tuple)
26
+ blockers: tuple[str, ...] = field(default_factory=tuple)
27
+ handoff_summary: str | None = None
28
+ stale: bool = False
29
+
30
+
31
+ def build_session_recall_guidance(snapshot: SessionRecallSnapshot | None) -> str | None:
32
+ """Render session recall guidance text from a snapshot.
33
+
34
+ Args:
35
+ snapshot: Optional session recall snapshot.
36
+
37
+ Returns:
38
+ A guidance block describing short-lived task/session context, or None
39
+ when no snapshot is available.
40
+ """
41
+ if snapshot is None:
42
+ return None
43
+
44
+ active_task = snapshot.active_task.strip() if snapshot.active_task else None
45
+ handoff_summary = snapshot.handoff_summary.strip() if snapshot.handoff_summary else None
46
+ recent_decisions = tuple(d.strip() for d in snapshot.recent_decisions if d.strip())
47
+ changed_files = tuple(f.strip() for f in snapshot.changed_files if f.strip())
48
+ blockers = tuple(b.strip() for b in snapshot.blockers if b.strip())
49
+
50
+ lines = ["Session Recall Snapshot:"]
51
+ if active_task:
52
+ lines.append(f"- Active task: {active_task}")
53
+ if recent_decisions:
54
+ lines.append("- Recent decisions:")
55
+ lines.extend(f" - {decision}" for decision in recent_decisions)
56
+ if changed_files:
57
+ lines.append("- Changed files:")
58
+ lines.extend(f" - {path}" for path in changed_files)
59
+ if blockers:
60
+ lines.append("- Blockers:")
61
+ lines.extend(f" - {blocker}" for blocker in blockers)
62
+ if handoff_summary:
63
+ lines.append(f"- Handoff summary: {handoff_summary}")
64
+ if snapshot.stale:
65
+ lines.append("- Recall freshness: stale")
66
+
67
+ if len(lines) == 1:
68
+ return None
69
+ return "\n".join(lines)
@@ -0,0 +1,48 @@
1
+ """State contracts for context compaction decisions.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+ from typing import Literal
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class SummaryInsertionPoint:
15
+ """Index metadata describing where a reference summary can be inserted.
16
+
17
+ Attributes:
18
+ protected_head_indexes: Initial message indexes preserved unchanged.
19
+ protected_tail_start_index: First recent-tail message index preserved unchanged.
20
+ replace_start_index: First message index replaced by the reference summary.
21
+ replace_end_index: Last message index replaced by the reference summary.
22
+ """
23
+
24
+ protected_head_indexes: tuple[int, ...]
25
+ protected_tail_start_index: int
26
+ replace_start_index: int
27
+ replace_end_index: int
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class CompactionState:
32
+ """Observed compaction metadata tracked outside mutable agent state.
33
+
34
+ Attributes:
35
+ compaction_count: Number of compaction attempts observed for the current scope.
36
+ last_summary_status: Outcome of the latest summary attempt.
37
+ offloaded_ref_count: Number of payload references produced by offloading.
38
+ estimated_token_savings: Estimated token reduction from the latest compaction.
39
+ last_reason: Stable reason code from the latest compaction decision.
40
+ last_error_code: Safe error code for the latest failed compaction step.
41
+ """
42
+
43
+ compaction_count: int = 0
44
+ last_summary_status: Literal["none", "succeeded", "failed", "skipped"] = "none"
45
+ offloaded_ref_count: int = 0
46
+ estimated_token_savings: int | None = None
47
+ last_reason: str | None = None
48
+ last_error_code: str | None = None
@@ -0,0 +1,44 @@
1
+ """Shared context utilities for token estimation, redaction, and safe preview.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+
11
+
12
+ def estimate_tokens(text: str, chars_per_token: int = 4) -> int:
13
+ """Estimate token count for a text string."""
14
+ if not text:
15
+ return 0
16
+ safe_ratio = max(chars_per_token, 1)
17
+ return max(1, (len(text) + safe_ratio - 1) // safe_ratio)
18
+
19
+
20
+ _secret_kv_pattern = re.compile(r"(?i)(api[_-]?key|token|password|secret)\s*[:=]\s*[^\s]+")
21
+ _long_base64_pattern = re.compile(r"(?=[^+/=]*[+/=])[A-Za-z0-9+/=]{120,}")
22
+ _auth_header_pattern = re.compile(r"(?i)(Authorization|X-API-Key|Cookie)\s*:\s*[^\n]+")
23
+ _credential_query_pattern = re.compile(r"(?i)(api_key|token|secret|key|password|signature)=[^\s&]+")
24
+ _signed_url_pattern = re.compile(r"(?i)\b(x-amz-signature|sig|signature)\s*=\s*[^\s&]+")
25
+
26
+
27
+ def redact_sensitive(text: str) -> tuple[str, bool]:
28
+ """Redact sensitive content from text."""
29
+ redacted = _secret_kv_pattern.sub(lambda m: f"{m.group(1)}=[REDACTED]", text)
30
+ redacted = _long_base64_pattern.sub("[BASE64_REDACTED]", redacted)
31
+ redacted = _auth_header_pattern.sub(r"\1: [REDACTED]", redacted)
32
+ redacted = _credential_query_pattern.sub(r"\1=[REDACTED]", redacted)
33
+ redacted = _signed_url_pattern.sub(lambda m: f"{m.group(1)}=[REDACTED]", redacted)
34
+ redaction_applied = redacted != text
35
+ return redacted, redaction_applied
36
+
37
+
38
+ def safe_preview(content: str, *, max_chars: int) -> tuple[str, bool]:
39
+ """Create a redacted preview of content."""
40
+ redacted, redaction_applied = redact_sensitive(content)
41
+ clipped = redacted[:max_chars]
42
+ if len(redacted) > max_chars:
43
+ clipped += "..."
44
+ return clipped, redaction_applied