agentengine-sdk-python 0.8.2__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 (250) hide show
  1. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
  2. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
  3. ksadk/_build_provenance.json +1 -0
  4. ksadk/agui/_agent_helpers.py +4 -0
  5. ksadk/api/client.py +3 -0
  6. ksadk/builders/managed_runtime_builder.py +3 -0
  7. ksadk/cli/__init__.py +6 -0
  8. ksadk/cli/cmd_plugin.py +657 -0
  9. ksadk/codex/runtime.py +50 -8
  10. ksadk/configs/env_registry.py +31 -3
  11. ksadk/configs/settings.py +9 -0
  12. ksadk/context_engine/contributors.py +73 -8
  13. ksadk/conversations/__init__.py +19 -0
  14. ksadk/conversations/context.py +104 -24
  15. ksadk/conversations/contracts.py +266 -0
  16. ksadk/conversations/message_projection.py +19 -1
  17. ksadk/conversations/projector.py +616 -0
  18. ksadk/conversations/reducer.py +98 -0
  19. ksadk/events/_v1_compat/projection.py +2 -0
  20. ksadk/events/adapters/codex.py +190 -0
  21. ksadk/harness/__init__.py +45 -35
  22. ksadk/harness/runtime.py +60 -1
  23. ksadk/kernel/contract_fingerprints.py +5 -4
  24. ksadk/kernel/contracts.py +8 -0
  25. ksadk/kernel/control.py +1 -0
  26. ksadk/kernel/ingress.py +21 -0
  27. ksadk/kernel/memory_store.py +1 -0
  28. ksadk/kernel/postgres_store.py +1 -0
  29. ksadk/kernel/sqlite_store.py +1 -0
  30. ksadk/kernel/worker.py +11 -0
  31. ksadk/memory/providers/local_sqlite.py +7 -0
  32. ksadk/plugins/__init__.py +167 -0
  33. ksadk/plugins/bridges/__init__.py +45 -0
  34. ksadk/plugins/bridges/codex.py +552 -0
  35. ksadk/plugins/bridges/dsh.py +1116 -0
  36. ksadk/plugins/builtins.py +747 -0
  37. ksadk/plugins/bundle.py +246 -0
  38. ksadk/plugins/bundle_security.py +167 -0
  39. ksadk/plugins/composition.py +529 -0
  40. ksadk/plugins/context_contributor.py +437 -0
  41. ksadk/plugins/contracts.py +451 -0
  42. ksadk/plugins/dsh_toolchain.py +935 -0
  43. ksadk/plugins/ecosystem_bridge.py +1105 -0
  44. ksadk/plugins/ecosystem_probe.py +191 -0
  45. ksadk/plugins/host.py +724 -0
  46. ksadk/plugins/providers/__init__.py +85 -0
  47. ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
  48. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
  49. ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
  50. ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
  51. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
  52. ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
  53. ksadk/plugins/providers/codex.py +722 -0
  54. ksadk/plugins/providers/codex_dsh.py +83 -0
  55. ksadk/plugins/providers/dsh.py +951 -0
  56. ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
  57. ksadk/plugins/providers/harness.py +627 -0
  58. ksadk/plugins/providers/harness_dsh.py +91 -0
  59. ksadk/plugins/providers/legacy.py +215 -0
  60. ksadk/plugins/providers/legacy_catalog.py +100 -0
  61. ksadk/plugins/providers/shipped_dsh.py +370 -0
  62. ksadk/plugins/resolver.py +331 -0
  63. ksadk/plugins/subagent_providers/__init__.py +12 -0
  64. ksadk/plugins/subagent_providers/codex.py +443 -0
  65. ksadk/plugins/subagents.py +333 -0
  66. ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
  67. ksadk/runtime/adapter.py +1 -0
  68. ksadk/runtime/factory.py +76 -2
  69. ksadk/runtime/framework_adapters.py +18 -0
  70. ksadk/runtime/runner_adapter.py +5 -0
  71. ksadk/sandbox/__init__.py +2 -1
  72. ksadk/sandbox/factory.py +72 -0
  73. ksadk/scheduler/__init__.py +18 -0
  74. ksadk/scheduler/calendar.py +102 -0
  75. ksadk/scheduler/contracts.py +254 -0
  76. ksadk/scheduler/dispatcher.py +129 -0
  77. ksadk/scheduler/engine.py +416 -0
  78. ksadk/scheduler/sqlite_store.py +563 -0
  79. ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
  80. ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
  81. ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
  82. ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
  83. ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
  84. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
  85. ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
  86. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
  87. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
  88. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
  89. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
  90. ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
  91. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
  92. ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
  93. ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
  94. ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
  95. ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
  96. ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
  97. ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
  98. ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
  99. ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
  100. ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
  101. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
  102. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
  103. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
  104. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
  105. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
  106. ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
  107. ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
  108. ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
  109. ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
  110. ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
  111. ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
  112. ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
  113. ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
  114. ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
  115. ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
  116. ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
  117. ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
  118. ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
  119. ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
  120. ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
  121. ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
  122. ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
  123. ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
  124. ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
  125. ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
  126. ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
  127. ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
  128. ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
  129. ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
  130. ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
  131. ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
  132. ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
  133. ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
  134. ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
  135. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
  136. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
  137. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
  138. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
  139. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
  140. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
  141. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
  142. ksadk/server/static/assets/index-B2k_urY8.js +241 -0
  143. ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
  144. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
  145. ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
  146. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
  147. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
  148. ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
  149. ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
  150. ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
  151. ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
  152. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
  153. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
  154. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
  155. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
  156. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
  157. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
  158. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
  159. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
  160. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
  161. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
  162. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
  163. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
  164. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
  165. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
  166. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
  167. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
  168. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
  169. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
  170. ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
  171. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
  172. ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
  173. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
  174. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
  175. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
  176. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
  177. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
  178. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
  179. ksadk/server/static/index.html +2 -2
  180. ksadk/skills/service_client.py +48 -0
  181. ksadk/studio/agent_lifecycle.py +26 -20
  182. ksadk/studio/api.py +513 -71
  183. ksadk/studio/api_catalog_routes.py +5 -0
  184. ksadk/studio/api_contracts.py +34 -1
  185. ksadk/studio/api_plugin_routes.py +480 -0
  186. ksadk/studio/attachment_store.py +187 -0
  187. ksadk/studio/authoring.py +10 -4
  188. ksadk/studio/authoring_coordinator.py +12 -2
  189. ksadk/studio/builder.py +123 -43
  190. ksadk/studio/cloud.py +4 -0
  191. ksadk/studio/codex_agent_service.py +12 -1
  192. ksadk/studio/codex_builder.py +54 -15
  193. ksadk/studio/codex_manifest.py +21 -1
  194. ksadk/studio/codex_run.py +16 -4
  195. ksadk/studio/compatibility_report.py +445 -0
  196. ksadk/studio/compiler.py +6 -1
  197. ksadk/studio/contracts.py +123 -4
  198. ksadk/studio/dsh_provider_registration.py +768 -0
  199. ksadk/studio/event_store.py +54 -6
  200. ksadk/studio/framework_run.py +37 -4
  201. ksadk/studio/hosted_kernel.py +1 -1
  202. ksadk/studio/operations.py +12 -2
  203. ksadk/studio/plugin_composition.py +301 -0
  204. ksadk/studio/plugin_kernel_adapter.py +128 -0
  205. ksadk/studio/plugin_runtime.py +652 -0
  206. ksadk/studio/resource_catalog.py +6 -1
  207. ksadk/studio/run_service.py +713 -75
  208. ksadk/studio/runtime_source.py +9 -1
  209. ksadk/studio/scheduler_runtime.py +374 -0
  210. ksadk/studio/scheduler_service.py +211 -0
  211. ksadk/studio/service.py +672 -82
  212. ksadk/studio/shared_web.py +167 -28
  213. ksadk/studio/soul.py +52 -0
  214. ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
  215. ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
  216. ksadk/studio/static/index.html +2 -2
  217. ksadk/studio/validator.py +1 -1
  218. ksadk/studio/workspace.py +1 -0
  219. ksadk/version.py +1 -1
  220. ksadk_runtime_common/workspace_files/path_utils.py +41 -0
  221. ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
  222. ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
  223. ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
  224. ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
  225. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
  226. ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
  227. ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
  228. ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
  229. ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
  230. ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
  231. ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
  232. ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
  233. ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
  234. ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
  235. ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
  236. ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
  237. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
  238. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
  239. ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
  240. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
  241. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
  242. ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
  243. ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
  244. ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
  245. ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
  246. ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
  247. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
  248. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
  249. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
  250. {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
@@ -51,6 +51,13 @@ class CodexBuildRecord(ContractModel):
51
51
  # New builds always persist a mapping (possibly empty), so run resolution
52
52
  # never consults mutable Catalog state after the build has been created.
53
53
  model_profiles: dict[str, dict[str, Any]] | None = None
54
+ # Resource ids and model names are different namespaces. Keep the exact
55
+ # Studio bindings separately so currentness checks never compare a model
56
+ # name (``glm-5.2``) with a Catalog id (``model:provider:glm-5-2:live``).
57
+ # ``None`` only allows older local records to be read and rejected as
58
+ # stale with an actionable rebuild; Phase 2 has not shipped yet, so the
59
+ # deployment path does not carry a legacy identity-migration branch.
60
+ model_profile_ids: list[str] | None = None
54
61
  created_at: datetime
55
62
 
56
63
 
@@ -272,7 +279,12 @@ class CodexStudioBuilder:
272
279
  allowed_models=snapshot.manifest.allowed_models,
273
280
  ignore_missing=True,
274
281
  )
275
- build_id = self._build_id(snapshot.manifest_sha256, model_profiles)
282
+ model_profile_ids = self._bound_model_profile_ids(snapshot.manifest.name)
283
+ build_id = self._build_id(
284
+ snapshot.manifest_sha256,
285
+ model_profiles,
286
+ model_profile_ids=model_profile_ids,
287
+ )
276
288
  try:
277
289
  existing = self.repository.get(build_id)
278
290
  except StudioError as exc:
@@ -337,6 +349,7 @@ class CodexStudioBuilder:
337
349
  proxy_mode=current_proxy_mode(),
338
350
  runtime_lock=lock,
339
351
  model_profiles=model_profiles,
352
+ model_profile_ids=model_profile_ids,
340
353
  created_at=datetime.now(timezone.utc),
341
354
  )
342
355
  return self.repository.save(record)
@@ -347,29 +360,41 @@ class CodexStudioBuilder:
347
360
  return False
348
361
  if record.model_profiles is None:
349
362
  return True
350
- try:
351
- current_profiles = self._model_profile_snapshot(
352
- snapshot.manifest.name,
353
- allowed_models=snapshot.manifest.allowed_models,
354
- )
355
- except StudioError as exc:
356
- if exc.code == "RESOURCE_NOT_FOUND":
357
- # A completed Build owns its connection snapshot. A later
358
- # Catalog cleanup must not make that immutable Build
359
- # undeployable; launch resolution reads the snapshot instead.
360
- return True
361
- raise
363
+ if record.model_profile_ids is None:
364
+ return False
365
+ draft = self.drafts.get(record.agent_name) if self.drafts is not None else None
366
+ if draft is None:
367
+ return not record.model_profiles
368
+
369
+ bound_ids = set(self._bound_model_profile_ids(record.agent_name))
370
+ if set(record.model_profile_ids) != bound_ids:
371
+ return False
372
+ current_profiles = self._model_profile_snapshot(
373
+ snapshot.manifest.name,
374
+ allowed_models=snapshot.manifest.allowed_models,
375
+ ignore_missing=True,
376
+ )
377
+ # Provider-discovered Catalog entries are process-local. A restart may
378
+ # temporarily remove them, but the Build still owns an immutable,
379
+ # runnable connection snapshot and must remain deployable.
380
+ if bound_ids and not current_profiles:
381
+ return True
362
382
  return record.model_profiles == current_profiles
363
383
 
364
384
  @staticmethod
365
385
  def _build_id(
366
386
  manifest_sha256: str,
367
387
  model_profiles: dict[str, dict[str, Any]],
388
+ *,
389
+ model_profile_ids: list[str] | None = None,
368
390
  ) -> str:
369
- if not model_profiles:
391
+ if not model_profiles and not model_profile_ids:
370
392
  return f"build_{manifest_sha256[:20]}"
371
393
  fingerprint = json.dumps(
372
- model_profiles,
394
+ {
395
+ "profiles": model_profiles,
396
+ "resourceIds": sorted(model_profile_ids or []),
397
+ },
373
398
  ensure_ascii=False,
374
399
  sort_keys=True,
375
400
  separators=(",", ":"),
@@ -417,10 +442,24 @@ class CodexStudioBuilder:
417
442
  by_alias=True,
418
443
  exclude_defaults=True,
419
444
  exclude_none=True,
445
+ exclude={"metadata", "discovery"},
420
446
  mode="json",
421
447
  )
422
448
  return profiles
423
449
 
450
+ def _bound_model_profile_ids(self, agent_id: str) -> list[str]:
451
+ if self.drafts is None:
452
+ return []
453
+ draft = self.drafts.get(agent_id)
454
+ if draft is None:
455
+ return []
456
+ bindings = draft.spec.bindings
457
+ resource_ids = list(getattr(bindings, "model_profile_ids", []) or [])
458
+ default_id = getattr(bindings, "model_profile_id", None)
459
+ if not resource_ids and default_id:
460
+ resource_ids = [default_id]
461
+ return list(dict.fromkeys(resource_ids))
462
+
424
463
  @staticmethod
425
464
  def _runtime_lock(artifact_path: Path) -> dict:
426
465
  if artifact_path.suffix == ".zip":
@@ -13,8 +13,9 @@ import yaml # type: ignore[import-untyped]
13
13
  from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator
14
14
 
15
15
  from ksadk.builders.managed_runtime_builder import serialize_managed_runtime_manifest
16
- from ksadk.studio.contracts import ContextSpec, MemorySpec
16
+ from ksadk.studio.contracts import ContextSpec, MemorySpec, SoulDocument
17
17
  from ksadk.studio.errors import StudioError, not_found
18
+ from ksadk.studio.soul import soul_digest as compute_soul_digest
18
19
  from ksadk.studio.workspace import Workspace
19
20
 
20
21
 
@@ -43,6 +44,12 @@ class CodexAgentManifest(BaseModel):
43
44
  # Codex Runtime 最终仍消费合并后的 base_instructions;该字段用于在 AgentVersion /
44
45
  # Build 中保留任务契约来源,避免为了运行投影而破坏 PromptSection 审计。
45
46
  task_prompt: str | None = Field(default=None, max_length=32768)
47
+ # Soul remains reviewed source in the ManagedRuntime manifest. Runtime
48
+ # launch deterministically compiles it before ``prompt``; these provenance
49
+ # fields prevent a Draft-only Soul from masquerading as deployed behavior.
50
+ soul: SoulDocument | None = None
51
+ soul_source: Literal["AgentSpec.soul"] | None = None
52
+ soul_digest: str | None = Field(default=None, pattern=r"^sha256:[0-9a-f]{64}$")
46
53
  skills: list[str] | None = None
47
54
  mcp_servers: list[dict[str, Any]] | None = None
48
55
  sandbox: str | None = None
@@ -98,6 +105,17 @@ class CodexAgentManifest(BaseModel):
98
105
  mcp_seen.add(name)
99
106
  mcp_deduped.append(server)
100
107
  self.mcp_servers = mcp_deduped
108
+ if self.soul is None:
109
+ if self.soul_source is not None or self.soul_digest is not None:
110
+ raise ValueError("soul source/digest require a SoulDocument")
111
+ else:
112
+ expected_digest = compute_soul_digest(self.soul)
113
+ if self.soul_source not in {None, "AgentSpec.soul"}:
114
+ raise ValueError("soul_source must identify AgentSpec.soul")
115
+ if self.soul_digest not in {None, expected_digest}:
116
+ raise ValueError("soul_digest does not match the SoulDocument")
117
+ self.soul_source = "AgentSpec.soul"
118
+ self.soul_digest = expected_digest
101
119
  return self
102
120
 
103
121
  @property
@@ -113,6 +131,8 @@ def normalized_manifest_bytes(manifest: CodexAgentManifest) -> bytes:
113
131
  payload["context"] = manifest.context.model_dump(mode="python", by_alias=True)
114
132
  if manifest.memory is not None:
115
133
  payload["memory"] = manifest.memory.model_dump(mode="python", by_alias=True)
134
+ if manifest.soul is not None:
135
+ payload["soul"] = manifest.soul.model_dump(mode="python", by_alias=True)
116
136
  return serialize_managed_runtime_manifest(payload)
117
137
 
118
138
 
ksadk/studio/codex_run.py CHANGED
@@ -12,9 +12,10 @@ from ksadk.configs import ModelConfig
12
12
  from ksadk.runtime import RuntimeLaunchContext
13
13
  from ksadk.studio.codex_builder import CodexBuildRepository
14
14
  from ksadk.studio.codex_manifest import CodexAgentManifest, CodexManifestRepository
15
- from ksadk.studio.contracts import ModelSpec
15
+ from ksadk.studio.contracts import Instructions, ModelSpec
16
16
  from ksadk.studio.errors import StudioError
17
17
  from ksadk.studio.run_service import StudioRunSpec
18
+ from ksadk.studio.soul import compose_system_instruction
18
19
  from ksadk.studio.workspace import Workspace
19
20
  from ksadk.tools.gateway import normalize_tool_approval_mode
20
21
 
@@ -87,18 +88,22 @@ class CodexRunSpecResolver:
87
88
  if runtime_env:
88
89
  launch_config["env"] = runtime_env
89
90
  agent_task = str(manifest.task_prompt or "").strip()
91
+ agent_system = compose_system_instruction(
92
+ Instructions(system=manifest.prompt),
93
+ manifest.soul,
94
+ ).system
90
95
  # PCM 策略从不可变 Manifest 读取(方案 §5.1:Build 锁定后 sidecar 修改不影响旧 Build)
91
96
  # manifest.context/memory 由 _manifest() 从 AgentSpec 写入,随 Build 进入 Artifact
92
97
  resolved_context = manifest.context
93
98
  resolved_memory = manifest.memory
94
- base_instructions = manifest.prompt
99
+ base_instructions = agent_system
95
100
  if agent_task:
96
- base_instructions = f"{manifest.prompt}\n\n{agent_task}"
101
+ base_instructions = f"{agent_system}\n\n{agent_task}"
97
102
  request_config: dict[str, Any] = {
98
103
  # Codex 原生只接收 base_instructions,因此运行前合并;PCM 证据仍使用下面
99
104
  # 两个独立来源生成 agent_identity / agent_policy 的分段 hash。
100
105
  "base_instructions": base_instructions,
101
- "agent_system": manifest.prompt,
106
+ "agent_system": agent_system,
102
107
  "agent_task": agent_task,
103
108
  "cwd": str(project_dir),
104
109
  "skills": skills,
@@ -136,6 +141,13 @@ class CodexRunSpecResolver:
136
141
  }
137
142
  if approval_profile:
138
143
  request_config["tool_approval_mode"] = approval_profile
144
+ if manifest.soul is not None:
145
+ request_config.update(
146
+ {
147
+ "soul_source": manifest.soul_source,
148
+ "soul_digest": manifest.soul_digest,
149
+ }
150
+ )
139
151
  return StudioRunSpec(
140
152
  launch_context=RuntimeLaunchContext(
141
153
  runtime_type="codex",
@@ -0,0 +1,445 @@
1
+ """Deterministic build-time compatibility report for AgentBundle v2.
2
+
3
+ The report contains only immutable, already-resolved facts. It deliberately
4
+ does not inspect environment variables, import plugin entrypoints, or claim
5
+ that a process is healthy. Runtime readiness remains an Activation concern.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import json
12
+ from collections.abc import Callable, Mapping
13
+ from typing import Any
14
+
15
+ from ksadk.plugins.contracts import LockedCapability, PluginLockEntry, PluginManifest
16
+ from ksadk.plugins.resolver import (
17
+ PluginResolutionError,
18
+ ResolvedComposition,
19
+ version_satisfies,
20
+ )
21
+ from ksadk.studio.contracts import AgentDraft
22
+
23
+ COMPATIBILITY_REPORT_FORMAT = "agentkit.compatibility-report/v1"
24
+ CURRENT_KERNEL_API_VERSION = "1.0.0"
25
+ CURRENT_RUNTIME_CONTRACT = "agentkit.runtime/v1"
26
+ SUPPORTED_RUNTIME_PROTOCOLS = (CURRENT_RUNTIME_CONTRACT,)
27
+
28
+
29
+ def compatibility_facts_digest(
30
+ *,
31
+ draft: AgentDraft,
32
+ composition: ResolvedComposition | None,
33
+ runtime_lock: Mapping[str, Any],
34
+ ) -> str:
35
+ """Address every static input that can change a compatibility conclusion."""
36
+
37
+ payload: dict[str, Any] = {
38
+ "allowedPermissions": sorted(set(draft.spec.security.allowed_permissions)),
39
+ "runtime": {
40
+ "type": str(runtime_lock.get("type") or ""),
41
+ "version": str(runtime_lock.get("version") or ""),
42
+ },
43
+ "composition": None,
44
+ }
45
+ if composition is not None:
46
+ payload["composition"] = {
47
+ "profileDigest": composition.profile_digest,
48
+ "pluginLockDigest": composition.plugin_lock_digest,
49
+ "manifests": [
50
+ manifest.model_dump(
51
+ by_alias=True,
52
+ exclude_none=True,
53
+ mode="json",
54
+ )
55
+ for manifest in sorted(
56
+ composition.manifests,
57
+ key=lambda item: (item.metadata.id, item.metadata.version),
58
+ )
59
+ ],
60
+ }
61
+ canonical = json.dumps(
62
+ payload,
63
+ ensure_ascii=False,
64
+ sort_keys=True,
65
+ separators=(",", ":"),
66
+ ).encode("utf-8")
67
+ return f"sha256:{hashlib.sha256(canonical).hexdigest()}"
68
+
69
+
70
+ def build_bundle_compatibility_report(
71
+ *,
72
+ draft: AgentDraft,
73
+ composition: ResolvedComposition | None,
74
+ runtime_lock: Mapping[str, Any],
75
+ resolved_digest: str,
76
+ facts_digest: str,
77
+ plugin_lock_digest: str,
78
+ composition_profile_digest: str | None,
79
+ ) -> dict[str, Any]:
80
+ """Project auditable static compatibility without reading host secrets."""
81
+
82
+ bundle = {
83
+ "bundleFormat": "agentkit.bundle/v2",
84
+ "compatibilityFactsDigest": facts_digest,
85
+ "resolvedDigest": resolved_digest,
86
+ "pluginLockDigest": plugin_lock_digest,
87
+ **(
88
+ {"compositionProfileDigest": composition_profile_digest}
89
+ if composition_profile_digest is not None
90
+ else {}
91
+ ),
92
+ }
93
+ allowed_permissions = sorted(set(draft.spec.security.allowed_permissions))
94
+ if composition is None:
95
+ return _legacy_report(
96
+ bundle=bundle,
97
+ runtime_lock=runtime_lock,
98
+ allowed_permissions=allowed_permissions,
99
+ )
100
+
101
+ manifests = {manifest.metadata.id: manifest for manifest in composition.manifests}
102
+ locked = {entry.id: entry for entry in composition.plugin_lock.plugins}
103
+ blockers: list[dict[str, str]] = []
104
+
105
+ def block(code: str, subject: str, reason: str) -> None:
106
+ blockers.append({"code": code, "subject": subject, "reason": reason})
107
+
108
+ permission_items: list[dict[str, Any]] = []
109
+ protocol_items: list[dict[str, Any]] = []
110
+ kernel_items: list[dict[str, str]] = []
111
+ capability_items: list[dict[str, str]] = []
112
+
113
+ for entry in composition.plugin_lock.plugins:
114
+ manifest = manifests.get(entry.id)
115
+ if manifest is None:
116
+ block(
117
+ "plugin_manifest_facts_missing",
118
+ entry.id,
119
+ "The exact manifest used to resolve this lock entry is unavailable.",
120
+ )
121
+ permission_items.append(
122
+ {
123
+ "pluginId": entry.id,
124
+ "required": [],
125
+ "unapproved": [],
126
+ "status": "blocked",
127
+ }
128
+ )
129
+ protocol_items.append(
130
+ {
131
+ "pluginId": entry.id,
132
+ "required": [],
133
+ "supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
134
+ "status": "blocked",
135
+ }
136
+ )
137
+ kernel_items.append(
138
+ {
139
+ "pluginId": entry.id,
140
+ "required": "unknown",
141
+ "resolved": CURRENT_KERNEL_API_VERSION,
142
+ "status": "blocked",
143
+ }
144
+ )
145
+ for capability in entry.provides:
146
+ capability_items.append(
147
+ _capability_item(entry, capability, mode="unknown", status="blocked")
148
+ )
149
+ continue
150
+
151
+ _append_manifest_conclusions(
152
+ entry=entry,
153
+ manifest=manifest,
154
+ allowed_permissions=allowed_permissions,
155
+ permission_items=permission_items,
156
+ protocol_items=protocol_items,
157
+ kernel_items=kernel_items,
158
+ capability_items=capability_items,
159
+ block=block,
160
+ )
161
+
162
+ provider_ref = composition.profile.agent_provider.ref
163
+ provider_id, requested_version = _plugin_ref_parts(provider_ref)
164
+ provider_entry = locked.get(provider_id)
165
+ provider_manifest = manifests.get(provider_id)
166
+ if provider_entry is None:
167
+ block(
168
+ "agent_provider_lock_missing",
169
+ provider_id,
170
+ "The CompositionProfile AgentProvider has no exact PluginLock entry.",
171
+ )
172
+ elif provider_entry.version != requested_version:
173
+ block(
174
+ "agent_provider_version_mismatch",
175
+ provider_id,
176
+ (
177
+ f"Profile requests {requested_version}, but the lock resolves "
178
+ f"{provider_entry.version}."
179
+ ),
180
+ )
181
+
182
+ blockers.sort(key=lambda item: (item["code"], item["subject"], item["reason"]))
183
+ blocked_subjects = {item["subject"] for item in blockers}
184
+ overall = "blocked" if blockers else "compatible"
185
+ provider_status = "blocked" if provider_id in blocked_subjects else "compatible"
186
+
187
+ return {
188
+ "format": COMPATIBILITY_REPORT_FORMAT,
189
+ "scope": "build-time-static",
190
+ "overallStatus": overall,
191
+ "bundle": bundle,
192
+ "host": {
193
+ "kind": _host_kind(provider_manifest),
194
+ "kernelApiVersion": CURRENT_KERNEL_API_VERSION,
195
+ "runtimeContract": CURRENT_RUNTIME_CONTRACT,
196
+ "readiness": "notEvaluated",
197
+ "status": overall,
198
+ },
199
+ "provider": _provider_conclusion(
200
+ provider_ref=provider_ref,
201
+ provider_id=provider_id,
202
+ requested_version=requested_version,
203
+ entry=provider_entry,
204
+ manifest=provider_manifest,
205
+ status=provider_status,
206
+ ),
207
+ "kernelApi": sorted(kernel_items, key=lambda item: item["pluginId"]),
208
+ "protocols": sorted(protocol_items, key=lambda item: item["pluginId"]),
209
+ "permissions": {
210
+ "allowed": allowed_permissions,
211
+ "plugins": sorted(permission_items, key=lambda item: item["pluginId"]),
212
+ "status": (
213
+ "blocked"
214
+ if any(item["status"] == "blocked" for item in permission_items)
215
+ else "compatible"
216
+ ),
217
+ },
218
+ "capabilities": sorted(
219
+ capability_items,
220
+ key=lambda item: (item["definition"], item["slot"], item["owner"]),
221
+ ),
222
+ "blockingReasons": blockers,
223
+ }
224
+
225
+
226
+ def _legacy_report(
227
+ *,
228
+ bundle: dict[str, Any],
229
+ runtime_lock: Mapping[str, Any],
230
+ allowed_permissions: list[str],
231
+ ) -> dict[str, Any]:
232
+ runtime_type = str(runtime_lock.get("type") or "")
233
+ version = str(runtime_lock.get("version") or "")
234
+ return {
235
+ "format": COMPATIBILITY_REPORT_FORMAT,
236
+ "scope": "build-time-static",
237
+ "overallStatus": "compatible",
238
+ "bundle": bundle,
239
+ "host": {
240
+ "kind": "legacy-runtime",
241
+ "kernelApiVersion": CURRENT_KERNEL_API_VERSION,
242
+ "runtimeContract": CURRENT_RUNTIME_CONTRACT,
243
+ "readiness": "notEvaluated",
244
+ "status": "compatible",
245
+ },
246
+ "provider": {
247
+ "ref": None,
248
+ "id": runtime_type or "builtin.legacy",
249
+ "hostRuntime": runtime_type or "unknown",
250
+ "isolation": "legacy",
251
+ "source": "builtin",
252
+ "digest": None,
253
+ "version": {
254
+ "requested": version or None,
255
+ "resolved": version or None,
256
+ "status": "compatible" if version else "unknown",
257
+ },
258
+ "status": "compatible",
259
+ },
260
+ "kernelApi": [],
261
+ "protocols": [
262
+ {
263
+ "pluginId": runtime_type or "builtin.legacy",
264
+ "required": [CURRENT_RUNTIME_CONTRACT],
265
+ "supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
266
+ "status": "compatible",
267
+ }
268
+ ],
269
+ "permissions": {
270
+ "allowed": allowed_permissions,
271
+ "plugins": [],
272
+ "status": "compatible",
273
+ },
274
+ "capabilities": [],
275
+ "blockingReasons": [],
276
+ }
277
+
278
+
279
+ def _append_manifest_conclusions(
280
+ *,
281
+ entry: PluginLockEntry,
282
+ manifest: PluginManifest,
283
+ allowed_permissions: list[str],
284
+ permission_items: list[dict[str, Any]],
285
+ protocol_items: list[dict[str, Any]],
286
+ kernel_items: list[dict[str, str]],
287
+ capability_items: list[dict[str, str]],
288
+ block: Callable[[str, str, str], None],
289
+ ) -> None:
290
+ if (
291
+ manifest.metadata.id != entry.id
292
+ or manifest.metadata.version != entry.version
293
+ or manifest.spec.provenance.digest != entry.digest
294
+ ):
295
+ block(
296
+ "plugin_manifest_lock_mismatch",
297
+ entry.id,
298
+ "Resolved manifest identity or digest does not match the PluginLock entry.",
299
+ )
300
+
301
+ required_permissions = sorted(set(manifest.spec.permissions))
302
+ unapproved = sorted(set(required_permissions) - set(allowed_permissions))
303
+ permission_status = "blocked" if unapproved else "compatible"
304
+ permission_items.append(
305
+ {
306
+ "pluginId": entry.id,
307
+ "required": required_permissions,
308
+ "unapproved": unapproved,
309
+ "status": permission_status,
310
+ }
311
+ )
312
+ if unapproved:
313
+ block(
314
+ "plugin_permission_unapproved",
315
+ entry.id,
316
+ "Unapproved permissions: " + ", ".join(unapproved),
317
+ )
318
+
319
+ protocols = sorted(set(manifest.spec.compatibility.runtime_protocols))
320
+ protocol_status = (
321
+ "compatible" if not protocols or CURRENT_RUNTIME_CONTRACT in protocols else "blocked"
322
+ )
323
+ protocol_items.append(
324
+ {
325
+ "pluginId": entry.id,
326
+ "required": protocols,
327
+ "supported": list(SUPPORTED_RUNTIME_PROTOCOLS),
328
+ "status": protocol_status,
329
+ }
330
+ )
331
+ if protocol_status == "blocked":
332
+ block(
333
+ "runtime_protocol_incompatible",
334
+ entry.id,
335
+ f"Plugin accepts {', '.join(protocols)}, host provides {CURRENT_RUNTIME_CONTRACT}.",
336
+ )
337
+
338
+ kernel_constraint = manifest.spec.compatibility.kernel_api
339
+ try:
340
+ kernel_compatible = version_satisfies(
341
+ CURRENT_KERNEL_API_VERSION,
342
+ kernel_constraint,
343
+ )
344
+ except PluginResolutionError:
345
+ kernel_compatible = False
346
+ kernel_items.append(
347
+ {
348
+ "pluginId": entry.id,
349
+ "required": kernel_constraint,
350
+ "resolved": CURRENT_KERNEL_API_VERSION,
351
+ "status": "compatible" if kernel_compatible else "blocked",
352
+ }
353
+ )
354
+ if not kernel_compatible:
355
+ block(
356
+ "kernel_api_incompatible",
357
+ entry.id,
358
+ f"Plugin requires {kernel_constraint}, host provides {CURRENT_KERNEL_API_VERSION}.",
359
+ )
360
+
361
+ offers = {(offer.definition, offer.slot): offer for offer in manifest.spec.provides}
362
+ for capability in entry.provides:
363
+ offer = offers.get((capability.definition, capability.slot))
364
+ status = "compatible" if capability.owner == entry.id and offer is not None else "blocked"
365
+ capability_items.append(
366
+ _capability_item(
367
+ entry,
368
+ capability,
369
+ mode=offer.mode if offer is not None else "unknown",
370
+ status=status,
371
+ )
372
+ )
373
+ if status == "blocked":
374
+ block(
375
+ "capability_lock_mismatch",
376
+ entry.id,
377
+ f"Locked capability {capability.definition} at {capability.slot} "
378
+ "does not match the resolved manifest owner.",
379
+ )
380
+
381
+
382
+ def _capability_item(
383
+ entry: PluginLockEntry,
384
+ capability: LockedCapability,
385
+ *,
386
+ mode: str,
387
+ status: str,
388
+ ) -> dict[str, str]:
389
+ return {
390
+ "definition": capability.definition,
391
+ "slot": capability.slot,
392
+ "owner": capability.owner,
393
+ "version": entry.version,
394
+ "mode": mode,
395
+ "status": status,
396
+ }
397
+
398
+
399
+ def _provider_conclusion(
400
+ *,
401
+ provider_ref: str,
402
+ provider_id: str,
403
+ requested_version: str,
404
+ entry: PluginLockEntry | None,
405
+ manifest: PluginManifest | None,
406
+ status: str,
407
+ ) -> dict[str, Any]:
408
+ return {
409
+ "ref": provider_ref,
410
+ "id": provider_id,
411
+ "hostRuntime": manifest.spec.runtime if manifest is not None else "unknown",
412
+ "isolation": manifest.spec.isolation if manifest is not None else "unknown",
413
+ "source": entry.source if entry is not None else "unknown",
414
+ "digest": entry.digest if entry is not None else None,
415
+ "version": {
416
+ "requested": requested_version,
417
+ "resolved": entry.version if entry is not None else None,
418
+ "status": (
419
+ "compatible"
420
+ if entry is not None and entry.version == requested_version
421
+ else "blocked"
422
+ ),
423
+ },
424
+ "status": status,
425
+ }
426
+
427
+
428
+ def _host_kind(provider: PluginManifest | None) -> str:
429
+ if provider is not None and provider.spec.domain == "runtime-native":
430
+ return "runtime-native"
431
+ return "composition-host"
432
+
433
+
434
+ def _plugin_ref_parts(value: str) -> tuple[str, str]:
435
+ plugin_id, version = value.removeprefix("plugin://").rsplit("@", 1)
436
+ return plugin_id, version
437
+
438
+
439
+ __all__ = [
440
+ "COMPATIBILITY_REPORT_FORMAT",
441
+ "CURRENT_KERNEL_API_VERSION",
442
+ "CURRENT_RUNTIME_CONTRACT",
443
+ "build_bundle_compatibility_report",
444
+ "compatibility_facts_digest",
445
+ ]
ksadk/studio/compiler.py CHANGED
@@ -20,6 +20,7 @@ from ksadk.studio.contracts import (
20
20
  )
21
21
  from ksadk.studio.errors import StudioError
22
22
  from ksadk.studio.resource_catalog import LocalResourceCatalog
23
+ from ksadk.studio.soul import compose_system_instruction
23
24
  from ksadk.studio.validator import AgentValidator
24
25
  from ksadk.studio.workspace import Workspace
25
26
 
@@ -72,7 +73,11 @@ class AgentCompiler:
72
73
  resolved = ResolvedAgentSpec(
73
74
  agent_id=draft.metadata.id,
74
75
  source_revision=draft.metadata.revision,
75
- instructions=materialized.spec.instructions,
76
+ instructions=compose_system_instruction(
77
+ materialized.spec.instructions,
78
+ materialized.spec.soul,
79
+ ),
80
+ soul=materialized.spec.soul,
76
81
  model=self.resolver.resolve_model(materialized.spec.model),
77
82
  capabilities=ResolvedCapabilities(
78
83
  skills=skills,