agentengine-sdk-python 0.8.0__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 (494) hide show
  1. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
  2. agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
  3. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +2 -0
  5. ksadk/a2a/_space_client_events.py +381 -0
  6. ksadk/a2a/bootstrap.py +0 -2
  7. ksadk/a2a/card.py +6 -111
  8. ksadk/a2a/control_plane.py +239 -1
  9. ksadk/a2a/event_adapter.py +156 -64
  10. ksadk/a2a/executor.py +195 -172
  11. ksadk/a2a/routes.py +12 -5
  12. ksadk/a2a/server.py +1 -8
  13. ksadk/a2a/service_env.py +33 -0
  14. ksadk/a2a/space_client.py +43 -349
  15. ksadk/a2a_card.py +101 -0
  16. ksadk/a2ui/core.py +222 -53
  17. ksadk/agui/_agent_helpers.py +243 -0
  18. ksadk/agui/a2ui_projection.py +12 -5
  19. ksadk/agui/agent.py +474 -275
  20. ksadk/agui/config.py +11 -5
  21. ksadk/agui/routes.py +7 -15
  22. ksadk/api/client.py +530 -40
  23. ksadk/api/environment.py +27 -0
  24. ksadk/builders/code_builder.py +352 -53
  25. ksadk/builders/container_builder.py +71 -44
  26. ksadk/builders/framework_requirements.py +2 -1
  27. ksadk/builders/ks3_uploader.py +2 -2
  28. ksadk/builders/managed_runtime_builder.py +60 -28
  29. ksadk/cli/__init__.py +25 -0
  30. ksadk/cli/cmd_a2a.py +18 -31
  31. ksadk/cli/cmd_create.py +13 -26
  32. ksadk/cli/cmd_dashboard.py +15 -1
  33. ksadk/cli/cmd_deploy.py +28 -3
  34. ksadk/cli/cmd_eval.py +443 -0
  35. ksadk/cli/cmd_evalset.py +284 -0
  36. ksadk/cli/cmd_files.py +5 -1
  37. ksadk/cli/cmd_hermes.py +137 -163
  38. ksadk/cli/cmd_invoke.py +28 -38
  39. ksadk/cli/cmd_launch.py +12 -0
  40. ksadk/cli/cmd_managed_runtime.py +95 -0
  41. ksadk/cli/cmd_observe.py +85 -0
  42. ksadk/cli/cmd_openclaw.py +85 -479
  43. ksadk/cli/cmd_replay.py +28 -4
  44. ksadk/cli/cmd_run.py +29 -67
  45. ksadk/cli/cmd_studio.py +201 -0
  46. ksadk/cli/cmd_web.py +15 -6
  47. ksadk/cli/dry_run.py +2 -1
  48. ksadk/cli/env_options.py +83 -0
  49. ksadk/cli/global_options.py +3 -1
  50. ksadk/cli/hermes_env.py +151 -0
  51. ksadk/cli/invoke_payload.py +49 -0
  52. ksadk/cli/network_options.py +7 -5
  53. ksadk/cli/openclaw_env.py +458 -0
  54. ksadk/cli/runtime_bootstrap.py +51 -0
  55. ksadk/cli/ui.py +6 -0
  56. ksadk/cli/workflow_common.py +5 -5
  57. ksadk/codex/__init__.py +3 -3
  58. ksadk/codex/client.py +833 -49
  59. ksadk/codex/phase.py +1 -1
  60. ksadk/codex/runtime.py +720 -127
  61. ksadk/common/kop_client.py +232 -0
  62. ksadk/configs/__init__.py +1 -3
  63. ksadk/configs/env_registry.py +244 -45
  64. ksadk/configs/env_registry_pcm.py +181 -0
  65. ksadk/configs/env_var_spec.py +18 -0
  66. ksadk/configs/global_config.py +6 -1
  67. ksadk/configs/settings.py +5 -108
  68. ksadk/context_engine/__init__.py +98 -0
  69. ksadk/context_engine/assembler.py +176 -0
  70. ksadk/context_engine/baseline.py +419 -0
  71. ksadk/context_engine/cache_observability.py +228 -0
  72. ksadk/context_engine/capabilities.py +443 -0
  73. ksadk/context_engine/contributors.py +344 -0
  74. ksadk/context_engine/hosted_pipeline.py +417 -0
  75. ksadk/context_engine/models.py +117 -0
  76. ksadk/context_engine/planner.py +698 -0
  77. ksadk/context_engine/policies.py +319 -0
  78. ksadk/context_engine/projection.py +31 -0
  79. ksadk/context_engine/shadow_plan.py +266 -0
  80. ksadk/context_engine/tokenizer.py +164 -0
  81. ksadk/conversations/__init__.py +85 -94
  82. ksadk/conversations/context.py +126 -6
  83. ksadk/conversations/message_projection.py +292 -28
  84. ksadk/conversations/model_context.py +49 -3
  85. ksadk/conversations/runtime_compaction.py +207 -5
  86. ksadk/conversations/runtime_input.py +193 -3
  87. ksadk/conversations/runtime_invocation.py +81 -3
  88. ksadk/conversations/runtime_observability.py +157 -4
  89. ksadk/conversations/runtime_payloads.py +42 -0
  90. ksadk/conversations/runtime_preparation.py +280 -2
  91. ksadk/conversations/runtime_resume.py +71 -32
  92. ksadk/conversations/runtime_stream_events.py +94 -9
  93. ksadk/conversations/runtime_streaming.py +175 -22
  94. ksadk/conversations/semantic_summary.py +311 -1
  95. ksadk/conversations/session_lock.py +51 -0
  96. ksadk/deployment/env_forward.py +72 -0
  97. ksadk/deployment/managed_runtime.py +38 -0
  98. ksadk/deployment/manager.py +24 -8
  99. ksadk/deployment/providers/serverless.py +228 -92
  100. ksadk/evaluation/__init__.py +116 -0
  101. ksadk/evaluation/a2a_adapter.py +452 -0
  102. ksadk/evaluation/adapters.py +67 -0
  103. ksadk/evaluation/agent_eval_client.py +395 -0
  104. ksadk/evaluation/cloud_binding.py +80 -0
  105. ksadk/evaluation/cloud_converter.py +194 -0
  106. ksadk/evaluation/cloud_service.py +199 -0
  107. ksadk/evaluation/contracts.py +478 -0
  108. ksadk/evaluation/evalset.py +351 -0
  109. ksadk/evaluation/evaluators.py +627 -0
  110. ksadk/evaluation/evidence.py +258 -0
  111. ksadk/evaluation/executor.py +143 -0
  112. ksadk/evaluation/local_adapter.py +550 -0
  113. ksadk/evaluation/service_env.py +27 -0
  114. ksadk/evaluation/storage.py +68 -0
  115. ksadk/evaluation/studio_build_adapter.py +253 -0
  116. ksadk/evaluation/target.py +82 -0
  117. ksadk/events/__init__.py +13 -13
  118. ksadk/events/_v1_compat/__init__.py +1 -0
  119. ksadk/events/_v1_compat/models.py +299 -0
  120. ksadk/events/_v1_compat/parser.py +247 -0
  121. ksadk/events/_v1_compat/projection.py +753 -0
  122. ksadk/events/adapters/__init__.py +34 -0
  123. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  124. ksadk/events/adapters/_a2a_support.py +275 -0
  125. ksadk/events/adapters/_codex_interactions.py +375 -0
  126. ksadk/events/adapters/_codex_items.py +801 -0
  127. ksadk/events/adapters/_codex_validators.py +311 -0
  128. ksadk/events/adapters/_langgraph_support.py +785 -0
  129. ksadk/events/adapters/a2a.py +841 -0
  130. ksadk/events/adapters/adk.py +503 -0
  131. ksadk/events/adapters/codex.py +717 -0
  132. ksadk/events/adapters/langgraph.py +745 -0
  133. ksadk/events/canonical.py +440 -0
  134. ksadk/events/canonical_replay.py +497 -0
  135. ksadk/events/canonical_store.py +468 -0
  136. ksadk/events/cold_recovery.py +257 -0
  137. ksadk/events/content.py +89 -0
  138. ksadk/events/identity.py +86 -0
  139. ksadk/events/pipeline.py +455 -0
  140. ksadk/events/projections.py +66 -0
  141. ksadk/events/reducer.py +661 -0
  142. ksadk/events/replay.py +3 -36
  143. ksadk/events/runtime_event.py +20 -256
  144. ksadk/events/session_event.py +324 -0
  145. ksadk/events/store.py +3 -316
  146. ksadk/events/v1_compat.py +41 -0
  147. ksadk/harness/__init__.py +3 -2
  148. ksadk/harness/app.py +114 -123
  149. ksadk/harness/config.py +1 -1
  150. ksadk/harness/runtime.py +467 -0
  151. ksadk/hermes_terminal.py +5 -0
  152. ksadk/identity/resolver.py +4 -3
  153. ksadk/interaction/__init__.py +28 -0
  154. ksadk/interaction/contracts.py +136 -0
  155. ksadk/interaction/ledger.py +189 -0
  156. ksadk/interaction/provider.py +122 -0
  157. ksadk/interaction/providers/__init__.py +52 -0
  158. ksadk/interaction/providers/adk.py +40 -0
  159. ksadk/interaction/providers/codex.py +94 -0
  160. ksadk/interaction/providers/langgraph.py +58 -0
  161. ksadk/kernel/__init__.py +117 -0
  162. ksadk/kernel/authorization.py +258 -0
  163. ksadk/kernel/bootstrap.py +1074 -0
  164. ksadk/kernel/contract_fingerprints.py +61 -0
  165. ksadk/kernel/contracts.py +362 -0
  166. ksadk/kernel/control.py +219 -0
  167. ksadk/kernel/errors.py +79 -0
  168. ksadk/kernel/ingress.py +1102 -0
  169. ksadk/kernel/mapping.py +111 -0
  170. ksadk/kernel/memory_store.py +1133 -0
  171. ksadk/kernel/postgres_store.py +1756 -0
  172. ksadk/kernel/recovery.py +452 -0
  173. ksadk/kernel/runtime_identity.py +103 -0
  174. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  175. ksadk/kernel/sqlite_store.py +1410 -0
  176. ksadk/kernel/state.py +145 -0
  177. ksadk/kernel/store.py +232 -0
  178. ksadk/kernel/worker.py +953 -0
  179. ksadk/knowledge_base/client.py +22 -4
  180. ksadk/knowledge_base/service.py +32 -5
  181. ksadk/managed_a2a_card.py +160 -0
  182. ksadk/managed_runtime.py +16 -9
  183. ksadk/memory/__init__.py +61 -0
  184. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  185. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  186. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
  188. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  189. ksadk/memory/adk/long_term_memory.py +3 -2
  190. ksadk/memory/coordinator.py +461 -0
  191. ksadk/memory/events.py +202 -0
  192. ksadk/memory/extraction.py +228 -0
  193. ksadk/memory/ltm_backend_factory.py +16 -3
  194. ksadk/memory/models.py +316 -0
  195. ksadk/memory/policy.py +215 -0
  196. ksadk/memory/provider.py +47 -0
  197. ksadk/memory/provider_adapter.py +159 -0
  198. ksadk/memory/provider_resolver.py +71 -0
  199. ksadk/memory/providers/__init__.py +5 -0
  200. ksadk/memory/providers/local_sqlite.py +490 -0
  201. ksadk/memory/resolved_policy.py +145 -0
  202. ksadk/memory/service.py +198 -8
  203. ksadk/memory/tool.py +4 -0
  204. ksadk/model_proxy/bootstrap.py +16 -9
  205. ksadk/model_proxy/config.py +22 -1
  206. ksadk/model_proxy/detect.py +202 -9
  207. ksadk/model_proxy/namespace.py +67 -15
  208. ksadk/model_proxy/server.py +168 -6
  209. ksadk/model_proxy/transform.py +105 -3
  210. ksadk/observability/__init__.py +25 -0
  211. ksadk/observability/session_log.py +420 -0
  212. ksadk/observability/trajectory.py +105 -0
  213. ksadk/prompts/__init__.py +71 -0
  214. ksadk/prompts/compiler.py +215 -0
  215. ksadk/prompts/models.py +82 -0
  216. ksadk/prompts/projection.py +89 -0
  217. ksadk/prompts/resolved.py +137 -0
  218. ksadk/prompts/sources.py +233 -0
  219. ksadk/runners/_langgraph_runner_streams.py +822 -0
  220. ksadk/runners/adk_runner.py +14 -31
  221. ksadk/runners/base_runner.py +44 -3
  222. ksadk/runners/factory.py +3 -3
  223. ksadk/runners/langgraph_runner.py +252 -433
  224. ksadk/runners/utils/__init__.py +0 -10
  225. ksadk/runners/utils/loader.py +16 -0
  226. ksadk/runtime/__init__.py +67 -41
  227. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  228. ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
  229. ksadk/runtime/adapter.py +199 -16
  230. ksadk/runtime/conversation_execution.py +687 -0
  231. ksadk/runtime/executor.py +392 -0
  232. ksadk/runtime/factory.py +342 -0
  233. ksadk/runtime/framework_adapters.py +6 -12
  234. ksadk/runtime/hosted_finalizer.py +268 -0
  235. ksadk/runtime/launch.py +61 -0
  236. ksadk/runtime/preprocessing.py +49 -14
  237. ksadk/runtime/runner_adapter.py +330 -391
  238. ksadk/runtime/runner_loading.py +36 -0
  239. ksadk/runtime/usage.py +33 -0
  240. ksadk/sandbox/backends/e2b.py +36 -3
  241. ksadk/server/__init__.py +39 -4
  242. ksadk/server/app.py +18 -492
  243. ksadk/server/composition.py +36 -2
  244. ksadk/server/factory.py +210 -149
  245. ksadk/server/routes/common.py +15 -46
  246. ksadk/server/routes/control.py +13 -9
  247. ksadk/server/routes/kernel_ingress.py +258 -0
  248. ksadk/server/routes/misc.py +10 -33
  249. ksadk/server/routes/models.py +14 -6
  250. ksadk/server/routes/openai_compat.py +129 -27
  251. ksadk/server/routes/projection.py +84 -16
  252. ksadk/server/routes/run.py +347 -460
  253. ksadk/server/routes/sessions.py +37 -40
  254. ksadk/server/routes/streaming.py +52 -7
  255. ksadk/server/routes/workspace.py +54 -21
  256. ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
  257. ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
  258. ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
  259. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  260. ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
  261. ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
  262. ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
  263. ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
  264. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
  265. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
  266. ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
  267. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
  268. ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
  269. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
  270. ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
  271. ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
  272. ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
  273. ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
  274. ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
  275. ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
  276. ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
  277. ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
  278. ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
  279. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
  280. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
  281. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
  282. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
  283. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
  284. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  285. ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
  286. ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
  287. ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
  288. ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
  289. ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
  290. ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
  291. ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
  292. ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
  293. ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
  294. ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
  295. ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
  296. ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
  297. ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
  298. ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
  299. ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
  300. ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
  301. ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
  302. ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
  303. ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
  304. ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
  305. ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
  306. ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
  307. ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
  308. ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
  309. ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
  310. ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
  311. ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
  312. ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
  313. ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
  314. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
  315. ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
  316. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
  317. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
  318. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
  319. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
  320. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
  321. ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
  322. ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
  323. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
  324. ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
  325. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
  326. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
  327. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
  328. ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
  329. ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
  330. ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
  331. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
  332. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
  333. ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
  334. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
  335. ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
  336. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
  337. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
  338. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
  339. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
  340. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
  341. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
  342. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
  343. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
  344. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
  345. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
  346. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
  347. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
  348. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
  349. ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
  350. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
  351. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
  352. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
  353. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
  354. ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
  355. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
  356. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
  357. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
  358. ksadk/server/static/index.html +2 -2
  359. ksadk/sessions/__init__.py +26 -9
  360. ksadk/sessions/_local_service_sync.py +688 -0
  361. ksadk/sessions/_local_tables.py +21 -0
  362. ksadk/sessions/_postgres_schema.py +305 -0
  363. ksadk/sessions/_postgres_tables.py +15 -0
  364. ksadk/sessions/base.py +80 -1
  365. ksadk/sessions/in_memory.py +53 -2
  366. ksadk/sessions/local_service.py +63 -604
  367. ksadk/sessions/postgres_service.py +58 -148
  368. ksadk/sessions/resilient.py +35 -1
  369. ksadk/skills/runtime/backends/e2b.py +1 -1
  370. ksadk/skills/service_client.py +13 -3
  371. ksadk/studio/__init__.py +5 -0
  372. ksadk/studio/agent_avatar_assets.py +120 -0
  373. ksadk/studio/agent_lifecycle.py +51 -0
  374. ksadk/studio/api.py +1598 -0
  375. ksadk/studio/api_catalog_routes.py +324 -0
  376. ksadk/studio/api_contracts.py +286 -0
  377. ksadk/studio/api_helpers.py +132 -0
  378. ksadk/studio/api_memory_routes.py +82 -0
  379. ksadk/studio/authoring.py +749 -0
  380. ksadk/studio/authoring_coordinator.py +1017 -0
  381. ksadk/studio/builder.py +397 -0
  382. ksadk/studio/capabilities.py +368 -0
  383. ksadk/studio/cloud.py +2099 -0
  384. ksadk/studio/codex_agent_service.py +694 -0
  385. ksadk/studio/codex_authoring.py +469 -0
  386. ksadk/studio/codex_builder.py +437 -0
  387. ksadk/studio/codex_manifest.py +307 -0
  388. ksadk/studio/codex_run.py +395 -0
  389. ksadk/studio/compiler.py +190 -0
  390. ksadk/studio/contracts.py +755 -0
  391. ksadk/studio/errors.py +47 -0
  392. ksadk/studio/event_store.py +214 -0
  393. ksadk/studio/framework_run.py +342 -0
  394. ksadk/studio/hosted_kernel.py +317 -0
  395. ksadk/studio/identifiers.py +33 -0
  396. ksadk/studio/manifest_resolver.py +131 -0
  397. ksadk/studio/mcp_runtime.py +229 -0
  398. ksadk/studio/model_client.py +629 -0
  399. ksadk/studio/model_profile_service.py +214 -0
  400. ksadk/studio/operations.py +275 -0
  401. ksadk/studio/otel_trace.py +1060 -0
  402. ksadk/studio/pagination.py +182 -0
  403. ksadk/studio/pcm_memory.py +85 -0
  404. ksadk/studio/python_tool_inspection.py +183 -0
  405. ksadk/studio/repository.py +327 -0
  406. ksadk/studio/resource_catalog.py +1260 -0
  407. ksadk/studio/run_service.py +1133 -0
  408. ksadk/studio/runtime_catalog.py +74 -0
  409. ksadk/studio/runtime_source.py +365 -0
  410. ksadk/studio/service.py +2249 -0
  411. ksadk/studio/shared_web.py +1004 -0
  412. ksadk/studio/skill_discovery.py +628 -0
  413. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  414. ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
  415. ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
  416. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  417. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  418. ksadk/studio/static/index.html +15 -0
  419. ksadk/studio/templates.py +722 -0
  420. ksadk/studio/validator.py +265 -0
  421. ksadk/studio/workspace.py +135 -0
  422. ksadk/tools/gateway.py +9 -0
  423. ksadk/toolsets/__init__.py +27 -1
  424. ksadk/toolsets/a2a.py +426 -0
  425. ksadk/tracing/__init__.py +19 -21
  426. ksadk/tracing/setup.py +317 -403
  427. ksadk/tracing/span_utils.py +0 -44
  428. ksadk/version.py +1 -1
  429. ksadk_runtime_common/memory_backend/registry.py +56 -56
  430. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  431. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  432. ksadk_runtime_common/workspace_files/router.py +8 -2
  433. agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
  434. ksadk/a2a/card_builder.py +0 -64
  435. ksadk/a2a/client.py +0 -309
  436. ksadk/events/parser.py +0 -191
  437. ksadk/harness/runner.py +0 -211
  438. ksadk/runners/codex_runner.py +0 -132
  439. ksadk/runners/utils/langfuse.py +0 -230
  440. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  441. ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
  442. ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
  443. ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
  444. ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
  445. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
  446. ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
  447. ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
  448. ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
  449. ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
  450. ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
  451. ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
  452. ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
  453. ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
  454. ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
  455. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
  456. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  457. ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
  458. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  459. ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
  460. ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
  461. ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
  462. ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
  463. ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
  464. ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
  465. ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
  466. ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
  467. ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
  468. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
  469. ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
  470. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
  471. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  472. ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
  473. ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
  474. ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
  475. ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
  476. ksadk/server/static/assets/katex-DATssjp1.js +0 -265
  477. ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
  478. ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
  479. ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
  480. ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
  481. ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
  482. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
  483. ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
  484. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
  485. ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
  486. ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
  487. ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
  488. ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
  489. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
  490. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
  491. ksadk/tracing/exporters/langfuse_exporter.py +0 -460
  492. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
  493. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
  494. {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,95 @@
1
+ """SQLite 长期记忆后端 — 持久化 LTM(适配 BaseLongTermMemoryBackend 接口)。
2
+
3
+ 用 ``SqliteMemoryProvider`` 的持久 SQLite 路径,解决 ``InMemoryLTMBackend`` 进程退出后
4
+ 数据丢失、每次新实例数据不延续的问题。recall 和 flush 共用同一 SQLite 文件。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import logging
11
+ from typing import List
12
+
13
+ from pydantic import PrivateAttr
14
+
15
+ from ksadk.memory.adk.backends.base_ltm_backend import BaseLongTermMemoryBackend
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class SqliteLTMBackend(BaseLongTermMemoryBackend):
21
+ """SQLite 持久长期记忆后端。
22
+
23
+ 使用 ``SqliteMemoryProvider`` 的持久化路径(``KSADK_MEMORY_DB_PATH`` 或本地 session dir),
24
+ 通过 ``MemoryCoordinator`` 做检索。recall 和 flush 共用同一文件,数据跨进程延续。
25
+
26
+ 适配 ``BaseLongTermMemoryBackend`` 接口(save_memory/search_memory),供
27
+ ``LongTermMemoryService`` 的 "local" backend 使用。
28
+ """
29
+
30
+ _provider: object = PrivateAttr(default=None)
31
+
32
+ def model_post_init(self, __context) -> None:
33
+ from ksadk.memory.providers.local_sqlite import (
34
+ SqliteMemoryProvider,
35
+ _resolve_default_db_path,
36
+ )
37
+
38
+ path = _resolve_default_db_path()
39
+ self._provider = SqliteMemoryProvider(db_path=path, tenant_id="local", workspace_id="local")
40
+ logger.info("SqliteLTMBackend initialized: index=%s, db=%s", self.index, path)
41
+
42
+ def save_memory(self, user_id: str, event_strings: List[str], **kwargs) -> bool:
43
+ """保存记忆到持久 SQLite。"""
44
+ if not event_strings:
45
+ return True
46
+ for event_str in event_strings:
47
+ try:
48
+ payload = json.loads(event_str)
49
+ content = str(payload.get("parts", [{}])[0].get("text", "") or event_str)
50
+ except (json.JSONDecodeError, TypeError, IndexError):
51
+ content = event_str
52
+ from ksadk.memory.models import MemoryCandidate
53
+
54
+ candidate = MemoryCandidate(
55
+ candidate_id=f"ltm_{abs(hash(content)) % 10**16}",
56
+ operation="add",
57
+ memory_type="profile",
58
+ scope="user",
59
+ scope_id=user_id,
60
+ content=content,
61
+ confidence=0.9,
62
+ importance=0.7,
63
+ source_event_ids=[],
64
+ reason="explicit_user_request",
65
+ )
66
+ from ksadk.memory.coordinator import MemoryCoordinator
67
+
68
+ coordinator = MemoryCoordinator(self._provider)
69
+ coordinator.flush_candidates([candidate])
70
+ return True
71
+
72
+ def search_memory(self, user_id: str, query: str, top_k: int = 5, **kwargs) -> List[str]:
73
+ """从持久 SQLite 检索记忆。"""
74
+ from ksadk.memory.coordinator import MemoryCoordinator, build_search_request
75
+
76
+ coordinator = MemoryCoordinator(self._provider)
77
+ request = build_search_request(query=query, user_id=user_id, top_k=top_k)
78
+ result = coordinator.recall(request)
79
+ if result.status != "ok":
80
+ return []
81
+ entries: list[str] = []
82
+ for record in result.records:
83
+ entries.append(
84
+ json.dumps(
85
+ {
86
+ "parts": [{"text": record.content}],
87
+ "metadata": {"memory_id": record.memory_id},
88
+ },
89
+ ensure_ascii=False,
90
+ )
91
+ )
92
+ return entries
93
+
94
+
95
+ __all__ = ["SqliteLTMBackend"]
@@ -246,8 +246,9 @@ class LongTermMemory(BaseMemoryService, BaseModel):
246
246
  KSADK_LTM_BACKEND: local / http / sdk
247
247
  KSADK_LTM_HTTP_URL: HTTP 记忆服务地址
248
248
  KSADK_LTM_HTTP_TOKEN: HTTP 认证 Token
249
- KSADK_LTM_ACCESS_KEY: SDK AK (fallback to KSYUN_ACCESS_KEY)
250
- KSADK_LTM_SECRET_KEY: SDK SK (fallback to KSYUN_SECRET_KEY)
249
+ KSADK_LTM_ACCESS_KEY: SDK AK (fallback to KSYUN_ACCESS_KEY / KSYUN_ACCESS_KEY_ID)
250
+ KSADK_LTM_SECRET_KEY: SDK SK (fallback to KSYUN_SECRET_KEY / KSYUN_SECRET_ACCESS_KEY)
251
+ KSADK_LTM_SESSION_TOKEN: SDK STS token (fallback to KSYUN_SESSION_TOKEN)
251
252
  KSADK_LTM_TOP_K: 检索数量 (默认 5)
252
253
  KSADK_LTM_INDEX: 索引名称
253
254
  """
@@ -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
+ ]