agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.2__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 (411) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +22 -2
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/RECORD +356 -222
  3. ksadk/a2a/_space_client_events.py +381 -0
  4. ksadk/a2a/event_adapter.py +156 -64
  5. ksadk/a2a/executor.py +179 -63
  6. ksadk/a2a/space_client.py +6 -333
  7. ksadk/a2ui/core.py +222 -53
  8. ksadk/agui/_agent_helpers.py +243 -0
  9. ksadk/agui/a2ui_projection.py +12 -5
  10. ksadk/agui/agent.py +443 -259
  11. ksadk/api/client.py +525 -27
  12. ksadk/builders/code_builder.py +284 -8
  13. ksadk/builders/container_builder.py +8 -1
  14. ksadk/builders/managed_runtime_builder.py +39 -35
  15. ksadk/cli/__init__.py +17 -0
  16. ksadk/cli/cmd_dashboard.py +15 -1
  17. ksadk/cli/cmd_deploy.py +10 -2
  18. ksadk/cli/cmd_eval.py +66 -9
  19. ksadk/cli/cmd_evalset.py +284 -0
  20. ksadk/cli/cmd_files.py +5 -1
  21. ksadk/cli/cmd_hermes.py +1 -126
  22. ksadk/cli/cmd_invoke.py +28 -38
  23. ksadk/cli/cmd_managed_runtime.py +95 -0
  24. ksadk/cli/cmd_observe.py +85 -0
  25. ksadk/cli/cmd_openclaw.py +1 -435
  26. ksadk/cli/cmd_replay.py +28 -4
  27. ksadk/cli/cmd_studio.py +99 -8
  28. ksadk/cli/cmd_web.py +10 -2
  29. ksadk/cli/hermes_env.py +151 -0
  30. ksadk/cli/invoke_payload.py +49 -0
  31. ksadk/cli/openclaw_env.py +458 -0
  32. ksadk/codex/client.py +180 -30
  33. ksadk/codex/runtime.py +428 -326
  34. ksadk/configs/env_registry.py +66 -12
  35. ksadk/configs/env_registry_pcm.py +181 -0
  36. ksadk/configs/env_var_spec.py +18 -0
  37. ksadk/configs/global_config.py +5 -0
  38. ksadk/context_engine/__init__.py +98 -0
  39. ksadk/context_engine/assembler.py +176 -0
  40. ksadk/context_engine/baseline.py +419 -0
  41. ksadk/context_engine/cache_observability.py +228 -0
  42. ksadk/context_engine/capabilities.py +443 -0
  43. ksadk/context_engine/contributors.py +344 -0
  44. ksadk/context_engine/hosted_pipeline.py +417 -0
  45. ksadk/context_engine/models.py +117 -0
  46. ksadk/context_engine/planner.py +698 -0
  47. ksadk/context_engine/policies.py +319 -0
  48. ksadk/context_engine/projection.py +31 -0
  49. ksadk/context_engine/shadow_plan.py +266 -0
  50. ksadk/context_engine/tokenizer.py +164 -0
  51. ksadk/conversations/context.py +126 -6
  52. ksadk/conversations/message_projection.py +292 -28
  53. ksadk/conversations/model_context.py +49 -3
  54. ksadk/conversations/runtime_compaction.py +207 -5
  55. ksadk/conversations/runtime_input.py +184 -2
  56. ksadk/conversations/runtime_invocation.py +81 -3
  57. ksadk/conversations/runtime_observability.py +141 -0
  58. ksadk/conversations/runtime_payloads.py +42 -0
  59. ksadk/conversations/runtime_preparation.py +272 -2
  60. ksadk/conversations/runtime_resume.py +20 -1
  61. ksadk/conversations/runtime_stream_events.py +94 -9
  62. ksadk/conversations/semantic_summary.py +311 -1
  63. ksadk/conversations/session_lock.py +51 -0
  64. ksadk/deployment/env_forward.py +72 -0
  65. ksadk/deployment/managed_runtime.py +5 -0
  66. ksadk/deployment/providers/serverless.py +143 -69
  67. ksadk/evaluation/__init__.py +32 -0
  68. ksadk/evaluation/a2a_adapter.py +9 -1
  69. ksadk/evaluation/adapters.py +18 -5
  70. ksadk/evaluation/agent_eval_client.py +395 -0
  71. ksadk/evaluation/cloud_binding.py +80 -0
  72. ksadk/evaluation/cloud_converter.py +194 -0
  73. ksadk/evaluation/cloud_service.py +199 -0
  74. ksadk/evaluation/contracts.py +73 -4
  75. ksadk/evaluation/evaluators.py +183 -17
  76. ksadk/evaluation/evidence.py +258 -0
  77. ksadk/evaluation/executor.py +31 -6
  78. ksadk/evaluation/local_adapter.py +550 -0
  79. ksadk/evaluation/service_env.py +27 -0
  80. ksadk/evaluation/studio_build_adapter.py +253 -0
  81. ksadk/evaluation/target.py +15 -6
  82. ksadk/events/__init__.py +13 -13
  83. ksadk/events/_v1_compat/__init__.py +1 -0
  84. ksadk/events/_v1_compat/models.py +299 -0
  85. ksadk/events/_v1_compat/parser.py +247 -0
  86. ksadk/events/_v1_compat/projection.py +753 -0
  87. ksadk/events/adapters/__init__.py +34 -0
  88. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  89. ksadk/events/adapters/_a2a_support.py +275 -0
  90. ksadk/events/adapters/_codex_interactions.py +375 -0
  91. ksadk/events/adapters/_codex_items.py +801 -0
  92. ksadk/events/adapters/_codex_validators.py +311 -0
  93. ksadk/events/adapters/_langgraph_support.py +785 -0
  94. ksadk/events/adapters/a2a.py +841 -0
  95. ksadk/events/adapters/adk.py +503 -0
  96. ksadk/events/adapters/codex.py +717 -0
  97. ksadk/events/adapters/langgraph.py +745 -0
  98. ksadk/events/canonical.py +440 -0
  99. ksadk/events/canonical_replay.py +497 -0
  100. ksadk/events/canonical_store.py +468 -0
  101. ksadk/events/cold_recovery.py +257 -0
  102. ksadk/events/content.py +89 -0
  103. ksadk/events/identity.py +86 -0
  104. ksadk/events/pipeline.py +455 -0
  105. ksadk/events/projections.py +66 -0
  106. ksadk/events/reducer.py +661 -0
  107. ksadk/events/replay.py +3 -36
  108. ksadk/events/runtime_event.py +20 -265
  109. ksadk/events/session_event.py +324 -0
  110. ksadk/events/store.py +3 -316
  111. ksadk/events/v1_compat.py +41 -0
  112. ksadk/harness/runtime.py +160 -57
  113. ksadk/identity/resolver.py +4 -3
  114. ksadk/interaction/__init__.py +28 -0
  115. ksadk/interaction/contracts.py +136 -0
  116. ksadk/interaction/ledger.py +189 -0
  117. ksadk/interaction/provider.py +122 -0
  118. ksadk/interaction/providers/__init__.py +52 -0
  119. ksadk/interaction/providers/adk.py +40 -0
  120. ksadk/interaction/providers/codex.py +94 -0
  121. ksadk/interaction/providers/langgraph.py +58 -0
  122. ksadk/kernel/__init__.py +117 -0
  123. ksadk/kernel/authorization.py +258 -0
  124. ksadk/kernel/bootstrap.py +1074 -0
  125. ksadk/kernel/contract_fingerprints.py +61 -0
  126. ksadk/kernel/contracts.py +362 -0
  127. ksadk/kernel/control.py +219 -0
  128. ksadk/kernel/errors.py +79 -0
  129. ksadk/kernel/ingress.py +1102 -0
  130. ksadk/kernel/mapping.py +111 -0
  131. ksadk/kernel/memory_store.py +1133 -0
  132. ksadk/kernel/postgres_store.py +1756 -0
  133. ksadk/kernel/recovery.py +452 -0
  134. ksadk/kernel/runtime_identity.py +103 -0
  135. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  136. ksadk/kernel/sqlite_store.py +1410 -0
  137. ksadk/kernel/state.py +145 -0
  138. ksadk/kernel/store.py +232 -0
  139. ksadk/kernel/worker.py +953 -0
  140. ksadk/knowledge_base/client.py +7 -0
  141. ksadk/knowledge_base/service.py +32 -5
  142. ksadk/memory/__init__.py +61 -0
  143. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  144. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  145. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  146. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  147. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  148. ksadk/memory/coordinator.py +461 -0
  149. ksadk/memory/events.py +202 -0
  150. ksadk/memory/extraction.py +228 -0
  151. ksadk/memory/ltm_backend_factory.py +16 -3
  152. ksadk/memory/models.py +316 -0
  153. ksadk/memory/policy.py +215 -0
  154. ksadk/memory/provider.py +47 -0
  155. ksadk/memory/provider_adapter.py +159 -0
  156. ksadk/memory/provider_resolver.py +71 -0
  157. ksadk/memory/providers/__init__.py +5 -0
  158. ksadk/memory/providers/local_sqlite.py +490 -0
  159. ksadk/memory/resolved_policy.py +145 -0
  160. ksadk/memory/service.py +188 -6
  161. ksadk/model_proxy/bootstrap.py +16 -9
  162. ksadk/model_proxy/detect.py +202 -9
  163. ksadk/model_proxy/namespace.py +39 -15
  164. ksadk/model_proxy/server.py +24 -5
  165. ksadk/model_proxy/transform.py +60 -2
  166. ksadk/observability/__init__.py +25 -0
  167. ksadk/observability/session_log.py +420 -0
  168. ksadk/observability/trajectory.py +105 -0
  169. ksadk/prompts/__init__.py +71 -0
  170. ksadk/prompts/compiler.py +215 -0
  171. ksadk/prompts/models.py +82 -0
  172. ksadk/prompts/projection.py +89 -0
  173. ksadk/prompts/resolved.py +137 -0
  174. ksadk/prompts/sources.py +233 -0
  175. ksadk/runners/_langgraph_runner_streams.py +822 -0
  176. ksadk/runners/adk_runner.py +5 -5
  177. ksadk/runners/base_runner.py +16 -0
  178. ksadk/runners/factory.py +1 -2
  179. ksadk/runners/langgraph_runner.py +198 -437
  180. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  181. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  182. ksadk/runtime/adapter.py +118 -2
  183. ksadk/runtime/conversation_execution.py +316 -182
  184. ksadk/runtime/executor.py +144 -3
  185. ksadk/runtime/factory.py +193 -7
  186. ksadk/runtime/hosted_finalizer.py +268 -0
  187. ksadk/runtime/launch.py +14 -1
  188. ksadk/runtime/preprocessing.py +25 -3
  189. ksadk/runtime/runner_adapter.py +288 -508
  190. ksadk/runtime/usage.py +33 -0
  191. ksadk/sandbox/backends/e2b.py +35 -2
  192. ksadk/server/composition.py +8 -0
  193. ksadk/server/factory.py +69 -6
  194. ksadk/server/routes/kernel_ingress.py +258 -0
  195. ksadk/server/routes/openai_compat.py +88 -8
  196. ksadk/server/routes/projection.py +35 -20
  197. ksadk/server/routes/run.py +94 -0
  198. ksadk/server/routes/sessions.py +2 -0
  199. ksadk/server/routes/streaming.py +5 -2
  200. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  201. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-DOH6MVcn.js} +4 -4
  202. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  203. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  204. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  205. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  206. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  207. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  208. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  209. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  210. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  211. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  212. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  213. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  214. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  215. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  216. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  217. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  218. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  219. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  220. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  221. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  222. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  223. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  224. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  225. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  227. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  228. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  229. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  230. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  231. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  232. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  233. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  234. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  235. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  236. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-8hqcx0sU.js} +1 -1
  237. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  238. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-BE7bu-DL.js} +1 -1
  239. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-BVDffZ0U.js} +1 -1
  240. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-BX8z72IC.js} +1 -1
  241. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-Bf2M8m3N.js} +1 -1
  242. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-BjU6y-A2.js} +1 -1
  243. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-BytlxIDT.js} +1 -1
  244. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-CSh_DE14.js} +1 -1
  245. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-CXYYBw3_.js} +1 -1
  246. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-C_wsv-Qd.js} +1 -1
  247. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-ClxGviKw.js} +1 -1
  248. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-CttYUqzS.js} +1 -1
  249. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DNp6rLRA.js} +1 -1
  250. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-DUX-id_F.js} +1 -1
  251. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-DmldrHd_.js} +1 -1
  252. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DnfXs8Vn.js} +2 -2
  253. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Dq9gLD7L.js} +1 -1
  254. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-W-TIVntx.js} +1 -1
  255. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-dDdADKFA.js} +1 -1
  256. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-dydu68Fl.js} +1 -1
  257. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-ngtN0DJB.js} +1 -1
  258. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  259. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  260. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  261. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  262. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  263. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  264. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  265. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  266. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  267. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  268. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  269. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  270. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  271. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  272. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  273. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-BHjG8b-J.js} +1 -1
  274. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  275. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  276. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  277. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  278. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  279. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  280. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  281. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  282. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  283. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  284. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  285. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  286. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  287. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  288. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  289. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  290. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  291. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  292. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  293. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  294. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  295. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  296. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  297. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  298. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  299. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  300. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  301. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  302. ksadk/server/static/index.html +2 -2
  303. ksadk/sessions/__init__.py +26 -9
  304. ksadk/sessions/_local_service_sync.py +688 -0
  305. ksadk/sessions/_local_tables.py +21 -0
  306. ksadk/sessions/_postgres_schema.py +305 -0
  307. ksadk/sessions/_postgres_tables.py +15 -0
  308. ksadk/sessions/base.py +80 -1
  309. ksadk/sessions/in_memory.py +53 -2
  310. ksadk/sessions/local_service.py +63 -604
  311. ksadk/sessions/postgres_service.py +58 -148
  312. ksadk/sessions/resilient.py +35 -1
  313. ksadk/studio/api.py +577 -25
  314. ksadk/studio/api_contracts.py +114 -5
  315. ksadk/studio/api_memory_routes.py +82 -0
  316. ksadk/studio/authoring.py +252 -27
  317. ksadk/studio/authoring_coordinator.py +799 -67
  318. ksadk/studio/builder.py +88 -11
  319. ksadk/studio/capabilities.py +17 -0
  320. ksadk/studio/cloud.py +1916 -95
  321. ksadk/studio/codex_agent_service.py +125 -14
  322. ksadk/studio/codex_authoring.py +469 -0
  323. ksadk/studio/codex_builder.py +138 -25
  324. ksadk/studio/codex_manifest.py +51 -22
  325. ksadk/studio/codex_run.py +46 -3
  326. ksadk/studio/compiler.py +1 -0
  327. ksadk/studio/contracts.py +114 -3
  328. ksadk/studio/event_store.py +25 -95
  329. ksadk/studio/framework_run.py +231 -3
  330. ksadk/studio/hosted_kernel.py +317 -0
  331. ksadk/studio/manifest_resolver.py +131 -0
  332. ksadk/studio/model_client.py +95 -9
  333. ksadk/studio/model_profile_service.py +1 -1
  334. ksadk/studio/operations.py +37 -5
  335. ksadk/studio/otel_trace.py +348 -42
  336. ksadk/studio/pcm_memory.py +85 -0
  337. ksadk/studio/repository.py +23 -2
  338. ksadk/studio/resource_catalog.py +43 -0
  339. ksadk/studio/run_service.py +563 -137
  340. ksadk/studio/runtime_source.py +42 -16
  341. ksadk/studio/service.py +1180 -72
  342. ksadk/studio/shared_web.py +32 -22
  343. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  344. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  345. ksadk/studio/static/index.html +2 -2
  346. ksadk/studio/templates.py +100 -8
  347. ksadk/studio/validator.py +19 -0
  348. ksadk/studio/workspace.py +30 -32
  349. ksadk/tracing/setup.py +304 -3
  350. ksadk/version.py +1 -1
  351. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  352. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  353. ksadk/events/parser.py +0 -191
  354. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  355. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  356. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  357. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  358. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  359. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  360. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  361. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  362. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  363. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  364. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  365. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  366. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  367. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  368. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  369. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  370. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  371. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  372. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  373. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  374. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  375. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  376. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  377. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  378. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  379. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  380. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  381. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  382. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  383. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  384. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  385. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  386. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  387. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  388. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  389. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  390. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  391. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  392. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  393. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  394. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  395. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  396. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  397. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  398. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  399. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  400. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  401. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  402. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  403. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  404. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  405. ksadk/studio/evaluation.py +0 -192
  406. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  407. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  408. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +0 -0
  409. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  410. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  411. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,461 @@
1
+ """Memory Coordinator —— core/recall/flush/commit 编排(方案 §10 / §11.1)。
2
+
3
+ Coordinator 是本地与云端一致的运行时编排层:负责召回(recall)、压缩前 best-effort Flush、
4
+ 候选评估与提交(commit)。Provider 故障返回结构化空结果或标准错误,不污染模型输入
5
+ (方案 §10.8)。
6
+
7
+ 本模块不依赖具体 Provider 实现,只依赖 ``MemoryProvider`` Protocol 与 ``MemoryPolicy``,
8
+ 便于本地 SQLite 与云端 HTTP/SDK 共用同一套编排逻辑与契约测试。
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+ import time
15
+ import uuid
16
+ from dataclasses import dataclass, field, replace
17
+ from typing import Any, Mapping
18
+
19
+ from ksadk.memory.models import (
20
+ CoreMemoryRequest,
21
+ MemoryCandidate,
22
+ MemoryCapabilities,
23
+ MemoryDeleteRequest,
24
+ MemoryRecord,
25
+ MemoryScope,
26
+ MemorySearchRequest,
27
+ MemorySearchResult,
28
+ )
29
+ from ksadk.memory.policy import MemoryEvaluation, MemoryPolicy
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+
34
+ def agent_user_scope_id(*, agent_id: str, user_id: str) -> str:
35
+ """构造默认的 Agent × User 记忆命名空间,避免跨 Agent 或跨用户污染。"""
36
+ agent = str(agent_id or "").strip()
37
+ user = str(user_id or "").strip()
38
+ if not agent:
39
+ return user
40
+ return f"agent:{agent}:user:{user}"
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class FlushResult:
45
+ """一次压缩前 Memory Flush 的结果(方案 §9.2)。"""
46
+
47
+ status: str # succeeded / partial / failed / skipped
48
+ proposed: int = 0
49
+ committed: int = 0
50
+ rejected: int = 0
51
+ errors: list[str] = field(default_factory=list)
52
+
53
+ def to_audit_dict(self) -> dict[str, Any]:
54
+ return {
55
+ "status": self.status,
56
+ "proposed": self.proposed,
57
+ "committed": self.committed,
58
+ "rejected": self.rejected,
59
+ }
60
+
61
+
62
+ class MemoryCoordinator:
63
+ """core/recall/flush/commit 编排(方案 §10)。
64
+
65
+ ``MemoryCoordinator`` 持有一个 ``MemoryProvider`` 与一个 ``MemoryPolicy``。本地与云端用
66
+ 不同 Provider 实现,但编排逻辑与契约一致(方案 §12)。
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ provider: Any,
72
+ *,
73
+ policy: MemoryPolicy | None = None,
74
+ tenant_id: str = "local",
75
+ workspace_id: str = "local",
76
+ ) -> None:
77
+ self._provider = provider
78
+ self._policy = policy or MemoryPolicy()
79
+ self._tenant_id = tenant_id
80
+ self._workspace_id = workspace_id
81
+
82
+ @property
83
+ def provider(self) -> Any:
84
+ return self._provider
85
+
86
+ @property
87
+ def policy(self) -> MemoryPolicy:
88
+ return self._policy
89
+
90
+ def capabilities(self) -> MemoryCapabilities:
91
+ try:
92
+ caps = self._provider.capabilities()
93
+ if isinstance(caps, MemoryCapabilities):
94
+ return caps
95
+ except Exception as exc: # noqa: BLE001
96
+ logger.debug("memory capabilities failed: %s", exc)
97
+ return MemoryCapabilities(
98
+ semantic_search=False,
99
+ keyword_search=False,
100
+ metadata_filter=False,
101
+ versioned_update=False,
102
+ hard_delete=False,
103
+ ttl=False,
104
+ max_record_chars=0,
105
+ )
106
+
107
+ # ---- recall(方案 §10.6)----
108
+
109
+ def recall(self, request: MemorySearchRequest) -> MemorySearchResult:
110
+ """召回长期记忆,失败返回结构化空结果,不抛异常文本进模型上下文。"""
111
+ if not request.query.strip() or not request.scopes:
112
+ return MemorySearchResult(
113
+ status="not_configured",
114
+ records=[],
115
+ error_code="empty_query_or_scope",
116
+ provider=self._provider_name(),
117
+ latency_ms=0,
118
+ accounting_accuracy="opaque",
119
+ )
120
+ try:
121
+ result = self._provider.search(request)
122
+ except Exception as exc: # noqa: BLE001
123
+ logger.warning("memory recall failed: %s", exc)
124
+ return MemorySearchResult(
125
+ status="failed",
126
+ records=[],
127
+ error_code="provider_error",
128
+ provider=self._provider_name(),
129
+ latency_ms=0,
130
+ accounting_accuracy="opaque",
131
+ )
132
+ return result
133
+
134
+ def list_core(self, request: CoreMemoryRequest) -> list[MemoryRecord]:
135
+ try:
136
+ return list(self._provider.list_core(request))
137
+ except Exception as exc: # noqa: BLE001
138
+ logger.warning("memory list_core failed: %s", exc)
139
+ return []
140
+
141
+ # ---- flush / commit(方案 §9.2 / §10.3)----
142
+
143
+ def flush_candidates(
144
+ self,
145
+ candidates: list[MemoryCandidate],
146
+ *,
147
+ existing_index: Mapping[str, MemoryRecord] | None = None,
148
+ ) -> FlushResult:
149
+ """压缩前 best-effort Memory Flush(方案 §9.2)。
150
+
151
+ 失败不阻止紧急 compaction(方案 §9.2 失败语义)。逐条评估 → commit/reject,不批量抛。
152
+ """
153
+ if not candidates:
154
+ return FlushResult(status="skipped")
155
+ committed = 0
156
+ rejected = 0
157
+ errors: list[str] = []
158
+ for candidate in candidates:
159
+ try:
160
+ existing = None
161
+ conflicting_records: list[MemoryRecord] = []
162
+ if existing_index and candidate.conflicts_with:
163
+ existing = existing_index.get(candidate.conflicts_with[0])
164
+ effective_candidate = candidate
165
+ if existing is None and candidate.slot_key:
166
+ slot_records = self._find_active_slot_records(candidate)
167
+ from ksadk.memory.policy import content_hash
168
+
169
+ candidate_hash = content_hash(candidate.content)
170
+ same_record = next(
171
+ (item for item in slot_records if item.content_hash == candidate_hash), None
172
+ )
173
+ conflicting_records = [
174
+ item for item in slot_records if item.content_hash != candidate_hash
175
+ ]
176
+ if same_record is not None:
177
+ if conflicting_records:
178
+ self._mark_superseded(
179
+ conflicting_records,
180
+ superseded_by=same_record.memory_id,
181
+ reason="conflict_supersede",
182
+ )
183
+ committed += 1
184
+ else:
185
+ # 同一槽位、同一事实重复声明:不新增重复记录。
186
+ rejected += 1
187
+ continue
188
+ if conflicting_records:
189
+ existing = max(
190
+ conflicting_records,
191
+ key=lambda item: (item.version, item.updated_at),
192
+ )
193
+ effective_candidate = replace(
194
+ candidate,
195
+ operation="update",
196
+ conflicts_with=[item.memory_id for item in conflicting_records],
197
+ )
198
+ evaluation = self._policy.evaluate(effective_candidate, existing=existing)
199
+ if evaluation.decision == "reject":
200
+ rejected += 1
201
+ continue
202
+ if evaluation.decision == "pending":
203
+ # pending 不在本轮 flush 提交(留 Coordinator 后台聚合)。
204
+ rejected += 1
205
+ continue
206
+ self._commit(
207
+ effective_candidate,
208
+ evaluation,
209
+ existing,
210
+ conflicting_records=conflicting_records,
211
+ )
212
+ committed += 1
213
+ except Exception as exc: # noqa: BLE001
214
+ errors.append(str(exc))
215
+ logger.warning("memory flush candidate failed: %s", exc)
216
+ status = "succeeded" if not errors else "partial"
217
+ return FlushResult(
218
+ status=status,
219
+ proposed=len(candidates),
220
+ committed=committed,
221
+ rejected=rejected,
222
+ errors=errors,
223
+ )
224
+
225
+ def _find_active_slot_records(self, candidate: MemoryCandidate) -> list[MemoryRecord]:
226
+ """定位同槽位 active 事实;兼容尚无 slot metadata 的历史记录。"""
227
+ if not candidate.slot_key or not self.capabilities().metadata_filter:
228
+ return []
229
+ result = self._provider.search(
230
+ MemorySearchRequest(
231
+ query="",
232
+ scopes=[(candidate.scope, candidate.scope_id)],
233
+ memory_types=[candidate.memory_type],
234
+ top_k=8,
235
+ max_tokens=8192,
236
+ min_score=0.0,
237
+ filters={"slot_key": candidate.slot_key},
238
+ )
239
+ )
240
+ if result.status != "ok":
241
+ return []
242
+ matches = [
243
+ record
244
+ for record in result.records
245
+ if record.status == "active"
246
+ and str(record.metadata.get("slot_key") or "") == candidate.slot_key
247
+ ]
248
+ # 旧版本记录没有 slot_key:仅在同 scope/type 内检索,并再次用确定性槽位函数校验,
249
+ # 不因正文相似就覆盖无关事实。即使已有新格式记录,也继续清理同槽位 legacy active。
250
+ legacy_result = self._provider.search(
251
+ MemorySearchRequest(
252
+ query=candidate.content,
253
+ scopes=[(candidate.scope, candidate.scope_id)],
254
+ memory_types=[candidate.memory_type],
255
+ top_k=32,
256
+ max_tokens=32768,
257
+ min_score=0.0,
258
+ )
259
+ )
260
+ if legacy_result.status != "ok":
261
+ return matches
262
+ from ksadk.memory.extraction import derive_profile_slot_key
263
+
264
+ by_id = {record.memory_id: record for record in matches}
265
+ for record in legacy_result.records:
266
+ if (
267
+ record.status == "active"
268
+ and derive_profile_slot_key(record.content) == candidate.slot_key
269
+ ):
270
+ by_id[record.memory_id] = record
271
+ return list(by_id.values())
272
+
273
+ def propose_and_commit(
274
+ self,
275
+ candidate: MemoryCandidate,
276
+ *,
277
+ existing: MemoryRecord | None = None,
278
+ ) -> MemoryEvaluation:
279
+ """同步提交单个候选(用户明确"记住/忘掉"路径,方案 §10.4)。"""
280
+ evaluation = self._policy.evaluate(candidate, existing=existing)
281
+ if evaluation.decision == "commit":
282
+ self._commit(candidate, evaluation, existing)
283
+ return evaluation
284
+
285
+ def delete(
286
+ self, memory_id: str, *, scope: MemoryScope, scope_id: str, hard: bool = False
287
+ ) -> bool:
288
+ """用户明确遗忘(方案 §10.4 / §19):不支持 hard delete 时明确返回失败。"""
289
+ caps = self.capabilities()
290
+ if hard and not caps.hard_delete:
291
+ logger.warning("hard delete requested but provider lacks hard_delete capability")
292
+ return False
293
+ try:
294
+ result = self._provider.delete(
295
+ MemoryDeleteRequest(memory_id=memory_id, scope=scope, scope_id=scope_id, hard=hard)
296
+ )
297
+ return bool(result.deleted)
298
+ except Exception as exc: # noqa: BLE001
299
+ logger.warning("memory delete failed: %s", exc)
300
+ return False
301
+
302
+ # ---- internals ----
303
+
304
+ def _commit(
305
+ self,
306
+ candidate: MemoryCandidate,
307
+ evaluation: MemoryEvaluation,
308
+ existing: MemoryRecord | None,
309
+ *,
310
+ conflicting_records: list[MemoryRecord] | None = None,
311
+ ) -> None:
312
+ from ksadk.memory.policy import content_hash
313
+
314
+ if evaluation.operation == "delete":
315
+ if candidate.conflicts_with:
316
+ self._provider.delete(
317
+ MemoryDeleteRequest(
318
+ memory_id=candidate.conflicts_with[0],
319
+ scope=candidate.scope,
320
+ scope_id=candidate.scope_id,
321
+ hard=self.capabilities().hard_delete,
322
+ )
323
+ )
324
+ return
325
+
326
+ now_iso = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
327
+ memory_id = f"mem_{uuid.uuid4().hex[:24]}"
328
+ if evaluation.operation == "update" and existing is not None:
329
+ # 保留旧事实用于审计,但立即移出 active 召回集合;新事实使用新 memory_id。
330
+ self._mark_superseded(
331
+ conflicting_records or [existing],
332
+ superseded_by=memory_id,
333
+ reason=evaluation.reason,
334
+ )
335
+ record = MemoryRecord(
336
+ memory_id=memory_id,
337
+ tenant_id=self._tenant_id,
338
+ workspace_id=self._workspace_id,
339
+ scope=candidate.scope,
340
+ scope_id=candidate.scope_id,
341
+ memory_type=candidate.memory_type,
342
+ content=candidate.content,
343
+ summary=candidate.content[:200],
344
+ status="active",
345
+ confidence=candidate.confidence,
346
+ importance=candidate.importance,
347
+ valid_from=now_iso,
348
+ valid_to="",
349
+ expires_at="",
350
+ source_session_id="",
351
+ source_event_ids=list(candidate.source_event_ids),
352
+ source_seq_range=None,
353
+ content_hash=content_hash(candidate.content),
354
+ version=(max((r.version for r in conflicting_records or [existing]), default=0) + 1)
355
+ if evaluation.operation == "update" and existing is not None
356
+ else evaluation.new_version or 1,
357
+ metadata={
358
+ "reason": candidate.reason,
359
+ "operation": evaluation.operation,
360
+ **({"slot_key": candidate.slot_key} if candidate.slot_key else {}),
361
+ **(
362
+ {
363
+ "supersedes": [
364
+ item.memory_id for item in conflicting_records or [existing]
365
+ ]
366
+ }
367
+ if evaluation.operation == "update" and existing is not None
368
+ else {}
369
+ ),
370
+ },
371
+ created_at=now_iso,
372
+ updated_at=now_iso,
373
+ )
374
+ self._provider.upsert(
375
+ record,
376
+ expected_version=None,
377
+ )
378
+
379
+ def _mark_superseded(
380
+ self,
381
+ records: list[MemoryRecord],
382
+ *,
383
+ superseded_by: str,
384
+ reason: str,
385
+ ) -> None:
386
+ now_iso = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
387
+ for record in records:
388
+ superseded = replace(
389
+ record,
390
+ status="superseded",
391
+ valid_to=now_iso,
392
+ metadata={
393
+ **record.metadata,
394
+ "superseded_by": superseded_by,
395
+ "superseded_reason": reason,
396
+ },
397
+ updated_at=now_iso,
398
+ )
399
+ self._provider.upsert(superseded, expected_version=record.version)
400
+
401
+ def _provider_name(self) -> str:
402
+ return type(self._provider).__name__
403
+
404
+
405
+ def build_search_request(
406
+ *,
407
+ query: str,
408
+ user_id: str = "",
409
+ agent_id: str = "",
410
+ workspace_id: str = "",
411
+ top_k: int = 8,
412
+ max_tokens: int = 4000,
413
+ min_score: float = 0.45,
414
+ ) -> MemorySearchRequest:
415
+ """便捷构造检索请求,按方案 §10.6 组装 scopes(user > agent > workspace > org)。
416
+
417
+ scope_id 由可信 Principal 决定,不信任用户自行提交(方案 §19)。
418
+ """
419
+ scopes: list[tuple[MemoryScope, str]] = []
420
+ if user_id:
421
+ scopes.append(("user", user_id))
422
+ if agent_id:
423
+ scopes.append(("agent", agent_id))
424
+ if workspace_id:
425
+ scopes.append(("workspace", workspace_id))
426
+ return MemorySearchRequest(
427
+ query=query,
428
+ scopes=scopes,
429
+ memory_types=["profile", "fact", "episode"],
430
+ top_k=top_k,
431
+ max_tokens=max_tokens,
432
+ min_score=min_score,
433
+ )
434
+
435
+
436
+ def recall_to_context_item(result: MemorySearchResult) -> dict[str, Any] | None:
437
+ """把检索结果投影成可注入模型的 ambient context(方案 §10.6 第 5 条)。
438
+
439
+ 失败(status != ok)返回 ``None``,不把错误字符串塞进正文(方案 §10.8)。无结果返回
440
+ ``None``(不注入"未找到…"噪声,方案 §10.8 第 4 条)。每条结果保留 memory_id/scope/score
441
+ 的安全短引用。
442
+ """
443
+ if result.status != "ok" or not result.records:
444
+ return None
445
+ lines: list[str] = []
446
+ for index, record in enumerate(result.records, 1):
447
+ lines.append(f"[{index}] {record.summary or record.content}")
448
+ return {
449
+ "formatted_text": "\n\n".join(lines),
450
+ "recall_count": len(result.records),
451
+ "accounting_accuracy": result.accounting_accuracy,
452
+ }
453
+
454
+
455
+ __all__ = [
456
+ "agent_user_scope_id",
457
+ "FlushResult",
458
+ "MemoryCoordinator",
459
+ "build_search_request",
460
+ "recall_to_context_item",
461
+ ]
ksadk/memory/events.py ADDED
@@ -0,0 +1,202 @@
1
+ """Memory 失败可观测的结构化事件(方案 §3)。
2
+
3
+ 不记录记忆正文和敏感信息。Studio 普通界面只提示"记忆保存失败",
4
+ 详细错误放 Trace。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from typing import Any, Literal
11
+
12
+ MemoryEventType = Literal[
13
+ "memory.recall.completed",
14
+ "memory.recall.projected",
15
+ "memory.recall.empty",
16
+ "memory.recall.failed",
17
+ "memory.candidate.created",
18
+ "memory.candidate.rejected",
19
+ "memory.flush.completed",
20
+ "memory.flush.failed",
21
+ ]
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class MemoryEvent:
26
+ """结构化 Memory 事件(不记录正文/敏感信息)。"""
27
+
28
+ type: MemoryEventType
29
+ run_id: str
30
+ session_id: str
31
+ provider: str
32
+ policy_rollout: str
33
+ candidate_count: int = 0
34
+ error_code: str | None = None
35
+ error_message: str | None = None
36
+ retryable: bool = False
37
+ metadata: dict[str, Any] = field(default_factory=dict)
38
+
39
+ def to_dict(self) -> dict[str, Any]:
40
+ """序列化为 plain dict(不含正文/敏感信息)。"""
41
+ return {
42
+ "type": self.type,
43
+ "run_id": self.run_id,
44
+ "session_id": self.session_id,
45
+ "provider": self.provider,
46
+ "policy_rollout": self.policy_rollout,
47
+ "candidate_count": self.candidate_count,
48
+ "error_code": self.error_code,
49
+ "error_message": self.error_message,
50
+ "retryable": self.retryable,
51
+ "metadata": self.metadata,
52
+ }
53
+
54
+
55
+ def recall_completed(
56
+ *, run_id: str, session_id: str, provider: str, rollout: str, count: int
57
+ ) -> MemoryEvent:
58
+ return MemoryEvent(
59
+ type="memory.recall.completed",
60
+ run_id=run_id,
61
+ session_id=session_id,
62
+ provider=provider,
63
+ policy_rollout=rollout,
64
+ candidate_count=count,
65
+ )
66
+
67
+
68
+ def recall_projected(
69
+ *,
70
+ run_id: str,
71
+ session_id: str,
72
+ provider: str,
73
+ rollout: str,
74
+ count: int,
75
+ runtime_type: str,
76
+ target: str,
77
+ ) -> MemoryEvent:
78
+ """记录召回结果已交付 Runner;不代表模型一定采纳了相关事实。"""
79
+ return MemoryEvent(
80
+ type="memory.recall.projected",
81
+ run_id=run_id,
82
+ session_id=session_id,
83
+ provider=provider,
84
+ policy_rollout=rollout,
85
+ candidate_count=count,
86
+ metadata={"runtime_type": runtime_type, "target": target},
87
+ )
88
+
89
+
90
+ def recall_empty(*, run_id: str, session_id: str, provider: str, rollout: str) -> MemoryEvent:
91
+ return MemoryEvent(
92
+ type="memory.recall.empty",
93
+ run_id=run_id,
94
+ session_id=session_id,
95
+ provider=provider,
96
+ policy_rollout=rollout,
97
+ )
98
+
99
+
100
+ def recall_failed(
101
+ *,
102
+ run_id: str,
103
+ session_id: str,
104
+ provider: str,
105
+ rollout: str,
106
+ error_code: str,
107
+ error_message: str,
108
+ retryable: bool = True,
109
+ ) -> MemoryEvent:
110
+ return MemoryEvent(
111
+ type="memory.recall.failed",
112
+ run_id=run_id,
113
+ session_id=session_id,
114
+ provider=provider,
115
+ policy_rollout=rollout,
116
+ error_code=error_code,
117
+ error_message=error_message,
118
+ retryable=retryable,
119
+ )
120
+
121
+
122
+ def candidate_created(
123
+ *, run_id: str, session_id: str, provider: str, rollout: str, count: int
124
+ ) -> MemoryEvent:
125
+ return MemoryEvent(
126
+ type="memory.candidate.created",
127
+ run_id=run_id,
128
+ session_id=session_id,
129
+ provider=provider,
130
+ policy_rollout=rollout,
131
+ candidate_count=count,
132
+ )
133
+
134
+
135
+ def candidate_rejected(
136
+ *, run_id: str, session_id: str, provider: str, rollout: str, count: int
137
+ ) -> MemoryEvent:
138
+ return MemoryEvent(
139
+ type="memory.candidate.rejected",
140
+ run_id=run_id,
141
+ session_id=session_id,
142
+ provider=provider,
143
+ policy_rollout=rollout,
144
+ candidate_count=count,
145
+ )
146
+
147
+
148
+ def flush_completed(
149
+ *,
150
+ run_id: str,
151
+ session_id: str,
152
+ provider: str,
153
+ rollout: str,
154
+ proposed: int,
155
+ committed: int,
156
+ rejected: int,
157
+ ) -> MemoryEvent:
158
+ return MemoryEvent(
159
+ type="memory.flush.completed",
160
+ run_id=run_id,
161
+ session_id=session_id,
162
+ provider=provider,
163
+ policy_rollout=rollout,
164
+ candidate_count=proposed,
165
+ metadata={"committed": committed, "rejected": rejected},
166
+ )
167
+
168
+
169
+ def flush_failed(
170
+ *,
171
+ run_id: str,
172
+ session_id: str,
173
+ provider: str,
174
+ rollout: str,
175
+ error_code: str,
176
+ error_message: str,
177
+ retryable: bool = True,
178
+ ) -> MemoryEvent:
179
+ return MemoryEvent(
180
+ type="memory.flush.failed",
181
+ run_id=run_id,
182
+ session_id=session_id,
183
+ provider=provider,
184
+ policy_rollout=rollout,
185
+ error_code=error_code,
186
+ error_message=error_message,
187
+ retryable=retryable,
188
+ )
189
+
190
+
191
+ __all__ = [
192
+ "MemoryEvent",
193
+ "MemoryEventType",
194
+ "candidate_created",
195
+ "candidate_rejected",
196
+ "flush_completed",
197
+ "flush_failed",
198
+ "recall_completed",
199
+ "recall_empty",
200
+ "recall_failed",
201
+ "recall_projected",
202
+ ]