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
@@ -0,0 +1,187 @@
1
+ """Bounded, content-addressed local attachments for ConversationInput."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import re
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+
11
+ from ksadk.studio.errors import StudioError, not_found
12
+ from ksadk.studio.workspace import Workspace
13
+
14
+ _ATTACHMENT_REF = re.compile(r"^attachment://sha256/(?P<digest>[0-9a-f]{64})$")
15
+ _SAFE_FILENAME = re.compile(r"[^A-Za-z0-9._-]+")
16
+ _TEXT_MEDIA_TYPES = {
17
+ "application/json",
18
+ "application/toml",
19
+ "application/xml",
20
+ "application/x-httpd-php",
21
+ "application/x-sh",
22
+ "application/x-yaml",
23
+ }
24
+ _TEXT_SUFFIXES = {
25
+ ".csv",
26
+ ".css",
27
+ ".go",
28
+ ".html",
29
+ ".ini",
30
+ ".java",
31
+ ".js",
32
+ ".json",
33
+ ".jsx",
34
+ ".log",
35
+ ".md",
36
+ ".py",
37
+ ".rs",
38
+ ".sh",
39
+ ".toml",
40
+ ".ts",
41
+ ".tsx",
42
+ ".txt",
43
+ ".xml",
44
+ ".yaml",
45
+ ".yml",
46
+ }
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class StoredConversationAttachment:
51
+ attachment_ref: str
52
+ path: Path
53
+ name: str
54
+ media_type: str
55
+ size: int
56
+ digest: str
57
+
58
+
59
+ class ConversationAttachmentStore:
60
+ """Persist only the small image/text inputs supported by local Studio."""
61
+
62
+ MAX_BYTES = 1_500_000
63
+
64
+ def __init__(self, workspace: Workspace) -> None:
65
+ self.workspace = workspace
66
+ self.root = self.workspace.resolve(".agentkit/assets/conversation-attachments")
67
+ self.root.mkdir(parents=True, exist_ok=True)
68
+
69
+ def store(self, content: bytes, *, filename: str, media_type: str) -> dict[str, object]:
70
+ if not content:
71
+ raise StudioError(
72
+ "CONVERSATION_ATTACHMENT_EMPTY",
73
+ "会话附件不能为空",
74
+ status_code=422,
75
+ field="file",
76
+ )
77
+ if len(content) > self.MAX_BYTES:
78
+ raise StudioError(
79
+ "CONVERSATION_ATTACHMENT_TOO_LARGE",
80
+ "会话附件不能超过 1.5 MiB",
81
+ status_code=413,
82
+ field="file",
83
+ details={"maxBytes": self.MAX_BYTES},
84
+ )
85
+ normalized_type = media_type.split(";", 1)[0].strip().lower()
86
+ safe_name = _SAFE_FILENAME.sub("-", Path(filename).name).strip(".-")[:160]
87
+ safe_name = safe_name or "attachment"
88
+ if not self._supported(content, filename=safe_name, media_type=normalized_type):
89
+ raise StudioError(
90
+ "CONVERSATION_ATTACHMENT_TYPE_UNSUPPORTED",
91
+ "会话附件仅支持图片或 UTF-8 文本、代码文件",
92
+ status_code=415,
93
+ field="file",
94
+ )
95
+
96
+ digest = hashlib.sha256(content).hexdigest()
97
+ content_path = self.root / f"{digest}.bin"
98
+ metadata_path = self.root / f"{digest}.json"
99
+ if not content_path.is_file():
100
+ self.workspace.atomic_write_bytes(content_path, content)
101
+ if not metadata_path.is_file():
102
+ self.workspace.atomic_write_text(
103
+ metadata_path,
104
+ json.dumps(
105
+ {
106
+ "digest": digest,
107
+ "name": safe_name,
108
+ "mediaType": normalized_type or "application/octet-stream",
109
+ "size": len(content),
110
+ },
111
+ ensure_ascii=False,
112
+ sort_keys=True,
113
+ separators=(",", ":"),
114
+ )
115
+ + "\n",
116
+ )
117
+ # The reference identifies content, so its persisted metadata is the
118
+ # authority as well. Returning a second upload's conflicting name or
119
+ # media type would create a ref that immediately fails on resolution.
120
+ stored = self.resolve(f"attachment://sha256/{digest}")
121
+ return {
122
+ "attachmentRef": stored.attachment_ref,
123
+ "name": stored.name,
124
+ "mediaType": stored.media_type,
125
+ "size": stored.size,
126
+ "digest": stored.digest,
127
+ }
128
+
129
+ def resolve(self, attachment_ref: str) -> StoredConversationAttachment:
130
+ match = _ATTACHMENT_REF.fullmatch(attachment_ref)
131
+ if match is None:
132
+ raise not_found("conversation-attachment", attachment_ref)
133
+ digest = match.group("digest")
134
+ content_path = self.root / f"{digest}.bin"
135
+ metadata_path = self.root / f"{digest}.json"
136
+ if not content_path.is_file() or not metadata_path.is_file():
137
+ raise not_found("conversation-attachment", attachment_ref)
138
+ try:
139
+ metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
140
+ content = content_path.read_bytes()
141
+ content_size = len(content)
142
+ except (OSError, json.JSONDecodeError) as exc:
143
+ raise StudioError(
144
+ "CONVERSATION_ATTACHMENT_CORRUPT",
145
+ "会话附件元数据损坏",
146
+ status_code=409,
147
+ details={"attachmentRef": attachment_ref},
148
+ ) from exc
149
+ actual_digest = hashlib.sha256(content).hexdigest()
150
+ if (
151
+ metadata.get("digest") != digest
152
+ or actual_digest != digest
153
+ or int(metadata.get("size") or -1) != content_size
154
+ ):
155
+ raise StudioError(
156
+ "CONVERSATION_ATTACHMENT_CORRUPT",
157
+ "会话附件完整性校验失败",
158
+ status_code=409,
159
+ details={"attachmentRef": attachment_ref},
160
+ )
161
+ return StoredConversationAttachment(
162
+ attachment_ref=attachment_ref,
163
+ path=content_path,
164
+ name=str(metadata.get("name") or "attachment"),
165
+ media_type=str(metadata.get("mediaType") or "application/octet-stream"),
166
+ size=content_size,
167
+ digest=digest,
168
+ )
169
+
170
+ @staticmethod
171
+ def _supported(content: bytes, *, filename: str, media_type: str) -> bool:
172
+ if media_type.startswith("image/"):
173
+ return True
174
+ if (
175
+ media_type.startswith("text/")
176
+ or media_type in _TEXT_MEDIA_TYPES
177
+ or Path(filename).suffix.lower() in _TEXT_SUFFIXES
178
+ ):
179
+ try:
180
+ content.decode("utf-8")
181
+ except UnicodeDecodeError:
182
+ return False
183
+ return True
184
+ return False
185
+
186
+
187
+ __all__ = ["ConversationAttachmentStore", "StoredConversationAttachment"]
ksadk/studio/authoring.py CHANGED
@@ -694,6 +694,16 @@ class AgentAuthoringService:
694
694
  ignored.add(".git")
695
695
  entries: list[dict[str, Any]] = []
696
696
  for path in sorted(root.rglob("*"), key=lambda item: item.as_posix()):
697
+ relative = path.relative_to(root).as_posix()
698
+ # Studio state and VCS internals may legitimately contain symlinks
699
+ # (for example managed Node dependencies). They are outside the
700
+ # imported project contract, so prune them before applying the
701
+ # source-tree symlink safety check.
702
+ if any(
703
+ relative == ignored_dir or relative.startswith(ignored_dir + "/")
704
+ for ignored_dir in (".agentkit", ".git")
705
+ ):
706
+ continue
697
707
  if path.is_symlink():
698
708
  raise StudioError(
699
709
  "AUTHORING_SOURCE_UNSAFE",
@@ -703,10 +713,6 @@ class AgentAuthoringService:
703
713
  )
704
714
  if not path.is_file() or path.name in ignored:
705
715
  continue
706
- # 跳过 .agentkit / .git 目录下的文件
707
- relative = path.relative_to(root).as_posix()
708
- if any(relative.startswith(ignored_dir + "/") for ignored_dir in (".agentkit", ".git")):
709
- continue
710
716
  content = path.read_bytes()
711
717
  entries.append(
712
718
  {
@@ -278,7 +278,6 @@ class StudioAuthoringCoordinator:
278
278
  resolved = (spec or default_agent_spec(template, description=description)).model_copy(
279
279
  deep=True
280
280
  )
281
- canonical_runtime = self.backend.runtime_ref(agent_id, runtime_type)
282
281
  proposed_runtime = resolved.runtime
283
282
  if proposed_runtime is not None and proposed_runtime.type != runtime_type:
284
283
  raise StudioError(
@@ -291,7 +290,18 @@ class StudioAuthoringCoordinator:
291
290
  "specRuntimeType": proposed_runtime.type,
292
291
  },
293
292
  )
294
- if proposed_runtime is not None:
293
+ if runtime_type == "plugin":
294
+ if proposed_runtime is None or proposed_runtime.provider_ref is None:
295
+ raise StudioError(
296
+ "AGENT_PROVIDER_REFERENCE_REQUIRED",
297
+ "外部 AgentProvider 必须选择一个已安装的精确版本",
298
+ status_code=422,
299
+ field="spec.runtime.providerRef",
300
+ )
301
+ canonical_runtime = proposed_runtime.model_copy(deep=True)
302
+ else:
303
+ canonical_runtime = self.backend.runtime_ref(agent_id, runtime_type)
304
+ if proposed_runtime is not None and runtime_type != "plugin":
295
305
  if runtime_type == "codex" and proposed_runtime.version:
296
306
  canonical_runtime.version = proposed_runtime.version
297
307
  elif runtime_type in {"adk", "langgraph"}:
ksadk/studio/builder.py CHANGED
@@ -10,7 +10,14 @@ from datetime import datetime, timezone
10
10
  from pathlib import Path
11
11
  from uuid import uuid4
12
12
 
13
+ from ksadk.plugins.bundle_security import assert_bundle_security
14
+ from ksadk.plugins.contracts import CompositionProfile, PluginLock, plugin_lock_digest
15
+ from ksadk.plugins.resolver import ResolvedComposition
13
16
  from ksadk.studio.capabilities import canonical_json, compute_bundle_digest, sha256_digest
17
+ from ksadk.studio.compatibility_report import (
18
+ build_bundle_compatibility_report,
19
+ compatibility_facts_digest,
20
+ )
14
21
  from ksadk.studio.compiler import AgentCompiler
15
22
  from ksadk.studio.contracts import (
16
23
  AgentDraft,
@@ -24,6 +31,7 @@ from ksadk.studio.hosted_kernel import (
24
31
  hosted_kernel_requirement_digest,
25
32
  )
26
33
  from ksadk.studio.repository import BuildRepository
34
+ from ksadk.studio.soul import render_soul_markdown
27
35
  from ksadk.studio.workspace import Workspace
28
36
 
29
37
  _ZIP_TIMESTAMP = (1980, 1, 1, 0, 0, 0)
@@ -43,29 +51,46 @@ class AgentBundleBuilder:
43
51
  self.compiler = compiler or AgentCompiler(workspace)
44
52
  self.repository = repository or BuildRepository(workspace)
45
53
 
46
- def build(self, draft: AgentDraft) -> BuildRecord:
54
+ def build(
55
+ self,
56
+ draft: AgentDraft,
57
+ *,
58
+ composition: ResolvedComposition | None = None,
59
+ ) -> BuildRecord:
47
60
  LOGGER.info(
48
61
  "bundle build started: agent=%s revision=%s",
49
62
  draft.metadata.id,
50
63
  draft.metadata.revision,
51
64
  )
52
65
  compiled = self.compiler.compile(draft)
53
- # Bundle v2 always carries a lock. Phase 1 deliberately supports no
54
- # user-selectable plugin factories yet, so the only valid lock is the
55
- # explicit empty set. This makes admission deterministic without
56
- # pulling the Phase 2 PluginHost into a deployed runtime.
57
- plugin_lock = {"lockFormat": "agentkit.plugin-lock/v1", "plugins": []}
58
- plugin_lock_digest = sha256_digest(canonical_json(plugin_lock))
66
+ # Bundle v2 already carries a deterministic empty lock. P2-00A now
67
+ # validates that wire shape through PluginLock while deliberately not
68
+ # resolving or loading a PluginHost before P2-02/P2-03.
69
+ parsed_plugin_lock = composition.plugin_lock if composition else PluginLock()
70
+ plugin_lock = parsed_plugin_lock.model_dump(
71
+ by_alias=True,
72
+ exclude_none=True,
73
+ mode="json",
74
+ )
75
+ plugin_lock_digest_value = plugin_lock_digest(parsed_plugin_lock)
76
+ composition_profile = composition.profile if composition else None
77
+ composition_profile_digest_value = composition.profile_digest if composition else None
59
78
  runtime_type, source_digest, runtime_lock = self._runtime_snapshot(draft, compiled)
60
- resolved_digest = sha256_digest(
61
- canonical_json(
62
- {
63
- "definitionDigest": compiled.resolved.resolved_digest,
64
- "runtime": runtime_lock,
65
- "sourceDigest": source_digest,
66
- }
67
- )
79
+ compatibility_facts_digest_value = compatibility_facts_digest(
80
+ draft=draft,
81
+ composition=composition,
82
+ runtime_lock=runtime_lock,
68
83
  )
84
+ resolved_digest_payload = {
85
+ "compatibilityFactsDigest": compatibility_facts_digest_value,
86
+ "definitionDigest": compiled.resolved.resolved_digest,
87
+ "runtime": runtime_lock,
88
+ "sourceDigest": source_digest,
89
+ }
90
+ if composition is not None:
91
+ resolved_digest_payload["compositionProfileDigest"] = composition_profile_digest_value
92
+ resolved_digest_payload["pluginLockDigest"] = plugin_lock_digest_value
93
+ resolved_digest = sha256_digest(canonical_json(resolved_digest_payload))
69
94
  short_digest = resolved_digest.removeprefix("sha256:")[:20]
70
95
  build_id = f"build_{short_digest}"
71
96
  final_dir = self.workspace.resolve(Path("dist") / draft.metadata.id / build_id)
@@ -98,13 +123,32 @@ class AgentBundleBuilder:
98
123
  runtime_lock=runtime_lock,
99
124
  resolved_digest=resolved_digest,
100
125
  plugin_lock=plugin_lock,
126
+ composition_profile=composition_profile,
127
+ composition_profile_digest_value=composition_profile_digest_value,
101
128
  hosted_kernel_requirement=hosted_kernel_requirement,
102
129
  hosted_kernel_requirement_digest_value=hosted_kernel_requirement_digest_value,
130
+ compatibility_facts_digest_value=compatibility_facts_digest_value,
131
+ )
132
+ self._write_json(
133
+ bundle_root / "compatibility-report.json",
134
+ build_bundle_compatibility_report(
135
+ draft=draft,
136
+ composition=composition,
137
+ runtime_lock=runtime_lock,
138
+ resolved_digest=resolved_digest,
139
+ facts_digest=compatibility_facts_digest_value,
140
+ plugin_lock_digest=plugin_lock_digest_value,
141
+ composition_profile_digest=composition_profile_digest_value,
142
+ ),
103
143
  )
104
144
  self._write_json(
105
145
  bundle_root / "hosted-kernel-requirements.json",
106
146
  hosted_kernel_requirement,
107
147
  )
148
+ # Secrets are references at every declarative boundary. Scan the
149
+ # final materialized Bundle before its file manifest/digest are
150
+ # sealed, so an accidental literal cannot become a deployable ZIP.
151
+ assert_bundle_security(bundle_root)
108
152
  # The manifest is a complete content declaration. Write this
109
153
  # auxiliary checksum file first, then include it in the manifest
110
154
  # entries; otherwise a Server-side full-membership check correctly
@@ -118,12 +162,21 @@ class AgentBundleBuilder:
118
162
  resolved_digest=resolved_digest,
119
163
  runtime_type=runtime_type,
120
164
  source_digest=source_digest,
121
- plugin_lock_digest=plugin_lock_digest,
165
+ plugin_lock_digest=plugin_lock_digest_value,
166
+ composition_mode="composed" if composition is not None else "legacy",
167
+ composition_profile_digest=composition_profile_digest_value,
122
168
  hosted_kernel_requirement_digest=hosted_kernel_requirement_digest_value,
123
169
  files=files,
124
170
  )
125
171
  manifest.bundle_digest = compute_bundle_digest(manifest)
126
- self._write_json(bundle_root / "manifest.json", manifest.model_dump(by_alias=True))
172
+ # Keep the on-disk manifest on the same ``exclude_none`` wire
173
+ # projection used by ``compute_bundle_digest``. New v2 archives
174
+ # always state whether they select legacy or composed execution;
175
+ # only historical archives may omit that discriminator.
176
+ self._write_json(
177
+ bundle_root / "manifest.json",
178
+ manifest.model_dump(by_alias=True, exclude_none=True),
179
+ )
127
180
  archive = staging / "agent-bundle.zip"
128
181
  self._write_zip(bundle_root, archive)
129
182
  final_dir.parent.mkdir(parents=True, exist_ok=True)
@@ -166,8 +219,11 @@ class AgentBundleBuilder:
166
219
  runtime_lock: dict,
167
220
  resolved_digest: str,
168
221
  plugin_lock: dict,
222
+ composition_profile: CompositionProfile | None,
223
+ composition_profile_digest_value: str | None,
169
224
  hosted_kernel_requirement: dict,
170
225
  hosted_kernel_requirement_digest_value: str,
226
+ compatibility_facts_digest_value: str,
171
227
  ) -> None:
172
228
  definition_digest = compiled.resolved.resolved_digest
173
229
  resolved_payload = compiled.resolved.model_dump(
@@ -186,14 +242,30 @@ class AgentBundleBuilder:
186
242
  self._write_json(root / "agentkit.lock", dependency_lock)
187
243
  self._write_json(root / "runtime-lock.json", runtime_lock)
188
244
  self._write_json(root / "plugin-lock.json", plugin_lock)
245
+ if composition_profile is not None:
246
+ # A resolved profile is an immutable composition input, not a
247
+ # second editable Agent spec. It is only written once its
248
+ # deterministic lock has already been resolved by PluginRegistry.
249
+ self._write_json(
250
+ root / "composition-profile.json",
251
+ composition_profile.model_dump(
252
+ by_alias=True,
253
+ exclude_none=True,
254
+ mode="json",
255
+ ),
256
+ )
189
257
  instructions = root / "instructions"
190
258
  instructions.mkdir()
191
259
  (instructions / "system.md").write_text(
192
- draft.spec.instructions.system.rstrip() + "\n", encoding="utf-8"
260
+ compiled.resolved.instructions.system.rstrip() + "\n", encoding="utf-8"
193
261
  )
194
262
  (instructions / "task.md").write_text(
195
- draft.spec.instructions.task.rstrip() + "\n", encoding="utf-8"
263
+ compiled.resolved.instructions.task.rstrip() + "\n", encoding="utf-8"
196
264
  )
265
+ if compiled.resolved.soul is not None:
266
+ (instructions / "soul.md").write_text(
267
+ render_soul_markdown(compiled.resolved.soul), encoding="utf-8"
268
+ )
197
269
  for skill in compiled.resolved.capabilities.skills:
198
270
  source = self.workspace.resolve(
199
271
  Path("capabilities/skills") / skill["name"],
@@ -238,25 +310,33 @@ class AgentBundleBuilder:
238
310
  "components": components,
239
311
  },
240
312
  )
241
- self._write_json(
242
- root / "provenance.json",
243
- {
244
- "format": "agentkit.provenance/v1",
245
- "agentId": draft.metadata.id,
246
- "sourceRevision": draft.metadata.revision,
247
- "sourceDigest": compiled.resolved.source_digest,
248
- "definitionDigest": definition_digest,
249
- "resolvedDigest": resolved_digest,
250
- "compilerVersion": compiled.resolved.compiler_version,
251
- "runtimeContract": "agentkit.runtime/v1",
252
- "hostedKernel": {
253
- "requirementsPath": "hosted-kernel-requirements.json",
254
- "requirementDigest": hosted_kernel_requirement_digest_value,
255
- "contractSet": hosted_kernel_requirement["kernelContract"]["set"],
256
- "contractDigest": hosted_kernel_requirement["kernelContract"]["digest"],
257
- },
313
+ provenance = {
314
+ "format": "agentkit.provenance/v1",
315
+ "agentId": draft.metadata.id,
316
+ "sourceRevision": draft.metadata.revision,
317
+ "sourceDigest": compiled.resolved.source_digest,
318
+ "definitionDigest": definition_digest,
319
+ "resolvedDigest": resolved_digest,
320
+ "compilerVersion": compiled.resolved.compiler_version,
321
+ "runtimeContract": "agentkit.runtime/v1",
322
+ "compatibility": {
323
+ "reportPath": "compatibility-report.json",
324
+ "factsDigest": compatibility_facts_digest_value,
258
325
  },
259
- )
326
+ "hostedKernel": {
327
+ "requirementsPath": "hosted-kernel-requirements.json",
328
+ "requirementDigest": hosted_kernel_requirement_digest_value,
329
+ "contractSet": hosted_kernel_requirement["kernelContract"]["set"],
330
+ "contractDigest": hosted_kernel_requirement["kernelContract"]["digest"],
331
+ },
332
+ }
333
+ if composition_profile is not None:
334
+ provenance["composition"] = {
335
+ "profilePath": "composition-profile.json",
336
+ "profileDigest": composition_profile_digest_value,
337
+ "pluginLockDigest": sha256_digest(canonical_json(plugin_lock)),
338
+ }
339
+ self._write_json(root / "provenance.json", provenance)
260
340
 
261
341
  def _runtime_snapshot(self, draft: AgentDraft, compiled) -> tuple[str, str, dict]:
262
342
  runtime = draft.spec.runtime
@@ -269,9 +349,7 @@ class AgentBundleBuilder:
269
349
  content = path.read_bytes()
270
350
  relative = path.relative_to(source_root).as_posix()
271
351
  digest = f"sha256:{hashlib.sha256(content).hexdigest()}"
272
- source_files.append(
273
- {"path": relative, "sha256": digest, "size": len(content)}
274
- )
352
+ source_files.append({"path": relative, "sha256": digest, "size": len(content)})
275
353
  source_digest = sha256_digest(canonical_json(source_files))
276
354
  bound_models = [
277
355
  item.model for item in self.compiler.catalog.resolve_models(draft.spec.bindings)
@@ -290,9 +368,11 @@ class AgentBundleBuilder:
290
368
  "model": compiled.resolved.model.model,
291
369
  "models": list(dict.fromkeys(bound_models)),
292
370
  }
293
- return runtime_type, source_digest, {
294
- key: value for key, value in lock.items() if value is not None
295
- }
371
+ return (
372
+ runtime_type,
373
+ source_digest,
374
+ {key: value for key, value in lock.items() if value is not None},
375
+ )
296
376
 
297
377
  def _copy_runtime_source(self, bundle_root: Path, draft: AgentDraft) -> None:
298
378
  runtime = draft.spec.runtime
ksadk/studio/cloud.py CHANGED
@@ -1151,6 +1151,7 @@ class DirectAgentEngineCloudDeploymentGateway:
1151
1151
  *,
1152
1152
  session_id: str,
1153
1153
  after_seq_id: int | None = None,
1154
+ offset: int | None = None,
1154
1155
  limit: int = 200,
1155
1156
  ) -> dict[str, Any]:
1156
1157
  """Read canonical events, including public Interaction/v1 frames."""
@@ -1160,6 +1161,7 @@ class DirectAgentEngineCloudDeploymentGateway:
1160
1161
  agent_id=self._chat_agent_id(deployment),
1161
1162
  session_id=session_id,
1162
1163
  after_seq_id=after_seq_id,
1164
+ offset=offset,
1163
1165
  limit=limit,
1164
1166
  )
1165
1167
  except AgentEngineAPIError as exc:
@@ -1922,6 +1924,7 @@ class CloudDeploymentService:
1922
1924
  *,
1923
1925
  session_id: str,
1924
1926
  after_seq_id: int | None = None,
1927
+ offset: int | None = None,
1925
1928
  limit: int = 200,
1926
1929
  ) -> dict[str, Any]:
1927
1930
  deployment = await self._chat_target(deployment_id)
@@ -1936,6 +1939,7 @@ class CloudDeploymentService:
1936
1939
  deployment,
1937
1940
  session_id=session_id,
1938
1941
  after_seq_id=after_seq_id,
1942
+ offset=offset,
1939
1943
  limit=limit,
1940
1944
  )
1941
1945
 
@@ -377,9 +377,17 @@ class CodexAgentService:
377
377
  def detail(self, agent_id: str | None = None) -> dict:
378
378
  snapshot = self.studio.codex_manifests.load(agent_id)
379
379
  _mcp_bindings, unresolved_mcp = self._mcp_bindings(snapshot.manifest)
380
+ builds_view: list[dict] = []
381
+ for item in self._builds(snapshot.manifest.name):
382
+ view = self.build_view(item)
383
+ try:
384
+ view["isCurrent"] = self.studio.codex_builder.is_current(item)
385
+ except Exception:
386
+ view["isCurrent"] = True
387
+ builds_view.append(view)
380
388
  return {
381
389
  "draft": self._project(snapshot),
382
- "builds": [self.build_view(item) for item in self._builds(snapshot.manifest.name)],
390
+ "builds": builds_view,
383
391
  "validation": {"valid": True, "level": "build", "diagnostics": []},
384
392
  "manifestSha256": snapshot.manifest_sha256,
385
393
  "sourcePath": self.studio.workspace.relative(snapshot.source_path),
@@ -505,6 +513,7 @@ class CodexAgentService:
505
513
  system=manifest.prompt,
506
514
  task=manifest.task_prompt or "",
507
515
  )
516
+ draft.spec.soul = manifest.soul
508
517
  draft.spec.bindings.model_profile_id = bindings[0]
509
518
  draft.spec.bindings.model_profile_ids = bindings[1]
510
519
  draft.spec.bindings.skills = skill_bindings
@@ -527,6 +536,7 @@ class CodexAgentService:
527
536
  system=manifest.prompt,
528
537
  task=manifest.task_prompt or "",
529
538
  ),
539
+ soul=manifest.soul,
530
540
  bindings=AgentBindings(
531
541
  model_profile_id=default_profile,
532
542
  model_profile_ids=profiles,
@@ -576,6 +586,7 @@ class CodexAgentService:
576
586
  models=models if len(models) > 1 else None,
577
587
  prompt=prompt,
578
588
  task_prompt=task_prompt,
589
+ soul=spec.soul,
579
590
  skills=skill_ids or None,
580
591
  mcp_servers=mcp_servers or None,
581
592
  sandbox=spec.execution.sandbox,