agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.1__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 (450) hide show
  1. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/METADATA +52 -20
  2. agentengine_sdk_python-0.8.1.dist-info/RECORD +644 -0
  3. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/WHEEL +1 -1
  4. ksadk/a2a/__init__.py +180 -11
  5. ksadk/a2a/bootstrap.py +332 -0
  6. ksadk/a2a/card.py +15 -0
  7. ksadk/a2a/context_store.py +203 -0
  8. ksadk/a2a/control_plane.py +1056 -0
  9. ksadk/a2a/credential.py +99 -0
  10. ksadk/a2a/event_adapter.py +149 -0
  11. ksadk/a2a/executor.py +361 -137
  12. ksadk/a2a/external_transport.py +516 -0
  13. ksadk/a2a/identity.py +304 -0
  14. ksadk/a2a/ids.py +22 -0
  15. ksadk/a2a/langgraph.py +285 -0
  16. ksadk/a2a/resume_store.py +201 -0
  17. ksadk/a2a/routes.py +112 -0
  18. ksadk/a2a/server.py +102 -62
  19. ksadk/a2a/service_env.py +33 -0
  20. ksadk/a2a/space_client.py +1122 -0
  21. ksadk/a2a/task_adapter.py +423 -0
  22. ksadk/a2a/task_event_dispatcher.py +167 -0
  23. ksadk/a2a/task_event_outbox.py +326 -0
  24. ksadk/a2a/task_store.py +206 -0
  25. ksadk/a2a_card.py +101 -0
  26. ksadk/a2ui/__init__.py +27 -0
  27. ksadk/a2ui/core.py +186 -0
  28. ksadk/a2ui/models.py +166 -0
  29. ksadk/a2ui/renderer.py +198 -0
  30. ksadk/agui/__init__.py +9 -0
  31. ksadk/agui/a2ui_projection.py +92 -0
  32. ksadk/agui/agent.py +872 -0
  33. ksadk/agui/config.py +92 -0
  34. ksadk/agui/routes.py +47 -0
  35. ksadk/api/client.py +238 -204
  36. ksadk/api/environment.py +27 -0
  37. ksadk/builders/__init__.py +2 -0
  38. ksadk/builders/base.py +16 -14
  39. ksadk/builders/code_builder.py +375 -270
  40. ksadk/builders/container_builder.py +240 -200
  41. ksadk/builders/framework_requirements.py +31 -12
  42. ksadk/builders/ks3_uploader.py +60 -29
  43. ksadk/builders/managed_runtime_builder.py +173 -0
  44. ksadk/builders/mcp_builder.py +91 -92
  45. ksadk/builders/requirements_utils.py +1 -5
  46. ksadk/cli/__init__.py +97 -171
  47. ksadk/cli/cmd_a2a.py +255 -84
  48. ksadk/cli/cmd_agent.py +19 -5
  49. ksadk/cli/cmd_build.py +158 -29
  50. ksadk/cli/cmd_completion.py +47 -35
  51. ksadk/cli/cmd_config.py +267 -198
  52. ksadk/cli/cmd_create.py +507 -740
  53. ksadk/cli/cmd_dashboard.py +120 -45
  54. ksadk/cli/cmd_deploy.py +135 -59
  55. ksadk/cli/cmd_destroy.py +44 -14
  56. ksadk/cli/cmd_eval.py +386 -0
  57. ksadk/cli/cmd_files.py +63 -24
  58. ksadk/cli/cmd_hermes.py +313 -135
  59. ksadk/cli/cmd_invoke.py +184 -122
  60. ksadk/cli/cmd_launch.py +76 -28
  61. ksadk/cli/cmd_mcp.py +98 -64
  62. ksadk/cli/cmd_model.py +14 -5
  63. ksadk/cli/cmd_openclaw.py +564 -268
  64. ksadk/cli/cmd_replay.py +71 -0
  65. ksadk/cli/cmd_run.py +58 -73
  66. ksadk/cli/cmd_status.py +80 -31
  67. ksadk/cli/cmd_studio.py +110 -0
  68. ksadk/cli/cmd_version.py +20 -13
  69. ksadk/cli/cmd_web.py +95 -18
  70. ksadk/cli/deploy_utils.py +20 -20
  71. ksadk/cli/dry_run.py +7 -4
  72. ksadk/cli/env_options.py +83 -0
  73. ksadk/cli/error_utils.py +37 -12
  74. ksadk/cli/global_options.py +4 -3
  75. ksadk/cli/local_runtime.py +1 -2
  76. ksadk/cli/model_catalog.py +6 -2
  77. ksadk/cli/network_options.py +41 -19
  78. ksadk/cli/resource_common.py +6 -2
  79. ksadk/cli/runtime_bootstrap.py +51 -0
  80. ksadk/cli/storage.py +0 -1
  81. ksadk/cli/ui.py +11 -3
  82. ksadk/cli/workflow_common.py +52 -18
  83. ksadk/codex/__init__.py +12 -0
  84. ksadk/codex/client.py +1042 -0
  85. ksadk/codex/phase.py +143 -0
  86. ksadk/codex/runtime.py +940 -0
  87. ksadk/common/aicp_env.py +0 -1
  88. ksadk/common/auth.py +2 -2
  89. ksadk/common/constants.py +1 -3
  90. ksadk/common/kop_client.py +232 -0
  91. ksadk/common/llm_utils.py +17 -13
  92. ksadk/compat/__init__.py +5 -0
  93. ksadk/compat/adk_compat.py +200 -0
  94. ksadk/compat/copilotkit_a2ui.py +330 -0
  95. ksadk/configs/__init__.py +12 -14
  96. ksadk/configs/env_registry.py +661 -116
  97. ksadk/configs/global_config.py +3 -2
  98. ksadk/configs/settings.py +133 -209
  99. ksadk/conversations/__init__.py +85 -92
  100. ksadk/conversations/attachment_storage.py +16 -11
  101. ksadk/conversations/attachments.py +44 -36
  102. ksadk/conversations/compaction_pipeline.py +12 -12
  103. ksadk/conversations/compaction_prompt.py +9 -5
  104. ksadk/conversations/context.py +221 -6
  105. ksadk/conversations/message_projection.py +438 -51
  106. ksadk/conversations/model_context.py +12 -6
  107. ksadk/conversations/model_options.py +0 -1
  108. ksadk/conversations/normalize.py +20 -16
  109. ksadk/conversations/reasoning_markup.py +1 -1
  110. ksadk/conversations/runtime.py +339 -5255
  111. ksadk/conversations/runtime_compaction.py +333 -0
  112. ksadk/conversations/runtime_constants.py +27 -0
  113. ksadk/conversations/runtime_governance.py +185 -0
  114. ksadk/conversations/runtime_input.py +660 -0
  115. ksadk/conversations/runtime_invocation.py +395 -0
  116. ksadk/conversations/runtime_metadata.py +475 -0
  117. ksadk/conversations/runtime_observability.py +367 -0
  118. ksadk/conversations/runtime_payloads.py +272 -0
  119. ksadk/conversations/runtime_persistence.py +440 -0
  120. ksadk/conversations/runtime_preparation.py +426 -0
  121. ksadk/conversations/runtime_resume.py +836 -0
  122. ksadk/conversations/runtime_stream_events.py +902 -0
  123. ksadk/conversations/runtime_streaming.py +700 -0
  124. ksadk/conversations/semantic_summary.py +17 -5
  125. ksadk/conversations/session_title.py +6 -3
  126. ksadk/deployment/__init__.py +15 -16
  127. ksadk/deployment/agent_access.py +12 -23
  128. ksadk/deployment/base.py +51 -38
  129. ksadk/deployment/managed_runtime.py +33 -0
  130. ksadk/deployment/manager.py +85 -71
  131. ksadk/deployment/providers/serverless.py +379 -210
  132. ksadk/deployment/registry.py +38 -32
  133. ksadk/deployment/state.py +11 -11
  134. ksadk/deployment/ui_config.py +1 -1
  135. ksadk/detection/__init__.py +1 -1
  136. ksadk/detection/detector.py +146 -83
  137. ksadk/detection/mcp_detector.py +9 -6
  138. ksadk/evaluation/__init__.py +84 -0
  139. ksadk/evaluation/a2a_adapter.py +444 -0
  140. ksadk/evaluation/adapters.py +54 -0
  141. ksadk/evaluation/contracts.py +409 -0
  142. ksadk/evaluation/evalset.py +351 -0
  143. ksadk/evaluation/evaluators.py +461 -0
  144. ksadk/evaluation/executor.py +118 -0
  145. ksadk/evaluation/storage.py +68 -0
  146. ksadk/evaluation/target.py +73 -0
  147. ksadk/events/__init__.py +25 -0
  148. ksadk/events/parser.py +191 -0
  149. ksadk/events/replay.py +37 -0
  150. ksadk/events/runtime_event.py +273 -0
  151. ksadk/events/store.py +317 -0
  152. ksadk/harness/__init__.py +35 -0
  153. ksadk/harness/app.py +269 -0
  154. ksadk/harness/config.py +181 -0
  155. ksadk/harness/reasoner.py +105 -0
  156. ksadk/harness/runtime.py +364 -0
  157. ksadk/harness/sandbox.py +141 -0
  158. ksadk/harness/tools.py +222 -0
  159. ksadk/hermes_terminal.py +28 -12
  160. ksadk/identity/resolver.py +15 -9
  161. ksadk/ids.py +32 -0
  162. ksadk/knowledge_base/adk_tool.py +1 -1
  163. ksadk/knowledge_base/client.py +38 -33
  164. ksadk/managed_a2a_card.py +160 -0
  165. ksadk/managed_runtime.py +195 -0
  166. ksadk/markdown.py +5 -2
  167. ksadk/mcp_runtime/__init__.py +9 -6
  168. ksadk/memory/__init__.py +1 -1
  169. ksadk/memory/adk/__init__.py +2 -0
  170. ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
  171. ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
  172. ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
  173. ksadk/memory/adk/backends/sdk_ltm_backend.py +36 -36
  174. ksadk/memory/adk/long_term_memory.py +34 -37
  175. ksadk/memory/adk/resilient_session_service.py +4 -5
  176. ksadk/memory/adk/short_term_memory.py +12 -21
  177. ksadk/memory/adk_tool.py +3 -2
  178. ksadk/memory/backends/base.py +19 -19
  179. ksadk/memory/backends/memory.py +24 -25
  180. ksadk/memory/backends/redis.py +31 -30
  181. ksadk/memory/langchain_tool.py +2 -1
  182. ksadk/memory/manager.py +52 -47
  183. ksadk/memory/service.py +16 -6
  184. ksadk/memory/tool.py +4 -0
  185. ksadk/model_policy.py +15 -7
  186. ksadk/model_proxy/__init__.py +51 -0
  187. ksadk/model_proxy/bootstrap.py +80 -0
  188. ksadk/model_proxy/cache.py +165 -0
  189. ksadk/model_proxy/config.py +66 -0
  190. ksadk/model_proxy/demo_webui.py +115 -0
  191. ksadk/model_proxy/detect.py +145 -0
  192. ksadk/model_proxy/gate.py +68 -0
  193. ksadk/model_proxy/namespace.py +201 -0
  194. ksadk/model_proxy/protocol_proxy.py +22 -0
  195. ksadk/model_proxy/server.py +443 -0
  196. ksadk/model_proxy/transform.py +735 -0
  197. ksadk/openclaw_gateway.py +29 -14
  198. ksadk/runners/adk_runner.py +354 -146
  199. ksadk/runners/base_runner.py +71 -29
  200. ksadk/runners/deepagents_runner.py +0 -1
  201. ksadk/runners/factory.py +18 -5
  202. ksadk/runners/langchain_runner.py +29 -742
  203. ksadk/runners/langgraph_runner.py +417 -97
  204. ksadk/runners/patch_langchain.py +16 -16
  205. ksadk/runners/remote_runner.py +134 -33
  206. ksadk/runners/usage_accumulator.py +1 -0
  207. ksadk/runners/utils/__init__.py +0 -10
  208. ksadk/runners/utils/loader.py +23 -7
  209. ksadk/runtime/__init__.py +67 -0
  210. ksadk/runtime/adapter.py +412 -0
  211. ksadk/runtime/conversation_execution.py +553 -0
  212. ksadk/runtime/executor.py +251 -0
  213. ksadk/runtime/factory.py +156 -0
  214. ksadk/runtime/framework_adapters.py +118 -0
  215. ksadk/runtime/launch.py +48 -0
  216. ksadk/runtime/preprocessing.py +131 -0
  217. ksadk/runtime/runner_adapter.py +1032 -0
  218. ksadk/runtime/runner_loading.py +36 -0
  219. ksadk/runtime_context.py +18 -3
  220. ksadk/runtime_state.py +0 -1
  221. ksadk/sandbox/__init__.py +4 -1
  222. ksadk/sandbox/backends/__init__.py +4 -1
  223. ksadk/sandbox/backends/e2b.py +13 -5
  224. ksadk/sandbox/backends/local_process.py +11 -3
  225. ksadk/sandbox/base.py +10 -15
  226. ksadk/sandbox/factory.py +14 -4
  227. ksadk/sandbox/registry.py +57 -6
  228. ksadk/server/__init__.py +39 -4
  229. ksadk/server/api_models.py +15 -5
  230. ksadk/server/app.py +24 -3928
  231. ksadk/server/composition.py +47 -0
  232. ksadk/server/factory.py +622 -0
  233. ksadk/server/routes/__init__.py +1 -0
  234. ksadk/server/routes/checkpoint_resolution.py +116 -0
  235. ksadk/server/routes/common.py +682 -0
  236. ksadk/server/routes/control.py +331 -0
  237. ksadk/server/routes/dependencies.py +98 -0
  238. ksadk/server/routes/misc.py +425 -0
  239. ksadk/server/routes/models.py +451 -0
  240. ksadk/server/routes/openai_compat.py +229 -0
  241. ksadk/server/routes/projection.py +848 -0
  242. ksadk/server/routes/routers.py +52 -0
  243. ksadk/server/routes/run.py +519 -0
  244. ksadk/server/routes/sessions.py +644 -0
  245. ksadk/server/routes/streaming.py +265 -0
  246. ksadk/server/routes/workspace.py +414 -0
  247. ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-CakCqxEN.js} +1 -1
  248. ksadk/server/static/assets/CodeBlock-CynLknyO.js +9 -0
  249. ksadk/server/static/assets/MathMessageMarkdown-3sQdOysS.js +8 -0
  250. ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +303 -0
  251. ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +1 -0
  252. ksadk/server/static/assets/{arc-BA13sHc9.js → arc-DrgjcKhl.js} +1 -1
  253. ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +1 -0
  254. ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-BXoVRbQ6.js} +1 -1
  255. ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-BnaB3Ywv.js} +1 -1
  256. ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-Dw4weZcp.js} +1 -1
  257. ksadk/server/static/assets/channel-Dt3rQTFI.js +1 -0
  258. ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-ChjpLK7j.js} +1 -1
  259. ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-B9drTgOW.js} +1 -1
  260. ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-CK4ROATy.js} +1 -1
  261. ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B9KtTTgw.js} +1 -1
  262. ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-1O1mki3m.js} +1 -1
  263. ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-B_fH2YuH.js} +1 -1
  264. ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D6rFLaVV.js} +1 -1
  265. ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +1 -0
  266. ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +1 -0
  267. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +1 -0
  268. ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-ChNs_Mdk.js} +1 -1
  269. ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-D0QXg_MQ.js} +1 -1
  270. ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-DBDDKwBQ.js} +1 -1
  271. ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-BkwDOxmO.js} +1 -1
  272. ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Bv8waYvY.js} +1 -1
  273. ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-e1VECDdu.js} +1 -1
  274. ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-Ds9adfRl.js} +1 -1
  275. ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-4N2NMVYg.js} +1 -1
  276. ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-B-jNR6Vn.js} +1 -1
  277. ksadk/server/static/assets/{dist-D57wnGWd.js → dist-B5J2uhNk.js} +1 -1
  278. ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-B5oS1zcj.js} +1 -1
  279. ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BB3-OwTQ.js} +1 -1
  280. ksadk/server/static/assets/{dist-2hInLS_J.js → dist-BIlKoW0k.js} +1 -1
  281. ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-BjOdlDjj.js} +1 -1
  282. ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-C1sz5Eo3.js} +1 -1
  283. ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-CWV4lDr1.js} +1 -1
  284. ksadk/server/static/assets/{dist-D-xOD048.js → dist-CmZHzlwZ.js} +1 -1
  285. ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-D6MpCZtz.js} +1 -1
  286. ksadk/server/static/assets/{dist-DyOkZmze.js → dist-DJN_6Y39.js} +1 -1
  287. ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-DQU9EWw-.js} +1 -1
  288. ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-DWKByxWV.js} +1 -1
  289. ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-Dli7qW-B.js} +1 -1
  290. ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-DsHPdk3W.js} +1 -1
  291. ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-X4TnqwOK.js} +1 -1
  292. ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-_pHPTyZ-.js} +1 -1
  293. ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-fhOuWds5.js} +1 -1
  294. ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-gLnrGsoU.js} +1 -1
  295. ksadk/server/static/assets/{dist-BssVmjIo.js → dist-j6Dxmf_j.js} +1 -1
  296. ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-o2OVmKvt.js} +1 -1
  297. ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-BPItFKH6.js} +1 -1
  298. ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +1 -0
  299. ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-BbYB9w5Y.js} +1 -1
  300. ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-TQXa0KXv.js} +1 -1
  301. ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +1 -0
  302. ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-bKblCnpa.js} +1 -1
  303. ksadk/server/static/assets/index-R52pJJvg.js +177 -0
  304. ksadk/server/static/assets/index-jJr3_955.css +2 -0
  305. ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +1 -0
  306. ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-BGVT7J_i.js} +1 -1
  307. ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-K0OOfVna.js} +1 -1
  308. ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-8LeOJaZp.js} +1 -1
  309. ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-C6uCgZrW.js} +1 -1
  310. ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-CYWseY5E.js} +1 -1
  311. ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-hdBcYzM8.js} +1 -1
  312. ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-BWrDjSZM.js} +2 -2
  313. ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-Bjy_2v4_.js} +1 -1
  314. ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +1 -0
  315. ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +1 -0
  316. ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-GmmqNiVH.js} +1 -1
  317. ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-BmkRbwCg.js} +1 -1
  318. ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +1 -0
  319. ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DSWFqL7c.js} +1 -1
  320. ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-l6iXmU65.js} +1 -1
  321. ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-Cq6UBeQB.js} +1 -1
  322. ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-qzTQpg3Y.js} +1 -1
  323. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +1 -0
  324. ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-DEz24vV0.js} +1 -1
  325. ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +1 -0
  326. ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +1 -0
  327. ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-CMCixki2.js} +1 -1
  328. ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +1 -0
  329. ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-CVzB8F9K.js} +1 -1
  330. ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-BFBqBLc1.js} +1 -1
  331. ksadk/server/static/index.html +2 -2
  332. ksadk/server/terminal_sessions.py +111 -58
  333. ksadk/sessions/__init__.py +69 -19
  334. ksadk/sessions/base.py +31 -11
  335. ksadk/sessions/continuity.py +2 -3
  336. ksadk/sessions/in_memory.py +46 -2
  337. ksadk/sessions/local_service.py +148 -17
  338. ksadk/sessions/postgres_service.py +143 -25
  339. ksadk/sessions/resilient.py +36 -8
  340. ksadk/skills/models.py +17 -5
  341. ksadk/skills/package_store.py +5 -2
  342. ksadk/skills/runtime/agent.py +20 -5
  343. ksadk/skills/runtime/artifacts.py +1 -5
  344. ksadk/skills/runtime/backends/e2b.py +10 -4
  345. ksadk/skills/runtime/backends/local.py +15 -3
  346. ksadk/skills/runtime/base.py +1 -2
  347. ksadk/skills/runtime/executor.py +10 -3
  348. ksadk/skills/runtime/factory.py +4 -2
  349. ksadk/skills/runtime/loader.py +1 -2
  350. ksadk/skills/runtime/registry.py +15 -10
  351. ksadk/skills/runtime/request.py +3 -1
  352. ksadk/skills/service_client.py +47 -16
  353. ksadk/skills/tool_defs.py +15 -10
  354. ksadk/studio/__init__.py +5 -0
  355. ksadk/studio/agent_avatar_assets.py +120 -0
  356. ksadk/studio/agent_lifecycle.py +51 -0
  357. ksadk/studio/api.py +1046 -0
  358. ksadk/studio/api_catalog_routes.py +324 -0
  359. ksadk/studio/api_contracts.py +177 -0
  360. ksadk/studio/api_helpers.py +132 -0
  361. ksadk/studio/authoring.py +524 -0
  362. ksadk/studio/authoring_coordinator.py +285 -0
  363. ksadk/studio/builder.py +320 -0
  364. ksadk/studio/capabilities.py +351 -0
  365. ksadk/studio/cloud.py +278 -0
  366. ksadk/studio/codex_agent_service.py +583 -0
  367. ksadk/studio/codex_builder.py +324 -0
  368. ksadk/studio/codex_manifest.py +278 -0
  369. ksadk/studio/codex_run.py +352 -0
  370. ksadk/studio/compiler.py +189 -0
  371. ksadk/studio/contracts.py +644 -0
  372. ksadk/studio/errors.py +47 -0
  373. ksadk/studio/evaluation.py +192 -0
  374. ksadk/studio/event_store.py +284 -0
  375. ksadk/studio/framework_run.py +114 -0
  376. ksadk/studio/identifiers.py +33 -0
  377. ksadk/studio/mcp_runtime.py +229 -0
  378. ksadk/studio/model_client.py +543 -0
  379. ksadk/studio/model_profile_service.py +214 -0
  380. ksadk/studio/operations.py +243 -0
  381. ksadk/studio/otel_trace.py +754 -0
  382. ksadk/studio/pagination.py +182 -0
  383. ksadk/studio/python_tool_inspection.py +183 -0
  384. ksadk/studio/repository.py +306 -0
  385. ksadk/studio/resource_catalog.py +1217 -0
  386. ksadk/studio/run_service.py +707 -0
  387. ksadk/studio/runtime_catalog.py +74 -0
  388. ksadk/studio/runtime_source.py +339 -0
  389. ksadk/studio/service.py +1141 -0
  390. ksadk/studio/shared_web.py +994 -0
  391. ksadk/studio/skill_discovery.py +628 -0
  392. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
  393. ksadk/studio/static/assets/index-CaEN0eTR.css +1 -0
  394. ksadk/studio/static/assets/index-DI2eY_NH.js +252 -0
  395. ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
  396. ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
  397. ksadk/studio/static/index.html +15 -0
  398. ksadk/studio/templates.py +630 -0
  399. ksadk/studio/validator.py +246 -0
  400. ksadk/studio/workspace.py +137 -0
  401. ksadk/terminal_exec_policy.py +3 -4
  402. ksadk/tools/gateway.py +101 -15
  403. ksadk/tools/result_budget.py +12 -4
  404. ksadk/toolsets/__init__.py +161 -37
  405. ksadk/toolsets/a2a.py +426 -0
  406. ksadk/toolsets/platform.py +21 -5
  407. ksadk/toolsets/sandbox.py +82 -16
  408. ksadk/toolsets/skills.py +200 -39
  409. ksadk/toolsets/web.py +123 -26
  410. ksadk/toolsets/workspace.py +212 -101
  411. ksadk/tracing/__init__.py +19 -21
  412. ksadk/tracing/exporters/inmemory_exporter.py +62 -51
  413. ksadk/tracing/setup.py +135 -506
  414. ksadk/tracing/span_utils.py +0 -41
  415. ksadk/tui/loop.py +78 -30
  416. ksadk/tui/stream_render.py +1 -0
  417. ksadk/ui_config.py +5 -3
  418. ksadk/version.py +1 -1
  419. ksadk_runtime_common/memory_backend/registry.py +56 -56
  420. ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
  421. ksadk_runtime_common/workspace_files/router.py +8 -2
  422. agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
  423. ksadk/a2a/card_builder.py +0 -64
  424. ksadk/a2a/client.py +0 -309
  425. ksadk/runners/utils/langfuse.py +0 -230
  426. ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
  427. ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
  428. ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
  429. ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
  430. ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
  431. ksadk/server/static/assets/channel-CTuydARX.js +0 -1
  432. ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
  433. ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
  434. ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
  435. ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
  436. ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
  437. ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
  438. ksadk/server/static/assets/index-DAURbCsP.css +0 -1
  439. ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
  440. ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
  441. ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
  442. ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
  443. ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
  444. ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
  445. ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
  446. ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
  447. ksadk/tracing/exporters/langfuse_exporter.py +0 -445
  448. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/entry_points.txt +0 -0
  449. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/licenses/LICENSE +0 -0
  450. {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,630 @@
1
+ """Agent templates and deterministic composition for Studio authoring."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+
7
+ import yaml # type: ignore[import-untyped]
8
+
9
+ from ksadk.studio.contracts import (
10
+ AgentBindings,
11
+ AgentSpec,
12
+ AgentTemplateComposeRequest,
13
+ AgentTemplateComposition,
14
+ AgentTemplateRecommendation,
15
+ CapabilityBinding,
16
+ ContextSpec,
17
+ ExecutionSpec,
18
+ Instructions,
19
+ ModelParameters,
20
+ ResourceDescriptor,
21
+ )
22
+ from ksadk.studio.errors import StudioError
23
+ from ksadk.studio.resource_catalog import LocalResourceCatalog
24
+ from ksadk.studio.workspace import Workspace
25
+
26
+ RESEARCH_SKILL_NAME = "deep-research-methodology"
27
+ RESEARCH_SKILL_VERSION = "1.0.0"
28
+
29
+ _RESEARCH_SKILL_MANIFEST = {
30
+ "name": RESEARCH_SKILL_NAME,
31
+ "displayName": "深度调研方法",
32
+ "version": RESEARCH_SKILL_VERSION,
33
+ "description": "用于问题拆解、来源检索、交叉验证、证据归档与引用输出的标准方法。",
34
+ "category": "research",
35
+ "instructionsFile": "SKILL.md",
36
+ }
37
+
38
+ _RESEARCH_SKILL_CONTENT = """---
39
+ name: Deep Research Methodology
40
+ description: A rigorous workflow for evidence-backed research and source synthesis.
41
+ version: 1.0.0
42
+ ---
43
+
44
+ # Deep Research Methodology
45
+
46
+ Apply this workflow to every research request:
47
+
48
+ 1. Clarify the research question, decision context, scope, time range, and exclusions.
49
+ 2. Build a question tree before collecting evidence. Separate facts, hypotheses, and unknowns.
50
+ 3. Search broadly, then prefer primary and authoritative sources over summaries.
51
+ 4. Record every material claim in a source ledger with title, URL, publisher, date, and access time.
52
+ 5. Cross-check important claims with at least two independent sources when possible.
53
+ 6. Explicitly identify conflicting evidence, stale information, and confidence limits.
54
+ 7. Synthesize findings around the user's decision instead of returning a source dump.
55
+ 8. Cite sources using stable labels such as [S1], [S2], and include a source table.
56
+ 9. Never invent a source, URL, statistic, quotation, or publication date.
57
+ 10. When external research tools are unavailable, state the limitation before answering.
58
+ """
59
+
60
+ _MCP_KEYWORDS = {
61
+ "browser",
62
+ "crawl",
63
+ "fetch",
64
+ "http",
65
+ "research",
66
+ "search",
67
+ "url",
68
+ "web",
69
+ }
70
+
71
+ _DEPTH_SETTINGS = {
72
+ "focused": {"max_steps": 8, "timeout_seconds": 180, "max_tokens": 3072},
73
+ "standard": {"max_steps": 16, "timeout_seconds": 360, "max_tokens": 4096},
74
+ "deep": {"max_steps": 28, "timeout_seconds": 900, "max_tokens": 6144},
75
+ }
76
+
77
+ _OUTPUT_NAMES_ZH = {
78
+ "brief": "决策简报",
79
+ "report": "结构化研究报告",
80
+ "evidence-table": "证据矩阵与结论",
81
+ }
82
+
83
+ _OUTPUT_NAMES_EN = {
84
+ "brief": "decision brief",
85
+ "report": "structured research report",
86
+ "evidence-table": "evidence matrix and conclusions",
87
+ }
88
+
89
+
90
+ def list_agent_templates() -> list[dict]:
91
+ return [
92
+ {
93
+ "id": "blank",
94
+ "name": "空白 Agent",
95
+ "description": "输入系统提示词,自主选择模型、Tool、MCP、Skill 与执行策略。",
96
+ "category": "general",
97
+ "recommended": True,
98
+ "steps": ["定义 Agent", "绑定能力", "配置 Prompt", "检查并创建"],
99
+ },
100
+ {
101
+ "id": "research",
102
+ "name": "Research Agent",
103
+ "description": "围绕一个研究目标规划检索、调用 MCP、验证来源并生成带引用的报告。",
104
+ "category": "knowledge-work",
105
+ "recommended": False,
106
+ "steps": ["定义目标", "绑定能力", "生成 Prompt", "检查并创建"],
107
+ },
108
+ ]
109
+
110
+
111
+ def default_agent_spec(
112
+ template: str,
113
+ *,
114
+ description: str = "",
115
+ ) -> AgentSpec:
116
+ if template == "blank":
117
+ return AgentSpec(
118
+ description=description,
119
+ instructions=Instructions(system="你是一个可靠的企业智能助手。", task=""),
120
+ )
121
+ if template == "research":
122
+ prompt = _research_instructions(
123
+ AgentTemplateComposeRequest(
124
+ goal="围绕用户输入的问题进行系统性深度调研并输出可核验结论",
125
+ ),
126
+ has_research_mcp=False,
127
+ )
128
+ return AgentSpec(
129
+ description=description or "执行深度调研并输出带来源引用的研究报告。",
130
+ instructions=prompt,
131
+ execution=ExecutionSpec(
132
+ strategy="plan-act-observe",
133
+ max_steps=28,
134
+ timeout_seconds=900,
135
+ ),
136
+ )
137
+ raise StudioError(
138
+ "AGENT_TEMPLATE_UNSUPPORTED",
139
+ "不支持的 Agent 模板",
140
+ status_code=422,
141
+ field="template",
142
+ details={"template": template},
143
+ )
144
+
145
+
146
+ def ensure_research_skill(workspace: Workspace) -> None:
147
+ root = workspace.resolve(f"capabilities/skills/{RESEARCH_SKILL_NAME}")
148
+ manifest = root / "skill.yaml"
149
+ instructions = root / "SKILL.md"
150
+ if root.exists():
151
+ if manifest.is_file() and instructions.is_file():
152
+ return
153
+ raise StudioError(
154
+ "RESEARCH_SKILL_CONFLICT",
155
+ "工作区存在不完整的同名 Research Skill",
156
+ status_code=409,
157
+ details={"path": workspace.relative(root)},
158
+ )
159
+ root.mkdir(parents=True)
160
+ workspace.atomic_write_text(
161
+ manifest,
162
+ yaml.safe_dump(
163
+ _RESEARCH_SKILL_MANIFEST,
164
+ allow_unicode=True,
165
+ sort_keys=False,
166
+ ),
167
+ )
168
+ workspace.atomic_write_text(instructions, _RESEARCH_SKILL_CONTENT)
169
+
170
+
171
+ def compose_blank_agent(
172
+ workspace: Workspace,
173
+ catalog: LocalResourceCatalog,
174
+ request: AgentTemplateComposeRequest,
175
+ ) -> AgentTemplateComposition:
176
+ del workspace
177
+ resources = catalog.list(limit=200)
178
+ models = [item for item in resources if item.kind == "model"]
179
+ tools = [item for item in resources if item.kind == "tool"]
180
+ skills = [item for item in resources if item.kind == "skill"]
181
+ mcps = [item for item in resources if item.kind == "mcp"]
182
+
183
+ model = _select_model(models, request.model_profile_id)
184
+ selected_model_ids = _select_model_ids(
185
+ models, request.model_profile_id, request.model_profile_ids
186
+ )
187
+ selected_tools = _select_resources(
188
+ tools,
189
+ request.tool_resource_ids,
190
+ kind="tool",
191
+ )
192
+ selected_skills = _select_resources(
193
+ skills,
194
+ request.skill_resource_ids,
195
+ kind="skill",
196
+ )
197
+ selected_mcps = _select_resources(
198
+ mcps,
199
+ request.mcp_resource_ids,
200
+ kind="mcp",
201
+ )
202
+ system_prompt = request.prompt.strip() or request.goal.strip()
203
+ task_prompt = request.task_prompt.strip() or (
204
+ "理解用户目标并给出准确、可执行的回答。调用 Tool 前检查输入,"
205
+ "对外部操作遵守权限策略;信息不足时说明假设并请求必要补充。"
206
+ )
207
+ description = request.description.strip() or system_prompt[:160]
208
+ bindings = AgentBindings(
209
+ model_profile_id=model.resource_id,
210
+ model_profile_ids=selected_model_ids,
211
+ model_parameters=ModelParameters(
212
+ temperature=0.2,
213
+ max_tokens=4096,
214
+ ),
215
+ policy_template=request.policy_template,
216
+ tools=[CapabilityBinding(resource_id=item.resource_id) for item in selected_tools],
217
+ mcp_servers=[CapabilityBinding(resource_id=item.resource_id) for item in selected_mcps],
218
+ skills=[CapabilityBinding(resource_id=item.resource_id) for item in selected_skills],
219
+ )
220
+ spec = AgentSpec(
221
+ description=description,
222
+ instructions=Instructions(system=system_prompt, task=task_prompt),
223
+ bindings=bindings,
224
+ execution=ExecutionSpec(
225
+ strategy=request.execution_strategy,
226
+ max_steps=request.max_steps,
227
+ timeout_seconds=request.timeout_seconds,
228
+ ),
229
+ context=ContextSpec(
230
+ max_input_tokens=65536,
231
+ reserve_output_tokens=8192,
232
+ ),
233
+ )
234
+ recommendations = [
235
+ AgentTemplateRecommendation(
236
+ kind="model",
237
+ status="bound",
238
+ title=model.display_name,
239
+ reason="负责理解用户请求、规划执行并生成回答。",
240
+ resource_id=model.resource_id,
241
+ )
242
+ ]
243
+ recommendations.extend(
244
+ _bound_recommendations(
245
+ selected_tools,
246
+ reason="按用户选择绑定到 Agent,可用范围由权限策略控制。",
247
+ )
248
+ )
249
+ recommendations.extend(
250
+ _bound_recommendations(
251
+ selected_mcps,
252
+ reason="按用户选择连接外部 MCP Server。",
253
+ )
254
+ )
255
+ recommendations.extend(
256
+ _bound_recommendations(
257
+ selected_skills,
258
+ reason="按用户选择注入版本化 Skill 指令。",
259
+ )
260
+ )
261
+ return AgentTemplateComposition(
262
+ template_id="blank",
263
+ spec=spec,
264
+ recommendations=recommendations,
265
+ warnings=[],
266
+ )
267
+
268
+
269
+ def compose_research_agent(
270
+ workspace: Workspace,
271
+ catalog: LocalResourceCatalog,
272
+ request: AgentTemplateComposeRequest,
273
+ ) -> AgentTemplateComposition:
274
+ ensure_research_skill(workspace)
275
+ resources = catalog.list(limit=200)
276
+ models = [item for item in resources if item.kind == "model"]
277
+ tools = [item for item in resources if item.kind == "tool"]
278
+ skills = [item for item in resources if item.kind == "skill"]
279
+ mcps = [item for item in resources if item.kind == "mcp"]
280
+
281
+ model = _select_model(models, request.model_profile_id)
282
+ selected_model_ids = _select_model_ids(
283
+ models, request.model_profile_id, request.model_profile_ids
284
+ )
285
+ research_skill = next(
286
+ (
287
+ item
288
+ for item in skills
289
+ if item.name == RESEARCH_SKILL_NAME and item.version == RESEARCH_SKILL_VERSION
290
+ ),
291
+ None,
292
+ )
293
+ if research_skill is None or research_skill.status != "ready":
294
+ raise StudioError(
295
+ "RESEARCH_SKILL_UNAVAILABLE",
296
+ "Research 模板无法解析内置调研 Skill",
297
+ status_code=409,
298
+ )
299
+
300
+ selected_skills = _select_resources(
301
+ skills,
302
+ [research_skill.resource_id, *request.skill_resource_ids],
303
+ kind="skill",
304
+ )
305
+ compatible_mcps = [item for item in mcps if _is_research_mcp(item)]
306
+ requested_mcp_ids = request.mcp_resource_ids or (
307
+ [item.resource_id for item in compatible_mcps[:1]] if request.auto_bind_mcp else []
308
+ )
309
+ selected_mcps = _select_resources(
310
+ mcps,
311
+ requested_mcp_ids,
312
+ kind="mcp",
313
+ )
314
+ default_tool_ids = [
315
+ item.resource_id
316
+ for item in tools
317
+ if item.name
318
+ in {
319
+ "list_workspace_files",
320
+ "search_workspace_files",
321
+ "read_workspace_file",
322
+ }
323
+ and item.status == "ready"
324
+ ]
325
+ requested_tool_ids = request.tool_resource_ids or (
326
+ default_tool_ids if request.auto_bind_tools else []
327
+ )
328
+ selected_tools = _select_resources(
329
+ tools,
330
+ requested_tool_ids,
331
+ kind="tool",
332
+ )
333
+
334
+ settings = _DEPTH_SETTINGS[request.depth]
335
+ bindings = AgentBindings(
336
+ model_profile_id=model.resource_id,
337
+ model_profile_ids=selected_model_ids,
338
+ model_parameters=ModelParameters(
339
+ temperature=0.2,
340
+ max_tokens=settings["max_tokens"],
341
+ ),
342
+ policy_template=request.policy_template,
343
+ tools=[CapabilityBinding(resource_id=item.resource_id) for item in selected_tools],
344
+ mcp_servers=[CapabilityBinding(resource_id=item.resource_id) for item in selected_mcps],
345
+ skills=[CapabilityBinding(resource_id=item.resource_id) for item in selected_skills],
346
+ )
347
+ has_research_mcp = bool(selected_mcps)
348
+ instructions = _research_instructions(
349
+ request,
350
+ has_research_mcp=has_research_mcp,
351
+ )
352
+ spec = AgentSpec(
353
+ description=request.description.strip()
354
+ or f"围绕“{_research_goal(request)[:160]}”执行深度调研并形成可核验结论。",
355
+ instructions=instructions,
356
+ bindings=bindings,
357
+ execution=ExecutionSpec(
358
+ strategy="plan-act-observe",
359
+ max_steps=settings["max_steps"],
360
+ timeout_seconds=settings["timeout_seconds"],
361
+ ),
362
+ context=ContextSpec(
363
+ max_input_tokens=65536,
364
+ reserve_output_tokens=8192,
365
+ ),
366
+ )
367
+
368
+ recommendations = [
369
+ AgentTemplateRecommendation(
370
+ kind="model",
371
+ status="bound",
372
+ title=model.display_name,
373
+ reason="负责问题拆解、证据综合与报告生成。",
374
+ resource_id=model.resource_id,
375
+ ),
376
+ AgentTemplateRecommendation(
377
+ kind="skill",
378
+ status="bound",
379
+ title=research_skill.display_name,
380
+ reason="注入问题树、来源分级、交叉验证和引用账本方法。",
381
+ resource_id=research_skill.resource_id,
382
+ ),
383
+ ]
384
+ recommendations.extend(
385
+ AgentTemplateRecommendation(
386
+ kind="tool",
387
+ status="bound",
388
+ title=item.display_name,
389
+ reason="用于读取和检索当前工作区中的研究资料。",
390
+ resource_id=item.resource_id,
391
+ )
392
+ for item in selected_tools
393
+ )
394
+ warnings: list[str] = []
395
+ if selected_mcps:
396
+ recommendations.extend(
397
+ AgentTemplateRecommendation(
398
+ kind="mcp",
399
+ status="bound",
400
+ title=item.display_name,
401
+ reason="提供外部来源搜索、抓取或浏览能力。",
402
+ resource_id=item.resource_id,
403
+ )
404
+ for item in selected_mcps
405
+ )
406
+ else:
407
+ warning = (
408
+ "当前没有已探测且包含搜索或抓取 Tool 的 MCP。Agent 仍可基于用户输入和"
409
+ "工作区资料调研,但无法主动检索外部来源。"
410
+ )
411
+ warnings.append(warning)
412
+ recommendations.append(
413
+ AgentTemplateRecommendation(
414
+ kind="mcp",
415
+ status="missing",
416
+ title="Web Research MCP",
417
+ reason=warning,
418
+ )
419
+ )
420
+ return AgentTemplateComposition(
421
+ template_id="research",
422
+ spec=spec,
423
+ recommendations=recommendations,
424
+ warnings=warnings,
425
+ )
426
+
427
+
428
+ def _select_model(
429
+ models: list[ResourceDescriptor],
430
+ resource_id: str | None,
431
+ ) -> ResourceDescriptor:
432
+ if resource_id:
433
+ selected = next(
434
+ (item for item in models if item.resource_id == resource_id),
435
+ None,
436
+ )
437
+ if selected is None:
438
+ raise StudioError(
439
+ "RESOURCE_NOT_FOUND",
440
+ "选择的 Model Profile 不存在",
441
+ status_code=404,
442
+ details={"resourceId": resource_id},
443
+ )
444
+ if selected.status not in {"ready", "missing-secret"}:
445
+ raise StudioError(
446
+ "RESOURCE_NOT_READY",
447
+ "选择的 Model Profile 当前不可用",
448
+ status_code=409,
449
+ details={"resourceId": resource_id, "status": selected.status},
450
+ )
451
+ return selected
452
+ selected = next(
453
+ (item for item in models if item.status in {"ready", "missing-secret"}),
454
+ None,
455
+ )
456
+ if selected is None:
457
+ raise StudioError(
458
+ "AGENT_MODEL_REQUIRED",
459
+ "Agent 需要一个可用的 Model Profile",
460
+ status_code=409,
461
+ )
462
+ return selected
463
+
464
+
465
+ def _select_model_ids(
466
+ models: list[ResourceDescriptor],
467
+ primary_id: str | None,
468
+ requested_ids: list[str] | None,
469
+ ) -> list[str]:
470
+ """Resolve the full set of bound model profile ids, deduped, primary first."""
471
+ valid = [item for item in models if item.status in {"ready", "missing-secret"}]
472
+ valid_ids = {item.resource_id for item in valid}
473
+ ordered: list[str] = []
474
+ if primary_id and primary_id in valid_ids:
475
+ ordered.append(primary_id)
476
+ for rid in requested_ids or []:
477
+ if rid in valid_ids and rid not in ordered:
478
+ ordered.append(rid)
479
+ return ordered
480
+
481
+
482
+
483
+ def _bound_recommendations(
484
+ resources: list[ResourceDescriptor],
485
+ *,
486
+ reason: str,
487
+ ) -> list[AgentTemplateRecommendation]:
488
+ return [
489
+ AgentTemplateRecommendation(
490
+ kind=item.kind,
491
+ status="bound",
492
+ title=item.display_name,
493
+ reason=reason,
494
+ resource_id=item.resource_id,
495
+ )
496
+ for item in resources
497
+ ]
498
+
499
+
500
+ def _select_resources(
501
+ resources: list[ResourceDescriptor],
502
+ resource_ids: Iterable[str],
503
+ *,
504
+ kind: str,
505
+ ) -> list[ResourceDescriptor]:
506
+ selected: list[ResourceDescriptor] = []
507
+ seen: set[str] = set()
508
+ by_id = {item.resource_id: item for item in resources}
509
+ for resource_id in resource_ids:
510
+ if resource_id in seen:
511
+ continue
512
+ seen.add(resource_id)
513
+ descriptor = by_id.get(resource_id)
514
+ if descriptor is None:
515
+ raise StudioError(
516
+ "RESOURCE_NOT_FOUND",
517
+ "模板引用的资源不存在",
518
+ status_code=404,
519
+ details={"resourceId": resource_id},
520
+ )
521
+ if descriptor.kind != kind:
522
+ raise StudioError(
523
+ "RESOURCE_KIND_INVALID",
524
+ "模板资源类型不匹配",
525
+ status_code=422,
526
+ details={"resourceId": resource_id, "expectedKind": kind},
527
+ )
528
+ if descriptor.status != "ready":
529
+ raise StudioError(
530
+ "RESOURCE_NOT_READY",
531
+ "模板不能绑定不可用资源",
532
+ status_code=409,
533
+ details={"resourceId": resource_id, "status": descriptor.status},
534
+ )
535
+ selected.append(descriptor)
536
+ return selected
537
+
538
+
539
+ def _is_research_mcp(resource: ResourceDescriptor) -> bool:
540
+ if resource.status != "ready":
541
+ return False
542
+ discovered_tools = resource.contract.get("discoveredTools") or []
543
+ if not discovered_tools:
544
+ return False
545
+ searchable = " ".join(
546
+ [
547
+ resource.name,
548
+ resource.display_name,
549
+ resource.description,
550
+ *[str(tool.get("name") or "") for tool in discovered_tools],
551
+ *[str(tool.get("description") or "") for tool in discovered_tools],
552
+ ]
553
+ ).lower()
554
+ return any(keyword in searchable for keyword in _MCP_KEYWORDS)
555
+
556
+
557
+ def _research_instructions(
558
+ request: AgentTemplateComposeRequest,
559
+ *,
560
+ has_research_mcp: bool,
561
+ ) -> Instructions:
562
+ research_goal = _research_goal(request)
563
+ if request.language == "en-US":
564
+ output_name = _OUTPUT_NAMES_EN[request.output_format]
565
+ role = f"You are Research Agent, a rigorous research specialist serving {request.audience}."
566
+ system = f"""{role}
567
+
568
+ Research objective:
569
+ {research_goal}
570
+
571
+ Operating principles:
572
+ 1. Clarify scope and assumptions before collecting evidence.
573
+ 2. Create a question tree and an explicit research plan.
574
+ 3. Prefer primary, authoritative, and recent sources.
575
+ 4. Cross-check material claims and distinguish facts from inference.
576
+ 5. Keep a source ledger and cite every externally verifiable claim.
577
+ 6. Never invent a source, URL, quotation, statistic, or publication date.
578
+ 7. Surface conflicting evidence, uncertainty, and information gaps.
579
+ 8. Produce a {output_name} for the user's decision context.
580
+ """
581
+ if not has_research_mcp:
582
+ system += (
583
+ "\nExternal research MCP is not currently bound. Use only supplied or "
584
+ "workspace evidence and state this limitation before the answer.\n"
585
+ )
586
+ task = """For each request, execute this contract:
587
+ - Restate the research question, scope, and exclusions.
588
+ - Present the plan before long-running research.
589
+ - Gather and rank evidence by source quality and recency.
590
+ - Synthesize findings into an executive summary, key findings, evidence table,
591
+ disagreements or risks, recommendations, and a source list.
592
+ - Use stable citations such as [S1] and map each citation to a real source.
593
+ - End with confidence and unresolved questions.
594
+ """
595
+ return Instructions(system=system.strip(), task=task.strip())
596
+
597
+ output_name = _OUTPUT_NAMES_ZH[request.output_format]
598
+ system = f"""你是 Research Agent,一名为{request.audience}服务的严谨深度调研专家。
599
+
600
+ 调研目标:
601
+ {research_goal}
602
+
603
+ 工作原则:
604
+ 1. 收集证据前先明确范围、时间窗口、假设和排除项。
605
+ 2. 建立问题树和可执行调研计划,再开始调用工具。
606
+ 3. 优先使用一手、权威且时效性匹配的来源。
607
+ 4. 对重要结论交叉验证,清楚区分事实、推断与未知。
608
+ 5. 维护来源账本,为每个可外部核验的关键主张提供引用。
609
+ 6. 不得虚构来源、URL、引文、统计数据或发布日期。
610
+ 7. 主动呈现冲突证据、不确定性和信息缺口。
611
+ 8. 围绕用户的决策场景输出{output_name}。
612
+ """
613
+ if not has_research_mcp:
614
+ system += (
615
+ "\n当前未绑定外部调研 MCP。只能使用用户提供内容和工作区资料,"
616
+ "回答前必须明确说明这一限制。\n"
617
+ )
618
+ task = """每次请求都必须执行以下任务契约:
619
+ - 复述研究问题、范围和排除项。
620
+ - 在长时间调研前先展示计划。
621
+ - 按来源质量和时效性收集、筛选和排序证据。
622
+ - 输出执行摘要、关键发现、证据表、冲突或风险、建议和来源列表。
623
+ - 使用 [S1]、[S2] 等稳定引用,并映射到真实来源。
624
+ - 结尾给出置信度和仍待解决的问题。
625
+ """
626
+ return Instructions(system=system.strip(), task=task.strip())
627
+
628
+
629
+ def _research_goal(request: AgentTemplateComposeRequest) -> str:
630
+ return request.goal.strip() or request.prompt.strip()