agentengine-sdk-python 0.8.1__py3-none-any.whl → 0.8.3__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 (476) hide show
  1. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +25 -12
  2. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +421 -232
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/a2a/_space_client_events.py +381 -0
  5. ksadk/a2a/event_adapter.py +156 -64
  6. ksadk/a2a/executor.py +179 -63
  7. ksadk/a2a/space_client.py +6 -333
  8. ksadk/a2ui/core.py +222 -53
  9. ksadk/agui/_agent_helpers.py +247 -0
  10. ksadk/agui/a2ui_projection.py +12 -5
  11. ksadk/agui/agent.py +443 -259
  12. ksadk/api/client.py +528 -27
  13. ksadk/builders/code_builder.py +284 -8
  14. ksadk/builders/container_builder.py +8 -1
  15. ksadk/builders/managed_runtime_builder.py +42 -35
  16. ksadk/cli/__init__.py +23 -0
  17. ksadk/cli/cmd_dashboard.py +15 -1
  18. ksadk/cli/cmd_deploy.py +10 -2
  19. ksadk/cli/cmd_eval.py +66 -9
  20. ksadk/cli/cmd_evalset.py +284 -0
  21. ksadk/cli/cmd_files.py +5 -1
  22. ksadk/cli/cmd_hermes.py +1 -126
  23. ksadk/cli/cmd_invoke.py +28 -38
  24. ksadk/cli/cmd_managed_runtime.py +95 -0
  25. ksadk/cli/cmd_observe.py +85 -0
  26. ksadk/cli/cmd_openclaw.py +1 -435
  27. ksadk/cli/cmd_plugin.py +657 -0
  28. ksadk/cli/cmd_replay.py +28 -4
  29. ksadk/cli/cmd_studio.py +99 -8
  30. ksadk/cli/cmd_web.py +10 -2
  31. ksadk/cli/hermes_env.py +151 -0
  32. ksadk/cli/invoke_payload.py +49 -0
  33. ksadk/cli/openclaw_env.py +458 -0
  34. ksadk/codex/client.py +180 -30
  35. ksadk/codex/runtime.py +475 -331
  36. ksadk/configs/env_registry.py +94 -12
  37. ksadk/configs/env_registry_pcm.py +181 -0
  38. ksadk/configs/env_var_spec.py +18 -0
  39. ksadk/configs/global_config.py +5 -0
  40. ksadk/configs/settings.py +9 -0
  41. ksadk/context_engine/__init__.py +98 -0
  42. ksadk/context_engine/assembler.py +176 -0
  43. ksadk/context_engine/baseline.py +419 -0
  44. ksadk/context_engine/cache_observability.py +228 -0
  45. ksadk/context_engine/capabilities.py +443 -0
  46. ksadk/context_engine/contributors.py +409 -0
  47. ksadk/context_engine/hosted_pipeline.py +417 -0
  48. ksadk/context_engine/models.py +117 -0
  49. ksadk/context_engine/planner.py +698 -0
  50. ksadk/context_engine/policies.py +319 -0
  51. ksadk/context_engine/projection.py +31 -0
  52. ksadk/context_engine/shadow_plan.py +266 -0
  53. ksadk/context_engine/tokenizer.py +164 -0
  54. ksadk/conversations/__init__.py +19 -0
  55. ksadk/conversations/context.py +230 -30
  56. ksadk/conversations/contracts.py +266 -0
  57. ksadk/conversations/message_projection.py +308 -26
  58. ksadk/conversations/model_context.py +49 -3
  59. ksadk/conversations/projector.py +616 -0
  60. ksadk/conversations/reducer.py +98 -0
  61. ksadk/conversations/runtime_compaction.py +207 -5
  62. ksadk/conversations/runtime_input.py +184 -2
  63. ksadk/conversations/runtime_invocation.py +81 -3
  64. ksadk/conversations/runtime_observability.py +141 -0
  65. ksadk/conversations/runtime_payloads.py +42 -0
  66. ksadk/conversations/runtime_preparation.py +272 -2
  67. ksadk/conversations/runtime_resume.py +20 -1
  68. ksadk/conversations/runtime_stream_events.py +94 -9
  69. ksadk/conversations/semantic_summary.py +311 -1
  70. ksadk/conversations/session_lock.py +51 -0
  71. ksadk/deployment/env_forward.py +72 -0
  72. ksadk/deployment/managed_runtime.py +5 -0
  73. ksadk/deployment/providers/serverless.py +143 -69
  74. ksadk/evaluation/__init__.py +32 -0
  75. ksadk/evaluation/a2a_adapter.py +9 -1
  76. ksadk/evaluation/adapters.py +18 -5
  77. ksadk/evaluation/agent_eval_client.py +395 -0
  78. ksadk/evaluation/cloud_binding.py +80 -0
  79. ksadk/evaluation/cloud_converter.py +194 -0
  80. ksadk/evaluation/cloud_service.py +199 -0
  81. ksadk/evaluation/contracts.py +73 -4
  82. ksadk/evaluation/evaluators.py +183 -17
  83. ksadk/evaluation/evidence.py +258 -0
  84. ksadk/evaluation/executor.py +31 -6
  85. ksadk/evaluation/local_adapter.py +550 -0
  86. ksadk/evaluation/service_env.py +27 -0
  87. ksadk/evaluation/studio_build_adapter.py +253 -0
  88. ksadk/evaluation/target.py +15 -6
  89. ksadk/events/__init__.py +13 -13
  90. ksadk/events/_v1_compat/__init__.py +1 -0
  91. ksadk/events/_v1_compat/models.py +299 -0
  92. ksadk/events/_v1_compat/parser.py +247 -0
  93. ksadk/events/_v1_compat/projection.py +755 -0
  94. ksadk/events/adapters/__init__.py +34 -0
  95. ksadk/events/adapters/_a2a_snapshot.py +622 -0
  96. ksadk/events/adapters/_a2a_support.py +275 -0
  97. ksadk/events/adapters/_codex_interactions.py +375 -0
  98. ksadk/events/adapters/_codex_items.py +801 -0
  99. ksadk/events/adapters/_codex_validators.py +311 -0
  100. ksadk/events/adapters/_langgraph_support.py +785 -0
  101. ksadk/events/adapters/a2a.py +841 -0
  102. ksadk/events/adapters/adk.py +503 -0
  103. ksadk/events/adapters/codex.py +907 -0
  104. ksadk/events/adapters/langgraph.py +745 -0
  105. ksadk/events/canonical.py +440 -0
  106. ksadk/events/canonical_replay.py +497 -0
  107. ksadk/events/canonical_store.py +468 -0
  108. ksadk/events/cold_recovery.py +257 -0
  109. ksadk/events/content.py +89 -0
  110. ksadk/events/identity.py +86 -0
  111. ksadk/events/pipeline.py +455 -0
  112. ksadk/events/projections.py +66 -0
  113. ksadk/events/reducer.py +661 -0
  114. ksadk/events/replay.py +3 -36
  115. ksadk/events/runtime_event.py +20 -265
  116. ksadk/events/session_event.py +324 -0
  117. ksadk/events/store.py +3 -316
  118. ksadk/events/v1_compat.py +41 -0
  119. ksadk/harness/__init__.py +45 -35
  120. ksadk/harness/runtime.py +220 -58
  121. ksadk/identity/resolver.py +4 -3
  122. ksadk/interaction/__init__.py +28 -0
  123. ksadk/interaction/contracts.py +136 -0
  124. ksadk/interaction/ledger.py +189 -0
  125. ksadk/interaction/provider.py +122 -0
  126. ksadk/interaction/providers/__init__.py +52 -0
  127. ksadk/interaction/providers/adk.py +40 -0
  128. ksadk/interaction/providers/codex.py +94 -0
  129. ksadk/interaction/providers/langgraph.py +58 -0
  130. ksadk/kernel/__init__.py +117 -0
  131. ksadk/kernel/authorization.py +258 -0
  132. ksadk/kernel/bootstrap.py +1074 -0
  133. ksadk/kernel/contract_fingerprints.py +62 -0
  134. ksadk/kernel/contracts.py +370 -0
  135. ksadk/kernel/control.py +220 -0
  136. ksadk/kernel/errors.py +79 -0
  137. ksadk/kernel/ingress.py +1123 -0
  138. ksadk/kernel/mapping.py +111 -0
  139. ksadk/kernel/memory_store.py +1134 -0
  140. ksadk/kernel/postgres_store.py +1757 -0
  141. ksadk/kernel/recovery.py +452 -0
  142. ksadk/kernel/runtime_identity.py +103 -0
  143. ksadk/kernel/sql/001_agent_kernel.sql +120 -0
  144. ksadk/kernel/sqlite_store.py +1411 -0
  145. ksadk/kernel/state.py +145 -0
  146. ksadk/kernel/store.py +232 -0
  147. ksadk/kernel/worker.py +964 -0
  148. ksadk/knowledge_base/client.py +7 -0
  149. ksadk/knowledge_base/service.py +32 -5
  150. ksadk/memory/__init__.py +61 -0
  151. ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
  152. ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
  153. ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
  154. ksadk/memory/adk/backends/sdk_ltm_backend.py +384 -2
  155. ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
  156. ksadk/memory/coordinator.py +461 -0
  157. ksadk/memory/events.py +202 -0
  158. ksadk/memory/extraction.py +228 -0
  159. ksadk/memory/ltm_backend_factory.py +16 -3
  160. ksadk/memory/models.py +316 -0
  161. ksadk/memory/policy.py +215 -0
  162. ksadk/memory/provider.py +47 -0
  163. ksadk/memory/provider_adapter.py +159 -0
  164. ksadk/memory/provider_resolver.py +71 -0
  165. ksadk/memory/providers/__init__.py +5 -0
  166. ksadk/memory/providers/local_sqlite.py +497 -0
  167. ksadk/memory/resolved_policy.py +145 -0
  168. ksadk/memory/service.py +188 -6
  169. ksadk/model_proxy/bootstrap.py +16 -9
  170. ksadk/model_proxy/detect.py +202 -9
  171. ksadk/model_proxy/namespace.py +39 -15
  172. ksadk/model_proxy/server.py +24 -5
  173. ksadk/model_proxy/transform.py +60 -2
  174. ksadk/observability/__init__.py +25 -0
  175. ksadk/observability/session_log.py +420 -0
  176. ksadk/observability/trajectory.py +105 -0
  177. ksadk/plugins/__init__.py +167 -0
  178. ksadk/plugins/bridges/__init__.py +45 -0
  179. ksadk/plugins/bridges/codex.py +552 -0
  180. ksadk/plugins/bridges/dsh.py +1116 -0
  181. ksadk/plugins/builtins.py +747 -0
  182. ksadk/plugins/bundle.py +246 -0
  183. ksadk/plugins/bundle_security.py +167 -0
  184. ksadk/plugins/composition.py +529 -0
  185. ksadk/plugins/context_contributor.py +437 -0
  186. ksadk/plugins/contracts.py +451 -0
  187. ksadk/plugins/dsh_toolchain.py +935 -0
  188. ksadk/plugins/ecosystem_bridge.py +1105 -0
  189. ksadk/plugins/ecosystem_probe.py +191 -0
  190. ksadk/plugins/host.py +724 -0
  191. ksadk/plugins/providers/__init__.py +85 -0
  192. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  193. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  194. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  195. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  196. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  197. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  198. ksadk/plugins/providers/codex.py +722 -0
  199. ksadk/plugins/providers/codex_dsh.py +83 -0
  200. ksadk/plugins/providers/dsh.py +951 -0
  201. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  202. ksadk/plugins/providers/harness.py +627 -0
  203. ksadk/plugins/providers/harness_dsh.py +91 -0
  204. ksadk/plugins/providers/legacy.py +215 -0
  205. ksadk/plugins/providers/legacy_catalog.py +100 -0
  206. ksadk/plugins/providers/shipped_dsh.py +370 -0
  207. ksadk/plugins/resolver.py +331 -0
  208. ksadk/plugins/subagent_providers/__init__.py +12 -0
  209. ksadk/plugins/subagent_providers/codex.py +443 -0
  210. ksadk/plugins/subagents.py +333 -0
  211. ksadk/prompts/__init__.py +71 -0
  212. ksadk/prompts/compiler.py +215 -0
  213. ksadk/prompts/models.py +82 -0
  214. ksadk/prompts/projection.py +89 -0
  215. ksadk/prompts/resolved.py +137 -0
  216. ksadk/prompts/sources.py +233 -0
  217. ksadk/runners/_langgraph_runner_streams.py +822 -0
  218. ksadk/runners/adk_runner.py +5 -5
  219. ksadk/runners/base_runner.py +16 -0
  220. ksadk/runners/factory.py +1 -2
  221. ksadk/runners/langgraph_runner.py +198 -437
  222. ksadk/runtime/_runner_adapter/__init__.py +1 -0
  223. ksadk/runtime/_runner_adapter/stream_mapping.py +797 -0
  224. ksadk/runtime/adapter.py +119 -2
  225. ksadk/runtime/conversation_execution.py +316 -182
  226. ksadk/runtime/executor.py +144 -3
  227. ksadk/runtime/factory.py +268 -8
  228. ksadk/runtime/framework_adapters.py +18 -0
  229. ksadk/runtime/hosted_finalizer.py +268 -0
  230. ksadk/runtime/launch.py +14 -1
  231. ksadk/runtime/preprocessing.py +25 -3
  232. ksadk/runtime/runner_adapter.py +293 -508
  233. ksadk/runtime/usage.py +33 -0
  234. ksadk/sandbox/__init__.py +2 -1
  235. ksadk/sandbox/backends/e2b.py +35 -2
  236. ksadk/sandbox/factory.py +72 -0
  237. ksadk/scheduler/__init__.py +18 -0
  238. ksadk/scheduler/calendar.py +102 -0
  239. ksadk/scheduler/contracts.py +254 -0
  240. ksadk/scheduler/dispatcher.py +129 -0
  241. ksadk/scheduler/engine.py +416 -0
  242. ksadk/scheduler/sqlite_store.py +563 -0
  243. ksadk/server/composition.py +8 -0
  244. ksadk/server/factory.py +69 -6
  245. ksadk/server/routes/kernel_ingress.py +258 -0
  246. ksadk/server/routes/openai_compat.py +88 -8
  247. ksadk/server/routes/projection.py +35 -20
  248. ksadk/server/routes/run.py +94 -0
  249. ksadk/server/routes/sessions.py +2 -0
  250. ksadk/server/routes/streaming.py +5 -2
  251. ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
  252. ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-BXk1l-G1.js} +4 -4
  253. ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
  254. ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.js → MathMessageMarkdown-D9uB55Oh.js} +4 -4
  255. ksadk/server/static/assets/MermaidBlock--OEYoXIJ.js +312 -0
  256. ksadk/server/static/assets/NativeTerminalPanel-DrEe1syq.js +1 -0
  257. ksadk/server/static/assets/abnfDiagram-VCTEODGH-eeTFJLvo.js +1 -0
  258. ksadk/server/static/assets/arc-S3ZNbIAd.js +1 -0
  259. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
  260. ksadk/server/static/assets/architectureDiagram-5GKGNRK7-CRjgEJDX.js +36 -0
  261. ksadk/server/static/assets/blockDiagram-NRAW4CY4-C7bsBoNH.js +129 -0
  262. ksadk/server/static/assets/c4Diagram-UCG6FXSJ-BX3c33Ob.js +38 -0
  263. ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
  264. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
  265. ksadk/server/static/assets/{chunk-FMBD7UC4-B_fH2YuH.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
  266. ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
  267. ksadk/server/static/assets/chunk-G27WJ6UU-CZwF3oUP.js +231 -0
  268. ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
  269. ksadk/server/static/assets/chunk-LCL6LL3I-CnorGV5q.js +206 -0
  270. ksadk/server/static/assets/chunk-POPQ4Y6H-CexntQA-.js +1 -0
  271. ksadk/server/static/assets/chunk-RHFEMEQ7-CHTC7UxA.js +168 -0
  272. ksadk/server/static/assets/chunk-SVP7TREG-BC1EWt_-.js +88 -0
  273. ksadk/server/static/assets/chunk-XXDRQBXY-BTG24xN0.js +1 -0
  274. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
  275. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
  276. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-ChNs_Mdk.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
  277. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
  278. ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-DEOCBe15.js +62 -0
  279. ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
  280. ksadk/server/static/assets/dagre-3AP2YEHR-DBThPuLa.js +4 -0
  281. ksadk/server/static/assets/dagre-ClTPrTht.js +1 -0
  282. ksadk/server/static/assets/diagram-S7CK7UJ4-DsZHrnpJ.js +30 -0
  283. ksadk/server/static/assets/diagram-UQ7AKVKN-BJR4nhVr.js +41 -0
  284. ksadk/server/static/assets/diagram-VSXAHHWV-xzcERX0a.js +3 -0
  285. ksadk/server/static/assets/diagram-VX7I27RA-tn2xM1xu.js +24 -0
  286. ksadk/server/static/assets/diagram-Z3DM3KII-BZPGBkw5.js +24 -0
  287. ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-4zN1_tq5.js} +1 -1
  288. ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-8VWI-2bZ.js} +1 -1
  289. ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-B-46q3Hk.js} +1 -1
  290. ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-B0gdk4rl.js} +1 -1
  291. ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-B1oWRmrH.js} +1 -1
  292. ksadk/server/static/assets/{dist-CmZHzlwZ.js → dist-BI1qQH4n.js} +1 -1
  293. ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-BJLUwH6W.js} +1 -1
  294. ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Bbwqa8TG.js} +1 -1
  295. ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-Btyo4vX4.js} +1 -1
  296. ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-C71CsujO.js} +1 -1
  297. ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-CXpH_Rdd.js} +1 -1
  298. ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-Cq4OL6nO.js} +1 -1
  299. ksadk/server/static/assets/{dist-Dli7qW-B.js → dist-D1V3f1B4.js} +1 -1
  300. ksadk/server/static/assets/{dist-fhOuWds5.js → dist-DJmCPRVB.js} +1 -1
  301. ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DQAB0qn_.js} +2 -2
  302. ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DUwKa_l6.js} +1 -1
  303. ksadk/server/static/assets/dist-DdRBIceA.js +1 -0
  304. ksadk/server/static/assets/{dist-DWKByxWV.js → dist-DfGFrb0v.js} +1 -1
  305. ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-DjhwGUgZ.js} +1 -1
  306. ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-DyqV4fL4.js} +1 -1
  307. ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-M67Hwu0n.js} +1 -1
  308. ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-u8tVH5Ak.js} +1 -1
  309. ksadk/server/static/assets/ebnfDiagram-PWID7BFC-DVfMsLge.js +1 -0
  310. ksadk/server/static/assets/erDiagram-SSCWMZ5O-CWEZSYaw.js +99 -0
  311. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
  312. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
  313. ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-TWIxoyYL.js +292 -0
  314. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
  315. ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-DDh2hd2S.js +106 -0
  316. ksadk/server/static/assets/index-B2k_urY8.js +241 -0
  317. ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
  318. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
  319. ksadk/server/static/assets/infoDiagram-RXCK75RN-CgoyWiDR.js +2 -0
  320. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-K0OOfVna.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +6 -6
  321. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +6 -6
  322. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-CNP3ui66.js} +10 -10
  323. ksadk/server/static/assets/katex-DWEzQy1d.js +257 -0
  324. ksadk/server/static/assets/{linear-hdBcYzM8.js → linear-C-qHp7d2.js} +1 -1
  325. ksadk/server/static/assets/mermaid-parser.core-Cl-K943T.js +166 -0
  326. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-Bjy_2v4_.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +29 -29
  327. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
  328. ksadk/server/static/assets/pegDiagram-XKGWAZYB-BQVc9ia_.js +1 -0
  329. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
  330. ksadk/server/static/assets/pieDiagram-E7YTZNPT-B6UCAvtY.js +39 -0
  331. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-BmkRbwCg.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +6 -6
  332. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
  333. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
  334. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
  335. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
  336. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
  337. ksadk/server/static/assets/railroadDiagram-O6MQD6OU-Dt3FFDmK.js +1 -0
  338. ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-Cz_vQtgF.js +84 -0
  339. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-l6iXmU65.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +7 -7
  340. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +10 -10
  341. ksadk/server/static/assets/sizeCapture-X5ZJPWSS-DXX54iyO.js +1 -0
  342. ksadk/server/static/assets/stateDiagram-HBIQ2CUA-Dp_lw9II.js +1 -0
  343. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
  344. ksadk/server/static/assets/swimlanes-XN3QIQJK-D8O5UlLG.js +1 -0
  345. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
  346. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-DEz24vV0.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +7 -7
  347. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
  348. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
  349. ksadk/server/static/assets/vennDiagram-4TSXK5OY-EnNl0DE7.js +34 -0
  350. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
  351. ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DBu5fbYr.js +78 -0
  352. ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-BSVXs4IY.js +7 -0
  353. ksadk/server/static/index.html +2 -2
  354. ksadk/sessions/__init__.py +26 -9
  355. ksadk/sessions/_local_service_sync.py +688 -0
  356. ksadk/sessions/_local_tables.py +21 -0
  357. ksadk/sessions/_postgres_schema.py +305 -0
  358. ksadk/sessions/_postgres_tables.py +15 -0
  359. ksadk/sessions/base.py +80 -1
  360. ksadk/sessions/in_memory.py +53 -2
  361. ksadk/sessions/local_service.py +63 -604
  362. ksadk/sessions/postgres_service.py +58 -148
  363. ksadk/sessions/resilient.py +35 -1
  364. ksadk/skills/service_client.py +48 -0
  365. ksadk/studio/agent_lifecycle.py +26 -20
  366. ksadk/studio/api.py +1063 -69
  367. ksadk/studio/api_catalog_routes.py +5 -0
  368. ksadk/studio/api_contracts.py +148 -6
  369. ksadk/studio/api_memory_routes.py +82 -0
  370. ksadk/studio/api_plugin_routes.py +480 -0
  371. ksadk/studio/attachment_store.py +187 -0
  372. ksadk/studio/authoring.py +259 -28
  373. ksadk/studio/authoring_coordinator.py +809 -67
  374. ksadk/studio/builder.py +197 -40
  375. ksadk/studio/capabilities.py +17 -0
  376. ksadk/studio/cloud.py +1920 -95
  377. ksadk/studio/codex_agent_service.py +137 -15
  378. ksadk/studio/codex_authoring.py +469 -0
  379. ksadk/studio/codex_builder.py +177 -25
  380. ksadk/studio/codex_manifest.py +71 -22
  381. ksadk/studio/codex_run.py +59 -4
  382. ksadk/studio/compatibility_report.py +445 -0
  383. ksadk/studio/compiler.py +7 -1
  384. ksadk/studio/contracts.py +234 -4
  385. ksadk/studio/dsh_provider_registration.py +768 -0
  386. ksadk/studio/event_store.py +79 -101
  387. ksadk/studio/framework_run.py +264 -3
  388. ksadk/studio/hosted_kernel.py +317 -0
  389. ksadk/studio/manifest_resolver.py +131 -0
  390. ksadk/studio/model_client.py +95 -9
  391. ksadk/studio/model_profile_service.py +1 -1
  392. ksadk/studio/operations.py +47 -5
  393. ksadk/studio/otel_trace.py +348 -42
  394. ksadk/studio/pcm_memory.py +85 -0
  395. ksadk/studio/plugin_composition.py +301 -0
  396. ksadk/studio/plugin_kernel_adapter.py +128 -0
  397. ksadk/studio/plugin_runtime.py +652 -0
  398. ksadk/studio/repository.py +23 -2
  399. ksadk/studio/resource_catalog.py +49 -1
  400. ksadk/studio/run_service.py +1266 -202
  401. ksadk/studio/runtime_source.py +51 -17
  402. ksadk/studio/scheduler_runtime.py +374 -0
  403. ksadk/studio/scheduler_service.py +211 -0
  404. ksadk/studio/service.py +1815 -117
  405. ksadk/studio/shared_web.py +199 -50
  406. ksadk/studio/soul.py +52 -0
  407. ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
  408. ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
  409. ksadk/studio/static/index.html +2 -2
  410. ksadk/studio/templates.py +100 -8
  411. ksadk/studio/validator.py +20 -1
  412. ksadk/studio/workspace.py +31 -32
  413. ksadk/tracing/setup.py +304 -3
  414. ksadk/version.py +1 -1
  415. ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
  416. ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
  417. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  418. ksadk/events/parser.py +0 -191
  419. ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
  420. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
  421. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
  422. ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
  423. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
  424. ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
  425. ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
  426. ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
  427. ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
  428. ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
  429. ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
  430. ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
  431. ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
  432. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
  435. ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
  436. ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
  437. ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
  438. ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
  439. ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
  440. ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
  441. ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
  442. ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
  443. ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
  444. ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
  445. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
  446. ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
  447. ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
  448. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
  449. ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
  450. ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
  451. ksadk/server/static/assets/index-R52pJJvg.js +0 -177
  452. ksadk/server/static/assets/index-jJr3_955.css +0 -2
  453. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
  454. ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
  455. ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
  456. ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
  457. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
  458. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
  459. ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
  460. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
  461. ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
  462. ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
  463. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
  464. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
  465. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
  466. ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
  467. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
  468. ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
  469. ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
  470. ksadk/studio/evaluation.py +0 -192
  471. ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
  472. ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
  473. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
  474. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
  475. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
  476. {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.3.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
+ ]