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
@@ -1,4 +1,4 @@
1
- """Persistent local Run and Event store."""
1
+ """Persistent local Run record store and derived trace access."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -6,11 +6,11 @@ import json
6
6
  import shutil
7
7
  from datetime import datetime, timezone
8
8
  from pathlib import Path
9
- from typing import List
9
+ from typing import Any
10
10
 
11
11
  from pydantic import ValidationError
12
12
 
13
- from ksadk.studio.contracts import RunEvent, RunRecord, RunStatus
13
+ from ksadk.studio.contracts import RunEvent, RunRecord
14
14
  from ksadk.studio.errors import StudioError, not_found
15
15
  from ksadk.studio.otel_trace import OtlpTraceStore
16
16
  from ksadk.studio.workspace import Workspace
@@ -28,40 +28,94 @@ class RunEventStore:
28
28
  path = self._path(record.id)
29
29
  if path.exists():
30
30
  raise StudioError("RUN_ALREADY_EXISTS", "Run 已存在", status_code=409)
31
- self._write(record, [])
31
+ self._write(record)
32
32
  return record
33
33
 
34
34
  def save(self, record: RunRecord) -> RunRecord:
35
35
  _, events = self._read(record.id)
36
- self._write(record, events)
36
+ self._write(record, events or None)
37
37
  return record
38
38
 
39
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
+ return self.append_many(run_id, [(event_type, data)])[0]
47
+
48
+ def append_many(
49
+ self,
50
+ run_id: str,
51
+ entries: list[tuple[str, dict[str, Any]]],
52
+ ) -> list[RunEvent]:
53
+ """Persist one logical Studio transition with a single file replace."""
40
54
  record, events = self._read(run_id)
41
- event = RunEvent(
42
- id=len(events) + 1,
55
+ appended: list[RunEvent] = []
56
+ for event_type, data in entries:
57
+ event = RunEvent(
58
+ id=len(events) + 1,
59
+ run_id=run_id,
60
+ type=event_type,
61
+ data=data,
62
+ )
63
+ events.append(event)
64
+ appended.append(event)
65
+ if appended:
66
+ self._write(record, events)
67
+ return appended
68
+
69
+ def append_interaction_resolution(
70
+ self,
71
+ run_id: str,
72
+ *,
73
+ resolved_type: str,
74
+ resolved_data: dict[str, Any],
75
+ action_data: dict[str, Any],
76
+ ) -> tuple[RunEvent, RunEvent, dict[str, Any]]:
77
+ """Atomically persist a terminal interaction and its replay receipt."""
78
+ record, events = self._read(run_id)
79
+ resolution_event_id = len(events) + 1
80
+ action_event_id = resolution_event_id + 1
81
+ receipt = {
82
+ "runId": run_id,
83
+ "interactionId": str(action_data.get("interactionId") or ""),
84
+ "status": "resolved",
85
+ "revision": int(action_data.get("revision") or 0),
86
+ "resolutionEventId": resolution_event_id,
87
+ "eventId": action_event_id,
88
+ }
89
+ resolved = RunEvent(
90
+ id=resolution_event_id,
91
+ run_id=run_id,
92
+ type=resolved_type,
93
+ data=resolved_data,
94
+ )
95
+ action = RunEvent(
96
+ id=action_event_id,
43
97
  run_id=run_id,
44
- type=event_type,
45
- data=data,
98
+ type="a2ui.action",
99
+ data={**action_data, "receipt": receipt},
46
100
  )
47
- events.append(event)
101
+ events.extend((resolved, action))
48
102
  self._write(record, events)
49
- return event
50
-
51
- def get(self, run_id: str) -> RunRecord:
52
- record, _ = self._read(run_id)
53
- return record
103
+ return resolved, action, receipt
54
104
 
55
105
  def events(self, run_id: str, *, after: int = 0) -> list[RunEvent]:
56
106
  _, events = self._read(run_id)
57
107
  return [event for event in events if event.id > after]
58
108
 
109
+ def get(self, run_id: str) -> RunRecord:
110
+ record, _ = self._read(run_id)
111
+ return record
112
+
59
113
  def list_runs(
60
114
  self,
61
115
  *,
62
116
  session_id: str | None = None,
63
117
  agent_id: str | None = None,
64
- ) -> List[RunRecord]:
118
+ ) -> list[RunRecord]:
65
119
  records: list[RunRecord] = []
66
120
  directory = self.workspace.resolve(".agentkit/runs")
67
121
  for path in sorted(directory.glob("run_*.json")):
@@ -126,82 +180,6 @@ class RunEventStore:
126
180
  deleted += 1
127
181
  return deleted
128
182
 
129
- def recover_interrupted(self) -> int:
130
- """Reconcile non-terminal records left behind by a stopped Studio.
131
-
132
- Events are persisted before the final RunRecord update. A browser
133
- disconnect or process stop can therefore leave a terminal event next
134
- to a stale ``RUNNING`` record. On startup the event log wins; a run
135
- without any terminal event is explicitly marked interrupted because
136
- its in-memory runtime task cannot survive a Studio restart.
137
- """
138
-
139
- recovered = 0
140
- for record in self.list_runs():
141
- if record.status not in {
142
- RunStatus.CREATED,
143
- RunStatus.RUNNING,
144
- RunStatus.PAUSED,
145
- RunStatus.WAITING_INPUT,
146
- }:
147
- continue
148
- events = self.events(record.id)
149
- terminal = next(
150
- (
151
- event
152
- for event in reversed(events)
153
- if event.type
154
- in {
155
- "run.completed",
156
- "run.failed",
157
- "run.cancelled",
158
- "run.interrupted",
159
- }
160
- ),
161
- None,
162
- )
163
- if terminal is None:
164
- terminal = self.append(
165
- record.id,
166
- "run.interrupted",
167
- {
168
- "status": "interrupted",
169
- "reason": "studio_restarted",
170
- },
171
- )
172
-
173
- if terminal.type == "run.completed":
174
- record.status = RunStatus.COMPLETED
175
- record.error = None
176
- elif terminal.type == "run.failed":
177
- record.status = RunStatus.FAILED
178
- record.error = {
179
- "code": "RUNTIME_RUN_FAILED",
180
- "message": str(
181
- terminal.data.get("error")
182
- or terminal.data.get("message")
183
- or "Agent 运行失败"
184
- ),
185
- }
186
- elif terminal.type == "run.cancelled":
187
- record.status = RunStatus.CANCELLED
188
- record.error = {"code": "RUN_CANCELLED", "message": "运行已取消"}
189
- else:
190
- record.status = RunStatus.INTERRUPTED
191
- record.error = {
192
- "code": "RUN_INTERRUPTED",
193
- "message": "Studio 重启后无法重新 attach 上一次本地运行",
194
- }
195
- record.completed_at = terminal.created_at
196
- if record.started_at is not None:
197
- record.duration_ms = max(
198
- 0,
199
- int((record.completed_at - record.started_at).total_seconds() * 1000),
200
- )
201
- self.save(record)
202
- recovered += 1
203
- return recovered
204
-
205
183
  def trace(self, trace_id: str) -> dict:
206
184
  return self.trace_store.get_trace_view(trace_id)
207
185
 
@@ -253,14 +231,14 @@ class RunEventStore:
253
231
  status=status,
254
232
  )
255
233
 
256
- def _read(self, run_id: str) -> tuple[RunRecord, List[RunEvent]]:
234
+ def _read(self, run_id: str) -> tuple[RunRecord, list[RunEvent]]:
257
235
  path = self._path(run_id)
258
236
  if not path.is_file():
259
237
  raise not_found("run", run_id)
260
238
  try:
261
239
  payload = json.loads(path.read_text(encoding="utf-8"))
262
240
  record = RunRecord.model_validate(payload["record"])
263
- events = [RunEvent.model_validate(item) for item in payload["events"]]
241
+ events = [RunEvent.model_validate(item) for item in payload.get("events", [])]
264
242
  return record, events
265
243
  except (OSError, ValueError, KeyError, ValidationError) as exc:
266
244
  raise StudioError(
@@ -270,15 +248,15 @@ class RunEventStore:
270
248
  details={"id": run_id},
271
249
  ) from exc
272
250
 
273
- def _write(self, record: RunRecord, events: List[RunEvent]) -> None:
274
- payload = {
275
- "record": record.model_dump(by_alias=True, exclude_none=True, mode="json"),
276
- "events": [
277
- event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
278
- ],
251
+ def _write(self, record: RunRecord, events: list[RunEvent] | None = None) -> None:
252
+ payload: dict[str, Any] = {
253
+ "record": record.model_dump(by_alias=True, exclude_none=True, mode="json")
279
254
  }
255
+ if events is not None:
256
+ payload["events"] = [
257
+ event.model_dump(by_alias=True, exclude_none=True, mode="json") for event in events
258
+ ]
280
259
  self.workspace.atomic_write_text(
281
260
  self._path(record.id),
282
261
  json.dumps(payload, ensure_ascii=False, sort_keys=True, indent=2) + "\n",
283
262
  )
284
- self.trace_store.sync(record, events)
@@ -2,10 +2,16 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import hashlib
5
6
  import json
7
+ from pathlib import Path
8
+ from typing import Any
6
9
 
7
10
  from ksadk.detection.detector import FrameworkDetector
11
+ from ksadk.plugins.bundle_security import BundleSecurityError, assert_bundle_security
8
12
  from ksadk.runtime import RuntimeLaunchContext
13
+ from ksadk.studio.capabilities import compute_bundle_digest
14
+ from ksadk.studio.contracts import BundleManifest
9
15
  from ksadk.studio.errors import StudioError
10
16
  from ksadk.studio.repository import BuildRepository
11
17
  from ksadk.studio.run_service import StudioRunSpec
@@ -13,7 +19,79 @@ from ksadk.studio.workspace import Workspace
13
19
  from ksadk.tools.gateway import normalize_tool_approval_mode
14
20
 
15
21
 
22
+ def _resolved_prompt_ownership(resolved: Any) -> str:
23
+ """从 resolved-agent-spec.json 的 context 块读 prompt_ownership。
24
+
25
+ resolved spec 由 ContractModel 以 ``by_alias=True`` 序列化,alias_generator 为
26
+ camelCase,故字段名为 ``promptOwnership``;``populate_by_name`` 仅作用于输入,JSON
27
+ 输出仍为 alias。此处 camelCase 与 snake 两种写法都查,稳妥兼容。非 dict / 缺失时
28
+ 返回空串(== framework 默认,不接管 Runner 输入)。
29
+ """
30
+ if not isinstance(resolved, dict):
31
+ return ""
32
+ context = resolved.get("context")
33
+ if not isinstance(context, dict):
34
+ return ""
35
+ return str(
36
+ context.get("promptOwnership")
37
+ or context.get("prompt_ownership")
38
+ or context.get("ownership")
39
+ or ""
40
+ )
41
+
42
+
43
+ def _resolved_context_engine_rollout(resolved: Any) -> str:
44
+ """读取 AgentVersion 固化的 Context Engine rollout。"""
45
+ if not isinstance(resolved, dict):
46
+ return ""
47
+ context = resolved.get("context")
48
+ if not isinstance(context, dict):
49
+ return ""
50
+ rollout = context.get("rollout")
51
+ if not isinstance(rollout, dict):
52
+ return ""
53
+ return str(rollout.get("contextEngine") or rollout.get("context_engine") or "")
54
+
55
+
56
+ def _resolved_memory_recall_enabled(resolved: Any) -> bool | None:
57
+ """读取 AgentVersion 的 Memory 召回开关;缺失时保留旧环境策略。"""
58
+ if not isinstance(resolved, dict):
59
+ return None
60
+ memory = resolved.get("memory")
61
+ if not isinstance(memory, dict) or "enabled" not in memory:
62
+ return None
63
+ enabled = bool(memory.get("enabled"))
64
+ recall = memory.get("recall")
65
+ if isinstance(recall, dict) and "enabled" in recall:
66
+ enabled = enabled and bool(recall.get("enabled"))
67
+ context = resolved.get("context")
68
+ contributors = context.get("contributors") if isinstance(context, dict) else None
69
+ if isinstance(contributors, dict):
70
+ explicit = contributors.get("memoryRecall", contributors.get("memory_recall"))
71
+ if explicit is not None:
72
+ enabled = enabled and bool(explicit)
73
+ return enabled
74
+
75
+
76
+ def _resolved_memory_write_rollout(resolved: Any) -> str:
77
+ """读取 AgentVersion 固化的 Memory 写入 rollout。"""
78
+ if not isinstance(resolved, dict):
79
+ return ""
80
+ context = resolved.get("context")
81
+ if not isinstance(context, dict):
82
+ return ""
83
+ rollout = context.get("rollout")
84
+ if not isinstance(rollout, dict):
85
+ return ""
86
+ return str(rollout.get("memoryWrite") or rollout.get("memory_write") or "")
87
+
88
+
16
89
  class FrameworkRunSpecResolver:
90
+ # manifest.json 是 bundle 自身的描述文件,不进入 manifest.files 清单
91
+ # (builder 在扫描文件列表之后才写它),校验时排除。checksums.txt 在本仓
92
+ # bundle 格式中是 manifest 声明的普通成员,参与校验。
93
+ _BUNDLE_META_FILES = frozenset({"manifest.json"})
94
+
17
95
  def __init__(
18
96
  self,
19
97
  workspace: Workspace,
@@ -43,6 +121,11 @@ class FrameworkRunSpecResolver:
43
121
  raise StudioError("BUILD_NOT_READY", "Build 尚未生成制品", status_code=409)
44
122
  artifact_root = self.workspace.resolve(build.artifact_path, must_exist=True).parent
45
123
  bundle_root = artifact_root / "agent-bundle"
124
+ self._verify_bundle_integrity(bundle_root, expected_bundle_digest=build.bundle_digest)
125
+ # v1 artifacts predate the no-literal-secret Bundle admission rule and
126
+ # must stay runnable. Every v2 bundle is checked again before local
127
+ # execution, including an externally restored but integrity-valid ZIP.
128
+ self._verify_bundle_security(bundle_root)
46
129
  project_dir = bundle_root / "runtime"
47
130
  if not project_dir.is_dir():
48
131
  raise StudioError(
@@ -67,13 +150,38 @@ class FrameworkRunSpecResolver:
67
150
  instructions = resolved.get("instructions") if isinstance(resolved, dict) else {}
68
151
  request_config = {
69
152
  "base_instructions": str((instructions or {}).get("system") or ""),
153
+ # Preserve system/task as separate PCM sources while keeping the
154
+ # framework runner's existing base_instructions projection.
155
+ "agent_system": str((instructions or {}).get("system") or ""),
156
+ "agent_task": str((instructions or {}).get("task") or ""),
157
+ **(
158
+ {"prompt_integration_mode": "ksadk_hosted"}
159
+ if _resolved_prompt_ownership(resolved) == "ksadk"
160
+ else {}
161
+ ),
162
+ "context_engine_rollout": _resolved_context_engine_rollout(resolved),
163
+ "memory_recall_enabled": _resolved_memory_recall_enabled(resolved),
164
+ "memory_write_rollout": _resolved_memory_write_rollout(resolved),
165
+ "memory_enabled": _resolved_memory_enabled(resolved),
166
+ "memory_write_mode": _resolved_memory_write_mode(resolved),
167
+ "flush_before_compaction": _resolved_memory_flush_before_compaction(resolved),
168
+ "provider_ref": _resolved_memory_provider_ref(resolved),
70
169
  "entry_point": detection.entry_point,
71
170
  "agent_variable": detection.agent_variable,
72
171
  }
73
- if approval_mode:
74
- request_config["tool_approval_mode"] = normalize_tool_approval_mode(
75
- approval_mode
172
+ # AgentVersion 的 ContextSpec 预算传到 Planner(方案 §8.2)
173
+ context_spec = resolved.get("context") if isinstance(resolved, dict) else {}
174
+ if isinstance(context_spec, dict):
175
+ max_input = context_spec.get("maxInputTokens") or context_spec.get("max_input_tokens")
176
+ reserve_output = context_spec.get("reserveOutputTokens") or context_spec.get(
177
+ "reserve_output_tokens"
76
178
  )
179
+ if max_input is not None:
180
+ request_config["max_input_tokens"] = int(max_input)
181
+ if reserve_output is not None:
182
+ request_config["reserve_output_tokens"] = int(reserve_output)
183
+ if approval_mode:
184
+ request_config["tool_approval_mode"] = normalize_tool_approval_mode(approval_mode)
77
185
  return StudioRunSpec(
78
186
  launch_context=RuntimeLaunchContext(
79
187
  runtime_type=runtime_type,
@@ -110,5 +218,158 @@ class FrameworkRunSpecResolver:
110
218
  )
111
219
  return selected
112
220
 
221
+ def _verify_bundle_integrity(
222
+ self,
223
+ bundle_dir: Path,
224
+ *,
225
+ expected_bundle_digest: str = "",
226
+ ) -> None:
227
+ """加载前校验 bundle 未被篡改:manifest 自身摘要、与 Build 记录一致、
228
+ 文件清单无增删、每个文件 sha256/size 匹配。"""
229
+ try:
230
+ manifest = BundleManifest.model_validate_json(
231
+ (bundle_dir / "manifest.json").read_text(encoding="utf-8")
232
+ )
233
+ except (OSError, ValueError) as exc:
234
+ raise StudioError(
235
+ "BUILD_ARTIFACT_INVALID",
236
+ "Build 缺少有效的 Bundle Manifest",
237
+ status_code=500,
238
+ ) from exc
239
+ if manifest.bundle_digest != compute_bundle_digest(manifest):
240
+ raise StudioError(
241
+ "BUILD_ARTIFACT_INVALID",
242
+ "Bundle Manifest 摘要不匹配,Bundle 可能已被篡改",
243
+ status_code=500,
244
+ details={"bundleDigest": manifest.bundle_digest},
245
+ )
246
+ if expected_bundle_digest and manifest.bundle_digest != expected_bundle_digest:
247
+ raise StudioError(
248
+ "BUILD_ARTIFACT_INVALID",
249
+ "Bundle 与 Build 记录的摘要不一致,Bundle 可能已被篡改",
250
+ status_code=500,
251
+ details={
252
+ "expected": expected_bundle_digest,
253
+ "actual": manifest.bundle_digest,
254
+ },
255
+ )
256
+ declared = {entry.path for entry in manifest.files}
257
+ actual: dict[str, Path] = {}
258
+ for path in bundle_dir.rglob("*"):
259
+ if not path.is_file():
260
+ continue
261
+ relative = path.relative_to(bundle_dir).as_posix()
262
+ if relative in self._BUNDLE_META_FILES:
263
+ continue
264
+ actual[relative] = path
265
+ extra = sorted(set(actual) - declared)
266
+ if extra:
267
+ raise StudioError(
268
+ "BUILD_ARTIFACT_INVALID",
269
+ "Bundle 含未在 Manifest 中声明的文件",
270
+ status_code=500,
271
+ details={"extraFiles": extra},
272
+ )
273
+ for entry in manifest.files:
274
+ file_path = actual.get(entry.path)
275
+ if file_path is None:
276
+ raise StudioError(
277
+ "BUILD_ARTIFACT_INVALID",
278
+ "Bundle 缺少 Manifest 声明的文件",
279
+ status_code=500,
280
+ details={"missingFile": entry.path},
281
+ )
282
+ content = file_path.read_bytes()
283
+ actual_sha = f"sha256:{hashlib.sha256(content).hexdigest()}"
284
+ if actual_sha != entry.sha256:
285
+ raise StudioError(
286
+ "BUILD_ARTIFACT_INVALID",
287
+ "Bundle 文件摘要不匹配",
288
+ status_code=500,
289
+ details={
290
+ "path": entry.path,
291
+ "expected": entry.sha256,
292
+ "actual": actual_sha,
293
+ },
294
+ )
295
+ if len(content) != entry.size:
296
+ raise StudioError(
297
+ "BUILD_ARTIFACT_INVALID",
298
+ "Bundle 文件大小不匹配",
299
+ status_code=500,
300
+ details={
301
+ "path": entry.path,
302
+ "expected": entry.size,
303
+ "actual": len(content),
304
+ },
305
+ )
306
+
307
+ @staticmethod
308
+ def _verify_bundle_security(bundle_dir: Path) -> None:
309
+ try:
310
+ manifest = BundleManifest.model_validate_json(
311
+ (bundle_dir / "manifest.json").read_text(encoding="utf-8")
312
+ )
313
+ except (OSError, ValueError):
314
+ # Integrity verification reports the canonical error for a malformed
315
+ # manifest; do not mask it with a second diagnostic path.
316
+ return
317
+ if manifest.bundle_format != "agentkit.bundle/v2":
318
+ return
319
+ try:
320
+ assert_bundle_security(bundle_dir)
321
+ except BundleSecurityError as exc:
322
+ raise StudioError(
323
+ "BUILD_ARTIFACT_INVALID",
324
+ "Bundle 包含不允许的明文凭证或本机路径",
325
+ status_code=422,
326
+ details={
327
+ "securityFindings": [
328
+ {
329
+ "path": finding.path,
330
+ "kind": finding.kind,
331
+ **({"field": finding.field} if finding.field else {}),
332
+ }
333
+ for finding in exc.findings
334
+ ]
335
+ },
336
+ ) from exc
337
+
113
338
 
114
339
  __all__ = ["FrameworkRunSpecResolver"]
340
+
341
+
342
+ def _resolved_memory_enabled(resolved: Any) -> bool:
343
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
344
+ return bool(memory.get("enabled", False)) if isinstance(memory, dict) else False
345
+
346
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
347
+ if not isinstance(memory, dict) or not memory.get("enabled", False):
348
+ return False
349
+ recall = memory.get("recall", {})
350
+ return bool(recall.get("enabled", True)) if isinstance(recall, dict) else True
351
+
352
+
353
+ def _resolved_memory_write_mode(resolved: Any) -> str:
354
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
355
+ write = memory.get("write", {}) if isinstance(memory, dict) else {}
356
+ return (
357
+ str(write.get("mode", "candidate") or "candidate")
358
+ if isinstance(write, dict)
359
+ else "candidate"
360
+ )
361
+
362
+
363
+ def _resolved_memory_flush_before_compaction(resolved: Any) -> bool:
364
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
365
+ write = memory.get("write", {}) if isinstance(memory, dict) else {}
366
+ return bool(write.get("flushBeforeCompaction", True)) if isinstance(write, dict) else True
367
+
368
+
369
+ def _resolved_memory_provider_ref(resolved: Any) -> str:
370
+ memory = resolved.get("memory") if isinstance(resolved, dict) else {}
371
+ return (
372
+ str(memory.get("providerRef", "local-default") or "local-default")
373
+ if isinstance(memory, dict)
374
+ else "local-default"
375
+ )