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
ksadk/studio/errors.py ADDED
@@ -0,0 +1,47 @@
1
+ """Stable errors shared by the Studio service and HTTP API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ class StudioError(Exception):
9
+ """A user-safe error with a stable machine-readable code."""
10
+
11
+ def __init__(
12
+ self,
13
+ code: str,
14
+ message: str,
15
+ *,
16
+ status_code: int = 400,
17
+ field: str | None = None,
18
+ details: dict[str, Any] | None = None,
19
+ ) -> None:
20
+ super().__init__(message)
21
+ self.code = code
22
+ self.message = message
23
+ self.status_code = status_code
24
+ self.field = field
25
+ self.details = details or {}
26
+
27
+ def as_dict(self, *, request_id: str | None = None) -> dict[str, Any]:
28
+ payload: dict[str, Any] = {
29
+ "code": self.code,
30
+ "message": self.message,
31
+ }
32
+ if self.field:
33
+ payload["field"] = self.field
34
+ if self.details:
35
+ payload["details"] = self.details
36
+ if request_id:
37
+ payload["requestId"] = request_id
38
+ return {"error": payload}
39
+
40
+
41
+ def not_found(resource: str, resource_id: str) -> StudioError:
42
+ return StudioError(
43
+ f"{resource.upper()}_NOT_FOUND",
44
+ f"{resource} 不存在",
45
+ status_code=404,
46
+ details={"id": resource_id},
47
+ )
@@ -0,0 +1,214 @@
1
+ """Persistent local Run record store and derived trace access."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import shutil
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from pydantic import ValidationError
12
+
13
+ from ksadk.studio.contracts import RunEvent, RunRecord
14
+ from ksadk.studio.errors import StudioError, not_found
15
+ from ksadk.studio.otel_trace import OtlpTraceStore
16
+ from ksadk.studio.workspace import Workspace
17
+
18
+
19
+ class RunEventStore:
20
+ def __init__(self, workspace: Workspace) -> None:
21
+ self.workspace = workspace
22
+ self.trace_store = OtlpTraceStore(workspace)
23
+
24
+ def _path(self, run_id: str) -> Path:
25
+ return self.workspace.resolve(Path(".agentkit/runs") / f"{run_id}.json")
26
+
27
+ def create(self, record: RunRecord) -> RunRecord:
28
+ path = self._path(record.id)
29
+ if path.exists():
30
+ raise StudioError("RUN_ALREADY_EXISTS", "Run 已存在", status_code=409)
31
+ self._write(record)
32
+ return record
33
+
34
+ def save(self, record: RunRecord) -> RunRecord:
35
+ _, events = self._read(record.id)
36
+ self._write(record, events or None)
37
+ return record
38
+
39
+ def append(self, run_id: str, event_type: str, data: dict) -> RunEvent:
40
+ """Persist a Studio lifecycle RunEvent (run.created, memory.recall.projected, …).
41
+
42
+ These Studio-level events (as opposed to RuntimeEvents) are durably
43
+ stored in the run JSON so the Studio events timeline survives restarts.
44
+ Runs that never call ``append`` keep ``set(run_payload) == {"record"}``.
45
+ """
46
+ record, events = self._read(run_id)
47
+ event = RunEvent(
48
+ id=len(events) + 1,
49
+ run_id=run_id,
50
+ type=event_type,
51
+ data=data,
52
+ )
53
+ events.append(event)
54
+ self._write(record, events)
55
+ return event
56
+
57
+ def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
58
+ _, events = self._read(run_id)
59
+ return [event for event in events if event.id > after]
60
+
61
+ def get(self, run_id: str) -> RunRecord:
62
+ record, _ = self._read(run_id)
63
+ return record
64
+
65
+ def list_runs(
66
+ self,
67
+ *,
68
+ session_id: str | None = None,
69
+ agent_id: str | None = None,
70
+ ) -> list[RunRecord]:
71
+ records: list[RunRecord] = []
72
+ directory = self.workspace.resolve(".agentkit/runs")
73
+ for path in sorted(directory.glob("run_*.json")):
74
+ try:
75
+ payload = json.loads(path.read_text(encoding="utf-8"))
76
+ record = RunRecord.model_validate(payload["record"])
77
+ except (OSError, ValueError, KeyError, ValidationError):
78
+ continue
79
+ if session_id and record.session_id != session_id:
80
+ continue
81
+ if agent_id and record.agent_id != agent_id:
82
+ continue
83
+ records.append(record)
84
+ records.sort(
85
+ key=lambda item: (
86
+ item.started_at or item.completed_at or datetime.min.replace(tzinfo=timezone.utc)
87
+ ),
88
+ reverse=False,
89
+ )
90
+ return records
91
+
92
+ def delete_session(self, session_id: str) -> int:
93
+ """Delete every persisted run that belongs to one local chat session."""
94
+
95
+ deleted = 0
96
+ for record in self.list_runs(session_id=session_id):
97
+ path = self._path(record.id)
98
+ if path.is_file():
99
+ self.trace_store.delete(record.trace_id, purge=True)
100
+ path.unlink()
101
+ deleted += 1
102
+ return deleted
103
+
104
+ def delete_agent(
105
+ self,
106
+ agent_id: str,
107
+ *,
108
+ purge: bool,
109
+ trash_directory: Path | None = None,
110
+ ) -> int:
111
+ """Remove the persisted Runs and Trace events owned by one Agent."""
112
+
113
+ deleted = 0
114
+ for record in self.list_runs(agent_id=agent_id):
115
+ path = self._path(record.id)
116
+ if not path.is_file():
117
+ continue
118
+ if purge:
119
+ self.trace_store.delete(record.trace_id, purge=True)
120
+ path.unlink()
121
+ else:
122
+ if trash_directory is None:
123
+ raise ValueError("recoverable deletion requires a trash directory")
124
+ destination = self.workspace.resolve(trash_directory / "runs" / path.name)
125
+ destination.parent.mkdir(parents=True, exist_ok=True)
126
+ self.trace_store.delete(
127
+ record.trace_id,
128
+ purge=False,
129
+ trash_directory=trash_directory,
130
+ )
131
+ shutil.move(str(path), str(destination))
132
+ deleted += 1
133
+ return deleted
134
+
135
+ def trace(self, trace_id: str) -> dict:
136
+ return self.trace_store.get_trace_view(trace_id)
137
+
138
+ def trace_otlp(self, trace_id: str) -> dict:
139
+ return self.trace_store.get_otlp(trace_id)
140
+
141
+ def list_traces(
142
+ self,
143
+ *,
144
+ agent_id: str | None = None,
145
+ status: str | None = None,
146
+ limit: int = 200,
147
+ ) -> list[dict]:
148
+ return self.trace_store.list_trace_summaries(
149
+ agent_id=agent_id,
150
+ status=status,
151
+ limit=limit,
152
+ )
153
+
154
+ def list_traces_page(
155
+ self,
156
+ *,
157
+ agent_id: str | None = None,
158
+ status: str | None = None,
159
+ query: str = "",
160
+ limit: int = 50,
161
+ cursor: str | None = None,
162
+ sort: str = "startedAt:desc",
163
+ ) -> dict:
164
+ return self.trace_store.paginate_trace_summaries(
165
+ agent_id=agent_id,
166
+ status=status,
167
+ query=query,
168
+ limit=limit,
169
+ cursor=cursor,
170
+ sort=sort,
171
+ )
172
+
173
+ def trace_overview(
174
+ self,
175
+ *,
176
+ range_name: str = "24h",
177
+ agent_id: str | None = None,
178
+ status: str | None = None,
179
+ ) -> dict:
180
+ return self.trace_store.trace_overview(
181
+ range_name=range_name,
182
+ agent_id=agent_id,
183
+ status=status,
184
+ )
185
+
186
+ def _read(self, run_id: str) -> tuple[RunRecord, list[RunEvent]]:
187
+ path = self._path(run_id)
188
+ if not path.is_file():
189
+ raise not_found("run", run_id)
190
+ try:
191
+ payload = json.loads(path.read_text(encoding="utf-8"))
192
+ record = RunRecord.model_validate(payload["record"])
193
+ events = [RunEvent.model_validate(item) for item in payload.get("events", [])]
194
+ return record, events
195
+ except (OSError, ValueError, KeyError, ValidationError) as exc:
196
+ raise StudioError(
197
+ "RUN_RECORD_INVALID",
198
+ "Run 记录损坏",
199
+ status_code=500,
200
+ details={"id": run_id},
201
+ ) from exc
202
+
203
+ def _write(self, record: RunRecord, events: list[RunEvent] | None = None) -> None:
204
+ payload: dict[str, Any] = {
205
+ "record": record.model_dump(by_alias=True, exclude_none=True, mode="json")
206
+ }
207
+ if events is not None:
208
+ payload["events"] = [
209
+ event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
210
+ ]
211
+ self.workspace.atomic_write_text(
212
+ self._path(record.id),
213
+ json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
214
+ )
@@ -0,0 +1,342 @@
1
+ """Resolve immutable ADK/LangGraph Studio builds into RuntimeLaunchContext."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from ksadk.detection.detector import FrameworkDetector
11
+ from ksadk.runtime import RuntimeLaunchContext
12
+ from ksadk.studio.capabilities import compute_bundle_digest
13
+ from ksadk.studio.contracts import BundleManifest
14
+ from ksadk.studio.errors import StudioError
15
+ from ksadk.studio.repository import BuildRepository
16
+ from ksadk.studio.run_service import StudioRunSpec
17
+ from ksadk.studio.workspace import Workspace
18
+ from ksadk.tools.gateway import normalize_tool_approval_mode
19
+
20
+
21
+ def _resolved_prompt_ownership(resolved: Any) -> str:
22
+ """从 resolved-agent-spec.json 的 context 块读 prompt_ownership。
23
+
24
+ resolved spec 由 ContractModel 以 ``by_alias=True`` 序列化,alias_generator 为
25
+ camelCase,故字段名为 ``promptOwnership``;``populate_by_name`` 仅作用于输入,JSON
26
+ 输出仍为 alias。此处 camelCase 与 snake 两种写法都查,稳妥兼容。非 dict / 缺失时
27
+ 返回空串(== framework 默认,不接管 Runner 输入)。
28
+ """
29
+ if not isinstance(resolved, dict):
30
+ return ""
31
+ context = resolved.get("context")
32
+ if not isinstance(context, dict):
33
+ return ""
34
+ return str(
35
+ context.get("promptOwnership")
36
+ or context.get("prompt_ownership")
37
+ or context.get("ownership")
38
+ or ""
39
+ )
40
+
41
+
42
+ def _resolved_context_engine_rollout(resolved: Any) -> str:
43
+ """读取 AgentVersion 固化的 Context Engine rollout。"""
44
+ if not isinstance(resolved, dict):
45
+ return ""
46
+ context = resolved.get("context")
47
+ if not isinstance(context, dict):
48
+ return ""
49
+ rollout = context.get("rollout")
50
+ if not isinstance(rollout, dict):
51
+ return ""
52
+ return str(rollout.get("contextEngine") or rollout.get("context_engine") or "")
53
+
54
+
55
+ def _resolved_memory_recall_enabled(resolved: Any) -> bool | None:
56
+ """读取 AgentVersion 的 Memory 召回开关;缺失时保留旧环境策略。"""
57
+ if not isinstance(resolved, dict):
58
+ return None
59
+ memory = resolved.get("memory")
60
+ if not isinstance(memory, dict) or "enabled" not in memory:
61
+ return None
62
+ enabled = bool(memory.get("enabled"))
63
+ recall = memory.get("recall")
64
+ if isinstance(recall, dict) and "enabled" in recall:
65
+ enabled = enabled and bool(recall.get("enabled"))
66
+ context = resolved.get("context")
67
+ contributors = context.get("contributors") if isinstance(context, dict) else None
68
+ if isinstance(contributors, dict):
69
+ explicit = contributors.get("memoryRecall", contributors.get("memory_recall"))
70
+ if explicit is not None:
71
+ enabled = enabled and bool(explicit)
72
+ return enabled
73
+
74
+
75
+ def _resolved_memory_write_rollout(resolved: Any) -> str:
76
+ """读取 AgentVersion 固化的 Memory 写入 rollout。"""
77
+ if not isinstance(resolved, dict):
78
+ return ""
79
+ context = resolved.get("context")
80
+ if not isinstance(context, dict):
81
+ return ""
82
+ rollout = context.get("rollout")
83
+ if not isinstance(rollout, dict):
84
+ return ""
85
+ return str(rollout.get("memoryWrite") or rollout.get("memory_write") or "")
86
+
87
+
88
+ class FrameworkRunSpecResolver:
89
+ # manifest.json 是 bundle 自身的描述文件,不进入 manifest.files 清单
90
+ # (builder 在扫描文件列表之后才写它),校验时排除。checksums.txt 在本仓
91
+ # bundle 格式中是 manifest 声明的普通成员,参与校验。
92
+ _BUNDLE_META_FILES = frozenset({"manifest.json"})
93
+
94
+ def __init__(
95
+ self,
96
+ workspace: Workspace,
97
+ *,
98
+ build_repository: BuildRepository | None = None,
99
+ ) -> None:
100
+ self.workspace = workspace
101
+ self.builds = build_repository or BuildRepository(workspace)
102
+
103
+ def resolve(
104
+ self,
105
+ build_id: str,
106
+ *,
107
+ model: str | None = None,
108
+ approval_mode: str | None = None,
109
+ ) -> StudioRunSpec:
110
+ build = self.builds.get(build_id)
111
+ runtime_type = build.runtime_type.strip().lower()
112
+ if runtime_type not in {"adk", "langgraph"}:
113
+ raise StudioError(
114
+ "BUILD_RUNTIME_UNSUPPORTED",
115
+ "Build 没有可由 RuntimeAdapter 启动的 ADK/LangGraph Runtime",
116
+ status_code=422,
117
+ details={"buildId": build_id, "runtimeType": runtime_type},
118
+ )
119
+ if not build.artifact_path:
120
+ raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
121
+ artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
122
+ bundle_root = artifact_root / "agent-bundle"
123
+ self._verify_bundle_integrity(
124
+ bundle_root, expected_bundle_digest=build.bundle_digest
125
+ )
126
+ project_dir = bundle_root / "runtime"
127
+ if not project_dir.is_dir():
128
+ raise StudioError(
129
+ "BUILD_RUNTIME_SOURCE_MISSING",
130
+ "Build 缺少不可变 Runtime 源码快照",
131
+ status_code=500,
132
+ )
133
+ detection = FrameworkDetector(str(project_dir)).detect()
134
+ if not detection.is_valid or detection.type.value != runtime_type:
135
+ raise StudioError(
136
+ "BUILD_RUNTIME_DETECTION_MISMATCH",
137
+ "Build 中的 Runtime 源码与 Runtime Lock 不一致",
138
+ status_code=422,
139
+ details={
140
+ "expected": runtime_type,
141
+ "detected": detection.type.value,
142
+ },
143
+ )
144
+ selected_model = self._select_model(build.runtime_lock, model)
145
+ resolved_path = bundle_root / "resolved-agent-spec.json"
146
+ resolved = json.loads(resolved_path.read_text(encoding="utf-8"))
147
+ instructions = resolved.get("instructions") if isinstance(resolved, dict) else {}
148
+ request_config = {
149
+ "base_instructions": str((instructions or {}).get("system") or ""),
150
+ # Preserve system/task as separate PCM sources while keeping the
151
+ # framework runner's existing base_instructions projection.
152
+ "agent_system": str((instructions or {}).get("system") or ""),
153
+ "agent_task": str((instructions or {}).get("task") or ""),
154
+ **(
155
+ {"prompt_integration_mode": "ksadk_hosted"}
156
+ if _resolved_prompt_ownership(resolved) == "ksadk"
157
+ else {}
158
+ ),
159
+ "context_engine_rollout": _resolved_context_engine_rollout(resolved),
160
+ "memory_recall_enabled": _resolved_memory_recall_enabled(resolved),
161
+ "memory_write_rollout": _resolved_memory_write_rollout(resolved),
162
+ "memory_enabled": _resolved_memory_enabled(resolved),
163
+ "memory_write_mode": _resolved_memory_write_mode(resolved),
164
+ "flush_before_compaction": _resolved_memory_flush_before_compaction(resolved),
165
+ "provider_ref": _resolved_memory_provider_ref(resolved),
166
+ "entry_point": detection.entry_point,
167
+ "agent_variable": detection.agent_variable,
168
+ }
169
+ # AgentVersion 的 ContextSpec 预算传到 Planner(方案 §8.2)
170
+ context_spec = resolved.get("context") if isinstance(resolved, dict) else {}
171
+ if isinstance(context_spec, dict):
172
+ max_input = context_spec.get("maxInputTokens") or context_spec.get("max_input_tokens")
173
+ reserve_output = context_spec.get("reserveOutputTokens") or context_spec.get(
174
+ "reserve_output_tokens"
175
+ )
176
+ if max_input is not None:
177
+ request_config["max_input_tokens"] = int(max_input)
178
+ if reserve_output is not None:
179
+ request_config["reserve_output_tokens"] = int(reserve_output)
180
+ if approval_mode:
181
+ request_config["tool_approval_mode"] = normalize_tool_approval_mode(approval_mode)
182
+ return StudioRunSpec(
183
+ launch_context=RuntimeLaunchContext(
184
+ runtime_type=runtime_type,
185
+ project_dir=project_dir,
186
+ detection=detection,
187
+ config=dict(detection.raw_config or {}),
188
+ ),
189
+ build_id=build.id,
190
+ agent_id=build.agent_id,
191
+ model=selected_model,
192
+ request_config=request_config,
193
+ manifest_sha256=build.resolved_digest,
194
+ )
195
+
196
+ @staticmethod
197
+ def _select_model(runtime_lock: dict, requested: str | None) -> str:
198
+ allowed = [str(value) for value in runtime_lock.get("models") or [] if str(value)]
199
+ default = str(runtime_lock.get("model") or "").strip()
200
+ if default and default not in allowed:
201
+ allowed.insert(0, default)
202
+ selected = str(requested or default).strip()
203
+ if not selected:
204
+ raise StudioError(
205
+ "AGENT_MODEL_REQUIRED",
206
+ "Build 没有绑定可运行模型",
207
+ status_code=422,
208
+ )
209
+ if allowed and selected not in allowed:
210
+ raise StudioError(
211
+ "MODEL_NOT_BOUND",
212
+ "请求模型未绑定到当前 Agent Build",
213
+ status_code=422,
214
+ details={"model": selected, "allowedModels": allowed},
215
+ )
216
+ return selected
217
+
218
+ def _verify_bundle_integrity(
219
+ self,
220
+ bundle_dir: Path,
221
+ *,
222
+ expected_bundle_digest: str = "",
223
+ ) -> None:
224
+ """加载前校验 bundle 未被篡改:manifest 自身摘要、与 Build 记录一致、
225
+ 文件清单无增删、每个文件 sha256/size 匹配。"""
226
+ try:
227
+ manifest = BundleManifest.model_validate_json(
228
+ (bundle_dir / "manifest.json").read_text(encoding="utf-8")
229
+ )
230
+ except (OSError, ValueError) as exc:
231
+ raise StudioError(
232
+ "BUILD_ARTIFACT_INVALID",
233
+ "Build 缺少有效的 Bundle Manifest",
234
+ status_code=500,
235
+ ) from exc
236
+ if manifest.bundle_digest != compute_bundle_digest(manifest):
237
+ raise StudioError(
238
+ "BUILD_ARTIFACT_INVALID",
239
+ "Bundle Manifest 摘要不匹配,Bundle 可能已被篡改",
240
+ status_code=500,
241
+ details={"bundleDigest": manifest.bundle_digest},
242
+ )
243
+ if expected_bundle_digest and manifest.bundle_digest != expected_bundle_digest:
244
+ raise StudioError(
245
+ "BUILD_ARTIFACT_INVALID",
246
+ "Bundle 与 Build 记录的摘要不一致,Bundle 可能已被篡改",
247
+ status_code=500,
248
+ details={
249
+ "expected": expected_bundle_digest,
250
+ "actual": manifest.bundle_digest,
251
+ },
252
+ )
253
+ declared = {entry.path for entry in manifest.files}
254
+ actual: dict[str, Path] = {}
255
+ for path in bundle_dir.rglob("*"):
256
+ if not path.is_file():
257
+ continue
258
+ relative = path.relative_to(bundle_dir).as_posix()
259
+ if relative in self._BUNDLE_META_FILES:
260
+ continue
261
+ actual[relative] = path
262
+ extra = sorted(set(actual) - declared)
263
+ if extra:
264
+ raise StudioError(
265
+ "BUILD_ARTIFACT_INVALID",
266
+ "Bundle 含未在 Manifest 中声明的文件",
267
+ status_code=500,
268
+ details={"extraFiles": extra},
269
+ )
270
+ for entry in manifest.files:
271
+ file_path = actual.get(entry.path)
272
+ if file_path is None:
273
+ raise StudioError(
274
+ "BUILD_ARTIFACT_INVALID",
275
+ "Bundle 缺少 Manifest 声明的文件",
276
+ status_code=500,
277
+ details={"missingFile": entry.path},
278
+ )
279
+ content = file_path.read_bytes()
280
+ actual_sha = f"sha256:{hashlib.sha256(content).hexdigest()}"
281
+ if actual_sha != entry.sha256:
282
+ raise StudioError(
283
+ "BUILD_ARTIFACT_INVALID",
284
+ "Bundle 文件摘要不匹配",
285
+ status_code=500,
286
+ details={
287
+ "path": entry.path,
288
+ "expected": entry.sha256,
289
+ "actual": actual_sha,
290
+ },
291
+ )
292
+ if len(content) != entry.size:
293
+ raise StudioError(
294
+ "BUILD_ARTIFACT_INVALID",
295
+ "Bundle 文件大小不匹配",
296
+ status_code=500,
297
+ details={
298
+ "path": entry.path,
299
+ "expected": entry.size,
300
+ "actual": len(content),
301
+ },
302
+ )
303
+
304
+
305
+ __all__ = ["FrameworkRunSpecResolver"]
306
+
307
+
308
+ def _resolved_memory_enabled(resolved: Any) -> bool:
309
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
310
+ return bool(memory.get("enabled", False)) if isinstance(memory, dict) else False
311
+
312
+
313
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
314
+ if not isinstance(memory, dict) or not memory.get("enabled", False):
315
+ return False
316
+ recall = memory.get("recall", {})
317
+ return bool(recall.get("enabled", True)) if isinstance(recall, dict) else True
318
+
319
+
320
+ def _resolved_memory_write_mode(resolved: Any) -> str:
321
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
322
+ write = memory.get("write", {}) if isinstance(memory, dict) else {}
323
+ return (
324
+ str(write.get("mode", "candidate") or "candidate")
325
+ if isinstance(write, dict)
326
+ else "candidate"
327
+ )
328
+
329
+
330
+ def _resolved_memory_flush_before_compaction(resolved: Any) -> bool:
331
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
332
+ write = memory.get("write", {}) if isinstance(memory, dict) else {}
333
+ return bool(write.get("flushBeforeCompaction", True)) if isinstance(write, dict) else True
334
+
335
+
336
+ def _resolved_memory_provider_ref(resolved: Any) -> str:
337
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
338
+ return (
339
+ str(memory.get("providerRef", "local-default") or "local-default")
340
+ if isinstance(memory, dict)
341
+ else "local-default"
342
+ )