agentengine-sdk-python 0.8.3__py3-none-any.whl → 0.8.5__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 (819) hide show
  1. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/METADATA +13 -9
  2. agentengine_sdk_python-0.8.5.dist-info/RECORD +1296 -0
  3. ksadk/_build_provenance.json +1 -1
  4. ksadk/_process.py +83 -0
  5. ksadk/_str_enum.py +17 -0
  6. ksadk/a2ui/core.py +3 -3
  7. ksadk/api/client.py +111 -91
  8. ksadk/builders/code_builder.py +74 -21
  9. ksadk/builders/framework_requirements.py +22 -3
  10. ksadk/builders/ks3_uploader.py +36 -7
  11. ksadk/builders/managed_runtime_builder.py +1 -0
  12. ksadk/cli/__init__.py +68 -3
  13. ksadk/cli/cmd_config.py +4 -4
  14. ksadk/cli/cmd_create.py +12 -12
  15. ksadk/cli/cmd_hermes.py +24 -2
  16. ksadk/cli/cmd_invoke.py +28 -5
  17. ksadk/cli/cmd_managed_runtime.py +13 -1
  18. ksadk/cli/cmd_openclaw.py +26 -1
  19. ksadk/cli/cmd_plugin.py +76 -13
  20. ksadk/cli/cmd_studio.py +64 -16
  21. ksadk/cli/cmd_web.py +2 -5
  22. ksadk/cli/openclaw_env.py +1 -1
  23. ksadk/cli/resource_common.py +26 -0
  24. ksadk/cli/runtime_bootstrap.py +23 -1
  25. ksadk/codex/client.py +425 -96
  26. ksadk/codex/projection.py +24 -0
  27. ksadk/codex/runtime.py +56 -298
  28. ksadk/common/auth.py +16 -10
  29. ksadk/configs/__init__.py +1 -1
  30. ksadk/configs/env_registry.py +153 -31
  31. ksadk/configs/env_registry_studio.py +86 -0
  32. ksadk/configs/global_config.py +1 -1
  33. ksadk/configs/settings.py +3 -3
  34. ksadk/connector/__init__.py +17 -0
  35. ksadk/connector/channel.py +477 -0
  36. ksadk/context_engine/capabilities.py +52 -4
  37. ksadk/conversations/attachment_storage.py +10 -3
  38. ksadk/conversations/attachments.py +16 -5
  39. ksadk/conversations/message_projection.py +133 -21
  40. ksadk/conversations/normalize.py +28 -10
  41. ksadk/conversations/projector.py +4 -6
  42. ksadk/conversations/runtime_baseline.py +37 -0
  43. ksadk/conversations/runtime_invocation.py +22 -4
  44. ksadk/conversations/runtime_observability.py +39 -10
  45. ksadk/conversations/runtime_payloads.py +9 -0
  46. ksadk/conversations/runtime_persistence.py +105 -9
  47. ksadk/conversations/runtime_preparation.py +42 -33
  48. ksadk/conversations/runtime_resume.py +50 -2
  49. ksadk/conversations/runtime_stream_events.py +34 -35
  50. ksadk/conversations/runtime_streaming.py +33 -7
  51. ksadk/deployment/env_forward.py +2 -2
  52. ksadk/deployment/providers/serverless.py +1 -1
  53. ksadk/events/adapters/_codex_items.py +16 -8
  54. ksadk/events/adapters/_codex_validators.py +18 -7
  55. ksadk/events/adapters/_langgraph_support.py +34 -0
  56. ksadk/events/adapters/langgraph.py +15 -1
  57. ksadk/events/canonical_store.py +3 -1
  58. ksadk/events/projections.py +1 -1
  59. ksadk/events/session_event.py +2 -2
  60. ksadk/harness/__init__.py +14 -0
  61. ksadk/harness/app.py +11 -0
  62. ksadk/harness/artifact_store.py +213 -0
  63. ksadk/harness/capabilities.py +115 -0
  64. ksadk/harness/capability_runtime.py +237 -0
  65. ksadk/harness/closure_contract.py +92 -0
  66. ksadk/harness/compaction_record.py +122 -0
  67. ksadk/harness/compiler.py +284 -0
  68. ksadk/harness/config.py +2 -2
  69. ksadk/harness/conformance/__init__.py +33 -0
  70. ksadk/harness/conformance/contract.py +506 -0
  71. ksadk/harness/conformance/fixtures.py +102 -0
  72. ksadk/harness/context_engine.py +403 -0
  73. ksadk/harness/context_maintenance.py +259 -0
  74. ksadk/harness/context_manifest.py +188 -0
  75. ksadk/harness/context_tuning.py +168 -0
  76. ksadk/harness/draft_runtime.py +322 -0
  77. ksadk/harness/engine/__init__.py +40 -0
  78. ksadk/harness/engine/base.py +122 -0
  79. ksadk/harness/engine/budgets.py +108 -0
  80. ksadk/harness/engine/capability_declarations.py +59 -0
  81. ksadk/harness/engine/completion_guard.py +42 -0
  82. ksadk/harness/engine/context_pipeline.py +579 -0
  83. ksadk/harness/engine/graph_builder.py +859 -0
  84. ksadk/harness/engine/langgraph.py +931 -0
  85. ksadk/harness/engine/mcp_disclosure.py +750 -0
  86. ksadk/harness/engine/policy_runtime.py +70 -0
  87. ksadk/harness/engine/postgres_checkpointer.py +63 -0
  88. ksadk/harness/engine/run_control_bridge.py +80 -0
  89. ksadk/harness/engine/run_types.py +88 -0
  90. ksadk/harness/engine/skill_disclosure.py +189 -0
  91. ksadk/harness/engine/spans.py +41 -0
  92. ksadk/harness/engine/subagents.py +343 -0
  93. ksadk/harness/engine/thread_ids.py +112 -0
  94. ksadk/harness/engine/tool_dispatch.py +144 -0
  95. ksadk/harness/event_tree.py +212 -0
  96. ksadk/harness/events.py +461 -0
  97. ksadk/harness/execution_policy.py +94 -0
  98. ksadk/harness/insights.py +210 -0
  99. ksadk/harness/lifecycle.py +578 -0
  100. ksadk/harness/lifecycle_conformance.py +233 -0
  101. ksadk/harness/lifecycle_local_plane.py +104 -0
  102. ksadk/harness/loop/__init__.py +44 -0
  103. ksadk/harness/loop/reason.py +454 -0
  104. ksadk/harness/loop/tools.py +762 -0
  105. ksadk/harness/managed_runtime.py +884 -0
  106. ksadk/harness/mcp_matrix.py +474 -0
  107. ksadk/harness/mcp_runtime.py +471 -0
  108. ksadk/harness/memory_consolidation.py +157 -0
  109. ksadk/harness/memory_loop.py +156 -0
  110. ksadk/harness/memory_runtime.py +541 -0
  111. ksadk/harness/metrics.py +90 -0
  112. ksadk/harness/model_capability.py +253 -0
  113. ksadk/harness/model_provider.py +220 -0
  114. ksadk/harness/observability/__init__.py +29 -0
  115. ksadk/harness/observability/inspection.py +528 -0
  116. ksadk/harness/observability/metrics.py +167 -0
  117. ksadk/harness/observability/otel_exporter.py +218 -0
  118. ksadk/harness/prompt_cache.py +70 -0
  119. ksadk/harness/public_activity.py +154 -0
  120. ksadk/harness/readiness.py +249 -0
  121. ksadk/harness/reasoner.py +466 -13
  122. ksadk/harness/release_readiness.py +140 -0
  123. ksadk/harness/resource_ref.py +69 -0
  124. ksadk/harness/run_control.py +668 -0
  125. ksadk/harness/runtime.py +171 -136
  126. ksadk/harness/runtime_capabilities.py +158 -0
  127. ksadk/harness/runtime_server.py +514 -0
  128. ksadk/harness/sandbox_adapters.py +739 -0
  129. ksadk/harness/sandbox_backend.py +530 -0
  130. ksadk/harness/sandbox_conformance.py +288 -0
  131. ksadk/harness/sandbox_lease.py +77 -0
  132. ksadk/harness/sandbox_lease_conformance.py +259 -0
  133. ksadk/harness/sandbox_matrix.py +170 -0
  134. ksadk/harness/sandbox_reconciliation.py +140 -0
  135. ksadk/harness/sandbox_recovery.py +586 -0
  136. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  137. ksadk/harness/session_store.py +243 -0
  138. ksadk/harness/skill_composition.py +212 -0
  139. ksadk/harness/skill_feedback.py +123 -0
  140. ksadk/harness/skill_matrix.py +233 -0
  141. ksadk/harness/skill_runtime.py +259 -0
  142. ksadk/harness/spec.py +332 -0
  143. ksadk/harness/state.py +153 -0
  144. ksadk/harness/strategies.py +149 -0
  145. ksadk/harness/subagent.py +253 -0
  146. ksadk/harness/tool_policy.py +131 -0
  147. ksadk/harness/tool_receipts.py +96 -0
  148. ksadk/harness/tool_reliability.py +81 -0
  149. ksadk/harness/tools.py +38 -13
  150. ksadk/harness/user_errors.py +69 -0
  151. ksadk/harness/working_context.py +81 -0
  152. ksadk/harness/working_context_patch.py +99 -0
  153. ksadk/identity/resolver.py +18 -0
  154. ksadk/interaction/__init__.py +1 -1
  155. ksadk/interaction/ledger.py +1 -1
  156. ksadk/interaction/provider.py +2 -1
  157. ksadk/interaction/providers/__init__.py +3 -1
  158. ksadk/interaction/providers/adk.py +1 -1
  159. ksadk/interaction/providers/codex.py +1 -1
  160. ksadk/interaction/providers/harness.py +50 -0
  161. ksadk/interaction/providers/langgraph.py +2 -1
  162. ksadk/kernel/__init__.py +10 -0
  163. ksadk/kernel/approval_presentation.py +91 -0
  164. ksadk/kernel/authorization.py +1 -1
  165. ksadk/kernel/bootstrap.py +114 -106
  166. ksadk/kernel/contract_fingerprints.py +1 -1
  167. ksadk/kernel/contracts.py +5 -0
  168. ksadk/kernel/control.py +32 -1
  169. ksadk/kernel/execution_grants.py +221 -0
  170. ksadk/kernel/execution_grants_memory.py +133 -0
  171. ksadk/kernel/execution_grants_postgres.py +217 -0
  172. ksadk/kernel/execution_grants_sqlite.py +209 -0
  173. ksadk/kernel/ingress.py +42 -29
  174. ksadk/kernel/mapping.py +1 -1
  175. ksadk/kernel/memory_store.py +24 -11
  176. ksadk/kernel/postgres_store.py +63 -33
  177. ksadk/kernel/recovery.py +78 -14
  178. ksadk/kernel/sql/001_agent_kernel.sql +23 -0
  179. ksadk/kernel/sqlite_store.py +331 -25
  180. ksadk/kernel/state.py +2 -3
  181. ksadk/kernel/store.py +72 -2
  182. ksadk/kernel/worker.py +144 -51
  183. ksadk/kernel/worker_history.py +72 -0
  184. ksadk/kernel/worker_identity.py +47 -0
  185. ksadk/knowledge_base/client.py +57 -27
  186. ksadk/mcp_runtime/__init__.py +12 -4
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
  188. ksadk/memory/adk/resilient_session_service.py +25 -17
  189. ksadk/memory/adk/short_term_memory.py +26 -9
  190. ksadk/memory/coordinator.py +22 -6
  191. ksadk/memory/extraction.py +40 -1
  192. ksadk/memory/models.py +84 -5
  193. ksadk/memory/provider_resolver.py +8 -0
  194. ksadk/memory/providers/local_postgres.py +200 -0
  195. ksadk/memory/providers/local_sqlite.py +42 -3
  196. ksadk/memory/retrieval.py +189 -0
  197. ksadk/memory/store_adapter.py +150 -0
  198. ksadk/model_policy.py +2 -2
  199. ksadk/model_proxy/detect.py +254 -0
  200. ksadk/model_proxy/server.py +14 -7
  201. ksadk/model_proxy/transform.py +40 -2
  202. ksadk/plugins/__init__.py +5 -1
  203. ksadk/plugins/artifacts.py +275 -0
  204. ksadk/plugins/bridges/__init__.py +4 -2
  205. ksadk/plugins/bridges/codex.py +120 -13
  206. ksadk/plugins/bridges/dsh.py +351 -156
  207. ksadk/plugins/builtins.py +72 -35
  208. ksadk/plugins/bundle_security.py +28 -4
  209. ksadk/plugins/codex_manifest.py +983 -0
  210. ksadk/plugins/companion_artifacts.py +83 -0
  211. ksadk/plugins/companions.py +368 -0
  212. ksadk/plugins/composition.py +8 -0
  213. ksadk/plugins/contracts.py +119 -1
  214. ksadk/plugins/delivery.py +153 -0
  215. ksadk/plugins/dsh_channels.py +156 -0
  216. ksadk/plugins/dsh_home.py +140 -0
  217. ksadk/plugins/dsh_installation_digest.py +71 -0
  218. ksadk/plugins/dsh_teams.py +105 -0
  219. ksadk/plugins/dsh_toolchain.py +203 -32
  220. ksadk/plugins/ecosystem_probe.py +6 -6
  221. ksadk/plugins/execution_host.py +99 -0
  222. ksadk/plugins/host.py +102 -39
  223. ksadk/plugins/kernel_adapter.py +205 -0
  224. ksadk/plugins/providers/__init__.py +23 -0
  225. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  226. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  227. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  228. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  229. ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
  230. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
  231. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
  232. ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
  233. ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
  234. ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
  235. ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
  236. ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
  237. ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
  238. ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
  239. ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
  240. ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
  241. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
  242. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  243. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  244. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  245. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  246. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  247. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  248. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  249. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  250. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  251. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  252. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  253. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  254. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  255. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  256. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  257. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  258. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  259. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  260. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  261. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  262. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  263. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
  264. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +920 -0
  265. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
  266. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  267. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  268. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +115 -0
  269. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +19 -0
  270. ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
  271. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  272. ksadk/plugins/providers/codex.py +344 -70
  273. ksadk/plugins/providers/codex_native.py +368 -0
  274. ksadk/plugins/providers/codex_turn.py +301 -0
  275. ksadk/plugins/providers/dsh_capabilities.py +1450 -0
  276. ksadk/plugins/providers/dsh_mcp.py +467 -0
  277. ksadk/plugins/providers/harness.py +294 -141
  278. ksadk/plugins/providers/harness_delegation.py +593 -0
  279. ksadk/plugins/providers/harness_managed.py +456 -0
  280. ksadk/plugins/providers/harness_tools.py +326 -0
  281. ksadk/plugins/providers/mcp_projection.py +150 -0
  282. ksadk/plugins/providers/platform_resources.py +657 -0
  283. ksadk/plugins/providers/shipped_dsh.py +4 -1
  284. ksadk/plugins/resolver.py +8 -1
  285. ksadk/plugins/subagent_providers/codex.py +28 -6
  286. ksadk/plugins/teams/__init__.py +5 -0
  287. ksadk/plugins/teams/api.py +405 -0
  288. ksadk/plugins/teams/application.py +680 -0
  289. ksadk/plugins/teams/artifacts.py +60 -0
  290. ksadk/plugins/teams/context.py +96 -0
  291. ksadk/plugins/teams/contracts.py +136 -0
  292. ksadk/plugins/teams/domain.py +1427 -0
  293. ksadk/plugins/teams/domain_values.py +24 -0
  294. ksadk/plugins/teams/errors.py +13 -0
  295. ksadk/plugins/teams/migration.py +311 -0
  296. ksadk/plugins/teams/migration_cli.py +322 -0
  297. ksadk/plugins/teams/postgres_store.py +138 -0
  298. ksadk/plugins/teams/runtime.py +777 -0
  299. ksadk/plugins/teams/source_projection.py +84 -0
  300. ksadk/plugins/teams/store.py +311 -0
  301. ksadk/plugins/teams/task_decisions.py +423 -0
  302. ksadk/plugins/teams/transport.py +91 -0
  303. ksadk/plugins/teams/workspaces.py +255 -0
  304. ksadk/resource_runtime/__init__.py +4 -0
  305. ksadk/resource_runtime/broker.py +616 -0
  306. ksadk/resource_runtime/build_artifacts.py +165 -0
  307. ksadk/resource_runtime/contracts.py +138 -0
  308. ksadk/resource_runtime/discovery_receipts.py +100 -0
  309. ksadk/resource_runtime/discovery_skills.py +172 -0
  310. ksadk/resource_runtime/errors.py +6 -0
  311. ksadk/resource_runtime/ipc.py +142 -0
  312. ksadk/resource_runtime/kernel_approval.py +165 -0
  313. ksadk/resource_runtime/knowledge.py +114 -0
  314. ksadk/resource_runtime/langgraph.py +94 -0
  315. ksadk/resource_runtime/leases.py +191 -0
  316. ksadk/resource_runtime/managed_projection.py +186 -0
  317. ksadk/resource_runtime/mcp_server.py +138 -0
  318. ksadk/resource_runtime/memory_provider.py +318 -0
  319. ksadk/resource_runtime/memory_receipts.py +34 -0
  320. ksadk/resource_runtime/operation_ledger.py +211 -0
  321. ksadk/resource_runtime/plugin_config.py +48 -0
  322. ksadk/resource_runtime/policy_authorization.py +54 -0
  323. ksadk/resource_runtime/process.py +110 -0
  324. ksadk/resource_runtime/skill_artifacts.py +153 -0
  325. ksadk/resource_runtime/skill_runtime.py +42 -0
  326. ksadk/resource_runtime/skill_workspace.py +118 -0
  327. ksadk/resource_runtime/skills.py +215 -0
  328. ksadk/resource_runtime/snapshots.py +180 -0
  329. ksadk/resource_runtime/socket_server.py +103 -0
  330. ksadk/resource_runtime/supervisor.py +380 -0
  331. ksadk/resource_runtime/worker.py +504 -0
  332. ksadk/runners/_langgraph_runner_streams.py +182 -38
  333. ksadk/runners/_langgraph_state_reader.py +106 -0
  334. ksadk/runners/_session_identity.py +285 -0
  335. ksadk/runners/adk_runner.py +166 -63
  336. ksadk/runners/base_runner.py +29 -1
  337. ksadk/runners/langgraph_runner.py +542 -195
  338. ksadk/runners/patch_langchain.py +47 -0
  339. ksadk/runners/usage_accumulator.py +11 -3
  340. ksadk/runtime/_runner_adapter/stream_mapping.py +194 -20
  341. ksadk/runtime/adapter.py +2 -0
  342. ksadk/runtime/conversation_execution.py +117 -17
  343. ksadk/runtime/executor.py +87 -3
  344. ksadk/runtime/factory.py +65 -274
  345. ksadk/runtime/framework_adapters.py +23 -0
  346. ksadk/runtime/preprocessing.py +21 -5
  347. ksadk/runtime/runner_adapter.py +106 -18
  348. ksadk/runtime/skill_eval_result.py +36 -0
  349. ksadk/runtime/timing.py +46 -0
  350. ksadk/runtime/usage.py +49 -18
  351. ksadk/runtime_context.py +142 -2
  352. ksadk/sandbox/backends/e2b.py +288 -25
  353. ksadk/sandbox/backends/local_process.py +72 -39
  354. ksadk/sandbox/base.py +64 -1
  355. ksadk/sandbox/diagnostics.py +82 -0
  356. ksadk/sandbox/e2b_connection.py +66 -0
  357. ksadk/sandbox/local_controls.py +746 -0
  358. ksadk/sandbox/local_launcher.py +90 -0
  359. ksadk/scheduler/dispatcher.py +1 -1
  360. ksadk/scheduler/sqlite_store.py +18 -0
  361. ksadk/server/composition.py +2 -0
  362. ksadk/server/factory.py +5 -0
  363. ksadk/server/invocation_identity.py +118 -0
  364. ksadk/server/persistence_capability.py +516 -0
  365. ksadk/server/routes/common.py +32 -3
  366. ksadk/server/routes/control.py +271 -52
  367. ksadk/server/routes/dependencies.py +16 -0
  368. ksadk/server/routes/kernel_ingress.py +9 -1
  369. ksadk/server/routes/misc.py +233 -25
  370. ksadk/server/routes/models.py +47 -4
  371. ksadk/server/routes/openai_compat.py +76 -13
  372. ksadk/server/routes/projection.py +252 -12
  373. ksadk/server/routes/run.py +106 -35
  374. ksadk/server/routes/sessions.py +491 -138
  375. ksadk/server/routes/streaming.py +43 -9
  376. ksadk/server/routes/workspace.py +130 -21
  377. ksadk/server/static/assets/{ArtifactsPanel-10GPXIJ6.js → ArtifactsPanel-C1YoaKhx.js} +1 -1
  378. ksadk/server/static/assets/{CodeBlock-BXk1l-G1.js → CodeBlock-DHuAWfr5.js} +10 -7
  379. ksadk/server/static/assets/MathMessageMarkdown-cvdrBwYr.js +8 -0
  380. ksadk/server/static/assets/{MermaidBlock--OEYoXIJ.js → MermaidBlock-DeBkbJvI.js} +9 -9
  381. ksadk/server/static/assets/{NativeTerminalPanel-DrEe1syq.js → NativeTerminalPanel-oJj44_sV.js} +1 -1
  382. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-eeTFJLvo.js → abnfDiagram-VCTEODGH-Dhfv25o2.js} +1 -1
  383. ksadk/server/static/assets/{arc-S3ZNbIAd.js → arc-C35w-pn1.js} +1 -1
  384. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +1 -0
  385. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-CRjgEJDX.js → architectureDiagram-5GKGNRK7-FoMY_u6D.js} +1 -1
  386. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-C7bsBoNH.js → blockDiagram-NRAW4CY4-zD4Rt7oE.js} +1 -1
  387. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BX3c33Ob.js → c4Diagram-UCG6FXSJ-BCtGGkhN.js} +1 -1
  388. ksadk/server/static/assets/channel-_KDifNys.js +1 -0
  389. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +1 -0
  390. ksadk/server/static/assets/{chunk-5VM5RSS4-bZ7ws-8m.js → chunk-5VM5RSS4-C2Ms13_k.js} +1 -1
  391. ksadk/server/static/assets/{chunk-F27PBJKO-D2r0pvhY.js → chunk-F27PBJKO-BoTj-qgx.js} +1 -1
  392. ksadk/server/static/assets/{chunk-G27WJ6UU-CZwF3oUP.js → chunk-G27WJ6UU-DOMyyjHH.js} +1 -1
  393. ksadk/server/static/assets/{chunk-JWPE2WC7-DigFYCML.js → chunk-JWPE2WC7-DbJJqDli.js} +1 -1
  394. ksadk/server/static/assets/{chunk-LCL6LL3I-CnorGV5q.js → chunk-LCL6LL3I-CLuRCt_W.js} +1 -1
  395. ksadk/server/static/assets/{chunk-POPQ4Y6H-CexntQA-.js → chunk-POPQ4Y6H-D0Dz847e.js} +1 -1
  396. ksadk/server/static/assets/{chunk-RHFEMEQ7-CHTC7UxA.js → chunk-RHFEMEQ7-BWSRzEcd.js} +1 -1
  397. ksadk/server/static/assets/{chunk-SVP7TREG-BC1EWt_-.js → chunk-SVP7TREG-CPoHqkCY.js} +1 -1
  398. ksadk/server/static/assets/{chunk-XXDRQBXY-BTG24xN0.js → chunk-XXDRQBXY-Bx1jS-X-.js} +1 -1
  399. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +1 -0
  400. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +1 -0
  401. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-CkonRdAS.js → cose-bilkent-JH36ORCC-LzyWm4m0.js} +1 -1
  402. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +1 -0
  403. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-DEOCBe15.js → cynefinDiagram-5FMLGOSQ-BlW_bHED.js} +1 -1
  404. ksadk/server/static/assets/{dagre-3AP2YEHR-DBThPuLa.js → dagre-3AP2YEHR-Bu_S86_i.js} +1 -1
  405. ksadk/server/static/assets/{dagre-ClTPrTht.js → dagre-B7nCawed.js} +1 -1
  406. ksadk/server/static/assets/{diagram-S7CK7UJ4-DsZHrnpJ.js → diagram-S7CK7UJ4-W_Zow2Km.js} +1 -1
  407. ksadk/server/static/assets/{diagram-UQ7AKVKN-BJR4nhVr.js → diagram-UQ7AKVKN-CLIKAHON.js} +1 -1
  408. ksadk/server/static/assets/{diagram-VSXAHHWV-xzcERX0a.js → diagram-VSXAHHWV-Dv6_QAlN.js} +1 -1
  409. ksadk/server/static/assets/{diagram-VX7I27RA-tn2xM1xu.js → diagram-VX7I27RA-BWAWRDtZ.js} +1 -1
  410. ksadk/server/static/assets/{diagram-Z3DM3KII-BZPGBkw5.js → diagram-Z3DM3KII-XA_rWMss.js} +1 -1
  411. ksadk/server/static/assets/dist-0X_j2Rcc.js +1 -0
  412. ksadk/server/static/assets/{dist-4zN1_tq5.js → dist-1nXCdsej.js} +1 -1
  413. ksadk/server/static/assets/{dist-M67Hwu0n.js → dist-2vL2sAdF.js} +1 -1
  414. ksadk/server/static/assets/{dist-BJLUwH6W.js → dist-B3bA05-e.js} +1 -1
  415. ksadk/server/static/assets/{dist-8VWI-2bZ.js → dist-BLpRy_Yx.js} +1 -1
  416. ksadk/server/static/assets/{dist-D1V3f1B4.js → dist-BO_UwatH.js} +1 -1
  417. ksadk/server/static/assets/{dist-Cq4OL6nO.js → dist-BdNFAney.js} +1 -1
  418. ksadk/server/static/assets/{dist-DfGFrb0v.js → dist-C0J5_3qM.js} +1 -1
  419. ksadk/server/static/assets/{dist-DyqV4fL4.js → dist-CGt_UGeO.js} +1 -1
  420. ksadk/server/static/assets/{dist-DjhwGUgZ.js → dist-CIRMvUM4.js} +1 -1
  421. ksadk/server/static/assets/{dist-B1oWRmrH.js → dist-CIpWk_5f.js} +1 -1
  422. ksadk/server/static/assets/{dist-CXpH_Rdd.js → dist-CPyieXEf.js} +1 -1
  423. ksadk/server/static/assets/{dist-Btyo4vX4.js → dist-D-92S-Fd.js} +1 -1
  424. ksadk/server/static/assets/{dist-u8tVH5Ak.js → dist-DNKuMzWc.js} +1 -1
  425. ksadk/server/static/assets/{dist-DQAB0qn_.js → dist-DWfdmz9s.js} +2 -2
  426. ksadk/server/static/assets/{dist-B-46q3Hk.js → dist-DppE_r-D.js} +1 -1
  427. ksadk/server/static/assets/{dist-C71CsujO.js → dist-DyG6Ya-z.js} +1 -1
  428. ksadk/server/static/assets/{dist-DJmCPRVB.js → dist-M-SrdhhZ.js} +1 -1
  429. ksadk/server/static/assets/{dist-Bbwqa8TG.js → dist-mqD5TZup.js} +1 -1
  430. ksadk/server/static/assets/{dist-BI1qQH4n.js → dist-n3n6t_FO.js} +1 -1
  431. ksadk/server/static/assets/{dist-DUwKa_l6.js → dist-qe8xjesy.js} +1 -1
  432. ksadk/server/static/assets/{dist-B0gdk4rl.js → dist-t6MzE0jU.js} +1 -1
  433. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-DVfMsLge.js → ebnfDiagram-PWID7BFC-BfCzF1Xi.js} +1 -1
  434. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CWEZSYaw.js → erDiagram-SSCWMZ5O-Dpz9_0zn.js} +1 -1
  435. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +1 -0
  436. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +1 -0
  437. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-TWIxoyYL.js → ganttDiagram-EL5Y4UJY-DDaG1f4_.js} +1 -1
  438. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +1 -0
  439. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DDh2hd2S.js → gitGraphDiagram-WWUBYQGX-DcxzRwYC.js} +1 -1
  440. ksadk/server/static/assets/index-BMd2mucF.css +2 -0
  441. ksadk/server/static/assets/index-D5qyyhTH.js +244 -0
  442. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +1 -0
  443. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CgoyWiDR.js → infoDiagram-RXCK75RN-CYMdn6lQ.js} +1 -1
  444. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CyRIu_om.js → ishikawaDiagram-5VMMS53U-CLHFAD6c.js} +1 -1
  445. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DN5JXHzN.js → journeyDiagram-EYS64GPL-BHSKQGAl.js} +1 -1
  446. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CNP3ui66.js → kanban-definition-3QL26DDD-D5W3tjTT.js} +1 -1
  447. ksadk/server/static/assets/{katex-DWEzQy1d.js → katex-mtjOi4KM.js} +1 -1
  448. ksadk/server/static/assets/{linear-C-qHp7d2.js → linear-BETqsxE_.js} +1 -1
  449. ksadk/server/static/assets/{mermaid-parser.core-Cl-K943T.js → mermaid-parser.core-DPWrvs90.js} +2 -2
  450. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-D5DB5mYm.js → mindmap-definition-FBJOCRG2-CJG2mfBP.js} +1 -1
  451. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +1 -0
  452. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-BQVc9ia_.js → pegDiagram-XKGWAZYB-GjAPNaqn.js} +1 -1
  453. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +1 -0
  454. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-B6UCAvtY.js → pieDiagram-E7YTZNPT-ToIewrqr.js} +1 -1
  455. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-mIr2d3eb.js → quadrantDiagram-AXDQQJYC-4d78KiEY.js} +1 -1
  456. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +1 -0
  457. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +1 -0
  458. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +1 -0
  459. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +1 -0
  460. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +1 -0
  461. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-Dt3FFDmK.js → railroadDiagram-O6MQD6OU-DKzx4xfv.js} +1 -1
  462. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-Cz_vQtgF.js → requirementDiagram-EFPCY7ZU-CJYljxQS.js} +1 -1
  463. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-wlO1TsH5.js → sankeyDiagram-P5KCCOFB-DLU2fV1w.js} +1 -1
  464. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CHRbElYq.js → sequenceDiagram-WJ2MYXX4-CVqysrA9.js} +1 -1
  465. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DXX54iyO.js → sizeCapture-X5ZJPWSS-BUxfmTHc.js} +1 -1
  466. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-Dp_lw9II.js → stateDiagram-HBIQ2CUA-CNFgYI9E.js} +1 -1
  467. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +1 -0
  468. ksadk/server/static/assets/{swimlanes-XN3QIQJK-D8O5UlLG.js → swimlanes-XN3QIQJK-B6qCMe8N.js} +1 -1
  469. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +8 -0
  470. ksadk/server/static/assets/{timeline-definition-24CTP7MA-8mfKcxvG.js → timeline-definition-24CTP7MA-CMD3x_U_.js} +1 -1
  471. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +1 -0
  472. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +1 -0
  473. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-EnNl0DE7.js → vennDiagram-4TSXK5OY-BqtUqvXM.js} +1 -1
  474. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +1 -0
  475. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DBu5fbYr.js → wardleyDiagram-VM6X3IG4-B5KfDjI-.js} +1 -1
  476. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BSVXs4IY.js → xychartDiagram-S5SC5T6Z-BaUlSZrn.js} +1 -1
  477. ksadk/server/static/index.html +2 -2
  478. ksadk/server/terminal_sessions.py +34 -2
  479. ksadk/session_context.py +66 -0
  480. ksadk/sessions/__init__.py +11 -21
  481. ksadk/sessions/_local_service_sync.py +263 -1
  482. ksadk/sessions/base.py +176 -0
  483. ksadk/sessions/errors.py +4 -0
  484. ksadk/sessions/in_memory.py +309 -19
  485. ksadk/sessions/invocation_identity.py +235 -0
  486. ksadk/sessions/local_service.py +83 -1
  487. ksadk/sessions/persistence.py +275 -0
  488. ksadk/sessions/postgres_service.py +358 -0
  489. ksadk/sessions/resilience.py +8 -0
  490. ksadk/sessions/resilient.py +362 -4
  491. ksadk/sessions/topology.py +135 -0
  492. ksadk/skills/__init__.py +26 -0
  493. ksadk/skills/events.py +464 -0
  494. ksadk/skills/manifest_cache.py +263 -0
  495. ksadk/skills/mcp_server/__init__.py +0 -0
  496. ksadk/skills/mcp_server/_registry.py +33 -0
  497. ksadk/skills/mcp_server/_routing.py +26 -0
  498. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  499. ksadk/skills/mcp_server/register.py +415 -0
  500. ksadk/skills/mcp_server/server.py +218 -0
  501. ksadk/skills/models.py +37 -4
  502. ksadk/skills/observability.py +132 -0
  503. ksadk/skills/package_store.py +261 -40
  504. ksadk/skills/runtime/agent.py +67 -9
  505. ksadk/skills/runtime/artifact_delivery.py +139 -0
  506. ksadk/skills/runtime/artifacts.py +87 -0
  507. ksadk/skills/runtime/backends/e2b.py +460 -27
  508. ksadk/skills/runtime/backends/local.py +629 -62
  509. ksadk/skills/runtime/base.py +81 -7
  510. ksadk/skills/runtime/executor.py +268 -1
  511. ksadk/skills/runtime/loader.py +118 -5
  512. ksadk/skills/runtime/pinned.py +114 -0
  513. ksadk/skills/runtime/request.py +49 -0
  514. ksadk/skills/service_client.py +167 -28
  515. ksadk/skills/tool_defs.py +108 -3
  516. ksadk/studio/api.py +810 -93
  517. ksadk/studio/api_catalog_routes.py +18 -0
  518. ksadk/studio/api_contracts.py +8 -2
  519. ksadk/studio/api_plugin_routes.py +562 -104
  520. ksadk/studio/api_resource_connections.py +221 -0
  521. ksadk/studio/authoring.py +12 -6
  522. ksadk/studio/authoring_coordinator.py +23 -16
  523. ksadk/studio/builder.py +88 -0
  524. ksadk/studio/capabilities.py +23 -6
  525. ksadk/studio/channel_connections.py +333 -0
  526. ksadk/studio/cloud.py +370 -112
  527. ksadk/studio/cloud_shared_web.py +638 -0
  528. ksadk/studio/codex_agent_service.py +130 -28
  529. ksadk/studio/codex_builder.py +242 -3
  530. ksadk/studio/codex_credentials.py +90 -0
  531. ksadk/studio/codex_manifest.py +31 -4
  532. ksadk/studio/codex_plugin_store.py +746 -0
  533. ksadk/studio/codex_provider_build.py +231 -0
  534. ksadk/studio/codex_run.py +190 -26
  535. ksadk/studio/compatibility_report.py +12 -1
  536. ksadk/studio/compiler.py +88 -14
  537. ksadk/studio/configuration.py +182 -0
  538. ksadk/studio/contracts.py +165 -11
  539. ksadk/studio/dsh_application.py +247 -0
  540. ksadk/studio/dsh_capability_service.py +1374 -0
  541. ksadk/studio/dsh_lifecycle.py +58 -0
  542. ksadk/studio/dsh_models.py +59 -0
  543. ksadk/studio/dsh_provider_registration.py +367 -21
  544. ksadk/studio/entry.py +53 -0
  545. ksadk/studio/event_store.py +36 -5
  546. ksadk/studio/execution_host.py +525 -0
  547. ksadk/studio/framework_run.py +32 -10
  548. ksadk/studio/hosted_kernel.py +89 -14
  549. ksadk/studio/kernel_registry.py +418 -0
  550. ksadk/studio/kernel_sqlite_migration.py +181 -0
  551. ksadk/studio/mcp_runtime.py +11 -3
  552. ksadk/studio/model_client.py +1180 -66
  553. ksadk/studio/model_profile_service.py +26 -11
  554. ksadk/studio/native_documents.py +172 -0
  555. ksadk/studio/plugin_composition.py +202 -24
  556. ksadk/studio/plugin_kernel_adapter.py +21 -106
  557. ksadk/studio/plugin_lifecycle.py +80 -0
  558. ksadk/studio/plugin_runtime.py +448 -56
  559. ksadk/studio/provider_recovery.py +59 -0
  560. ksadk/studio/recovery_page.py +70 -0
  561. ksadk/studio/resource_authority.py +664 -0
  562. ksadk/studio/resource_binding_validation.py +77 -0
  563. ksadk/studio/resource_build_admission.py +196 -0
  564. ksadk/studio/resource_build_materializer.py +149 -0
  565. ksadk/studio/resource_catalog.py +149 -2
  566. ksadk/studio/resource_connections.py +220 -0
  567. ksadk/studio/run_activity.py +895 -0
  568. ksadk/studio/run_documents.py +127 -0
  569. ksadk/studio/run_service.py +789 -83
  570. ksadk/studio/runtime_catalog.py +53 -10
  571. ksadk/studio/runtime_source.py +16 -8
  572. ksadk/studio/scheduler_assistant.py +317 -0
  573. ksadk/studio/scheduler_runtime.py +32 -280
  574. ksadk/studio/scheduler_service.py +3 -0
  575. ksadk/studio/service.py +861 -120
  576. ksadk/studio/shared_web.py +579 -82
  577. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +8 -0
  578. ksadk/studio/static/assets/CodeBlock-DMIf4h33-UIqo-BPW.js +44 -0
  579. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  580. ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  581. ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  582. ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  583. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  584. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  585. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  586. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  587. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  588. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  589. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  590. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  591. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  592. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  593. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  594. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  595. ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  596. ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  597. ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  598. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  599. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  600. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  601. ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  602. ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  603. ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  604. ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  605. ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  606. ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  607. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  608. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  609. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  610. ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  611. ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  612. ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  613. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  614. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  615. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  616. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  617. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  618. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  619. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  620. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  621. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  622. ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  623. ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  624. ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  625. ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  626. ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  627. ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  628. ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  629. ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  630. ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  631. ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  632. ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  633. ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  634. ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  635. ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  636. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  637. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  638. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  639. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-BEOyPC3w.css +1 -0
  640. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-OhNwH4K9.js +8 -0
  641. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  642. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-g0I-I4dD.js +59 -0
  643. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  644. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +3 -0
  645. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  646. ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
  647. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  648. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  649. ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
  650. ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CLB4L11u.js +129 -0
  651. ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BOma_Z_F.js +38 -0
  652. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  653. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  654. ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  655. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  656. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  657. ksadk/studio/static/assets/chunk-4HAMMTFA-DVtDP4rm.js +62 -0
  658. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  659. ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  660. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  661. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  662. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  663. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  664. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  665. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  666. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  667. ksadk/studio/static/assets/chunk-DU6HZSFF-CpEZCUgg.js +128 -0
  668. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  669. ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  670. ksadk/studio/static/assets/chunk-GMAD6QVW-DE_8H717.js +72 -0
  671. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  672. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  673. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  674. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  675. ksadk/studio/static/assets/chunk-IMKFNOWR-D38axYOR.js +231 -0
  676. ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  677. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  678. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  679. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  680. ksadk/studio/static/assets/chunk-OSK3NFVY-DiCQjx9b.js +10 -0
  681. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  682. ksadk/studio/static/assets/chunk-P2QGCYS3-VdhKmfYq.js +1 -0
  683. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  684. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  685. ksadk/studio/static/assets/chunk-SHT3W25Y-DsCFnRVE.js +168 -0
  686. ksadk/studio/static/assets/chunk-SVP7TREG-DljApgRX.js +88 -0
  687. ksadk/studio/static/assets/chunk-TICWLB2K-DWqRtyqa.js +206 -0
  688. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  689. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  690. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  691. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  692. ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  693. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  694. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  695. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  696. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  697. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  698. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  699. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  700. ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  701. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  702. ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
  703. ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  704. ksadk/studio/static/assets/diagram-S7CK7UJ4-C6aH78c4.js +30 -0
  705. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  706. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  707. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  708. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  709. ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
  710. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  711. ksadk/studio/static/assets/erDiagram-RLTQ6QDP-CGthTMmJ.js +99 -0
  712. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  713. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  714. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  715. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  716. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  717. ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
  718. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  719. ksadk/studio/static/assets/index-CfEnms6Y.css +2 -0
  720. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  721. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  722. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  723. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  724. ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
  725. ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-BUGEl8cO.js +70 -0
  726. ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-Ch2ZYxvr.js +139 -0
  727. ksadk/studio/static/assets/kanban-definition-UXKFOSKX-Da-Fp4vC.js +89 -0
  728. ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
  729. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  730. ksadk/studio/static/assets/line-BDaeq300.js +1 -0
  731. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  732. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  733. ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-CvlsVQ38.js +96 -0
  734. ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
  735. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  736. ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
  737. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  738. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  739. ksadk/studio/static/assets/pieDiagram-E7YTZNPT-DlrWiSOv.js +39 -0
  740. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  741. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  742. ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-BA3hpUZM.js +7 -0
  743. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  744. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  745. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  746. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  747. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  748. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  749. ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-E-Ge0FcV.js +84 -0
  750. ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
  751. ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  752. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  753. ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-CcElXGg4.js +162 -0
  754. ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  755. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  756. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  757. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  758. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  759. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  760. ksadk/studio/static/assets/timeline-definition-24CTP7MA-CIuYhNy3.js +120 -0
  761. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  762. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  763. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  764. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  765. ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-CMJiaedy.js +78 -0
  766. ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-BdgtMvW2.js +7 -0
  767. ksadk/studio/static/index.html +8 -2
  768. ksadk/studio/teams_catalog.py +133 -0
  769. ksadk/studio/teams_installation.py +214 -0
  770. ksadk/studio/teams_node.py +545 -0
  771. ksadk/studio/teams_node_runner.py +69 -0
  772. ksadk/studio/teams_remote.py +274 -0
  773. ksadk/studio/templates.py +40 -19
  774. ksadk/studio/validator.py +13 -0
  775. ksadk/studio/workspace.py +19 -4
  776. ksadk/studio/workspace_plugins.py +136 -0
  777. ksadk/studio/workspace_registry.py +286 -0
  778. ksadk/toolsets/__init__.py +11 -0
  779. ksadk/toolsets/skills.py +446 -378
  780. ksadk/toolsets/workspace.py +3 -3
  781. ksadk/toolsets/workspace_identity.py +15 -0
  782. ksadk/version.py +1 -1
  783. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  784. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  785. ksadk_runtime_common/workspace_files/router.py +26 -13
  786. agentengine_sdk_python-0.8.3.dist-info/RECORD +0 -833
  787. ksadk/server/static/assets/MathMessageMarkdown-D9uB55Oh.js +0 -8
  788. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +0 -1
  789. ksadk/server/static/assets/channel-s354Yo6o.js +0 -1
  790. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +0 -1
  791. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +0 -1
  792. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +0 -1
  793. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +0 -1
  794. ksadk/server/static/assets/dist-DdRBIceA.js +0 -1
  795. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +0 -1
  796. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +0 -1
  797. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +0 -1
  798. ksadk/server/static/assets/index-B2k_urY8.js +0 -241
  799. ksadk/server/static/assets/index-ILPt6IWF.css +0 -2
  800. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +0 -1
  801. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +0 -1
  802. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +0 -1
  803. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +0 -1
  804. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +0 -1
  805. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +0 -1
  806. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +0 -1
  807. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +0 -1
  808. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +0 -1
  809. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +0 -8
  810. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +0 -1
  811. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +0 -1
  812. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +0 -1
  813. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
  814. ksadk/studio/static/assets/index-DXs1Eq4M.css +0 -1
  815. ksadk/studio/static/assets/index-DeDqwTsD.js +0 -283
  816. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/WHEEL +0 -0
  817. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/entry_points.txt +0 -0
  818. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/licenses/LICENSE +0 -0
  819. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/top_level.txt +0 -0
@@ -4,12 +4,11 @@ LangGraphRunner - LangGraph 框架运行时
4
4
  直接透传 LangGraph 原生能力,最小化封装
5
5
  """
6
6
 
7
- from __future__ import annotations
8
-
9
7
  import asyncio
10
8
  import base64
11
9
  import os
12
10
  import re
11
+ import sqlite3
13
12
  import uuid
14
13
  from typing import Any, AsyncIterator, Dict, Mapping
15
14
 
@@ -17,28 +16,40 @@ from langgraph.types import Command
17
16
 
18
17
  from ksadk.conversations.attachments import classify_attachment_kind, read_attachment_uri_bytes
19
18
  from ksadk.runners._langgraph_runner_streams import _LangGraphStreamMixin
19
+ from ksadk.runners._langgraph_state_reader import (
20
+ interrupt_info_from_state,
21
+ known_subgraph_namespaces,
22
+ read_graph_state,
23
+ )
24
+ from ksadk.runners._session_identity import LangGraphSessionIdentityMixin
20
25
  from ksadk.runners.base_runner import BaseRunner
21
26
  from ksadk.runners.utils import load_agent_module
27
+ from ksadk.runtime.skill_eval_result import skill_eval_response_fields
28
+ from ksadk.runtime.timing import extract_timing
29
+ from ksadk.sessions import resolve_persistence_topology
22
30
  from ksadk.sessions.continuity import LangGraphSessionAdapter
23
31
 
24
32
 
25
- class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
33
+ class LangGraphRunner(LangGraphSessionIdentityMixin, _LangGraphStreamMixin, BaseRunner):
26
34
  """LangGraph 框架运行时
27
35
 
28
36
  透传原生 LangGraph 功能,支持任意 State 格式
29
37
  """
30
38
 
31
- # ToolGateway approvals can arise after an otherwise terminal tool call;
32
- # this runner opts into the runtime's semantic follow-up continuation.
39
+ # ToolGateway approvals can occur after a terminal-looking tool call, so
40
+ # the semantic stream must remain resumable for a follow-up decision.
33
41
  supports_gateway_approval_semantic_resume = True
34
42
 
35
43
  def __init__(self, detection_result: Any, project_dir: str):
36
44
  super().__init__(detection_result, project_dir)
45
+ self._module: Any = None
37
46
  self._managed_checkpoint_lock = asyncio.Lock()
38
47
  self._managed_checkpoint_prepared = False
48
+ self._managed_checkpoint_state = "uninitialized"
39
49
  self._managed_checkpoint_error: tuple[str, str] | None = None
40
50
  self._managed_checkpoint_pool: Any = None
41
- self._managed_checkpoint_namespace = ""
51
+ self._identity_thread_bindings: dict[str, str] = {}
52
+ self._identity_thread_lock = asyncio.Lock()
42
53
 
43
54
  def load_agent(self) -> None:
44
55
  self._load_agent(force_reload=False)
@@ -62,86 +73,241 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
62
73
  normalized = self.sync_process_model_env(model)
63
74
  if normalized is None or self._agent is None:
64
75
  return
65
- # Studio's generated graph reads the model environment while building
66
- # each model turn. Reloading it here would discard the managed
67
- # PostgreSQL checkpointer that was installed asynchronously below.
68
- if (
69
- normalized == getattr(self, "_loaded_model_name", None)
70
- or self._managed_checkpoint_pool is not None
71
- ):
76
+ if normalized == getattr(self, "_loaded_model_name", None):
72
77
  return
73
78
  self._load_agent(force_reload=True)
74
79
 
75
80
  def get_session_adapter(self):
76
81
  return LangGraphSessionAdapter()
77
82
 
78
- def describe_checkpoint_capability(self) -> dict[str, Any]:
79
- agent = getattr(self, "_agent", None)
80
- checkpointer = getattr(agent, "checkpointer", None)
81
- if checkpointer is None:
82
- checkpointer = getattr(agent, "_checkpointer", None)
83
- if checkpointer is None:
84
- error_code, error_reason = self._managed_checkpoint_error or ("", "")
83
+ def describe_lazy_checkpoint_capability(self) -> dict[str, Any] | None:
84
+ """Describe a checkpointer created lazily by a custom runner.
85
+
86
+ Standard LangGraph runners expose the compiled graph through ``_agent``.
87
+ Custom runners that construct a graph per invocation can override this
88
+ hook so bootstrap capability discovery does not depend on a resident
89
+ graph object.
90
+ """
91
+ return None
92
+
93
+ @staticmethod
94
+ def _checkpoint_backend_from_saver(checkpointer: Any) -> str:
95
+ for saver_type in type(checkpointer).__mro__:
96
+ qualified_name = f"{saver_type.__module__}.{saver_type.__name__}".lower()
97
+ if "checkpoint.postgres" in qualified_name or "postgressaver" in qualified_name:
98
+ return "postgres"
99
+ if "checkpoint.sqlite" in qualified_name or "sqlitesaver" in qualified_name:
100
+ return "sqlite"
101
+ if "checkpoint.memory" in qualified_name or saver_type.__name__.lower() in {
102
+ "memorysaver",
103
+ "inmemorysaver",
104
+ }:
105
+ return "memory"
106
+ return "unknown"
107
+
108
+ @staticmethod
109
+ def _sqlite_target_storage(database: Any) -> str:
110
+ target = os.fspath(database).strip() if isinstance(database, (str, os.PathLike)) else ""
111
+ if not target:
112
+ return "memory"
113
+ lowered = target.lower()
114
+ if lowered == ":memory:":
115
+ return "memory"
116
+ if lowered.startswith("file:"):
117
+ path, _, query = lowered.partition("?")
118
+ if path in {"file:", "file::memory:"} or "mode=memory" in query.split("&"):
119
+ return "memory"
120
+ return "file"
121
+
122
+ @classmethod
123
+ def _sqlite_checkpoint_storage(cls, checkpointer: Any) -> str:
124
+ connection = getattr(checkpointer, "conn", None)
125
+ if isinstance(connection, sqlite3.Connection):
126
+ try:
127
+ rows = connection.execute("PRAGMA database_list").fetchall()
128
+ except Exception:
129
+ return "unknown"
130
+ for row in rows:
131
+ if len(row) >= 3 and row[1] == "main":
132
+ return "file" if str(row[2] or "").strip() else "memory"
133
+ return "unknown"
134
+
135
+ # AsyncSqliteSaver keeps the original aiosqlite connector closure. Its
136
+ # public PRAGMA API is async, while capability discovery is synchronous,
137
+ # so inspect the connection target and fail closed if it is unavailable.
138
+ connector = getattr(connection, "_connector", None)
139
+ code = getattr(connector, "__code__", None)
140
+ closure = getattr(connector, "__closure__", None)
141
+ if code is None or closure is None:
142
+ return "unknown"
143
+ try:
144
+ closed_values = {
145
+ name: cell.cell_contents for name, cell in zip(code.co_freevars, closure)
146
+ }
147
+ except (AttributeError, ValueError):
148
+ return "unknown"
149
+ if "database" not in closed_values:
150
+ return "unknown"
151
+ return cls._sqlite_target_storage(closed_values["database"])
152
+
153
+ @classmethod
154
+ def _checkpoint_capability_for_backend(
155
+ cls,
156
+ backend: str,
157
+ *,
158
+ checkpointer: Any = None,
159
+ ) -> dict[str, Any]:
160
+ if backend == "postgres":
161
+ return {
162
+ "Supported": True,
163
+ "Backend": "postgres",
164
+ "Scope": "shared",
165
+ "Durable": True,
166
+ "SharedAcrossPods": True,
167
+ "ResumeMode": "time_travel",
168
+ "Reason": "",
169
+ }
170
+ if backend == "sqlite":
171
+ if checkpointer is not None:
172
+ storage = cls._sqlite_checkpoint_storage(checkpointer)
173
+ if storage != "file":
174
+ return {
175
+ "Supported": False,
176
+ "Backend": "sqlite",
177
+ "Scope": "process_local" if storage == "memory" else "unknown",
178
+ "Durable": False,
179
+ "SharedAcrossPods": False,
180
+ "ResumeMode": "none",
181
+ "ReasonCode": "CHECKPOINTER_NOT_DURABLE",
182
+ "Reason": (
183
+ "In-memory SQLite checkpoint cannot be recovered after process restart"
184
+ if storage == "memory"
185
+ else "SQLite checkpoint file target cannot be verified as durable"
186
+ ),
187
+ }
188
+ return {
189
+ "Supported": True,
190
+ "Backend": "sqlite",
191
+ "Scope": "pod_local",
192
+ "Durable": True,
193
+ "SharedAcrossPods": False,
194
+ "ResumeMode": "time_travel",
195
+ "Reason": (
196
+ "SQLite checkpoint is durable for local web debugging "
197
+ "but is not shared across pods"
198
+ ),
199
+ }
200
+ if backend == "memory":
85
201
  return {
86
202
  "Supported": False,
87
- "Backend": "none",
88
- "Scope": "unknown",
203
+ "Backend": "memory",
204
+ "Scope": "process_local",
89
205
  "Durable": False,
90
206
  "SharedAcrossPods": False,
91
207
  "ResumeMode": "none",
92
- **({"ReasonCode": error_code} if error_code else {}),
93
- "Reason": error_reason or "LangGraph graph has no configured checkpointer",
208
+ "ReasonCode": "CHECKPOINTER_NOT_DURABLE",
209
+ "Reason": (
210
+ "In-memory checkpoint cannot be recovered after process restart or across pods"
211
+ ),
94
212
  }
213
+ return {
214
+ "Supported": False,
215
+ "Backend": "unknown",
216
+ "Scope": "unknown",
217
+ "Durable": False,
218
+ "SharedAcrossPods": False,
219
+ "ResumeMode": "none",
220
+ "ReasonCode": "CHECKPOINTER_NOT_DURABLE",
221
+ "Reason": "LangGraph checkpointer backend is not recognized as durable",
222
+ }
95
223
 
96
- backend = self._checkpoint_backend_from_saver(checkpointer)
97
- if backend == "unknown":
98
- # Some third-party savers hide their concrete type. Preserve the
99
- # explicit legacy declaration for those cases, but never let it
100
- # override a detectable in-memory saver.
101
- backend = str(os.getenv("KSADK_CHECKPOINT_BACKEND") or "").strip().lower()
102
- if backend == "local":
103
- backend = "sqlite"
104
- if not backend:
105
- backend = "unknown"
106
- scope = "unknown"
107
- durable = False
108
- shared = False
109
- reason = ""
110
- if backend == "postgres":
111
- scope = "shared"
112
- durable = True
113
- shared = True
114
- elif backend == "sqlite":
115
- scope = "pod_local"
116
- durable = True
117
- shared = False
118
- reason = (
119
- "SQLite checkpoint is durable for local web debugging but is not shared across pods"
224
+ @staticmethod
225
+ def _invalid_lazy_checkpoint_capability(
226
+ capability: Mapping[str, Any] | None = None,
227
+ ) -> dict[str, Any]:
228
+ source = capability or {}
229
+ return {
230
+ "Supported": False,
231
+ "Backend": str(source.get("Backend") or "unknown").strip().lower(),
232
+ "Scope": str(source.get("Scope") or "unknown").strip().lower(),
233
+ "Durable": bool(source.get("Durable")),
234
+ "SharedAcrossPods": bool(source.get("SharedAcrossPods")),
235
+ "ResumeMode": "none",
236
+ "ReasonCode": "CHECKPOINTER_NOT_DURABLE",
237
+ "Reason": "Lazy LangGraph checkpoint capability is invalid or not durably resumable",
238
+ }
239
+
240
+ @classmethod
241
+ def _normalize_lazy_checkpoint_capability(cls, capability: Any) -> dict[str, Any]:
242
+ if not isinstance(capability, Mapping):
243
+ return cls._invalid_lazy_checkpoint_capability()
244
+
245
+ backend = str(capability.get("Backend") or "unknown").strip().lower()
246
+ scope = str(capability.get("Scope") or "unknown").strip().lower()
247
+ durable = capability.get("Durable") is True
248
+ shared = capability.get("SharedAcrossPods") is True
249
+ resume_mode = str(capability.get("ResumeMode") or "none").strip().lower()
250
+ supported = capability.get("Supported") is True
251
+
252
+ if supported:
253
+ valid = (
254
+ durable
255
+ and resume_mode == "time_travel"
256
+ and (
257
+ (backend == "postgres" and scope == "shared" and shared)
258
+ or (backend == "sqlite" and scope == "pod_local" and not shared)
259
+ )
120
260
  )
121
- elif backend in {"memory", "inmemory"}:
122
- backend = "memory"
123
- scope = "process_local"
124
- durable = False
125
- shared = False
126
- reason = "In-memory checkpoint cannot be recovered after process restart or across pods"
261
+ if not valid:
262
+ return cls._invalid_lazy_checkpoint_capability(capability)
127
263
 
128
264
  return {
129
- # A local saver may be useful for interactive development, but it
130
- # is not a native durable-resume capability in a hosted runtime.
131
- "Supported": backend not in {"memory", "inmemory", "unknown", ""},
265
+ "Supported": supported,
132
266
  "Backend": backend,
133
267
  "Scope": scope,
134
268
  "Durable": durable,
135
269
  "SharedAcrossPods": shared,
136
- "ResumeMode": "time_travel" if durable else "none",
137
- **(
138
- {"ReasonCode": "CHECKPOINTER_NOT_DURABLE"}
139
- if backend in {"memory", "inmemory", "unknown", ""}
140
- else {}
141
- ),
142
- "Reason": reason,
270
+ "ResumeMode": resume_mode if supported else "none",
271
+ "Reason": str(capability.get("Reason") or "").strip(),
143
272
  }
144
273
 
274
+ def describe_checkpoint_capability(self) -> dict[str, Any]:
275
+ agent = getattr(self, "_agent", None)
276
+ checkpointer = getattr(agent, "checkpointer", None)
277
+ if checkpointer is None:
278
+ checkpointer = getattr(agent, "_checkpointer", None)
279
+ if checkpointer is None:
280
+ lazy_capability = self.describe_lazy_checkpoint_capability()
281
+ if lazy_capability is not None:
282
+ return self._normalize_lazy_checkpoint_capability(lazy_capability)
283
+ if self._managed_checkpoint_error is not None:
284
+ reason_code, reason = self._managed_checkpoint_error
285
+ return {
286
+ "Supported": False,
287
+ "Backend": "postgres",
288
+ "Scope": "unknown",
289
+ "Durable": False,
290
+ "SharedAcrossPods": False,
291
+ "ResumeMode": "none",
292
+ "ReasonCode": reason_code,
293
+ "Reason": reason,
294
+ }
295
+ return {
296
+ "Supported": False,
297
+ "Backend": "none",
298
+ "Scope": "unknown",
299
+ "Durable": False,
300
+ "SharedAcrossPods": False,
301
+ "ReasonCode": "CHECKPOINTER_NOT_DURABLE",
302
+ "Reason": "LangGraph graph has no configured checkpointer",
303
+ }
304
+ backend = self._checkpoint_backend_from_saver(checkpointer)
305
+ if backend == "unknown":
306
+ configured_backend = str(os.getenv("KSADK_CHECKPOINT_BACKEND") or "").strip().lower()
307
+ if configured_backend in {"postgres", "sqlite", "memory"}:
308
+ backend = configured_backend
309
+ return self._checkpoint_capability_for_backend(backend, checkpointer=checkpointer)
310
+
145
311
  def get_runtime_capabilities(self) -> dict[str, Any]:
146
312
  capabilities = super().get_runtime_capabilities()
147
313
  capabilities["model_call_boundaries"] = True
@@ -158,36 +324,14 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
158
324
  }
159
325
  return capabilities
160
326
 
161
- @staticmethod
162
- def _checkpoint_backend_from_saver(checkpointer: Any) -> str:
163
- if checkpointer is None:
164
- return "unknown"
165
- for saver_type in type(checkpointer).__mro__:
166
- qualified_name = f"{saver_type.__module__}.{saver_type.__name__}".lower()
167
- if "checkpoint.postgres" in qualified_name or "postgressaver" in qualified_name:
168
- return "postgres"
169
- if "checkpoint.sqlite" in qualified_name or "sqlitesaver" in qualified_name:
170
- return "sqlite"
171
- if "checkpoint.memory" in qualified_name or saver_type.__name__.lower() in {
172
- "memorysaver",
173
- "inmemorysaver",
174
- }:
175
- return "memory"
176
- return "unknown"
177
-
178
327
  @staticmethod
179
328
  def _env_flag(name: str) -> bool:
180
- return str(os.getenv(name) or "").strip().lower() in {"1", "true", "yes", "on"}
181
-
182
- @staticmethod
183
- def _resolve_checkpoint_namespace() -> str:
184
- session_namespace = str(os.getenv("KSADK_SESSION_NAMESPACE") or "").strip()
185
- if session_namespace:
186
- return session_namespace
187
- agent_id = str(
188
- os.getenv("AGENTENGINE_AGENT_ID") or os.getenv("KSADK_AGENT_ID") or "default"
189
- ).strip()
190
- return f"agent:{agent_id}"
329
+ return str(os.getenv(name) or "").strip().lower() in {
330
+ "1",
331
+ "true",
332
+ "yes",
333
+ "on",
334
+ }
191
335
 
192
336
  async def _create_managed_postgres_saver(self, dsn: str) -> tuple[Any, Any]:
193
337
  from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
@@ -217,36 +361,160 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
217
361
  raise
218
362
 
219
363
  async def prepare_runtime_capabilities(self) -> None:
220
- """Install the managed saver before a graph can begin an interaction.
364
+ await self._prepare_managed_checkpoint(allow_transient_retry=False)
365
+
366
+ async def refresh_runtime_capabilities(self) -> None:
367
+ await self._prepare_managed_checkpoint(allow_transient_retry=True)
368
+
369
+ async def attach_runtime_handle(self, handle: Any) -> bool:
370
+ """Validate a persisted LangGraph checkpoint handle for Runtime v2.
221
371
 
222
- The graph module must opt into this seam by exporting
223
- ``ksadk_graph_factory(*, checkpointer)``. We never mutate a compiled
224
- graph's private attributes: failed configuration remains fail-closed
225
- and capability discovery honestly reports why native resume is absent.
372
+ The concrete graph resolves the checkpoint during its native resume
373
+ call. Attachment verifies the durable backend and the complete native
374
+ address without fabricating process-local ownership.
226
375
  """
227
- if self._managed_checkpoint_prepared:
376
+
377
+ if str(getattr(handle, "runtime_type", "") or "").strip().lower() != "langgraph":
378
+ return False
379
+ native_ref = getattr(handle, "native_ref", None)
380
+ if not isinstance(native_ref, Mapping):
381
+ return False
382
+ framework_ref = native_ref.get("framework_ref")
383
+ langgraph_ref = (
384
+ framework_ref.get("langgraph") if isinstance(framework_ref, Mapping) else None
385
+ )
386
+ checkpoint_id = str(
387
+ native_ref.get("checkpoint_id")
388
+ or (langgraph_ref.get("checkpoint_id") if isinstance(langgraph_ref, Mapping) else "")
389
+ or ""
390
+ ).strip()
391
+ thread_id = str(
392
+ native_ref.get("thread_id")
393
+ or (langgraph_ref.get("thread_id") if isinstance(langgraph_ref, Mapping) else "")
394
+ or ""
395
+ ).strip()
396
+ if not checkpoint_id or not thread_id:
397
+ return False
398
+
399
+ await self.prepare_runtime_capabilities()
400
+ capability = self.describe_checkpoint_capability()
401
+ if not bool(
402
+ capability.get("Supported")
403
+ and capability.get("Durable")
404
+ and capability.get("SharedAcrossPods")
405
+ ):
406
+ return False
407
+
408
+ configurable = {
409
+ "thread_id": thread_id,
410
+ "checkpoint_id": checkpoint_id,
411
+ }
412
+ checkpoint_ns = str(
413
+ native_ref.get("checkpoint_ns")
414
+ or (langgraph_ref.get("checkpoint_ns") if isinstance(langgraph_ref, Mapping) else "")
415
+ or ""
416
+ ).strip()
417
+ if checkpoint_ns:
418
+ configurable["checkpoint_ns"] = checkpoint_ns
419
+ config = {"configurable": configurable}
420
+
421
+ if callable(
422
+ getattr(self._agent, "aget_state", None) or getattr(self._agent, "get_state", None)
423
+ ):
424
+ return await self._checkpoint_state_resolves(
425
+ config,
426
+ thread_id=thread_id,
427
+ checkpoint_id=checkpoint_id,
428
+ checkpoint_ns=checkpoint_ns,
429
+ )
430
+
431
+ with_graph = getattr(self, "_with_graph", None)
432
+ if not callable(with_graph):
433
+ return False
434
+
435
+ async def validate_lazy_graph() -> bool:
436
+ return await self._checkpoint_state_resolves(
437
+ config,
438
+ thread_id=thread_id,
439
+ checkpoint_id=checkpoint_id,
440
+ checkpoint_ns=checkpoint_ns,
441
+ )
442
+
443
+ return bool(await with_graph(validate_lazy_graph))
444
+
445
+ async def _checkpoint_state_resolves(
446
+ self,
447
+ config: Mapping[str, Any],
448
+ *,
449
+ thread_id: str,
450
+ checkpoint_id: str,
451
+ checkpoint_ns: str,
452
+ ) -> bool:
453
+ """Confirm one exact persisted checkpoint through the active graph."""
454
+
455
+ state, _error = await self._read_graph_state(config)
456
+ if state is None:
457
+ return False
458
+ state_created_at = (
459
+ state.get("created_at")
460
+ if isinstance(state, Mapping)
461
+ else getattr(state, "created_at", None)
462
+ )
463
+ state_metadata = (
464
+ state.get("metadata")
465
+ if isinstance(state, Mapping)
466
+ else getattr(state, "metadata", None)
467
+ )
468
+ if state_created_at is None and state_metadata is None:
469
+ return False
470
+ resolved_ref = self._checkpoint_ref_from_state(state).get("langgraph", {})
471
+ if not isinstance(resolved_ref, Mapping):
472
+ return False
473
+ if str(resolved_ref.get("thread_id") or "").strip() != thread_id:
474
+ return False
475
+ if str(resolved_ref.get("checkpoint_id") or "").strip() != checkpoint_id:
476
+ return False
477
+ if checkpoint_ns and str(resolved_ref.get("checkpoint_ns") or "").strip() != checkpoint_ns:
478
+ return False
479
+ return True
480
+
481
+ async def _prepare_managed_checkpoint(self, *, allow_transient_retry: bool) -> None:
482
+ if self._managed_checkpoint_state in {"ready", "terminal_failure"}:
483
+ return
484
+ if self._managed_checkpoint_state == "transient_failure" and not allow_transient_retry:
228
485
  return
229
486
  async with self._managed_checkpoint_lock:
230
- if self._managed_checkpoint_prepared:
487
+ if self._managed_checkpoint_state in {"ready", "terminal_failure"}:
488
+ return
489
+ if self._managed_checkpoint_state == "transient_failure" and not allow_transient_retry:
231
490
  return
232
491
 
233
492
  checkpointer = getattr(self._agent, "checkpointer", None)
234
493
  if checkpointer is None:
235
494
  checkpointer = getattr(self._agent, "_checkpointer", None)
236
495
  if self._checkpoint_backend_from_saver(checkpointer) == "postgres":
237
- self._managed_checkpoint_namespace = self._resolve_checkpoint_namespace()
238
496
  self._managed_checkpoint_prepared = True
497
+ self._managed_checkpoint_state = "ready"
239
498
  return
240
499
 
241
- dsn = str(
242
- os.getenv("KSADK_LANGGRAPH_CHECKPOINT_DSN")
243
- or os.getenv("KSADK_SESSION_DSN")
244
- or ""
245
- ).strip()
246
- if not self._env_flag("KSADK_LANGGRAPH_AUTO_CHECKPOINT") or not dsn:
500
+ auto_enabled = self._env_flag("KSADK_LANGGRAPH_AUTO_CHECKPOINT")
501
+ checkpoint_target = resolve_persistence_topology(framework="langgraph").checkpoint
502
+ if (
503
+ not auto_enabled
504
+ or checkpoint_target.backend != "postgres"
505
+ or not checkpoint_target.dsn
506
+ ):
247
507
  self._managed_checkpoint_prepared = True
508
+ self._managed_checkpoint_state = "terminal_failure"
248
509
  return
249
510
 
511
+ # 探测路径可能先于首个 chat 请求 probe(本地调试与手动部署形态的
512
+ # capability adapter 均未 preflight)。此时驻留图还没加载,先完成
513
+ # 模块加载:既避免把"未加载"误判为"无 durable checkpointer",
514
+ # 也避免对未初始化的 _module 抛 AttributeError 被静默吞掉。
515
+ if self._agent is None:
516
+ self.load_agent()
517
+
250
518
  factory = getattr(self._module, "ksadk_graph_factory", None)
251
519
  if not callable(factory):
252
520
  self._managed_checkpoint_error = (
@@ -255,37 +523,78 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
255
523
  "ksadk_graph_factory(*, checkpointer) for managed PostgreSQL checkpoints",
256
524
  )
257
525
  self._managed_checkpoint_prepared = True
526
+ self._managed_checkpoint_state = "terminal_failure"
527
+ return
528
+
529
+ # 托管 checkpointer 从 checkpoint 恢复 messages(append-only reducer)。
530
+ # 若接入方未导出 ksadk_prepare_state,runner 走 _to_state 把 history 再注入
531
+ # 一遍,与 checkpointer 恢复的 messages 双重叠加。托管 checkpoint 必须同时
532
+ # 提供 hook,否则 fail-closed,避免生产 auto checkpoint 下静默双重注入。
533
+ prepare_state_hook = getattr(self._module, "ksadk_prepare_state", None)
534
+ if not callable(prepare_state_hook):
535
+ self._managed_checkpoint_error = (
536
+ "PREPARE_STATE_HOOK_REQUIRED",
537
+ "Managed PostgreSQL checkpoint requires ksadk_prepare_state hook to "
538
+ "avoid double history injection (checkpointer messages restore + "
539
+ "_to_state history). Export ksadk_prepare_state(payload, "
540
+ "session_context) in the agent module.",
541
+ )
542
+ self._managed_checkpoint_prepared = True
543
+ self._managed_checkpoint_state = "terminal_failure"
258
544
  return
259
545
 
260
546
  pool = None
261
547
  try:
262
- saver, pool = await self._create_managed_postgres_saver(dsn)
548
+ saver, pool = await self._create_managed_postgres_saver(checkpoint_target.dsn)
263
549
  managed_graph = factory(checkpointer=saver)
264
550
  if not callable(getattr(managed_graph, "invoke", None)):
265
551
  raise TypeError("ksadk_graph_factory must return a compiled LangGraph graph")
266
552
  self._agent = managed_graph
267
553
  self._managed_checkpoint_pool = pool
268
- self._managed_checkpoint_namespace = self._resolve_checkpoint_namespace()
269
554
  self._managed_checkpoint_error = None
555
+ self._managed_checkpoint_state = "ready"
270
556
  except (ModuleNotFoundError, ImportError):
271
557
  self._managed_checkpoint_error = (
272
558
  "DEPENDENCY_MISSING",
273
559
  "langgraph-checkpoint-postgres and psycopg are required "
274
560
  "for managed checkpoints",
275
561
  )
276
- except Exception as exc: # noqa: BLE001
562
+ self._managed_checkpoint_state = "terminal_failure"
563
+ except Exception as exc:
277
564
  error_name = type(exc).__name__.lower()
565
+ authentication_failure = any(
566
+ marker in error_name
567
+ for marker in ("password", "authentication", "authorization")
568
+ )
569
+ permission_failure = any(
570
+ marker in error_name for marker in ("privilege", "permission")
571
+ )
572
+ terminal = (
573
+ authentication_failure
574
+ or permission_failure
575
+ or isinstance(exc, (TypeError, ValueError))
576
+ )
577
+ reason_code = (
578
+ "AUTH_FAILED"
579
+ if authentication_failure
580
+ else "SCHEMA_PERMISSION_DENIED"
581
+ if permission_failure
582
+ else "CHECKPOINTER_NOT_DURABLE"
583
+ if terminal
584
+ else "CHECKPOINT_STORE_UNREACHABLE"
585
+ )
278
586
  self._managed_checkpoint_error = (
279
- "SCHEMA_PERMISSION_DENIED"
280
- if "privilege" in error_name or "permission" in error_name
281
- else "DB_UNREACHABLE",
587
+ reason_code,
282
588
  "Managed LangGraph PostgreSQL checkpointer initialization failed",
283
589
  )
590
+ self._managed_checkpoint_state = (
591
+ "terminal_failure" if terminal else "transient_failure"
592
+ )
284
593
  finally:
285
594
  if pool is not None and self._managed_checkpoint_pool is None:
286
595
  try:
287
596
  await pool.close()
288
- except Exception: # noqa: BLE001
597
+ except Exception:
289
598
  pass
290
599
  self._managed_checkpoint_prepared = True
291
600
 
@@ -297,11 +606,14 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
297
606
  await super().close()
298
607
 
299
608
  def _get_config(self, session_id: str) -> dict:
300
- """获取运行配置"""
301
- config = {"configurable": {"thread_id": session_id}}
302
- if self._managed_checkpoint_namespace:
303
- config["configurable"]["checkpoint_ns"] = self._managed_checkpoint_namespace
304
- return config
609
+ """获取运行配置
610
+
611
+ 只写 thread_id:checkpoint_ns 是 LangGraph 的子图寻址字段,不是租户
612
+ 隔离字段。把租户/agent scope 塞进 configurable.checkpoint_ns 会让
613
+ Pregel 的 aget_state 走子图重定向并抛 "Subgraph <scope> not found",
614
+ 静默打掉流式路径的待审批探测。租户隔离由 thread_id 承担。
615
+ """
616
+ return {"configurable": {"thread_id": session_id}}
305
617
 
306
618
  @staticmethod
307
619
  def _extract_langgraph_checkpoint_ref(payload: Dict[str, Any]) -> dict[str, Any]:
@@ -313,19 +625,28 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
313
625
  return {}
314
626
  return dict(langgraph_ref)
315
627
 
316
- @classmethod
628
+ def _known_subgraph_namespaces(self) -> set[str]:
629
+ """当前图里真实存在的子图 namespace 集合(无法探测时返回空集)。"""
630
+ return known_subgraph_namespaces(self._agent)
631
+
317
632
  def _apply_checkpoint_resume_config(
318
- cls,
633
+ self,
319
634
  config: dict[str, Any],
320
635
  *,
321
636
  session_id: str,
322
637
  checkpoint_ref: dict[str, Any],
638
+ enforce_bound_thread: bool = False,
323
639
  ) -> dict[str, Any]:
324
640
  checkpoint_id = str(checkpoint_ref.get("checkpoint_id") or "").strip()
325
641
  if not checkpoint_id:
326
642
  raise ValueError("checkpoint_resume requires framework_ref.langgraph.checkpoint_id")
327
643
 
328
- thread_id = str(checkpoint_ref.get("thread_id") or session_id or "").strip()
644
+ configured = dict(config.get("configurable") or {})
645
+ bound_thread_id = str(configured.get("thread_id") or session_id or "").strip()
646
+ requested_thread_id = str(checkpoint_ref.get("thread_id") or "").strip()
647
+ if enforce_bound_thread and requested_thread_id and requested_thread_id != bound_thread_id:
648
+ raise ValueError("checkpoint_resume thread does not belong to this session")
649
+ thread_id = requested_thread_id or bound_thread_id
329
650
  if not thread_id:
330
651
  raise ValueError(
331
652
  "checkpoint_resume requires session_id or framework_ref.langgraph.thread_id"
@@ -334,11 +655,57 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
334
655
  next_config = dict(config)
335
656
  configurable = dict(next_config.get("configurable") or {})
336
657
  configurable["thread_id"] = thread_id
337
- configurable["checkpoint_ns"] = str(checkpoint_ref.get("checkpoint_ns") or "")
658
+ # checkpoint_ns 只承载 LangGraph 子图寻址语义。真实运行时 namespace 的
659
+ # 格式是 "<子图名>:<task_path>"(如 inner:<task-id>),get_subgraphs()
660
+ # 返回的是裸子图名——所以校验必须只比对首段,合法时保留原始完整
661
+ # namespace(带任务路径;否则 aget_state 定位不到对应 checkpoint)。
662
+ # 不匹配的地址(含历史租户/agent scope 残留)显性报错,绝不静默改写
663
+ # 成根地址——静默改写曾让恢复悄悄指向不存在的 checkpoint。
664
+ requested_namespace = str(checkpoint_ref.get("checkpoint_ns") or "").strip()
665
+ if requested_namespace:
666
+ known = self._known_subgraph_namespaces()
667
+ leading = requested_namespace.split(":", 1)[0]
668
+ if leading not in known:
669
+ raise ValueError(
670
+ "checkpoint_resume checkpoint_ns does not address any subgraph "
671
+ f"of this graph: {requested_namespace!r} "
672
+ f"(known subgraphs: {sorted(known) or 'none'})"
673
+ )
674
+ configurable["checkpoint_ns"] = requested_namespace
338
675
  configurable["checkpoint_id"] = checkpoint_id
339
676
  next_config["configurable"] = configurable
340
677
  return next_config
341
678
 
679
+ @staticmethod
680
+ def _unwrap_resume_value(resume_value: Any) -> Any:
681
+ """从 ksadk_resume 包装中提取实际 resume value。
682
+
683
+ KsADK 的 ksadk_resume 协议把用户决策包在 ``{"type":"ksadk_resume",
684
+ "interrupt_id":..., "value":{...}}`` 里,但 ``Command(resume=...)``
685
+ 期望直接收到框架能识别的值(如 HumanInTheLoopMiddleware 的
686
+ ``{"decisions":[...]}``)。这里拆掉外层包装,把 ``value`` 内容
687
+ 作为 resume value 返回。有 interrupt_id 时保留原生 {id: value} 定向
688
+ 恢复语义,避免并行 interrupt 丢失目标;无 ID 时保留单 interrupt 值路径。
689
+
690
+ 非 ksadk_resume 类型(mcp_approval_response 等)原样返回,保持
691
+ 既有内置工具审批路径不变;ToolGateway 走 semantic resume 分支,
692
+ 不经过此处。
693
+ """
694
+ if isinstance(resume_value, Mapping):
695
+ item_type = str(resume_value.get("type") or "").strip()
696
+ if item_type in {"ksadk_resume", "ksadk.approval_response"}:
697
+ inner = resume_value.get("value")
698
+ if inner is not None:
699
+ interrupt_id = str(
700
+ resume_value.get("interrupt_id")
701
+ or resume_value.get("approval_request_id")
702
+ or resume_value.get("id")
703
+ or ""
704
+ ).strip()
705
+ # Parallel graph tasks must receive only their own decision.
706
+ return {interrupt_id: inner} if interrupt_id else inner
707
+ return resume_value
708
+
342
709
  @staticmethod
343
710
  def _checkpoint_resume_input(
344
711
  value: Any,
@@ -353,14 +720,7 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
353
720
 
354
721
  @staticmethod
355
722
  def _is_gateway_approval_semantic_resume(value: Any) -> bool:
356
- """Whether ``value`` came from a completed ToolGateway approval.
357
-
358
- Native LangGraph ``interrupt()`` values must keep using
359
- ``Command(resume=...)``. In contrast, a ToolGateway can return an
360
- ``approval_required`` result from an otherwise normal tool call; the
361
- graph then reaches its terminal node before KsADK shows the approval
362
- card. Its approved tool result needs a new semantic graph turn.
363
- """
723
+ """Return whether a completed ToolGateway approval needs a fresh turn."""
364
724
 
365
725
  return bool(
366
726
  isinstance(value, Mapping)
@@ -370,13 +730,7 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
370
730
 
371
731
  @staticmethod
372
732
  def _gateway_approval_follow_up_input() -> str:
373
- """A neutral prompt for the post-approval semantic continuation.
374
-
375
- The actual approval response and durable tool result are already in
376
- the session history. Do not repeat their contents here: project hooks
377
- commonly route by input keywords, and copying a workspace path back
378
- into a synthetic user message can accidentally trigger another tool.
379
- """
733
+ """Build the neutral prompt used after an approved terminal tool call."""
380
734
 
381
735
  return (
382
736
  "系统已完成此前获批的操作。请基于会话记录中的真实结果,直接向用户说明完成情况;"
@@ -422,13 +776,8 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
422
776
  }
423
777
 
424
778
  async def _latest_checkpoint_metadata(self, config: dict[str, Any]) -> dict[str, Any]:
425
- state = None
426
- try:
427
- if callable(getattr(self._agent, "aget_state", None)):
428
- state = await self._agent.aget_state(config)
429
- elif callable(getattr(self._agent, "get_state", None)):
430
- state = self._agent.get_state(config)
431
- except Exception:
779
+ state, _error = await self._read_graph_state(config)
780
+ if state is None:
432
781
  return {}
433
782
  framework_ref = self._checkpoint_ref_from_state(state)
434
783
  if not framework_ref:
@@ -464,13 +813,8 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
464
813
  }
465
814
 
466
815
  async def _latest_state_usage(self, config: dict[str, Any]) -> dict[str, Any]:
467
- state = None
468
- try:
469
- if callable(getattr(self._agent, "aget_state", None)):
470
- state = await self._agent.aget_state(config)
471
- elif callable(getattr(self._agent, "get_state", None)):
472
- state = self._agent.get_state(config)
473
- except Exception:
816
+ state, _error = await self._read_graph_state(config)
817
+ if state is None:
474
818
  return {}
475
819
  values = getattr(state, "values", None)
476
820
  if values is not None:
@@ -759,10 +1103,15 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
759
1103
  final_metadata = final_chunk.get("metadata")
760
1104
  if isinstance(final_metadata, Mapping):
761
1105
  metadata = {**dict(final_metadata), **metadata}
762
- result: dict[str, Any] = {"output": output_text, "raw": {"chunks": chunks}}
1106
+ result: dict[str, Any] = {
1107
+ "output": output_text, "raw": {"chunks": chunks},
1108
+ **skill_eval_response_fields(final_chunk),
1109
+ }
763
1110
  usage = final_chunk.get("usage")
764
1111
  if isinstance(usage, Mapping) and usage:
765
1112
  result["usage"] = dict(usage)
1113
+ if timing := extract_timing(final_chunk):
1114
+ result["timing"] = timing
766
1115
  if metadata:
767
1116
  result["metadata"] = metadata
768
1117
  return result
@@ -788,43 +1137,32 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
788
1137
  resume_payload_provided = bool(payload.pop("resume_payload_provided", False))
789
1138
  resume_interrupt_id = str(payload.pop("resume_interrupt_id", "") or "")
790
1139
  resume_value = payload.get("input")
791
- is_gateway_approval_resume = bool(
792
- is_resume and self._is_gateway_approval_semantic_resume(resume_value)
793
- )
794
- if is_gateway_approval_resume:
795
- # ``Command(resume=...)`` only works for a graph that actually
796
- # yielded LangGraph's native interrupt. ToolGateway approvals are
797
- # intercepted after a normal tool result, when the graph already
798
- # ended, so restart a normal turn from the persisted transcript.
799
- payload["input"] = self._gateway_approval_follow_up_input()
800
- resume_value = payload["input"]
801
1140
  checkpoint_ref = self._extract_langgraph_checkpoint_ref(payload)
802
1141
  history = payload.pop("history", [])
803
- native_context = self.build_native_context(payload.get("platform_context"))
804
- config = self._get_config(session_id)
1142
+ native_context = self.build_native_context(
1143
+ payload.get("platform_context"),
1144
+ context_schema=getattr(self._agent, "context_schema", None),
1145
+ )
1146
+ config = await self._get_session_config(session_id)
805
1147
  if is_checkpoint_resume:
806
1148
  config = self._apply_checkpoint_resume_config(
807
1149
  config,
808
1150
  session_id=session_id,
809
1151
  checkpoint_ref=checkpoint_ref,
1152
+ enforce_bound_thread=bool(self._invocation_identity_scope_ref()),
810
1153
  )
811
1154
 
812
1155
  # 判断输入格式 / resume
813
1156
  if is_checkpoint_resume:
814
1157
  state = resume_value
815
- elif is_resume and not is_gateway_approval_resume:
1158
+ elif is_resume:
816
1159
  # ``Command(resume=...)`` is delivered to the graph's suspended
817
1160
  # interrupt. A custom prepare-state hook is for new user input;
818
1161
  # applying it here can rewrite an approval decision into ordinary
819
1162
  # graph state and turn an approved HITL action into a rejection.
820
- state = resume_value
1163
+ state = self._unwrap_resume_value(resume_value)
821
1164
  elif self._has_prepare_state_hook():
822
- state = self._prepare_state_with_hook(
823
- payload,
824
- session_id,
825
- history,
826
- is_resume=is_gateway_approval_resume,
827
- )
1165
+ state = self._prepare_state_with_hook(payload, session_id, history)
828
1166
  else:
829
1167
  state = self._to_state(payload, history)
830
1168
 
@@ -839,7 +1177,7 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
839
1177
  config=config,
840
1178
  context=native_context,
841
1179
  )
842
- elif is_resume and not is_gateway_approval_resume:
1180
+ elif is_resume:
843
1181
  result = await self._invoke_graph(
844
1182
  Command(resume=state),
845
1183
  config=config,
@@ -852,7 +1190,12 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
852
1190
  context=native_context,
853
1191
  )
854
1192
 
855
- output = {"output": self._extract_output(result), "raw": result}
1193
+ output = {
1194
+ "output": self._extract_output(result), "raw": result,
1195
+ **skill_eval_response_fields(result),
1196
+ }
1197
+ if timing := extract_timing(result):
1198
+ output["timing"] = timing
856
1199
  usage = self._extract_usage(result)
857
1200
  if usage:
858
1201
  output["usage"] = usage
@@ -866,7 +1209,14 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
866
1209
 
867
1210
  except Exception as e:
868
1211
  if "Interrupt" in type(e).__name__:
869
- interrupt_info = self._get_interrupt_info(self._agent.get_state(config))
1212
+ state, error = await self._read_graph_state(config, include_subgraphs=True)
1213
+ if state is None:
1214
+ # 图已经抛出 interrupt,但状态读不回来:这里必须显性失败,
1215
+ # 不能返回空 interrupt_info,更不能伪装成正常完成。
1216
+ raise RuntimeError(
1217
+ "graph interrupted but its checkpoint state could not be read"
1218
+ ) from error
1219
+ interrupt_info = self._get_interrupt_info(state)
870
1220
  return {
871
1221
  "type": "interrupt",
872
1222
  "interrupt_info": interrupt_info,
@@ -901,20 +1251,20 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
901
1251
  return str(content)
902
1252
  return str(result) if result else ""
903
1253
 
1254
+ async def _read_graph_state(
1255
+ self,
1256
+ config: Mapping[str, Any],
1257
+ *,
1258
+ include_subgraphs: bool = False,
1259
+ ) -> tuple[Any | None, Exception | None]:
1260
+ """统一的图状态读取入口(实现在 `_langgraph_state_reader`,全仓唯一)。"""
1261
+ return await read_graph_state(
1262
+ self._agent, config, include_subgraphs=include_subgraphs
1263
+ )
1264
+
904
1265
  def _get_interrupt_info(self, state) -> dict:
905
- """从 state 中获取 interrupt 信息"""
906
- if hasattr(state, "tasks") and state.tasks:
907
- for task in state.tasks:
908
- if hasattr(task, "interrupts") and task.interrupts:
909
- for intr in task.interrupts:
910
- if hasattr(intr, "value"):
911
- value = intr.value
912
- info = dict(value) if isinstance(value, Mapping) else {"value": value}
913
- interrupt_id = str(getattr(intr, "id", "") or "")
914
- if interrupt_id:
915
- info.setdefault("approval_request_id", interrupt_id)
916
- return info
917
- return {}
1266
+ """从 state 中获取 interrupt 信息(含子图嵌套任务)。"""
1267
+ return interrupt_info_from_state(state)
918
1268
 
919
1269
  async def _stream_checkpoint_resume_updates(
920
1270
  self,
@@ -958,6 +1308,7 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
958
1308
  latest_config = self._latest_checkpoint_config(config)
959
1309
  state_usage = await self._latest_state_usage(latest_config)
960
1310
  state_output = ""
1311
+ result_fields: dict[str, Any] = {}
961
1312
  try:
962
1313
  state = None
963
1314
  if callable(getattr(self._agent, "aget_state", None)):
@@ -967,12 +1318,14 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
967
1318
  values = getattr(state, "values", None)
968
1319
  if values is not None:
969
1320
  state_output = self._extract_output(values)
1321
+ result_fields = skill_eval_response_fields(values)
970
1322
  except Exception:
971
1323
  state_output = ""
972
1324
  final_output = state_output or self._extract_output(latest_output)
973
1325
  yield {
974
1326
  "type": "final",
975
1327
  "output": final_output,
1328
+ **result_fields,
976
1329
  **({"usage": state_usage} if state_usage else {}),
977
1330
  **({"resume_noop": True} if not emitted_update else {}),
978
1331
  }
@@ -1052,15 +1405,9 @@ class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
1052
1405
  return events
1053
1406
 
1054
1407
  def _filter_tool_tags(self, content: str) -> str:
1055
- """过滤完整的 XML tool_call 标签。"""
1408
+ """过滤 <tool_call> 标签"""
1056
1409
  if not isinstance(content, str):
1057
1410
  return content
1058
1411
  content = re.sub(r"<tool_call>.*?</tool_call>", "", content, flags=re.DOTALL)
1059
1412
  content = re.sub(r"</?(?:tool_call|arg_key|arg_value)>", "", content)
1060
1413
  return content
1061
-
1062
- async def stream(self, input_data: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
1063
- """Prepare the managed checkpoint before yielding the first event."""
1064
- await self.prepare_runtime_capabilities()
1065
- async for event in super().stream(input_data):
1066
- yield event