agentengine-sdk-python 0.8.0__py3-none-any.whl → 0.8.2__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.
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
- agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +2 -0
- ksadk/a2a/_space_client_events.py +381 -0
- ksadk/a2a/bootstrap.py +0 -2
- ksadk/a2a/card.py +6 -111
- ksadk/a2a/control_plane.py +239 -1
- ksadk/a2a/event_adapter.py +156 -64
- ksadk/a2a/executor.py +195 -172
- ksadk/a2a/routes.py +12 -5
- ksadk/a2a/server.py +1 -8
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +43 -349
- ksadk/a2a_card.py +101 -0
- ksadk/a2ui/core.py +222 -53
- ksadk/agui/_agent_helpers.py +243 -0
- ksadk/agui/a2ui_projection.py +12 -5
- ksadk/agui/agent.py +474 -275
- ksadk/agui/config.py +11 -5
- ksadk/agui/routes.py +7 -15
- ksadk/api/client.py +530 -40
- ksadk/api/environment.py +27 -0
- ksadk/builders/code_builder.py +352 -53
- ksadk/builders/container_builder.py +71 -44
- ksadk/builders/framework_requirements.py +2 -1
- ksadk/builders/ks3_uploader.py +2 -2
- ksadk/builders/managed_runtime_builder.py +60 -28
- ksadk/cli/__init__.py +25 -0
- ksadk/cli/cmd_a2a.py +18 -31
- ksadk/cli/cmd_create.py +13 -26
- ksadk/cli/cmd_dashboard.py +15 -1
- ksadk/cli/cmd_deploy.py +28 -3
- ksadk/cli/cmd_eval.py +443 -0
- ksadk/cli/cmd_evalset.py +284 -0
- ksadk/cli/cmd_files.py +5 -1
- ksadk/cli/cmd_hermes.py +137 -163
- ksadk/cli/cmd_invoke.py +28 -38
- ksadk/cli/cmd_launch.py +12 -0
- ksadk/cli/cmd_managed_runtime.py +95 -0
- ksadk/cli/cmd_observe.py +85 -0
- ksadk/cli/cmd_openclaw.py +85 -479
- ksadk/cli/cmd_replay.py +28 -4
- ksadk/cli/cmd_run.py +29 -67
- ksadk/cli/cmd_studio.py +201 -0
- ksadk/cli/cmd_web.py +15 -6
- ksadk/cli/dry_run.py +2 -1
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/global_options.py +3 -1
- ksadk/cli/hermes_env.py +151 -0
- ksadk/cli/invoke_payload.py +49 -0
- ksadk/cli/network_options.py +7 -5
- ksadk/cli/openclaw_env.py +458 -0
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/ui.py +6 -0
- ksadk/cli/workflow_common.py +5 -5
- ksadk/codex/__init__.py +3 -3
- ksadk/codex/client.py +833 -49
- ksadk/codex/phase.py +1 -1
- ksadk/codex/runtime.py +720 -127
- ksadk/common/kop_client.py +232 -0
- ksadk/configs/__init__.py +1 -3
- ksadk/configs/env_registry.py +244 -45
- ksadk/configs/env_registry_pcm.py +181 -0
- ksadk/configs/env_var_spec.py +18 -0
- ksadk/configs/global_config.py +6 -1
- ksadk/configs/settings.py +5 -108
- ksadk/context_engine/__init__.py +98 -0
- ksadk/context_engine/assembler.py +176 -0
- ksadk/context_engine/baseline.py +419 -0
- ksadk/context_engine/cache_observability.py +228 -0
- ksadk/context_engine/capabilities.py +443 -0
- ksadk/context_engine/contributors.py +344 -0
- ksadk/context_engine/hosted_pipeline.py +417 -0
- ksadk/context_engine/models.py +117 -0
- ksadk/context_engine/planner.py +698 -0
- ksadk/context_engine/policies.py +319 -0
- ksadk/context_engine/projection.py +31 -0
- ksadk/context_engine/shadow_plan.py +266 -0
- ksadk/context_engine/tokenizer.py +164 -0
- ksadk/conversations/__init__.py +85 -94
- ksadk/conversations/context.py +126 -6
- ksadk/conversations/message_projection.py +292 -28
- ksadk/conversations/model_context.py +49 -3
- ksadk/conversations/runtime_compaction.py +207 -5
- ksadk/conversations/runtime_input.py +193 -3
- ksadk/conversations/runtime_invocation.py +81 -3
- ksadk/conversations/runtime_observability.py +157 -4
- ksadk/conversations/runtime_payloads.py +42 -0
- ksadk/conversations/runtime_preparation.py +280 -2
- ksadk/conversations/runtime_resume.py +71 -32
- ksadk/conversations/runtime_stream_events.py +94 -9
- ksadk/conversations/runtime_streaming.py +175 -22
- ksadk/conversations/semantic_summary.py +311 -1
- ksadk/conversations/session_lock.py +51 -0
- ksadk/deployment/env_forward.py +72 -0
- ksadk/deployment/managed_runtime.py +38 -0
- ksadk/deployment/manager.py +24 -8
- ksadk/deployment/providers/serverless.py +228 -92
- ksadk/evaluation/__init__.py +116 -0
- ksadk/evaluation/a2a_adapter.py +452 -0
- ksadk/evaluation/adapters.py +67 -0
- ksadk/evaluation/agent_eval_client.py +395 -0
- ksadk/evaluation/cloud_binding.py +80 -0
- ksadk/evaluation/cloud_converter.py +194 -0
- ksadk/evaluation/cloud_service.py +199 -0
- ksadk/evaluation/contracts.py +478 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +627 -0
- ksadk/evaluation/evidence.py +258 -0
- ksadk/evaluation/executor.py +143 -0
- ksadk/evaluation/local_adapter.py +550 -0
- ksadk/evaluation/service_env.py +27 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/studio_build_adapter.py +253 -0
- ksadk/evaluation/target.py +82 -0
- ksadk/events/__init__.py +13 -13
- ksadk/events/_v1_compat/__init__.py +1 -0
- ksadk/events/_v1_compat/models.py +299 -0
- ksadk/events/_v1_compat/parser.py +247 -0
- ksadk/events/_v1_compat/projection.py +753 -0
- ksadk/events/adapters/__init__.py +34 -0
- ksadk/events/adapters/_a2a_snapshot.py +622 -0
- ksadk/events/adapters/_a2a_support.py +275 -0
- ksadk/events/adapters/_codex_interactions.py +375 -0
- ksadk/events/adapters/_codex_items.py +801 -0
- ksadk/events/adapters/_codex_validators.py +311 -0
- ksadk/events/adapters/_langgraph_support.py +785 -0
- ksadk/events/adapters/a2a.py +841 -0
- ksadk/events/adapters/adk.py +503 -0
- ksadk/events/adapters/codex.py +717 -0
- ksadk/events/adapters/langgraph.py +745 -0
- ksadk/events/canonical.py +440 -0
- ksadk/events/canonical_replay.py +497 -0
- ksadk/events/canonical_store.py +468 -0
- ksadk/events/cold_recovery.py +257 -0
- ksadk/events/content.py +89 -0
- ksadk/events/identity.py +86 -0
- ksadk/events/pipeline.py +455 -0
- ksadk/events/projections.py +66 -0
- ksadk/events/reducer.py +661 -0
- ksadk/events/replay.py +3 -36
- ksadk/events/runtime_event.py +20 -256
- ksadk/events/session_event.py +324 -0
- ksadk/events/store.py +3 -316
- ksadk/events/v1_compat.py +41 -0
- ksadk/harness/__init__.py +3 -2
- ksadk/harness/app.py +114 -123
- ksadk/harness/config.py +1 -1
- ksadk/harness/runtime.py +467 -0
- ksadk/hermes_terminal.py +5 -0
- ksadk/identity/resolver.py +4 -3
- ksadk/interaction/__init__.py +28 -0
- ksadk/interaction/contracts.py +136 -0
- ksadk/interaction/ledger.py +189 -0
- ksadk/interaction/provider.py +122 -0
- ksadk/interaction/providers/__init__.py +52 -0
- ksadk/interaction/providers/adk.py +40 -0
- ksadk/interaction/providers/codex.py +94 -0
- ksadk/interaction/providers/langgraph.py +58 -0
- ksadk/kernel/__init__.py +117 -0
- ksadk/kernel/authorization.py +258 -0
- ksadk/kernel/bootstrap.py +1074 -0
- ksadk/kernel/contract_fingerprints.py +61 -0
- ksadk/kernel/contracts.py +362 -0
- ksadk/kernel/control.py +219 -0
- ksadk/kernel/errors.py +79 -0
- ksadk/kernel/ingress.py +1102 -0
- ksadk/kernel/mapping.py +111 -0
- ksadk/kernel/memory_store.py +1133 -0
- ksadk/kernel/postgres_store.py +1756 -0
- ksadk/kernel/recovery.py +452 -0
- ksadk/kernel/runtime_identity.py +103 -0
- ksadk/kernel/sql/001_agent_kernel.sql +120 -0
- ksadk/kernel/sqlite_store.py +1410 -0
- ksadk/kernel/state.py +145 -0
- ksadk/kernel/store.py +232 -0
- ksadk/kernel/worker.py +953 -0
- ksadk/knowledge_base/client.py +22 -4
- ksadk/knowledge_base/service.py +32 -5
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +16 -9
- ksadk/memory/__init__.py +61 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
- ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
- ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
- ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
- ksadk/memory/adk/long_term_memory.py +3 -2
- ksadk/memory/coordinator.py +461 -0
- ksadk/memory/events.py +202 -0
- ksadk/memory/extraction.py +228 -0
- ksadk/memory/ltm_backend_factory.py +16 -3
- ksadk/memory/models.py +316 -0
- ksadk/memory/policy.py +215 -0
- ksadk/memory/provider.py +47 -0
- ksadk/memory/provider_adapter.py +159 -0
- ksadk/memory/provider_resolver.py +71 -0
- ksadk/memory/providers/__init__.py +5 -0
- ksadk/memory/providers/local_sqlite.py +490 -0
- ksadk/memory/resolved_policy.py +145 -0
- ksadk/memory/service.py +198 -8
- ksadk/memory/tool.py +4 -0
- ksadk/model_proxy/bootstrap.py +16 -9
- ksadk/model_proxy/config.py +22 -1
- ksadk/model_proxy/detect.py +202 -9
- ksadk/model_proxy/namespace.py +67 -15
- ksadk/model_proxy/server.py +168 -6
- ksadk/model_proxy/transform.py +105 -3
- ksadk/observability/__init__.py +25 -0
- ksadk/observability/session_log.py +420 -0
- ksadk/observability/trajectory.py +105 -0
- ksadk/prompts/__init__.py +71 -0
- ksadk/prompts/compiler.py +215 -0
- ksadk/prompts/models.py +82 -0
- ksadk/prompts/projection.py +89 -0
- ksadk/prompts/resolved.py +137 -0
- ksadk/prompts/sources.py +233 -0
- ksadk/runners/_langgraph_runner_streams.py +822 -0
- ksadk/runners/adk_runner.py +14 -31
- ksadk/runners/base_runner.py +44 -3
- ksadk/runners/factory.py +3 -3
- ksadk/runners/langgraph_runner.py +252 -433
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +16 -0
- ksadk/runtime/__init__.py +67 -41
- ksadk/runtime/_runner_adapter/__init__.py +1 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
- ksadk/runtime/adapter.py +199 -16
- ksadk/runtime/conversation_execution.py +687 -0
- ksadk/runtime/executor.py +392 -0
- ksadk/runtime/factory.py +342 -0
- ksadk/runtime/framework_adapters.py +6 -12
- ksadk/runtime/hosted_finalizer.py +268 -0
- ksadk/runtime/launch.py +61 -0
- ksadk/runtime/preprocessing.py +49 -14
- ksadk/runtime/runner_adapter.py +330 -391
- ksadk/runtime/runner_loading.py +36 -0
- ksadk/runtime/usage.py +33 -0
- ksadk/sandbox/backends/e2b.py +36 -3
- ksadk/server/__init__.py +39 -4
- ksadk/server/app.py +18 -492
- ksadk/server/composition.py +36 -2
- ksadk/server/factory.py +210 -149
- ksadk/server/routes/common.py +15 -46
- ksadk/server/routes/control.py +13 -9
- ksadk/server/routes/kernel_ingress.py +258 -0
- ksadk/server/routes/misc.py +10 -33
- ksadk/server/routes/models.py +14 -6
- ksadk/server/routes/openai_compat.py +129 -27
- ksadk/server/routes/projection.py +84 -16
- ksadk/server/routes/run.py +347 -460
- ksadk/server/routes/sessions.py +37 -40
- ksadk/server/routes/streaming.py +52 -7
- ksadk/server/routes/workspace.py +54 -21
- ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
- ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
- ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
- ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
- ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
- ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
- ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
- ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
- ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
- ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
- ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
- ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
- ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
- ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
- ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
- ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
- ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
- ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
- ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
- ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
- ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
- ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
- ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
- ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
- ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
- ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
- ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
- ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
- ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
- ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
- ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
- ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
- ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
- ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
- ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
- ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
- ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
- ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
- ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
- ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
- ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
- ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
- ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
- ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
- ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
- ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
- ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
- ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
- ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
- ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
- ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
- ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
- ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
- ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
- ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
- ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
- ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
- ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
- ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
- ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
- ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
- ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
- ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
- ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
- ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
- ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
- ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
- ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
- ksadk/server/static/index.html +2 -2
- ksadk/sessions/__init__.py +26 -9
- ksadk/sessions/_local_service_sync.py +688 -0
- ksadk/sessions/_local_tables.py +21 -0
- ksadk/sessions/_postgres_schema.py +305 -0
- ksadk/sessions/_postgres_tables.py +15 -0
- ksadk/sessions/base.py +80 -1
- ksadk/sessions/in_memory.py +53 -2
- ksadk/sessions/local_service.py +63 -604
- ksadk/sessions/postgres_service.py +58 -148
- ksadk/sessions/resilient.py +35 -1
- ksadk/skills/runtime/backends/e2b.py +1 -1
- ksadk/skills/service_client.py +13 -3
- ksadk/studio/__init__.py +5 -0
- ksadk/studio/agent_avatar_assets.py +120 -0
- ksadk/studio/agent_lifecycle.py +51 -0
- ksadk/studio/api.py +1598 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +286 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/api_memory_routes.py +82 -0
- ksadk/studio/authoring.py +749 -0
- ksadk/studio/authoring_coordinator.py +1017 -0
- ksadk/studio/builder.py +397 -0
- ksadk/studio/capabilities.py +368 -0
- ksadk/studio/cloud.py +2099 -0
- ksadk/studio/codex_agent_service.py +694 -0
- ksadk/studio/codex_authoring.py +469 -0
- ksadk/studio/codex_builder.py +437 -0
- ksadk/studio/codex_manifest.py +307 -0
- ksadk/studio/codex_run.py +395 -0
- ksadk/studio/compiler.py +190 -0
- ksadk/studio/contracts.py +755 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/event_store.py +214 -0
- ksadk/studio/framework_run.py +342 -0
- ksadk/studio/hosted_kernel.py +317 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/manifest_resolver.py +131 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +629 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +275 -0
- ksadk/studio/otel_trace.py +1060 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/pcm_memory.py +85 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +327 -0
- ksadk/studio/resource_catalog.py +1260 -0
- ksadk/studio/run_service.py +1133 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +365 -0
- ksadk/studio/service.py +2249 -0
- ksadk/studio/shared_web.py +1004 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
- ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
- ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
- ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- ksadk/studio/static/index.html +15 -0
- ksadk/studio/templates.py +722 -0
- ksadk/studio/validator.py +265 -0
- ksadk/studio/workspace.py +135 -0
- ksadk/tools/gateway.py +9 -0
- ksadk/toolsets/__init__.py +27 -1
- ksadk/toolsets/a2a.py +426 -0
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/setup.py +317 -403
- ksadk/tracing/span_utils.py +0 -44
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
- ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/events/parser.py +0 -191
- ksadk/harness/runner.py +0 -211
- ksadk/runners/codex_runner.py +0 -132
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
- ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
- ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
- ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
- ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
- ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
- ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
- ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
- ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
- ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
- ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
- ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
- ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
- ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
- ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
- ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
- ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
- ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
- ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
- ksadk/server/static/assets/katex-DATssjp1.js +0 -265
- ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
- ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
- ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
- ksadk/tracing/exporters/langfuse_exporter.py +0 -460
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
ksadk/agui/agent.py
CHANGED
|
@@ -7,6 +7,7 @@ import copy
|
|
|
7
7
|
import hashlib
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
|
+
import time
|
|
10
11
|
from dataclasses import dataclass, field
|
|
11
12
|
from importlib import import_module
|
|
12
13
|
from typing import Any, AsyncIterator, Callable, Mapping, Optional, cast
|
|
@@ -36,20 +37,43 @@ from ag_ui.core import (
|
|
|
36
37
|
ToolCallStartEvent,
|
|
37
38
|
)
|
|
38
39
|
|
|
39
|
-
from ksadk.agui
|
|
40
|
+
from ksadk.agui import _agent_helpers
|
|
40
41
|
from ksadk.conversations.runtime_metadata import (
|
|
41
42
|
_update_session_metadata_after_assistant_turn,
|
|
42
43
|
prime_session_metadata_for_user_turn,
|
|
43
44
|
)
|
|
44
|
-
from ksadk.events.
|
|
45
|
+
from ksadk.events.canonical import (
|
|
46
|
+
ApprovalResponse,
|
|
47
|
+
ContentSnapshot,
|
|
48
|
+
ContinuationCreated,
|
|
49
|
+
InteractionRequested,
|
|
50
|
+
InteractionResolved,
|
|
51
|
+
ItemCompleted,
|
|
52
|
+
ItemSnapshotReplaced,
|
|
53
|
+
ItemStarted,
|
|
54
|
+
ItemUpdated,
|
|
55
|
+
RunCanceled,
|
|
56
|
+
RunCompleted,
|
|
57
|
+
RunFailed,
|
|
58
|
+
RunInterrupted,
|
|
59
|
+
RunStarted,
|
|
60
|
+
RuntimeEvent,
|
|
61
|
+
SourceRef,
|
|
62
|
+
)
|
|
63
|
+
from ksadk.events.content import (
|
|
64
|
+
TextContent,
|
|
65
|
+
ToolCallContent,
|
|
66
|
+
ToolResultContent,
|
|
67
|
+
)
|
|
45
68
|
from ksadk.runtime.adapter import (
|
|
46
69
|
CancelResult,
|
|
47
70
|
ResumePayload,
|
|
48
71
|
ResumeTarget,
|
|
49
72
|
RunHandle,
|
|
50
|
-
|
|
73
|
+
RuntimeLaunchContext,
|
|
51
74
|
StartRequest,
|
|
52
75
|
)
|
|
76
|
+
from ksadk.runtime.executor import RuntimeExecutor
|
|
53
77
|
|
|
54
78
|
EventStoreFactory = Callable[[], Any]
|
|
55
79
|
SessionServiceFactory = Callable[[], Any]
|
|
@@ -85,7 +109,8 @@ class _ThreadRun:
|
|
|
85
109
|
|
|
86
110
|
@dataclass
|
|
87
111
|
class _SharedRuntime:
|
|
88
|
-
|
|
112
|
+
executor: RuntimeExecutor
|
|
113
|
+
launch_context: RuntimeLaunchContext
|
|
89
114
|
event_store_factory: Optional[EventStoreFactory]
|
|
90
115
|
session_service_factory: Optional[SessionServiceFactory]
|
|
91
116
|
threads: dict[str, _ThreadRun] = field(default_factory=dict)
|
|
@@ -103,6 +128,7 @@ class _WireState:
|
|
|
103
128
|
reasoning_open: bool = False
|
|
104
129
|
terminal: bool = False
|
|
105
130
|
text_content: str = ""
|
|
131
|
+
reasoning_content: str = ""
|
|
106
132
|
|
|
107
133
|
|
|
108
134
|
class KsadkAGUIAgent:
|
|
@@ -118,22 +144,35 @@ class KsadkAGUIAgent:
|
|
|
118
144
|
self,
|
|
119
145
|
*,
|
|
120
146
|
name: str,
|
|
121
|
-
|
|
147
|
+
executor: RuntimeExecutor | None = None,
|
|
148
|
+
launch_context: RuntimeLaunchContext | None = None,
|
|
122
149
|
event_store_factory: Optional[EventStoreFactory] = None,
|
|
123
150
|
session_service_factory: Optional[SessionServiceFactory] = None,
|
|
124
151
|
_shared: Optional[_SharedRuntime] = None,
|
|
125
152
|
) -> None:
|
|
126
153
|
self.name = name
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
154
|
+
if _shared is not None:
|
|
155
|
+
self._shared = _shared
|
|
156
|
+
else:
|
|
157
|
+
if executor is None or launch_context is None:
|
|
158
|
+
raise ValueError("AG-UI requires RuntimeExecutor and RuntimeLaunchContext")
|
|
159
|
+
self._shared = _SharedRuntime(
|
|
160
|
+
executor,
|
|
161
|
+
launch_context,
|
|
162
|
+
event_store_factory,
|
|
163
|
+
session_service_factory,
|
|
164
|
+
)
|
|
132
165
|
|
|
133
166
|
def clone(self) -> "KsadkAGUIAgent":
|
|
134
|
-
return type(self)(name=self.name,
|
|
167
|
+
return type(self)(name=self.name, _shared=self._shared)
|
|
135
168
|
|
|
136
169
|
async def run(self, input: RunAgentInput) -> AsyncIterator[BaseEvent]:
|
|
170
|
+
from ksadk.kernel import ingress as _kernel_ingress
|
|
171
|
+
|
|
172
|
+
if _kernel_ingress.kernel_route_active():
|
|
173
|
+
async for event in self._kernel_run(input):
|
|
174
|
+
yield event
|
|
175
|
+
return
|
|
137
176
|
wire = _WireState(
|
|
138
177
|
thread_id=input.thread_id,
|
|
139
178
|
run_id=input.run_id,
|
|
@@ -160,8 +199,11 @@ class KsadkAGUIAgent:
|
|
|
160
199
|
return
|
|
161
200
|
|
|
162
201
|
run.active = True
|
|
163
|
-
async for runtime_event in self._shared.
|
|
164
|
-
persisted = await self._persist(
|
|
202
|
+
async for runtime_event in self._shared.executor.stream(run.handle):
|
|
203
|
+
persisted = await self._persist(
|
|
204
|
+
self._event_for_persistence(runtime_event, run),
|
|
205
|
+
session_id=input.thread_id,
|
|
206
|
+
)
|
|
165
207
|
async for event in self._project(persisted, wire, run):
|
|
166
208
|
yield event
|
|
167
209
|
if not wire.terminal:
|
|
@@ -193,6 +235,102 @@ class KsadkAGUIAgent:
|
|
|
193
235
|
if run is not None and not run.cancel_failed:
|
|
194
236
|
run.active = False
|
|
195
237
|
|
|
238
|
+
async def _kernel_run(self, input: RunAgentInput) -> AsyncIterator[BaseEvent]:
|
|
239
|
+
"""kernel 路径(灰度 opt-in):AG-UI run -> AgentControlCommand -> receipt。
|
|
240
|
+
|
|
241
|
+
mutation 只走 kernel.submit;AG-UI 事件 shape 保留,cursor 源自同一
|
|
242
|
+
Session seq(SessionEventSubscription.after_seq)。
|
|
243
|
+
"""
|
|
244
|
+
from ksadk.kernel import ingress as _kernel_ingress
|
|
245
|
+
|
|
246
|
+
yield RunStartedEvent(
|
|
247
|
+
thread_id=input.thread_id,
|
|
248
|
+
run_id=input.run_id,
|
|
249
|
+
parent_run_id=input.parent_run_id,
|
|
250
|
+
input=input,
|
|
251
|
+
)
|
|
252
|
+
message_id = f"{input.run_id}:assistant"
|
|
253
|
+
text = ""
|
|
254
|
+
try:
|
|
255
|
+
trusted = _kernel_ingress.trusted_context(
|
|
256
|
+
source_kind="agui",
|
|
257
|
+
source_ref=input.run_id,
|
|
258
|
+
session_id=input.thread_id,
|
|
259
|
+
operations=("enqueue",),
|
|
260
|
+
launch_context=self._shared.launch_context,
|
|
261
|
+
)
|
|
262
|
+
command = _kernel_ingress.map_agui_request(
|
|
263
|
+
session_id=input.thread_id,
|
|
264
|
+
idempotency_key=input.run_id,
|
|
265
|
+
content=[
|
|
266
|
+
{"role": "user", "content": _agui_user_text(input)}
|
|
267
|
+
],
|
|
268
|
+
run_id=input.run_id,
|
|
269
|
+
trusted=trusted,
|
|
270
|
+
)
|
|
271
|
+
receipt = await _kernel_ingress.submit_command(
|
|
272
|
+
command, permit=trusted.permit
|
|
273
|
+
)
|
|
274
|
+
if receipt.status not in ("accepted", "duplicate"):
|
|
275
|
+
yield RunErrorEvent(
|
|
276
|
+
message=f"agent kernel rejected command: {receipt.status}",
|
|
277
|
+
code=receipt.status.upper(),
|
|
278
|
+
)
|
|
279
|
+
return
|
|
280
|
+
text_open = False
|
|
281
|
+
async for _seq, payload in _kernel_ingress.subscribe_projected(
|
|
282
|
+
input.thread_id,
|
|
283
|
+
trusted=trusted,
|
|
284
|
+
after_seq=int(receipt.accepted_seq or 0),
|
|
285
|
+
projector=_agui_envelope_payload,
|
|
286
|
+
):
|
|
287
|
+
if payload is None:
|
|
288
|
+
continue
|
|
289
|
+
kind, value = payload
|
|
290
|
+
if kind == "delta":
|
|
291
|
+
if not text_open:
|
|
292
|
+
text_open = True
|
|
293
|
+
yield TextMessageStartEvent(message_id=message_id)
|
|
294
|
+
text += value
|
|
295
|
+
yield TextMessageContentEvent(message_id=message_id, delta=value)
|
|
296
|
+
elif kind == "completed":
|
|
297
|
+
final = value or text
|
|
298
|
+
if final and not text_open:
|
|
299
|
+
text_open = True
|
|
300
|
+
yield TextMessageStartEvent(message_id=message_id)
|
|
301
|
+
if final.startswith(text) and len(final) > len(text):
|
|
302
|
+
yield TextMessageContentEvent(
|
|
303
|
+
message_id=message_id, delta=final[len(text):]
|
|
304
|
+
)
|
|
305
|
+
text = final
|
|
306
|
+
if text_open:
|
|
307
|
+
yield TextMessageEndEvent(message_id=message_id)
|
|
308
|
+
yield RunFinishedEvent(
|
|
309
|
+
thread_id=input.thread_id,
|
|
310
|
+
run_id=input.run_id,
|
|
311
|
+
outcome=RunFinishedSuccessOutcome(),
|
|
312
|
+
result={"output_text": text},
|
|
313
|
+
)
|
|
314
|
+
return
|
|
315
|
+
if text_open:
|
|
316
|
+
yield TextMessageEndEvent(message_id=message_id)
|
|
317
|
+
yield RunFinishedEvent(
|
|
318
|
+
thread_id=input.thread_id,
|
|
319
|
+
run_id=input.run_id,
|
|
320
|
+
outcome=RunFinishedSuccessOutcome(),
|
|
321
|
+
result={"output_text": text},
|
|
322
|
+
)
|
|
323
|
+
except Exception:
|
|
324
|
+
logger.exception(
|
|
325
|
+
"AG-UI kernel ingress failed for thread=%s run=%s",
|
|
326
|
+
input.thread_id,
|
|
327
|
+
input.run_id,
|
|
328
|
+
)
|
|
329
|
+
yield RunErrorEvent(
|
|
330
|
+
message="Agent kernel ingress failed",
|
|
331
|
+
code="KERNEL_ERROR",
|
|
332
|
+
)
|
|
333
|
+
|
|
196
334
|
async def _resolve_run(self, input: RunAgentInput) -> tuple[_ThreadRun, bool]:
|
|
197
335
|
async with self._shared.lock:
|
|
198
336
|
if input.resume:
|
|
@@ -230,7 +368,10 @@ class KsadkAGUIAgent:
|
|
|
230
368
|
config=request_config,
|
|
231
369
|
metadata={"invocation_id": input.run_id, "transport": "ag-ui"},
|
|
232
370
|
)
|
|
233
|
-
handle = await self._shared.
|
|
371
|
+
handle = await self._shared.executor.start(
|
|
372
|
+
self._shared.launch_context,
|
|
373
|
+
request,
|
|
374
|
+
)
|
|
234
375
|
await self._persist_user_input(input, request, handle)
|
|
235
376
|
run = _ThreadRun(handle=handle)
|
|
236
377
|
self._shared.threads[input.thread_id] = run
|
|
@@ -287,7 +428,7 @@ class KsadkAGUIAgent:
|
|
|
287
428
|
for interrupt_id, fingerprint in fingerprints.items():
|
|
288
429
|
self._shared.consumed_resumes[(input.thread_id, interrupt_id)] = fingerprint
|
|
289
430
|
|
|
290
|
-
resumed = await self._shared.
|
|
431
|
+
resumed = await self._shared.executor.resume(
|
|
291
432
|
current.handle,
|
|
292
433
|
ResumeTarget(kind="checkpoint_id", id=next(iter(checkpoint_ids))),
|
|
293
434
|
ResumePayload(
|
|
@@ -319,155 +460,183 @@ class KsadkAGUIAgent:
|
|
|
319
460
|
default=str,
|
|
320
461
|
)
|
|
321
462
|
decision = self._approval_decision_for_audit(entry.status, entry.payload)
|
|
322
|
-
event =
|
|
323
|
-
|
|
463
|
+
event = InteractionResolved(
|
|
464
|
+
schema_version=2,
|
|
324
465
|
event_id=f"evt_agui_resume_{hashlib.sha256(event_key.encode()).hexdigest()}",
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
466
|
+
seq=0,
|
|
467
|
+
timestamp=time.time(),
|
|
468
|
+
run_id=run.handle.run_id,
|
|
469
|
+
scope_id=f"ksadk:{run.handle.run_id}",
|
|
470
|
+
source=SourceRef(
|
|
471
|
+
framework="ksadk",
|
|
472
|
+
metadata={
|
|
473
|
+
"agent_id": str(run.handle.native_ref.get("agent_id") or self.name),
|
|
474
|
+
"user_id": str(run.handle.native_ref.get("user_id") or "agui-user"),
|
|
475
|
+
"session_id": input.thread_id,
|
|
476
|
+
"protocol": "ag-ui",
|
|
477
|
+
"resume_fingerprint": fingerprint,
|
|
478
|
+
},
|
|
479
|
+
),
|
|
480
|
+
interaction_id=entry.interrupt_id,
|
|
481
|
+
interaction_kind="approval",
|
|
482
|
+
response=ApprovalResponse(
|
|
483
|
+
response_type="approval",
|
|
484
|
+
decision=(
|
|
485
|
+
decision if decision in ("approved", "rejected", "canceled") else "rejected"
|
|
486
|
+
),
|
|
487
|
+
data={"call_id": entry.interrupt_id},
|
|
488
|
+
),
|
|
337
489
|
)
|
|
338
490
|
if index == 0:
|
|
339
|
-
_persisted, reservation_created = await self._reserve(
|
|
491
|
+
_persisted, reservation_created = await self._reserve(
|
|
492
|
+
event, session_id=input.thread_id
|
|
493
|
+
)
|
|
340
494
|
if not reservation_created:
|
|
341
495
|
return False
|
|
342
496
|
else:
|
|
343
|
-
await self._persist(event)
|
|
497
|
+
await self._persist(event, session_id=input.thread_id)
|
|
344
498
|
return reservation_created
|
|
345
499
|
|
|
346
|
-
@staticmethod
|
|
347
|
-
def _approval_decision_for_audit(status: str, payload: Any) -> str:
|
|
348
|
-
"""Persist a stable decision value while accepting official AG-UI envelopes."""
|
|
349
|
-
|
|
350
|
-
if status != "resolved":
|
|
351
|
-
return "rejected"
|
|
352
|
-
if payload is True:
|
|
353
|
-
return "approved"
|
|
354
|
-
if isinstance(payload, Mapping):
|
|
355
|
-
for key in ("approve", "approved"):
|
|
356
|
-
if key in payload:
|
|
357
|
-
return "approved" if bool(payload[key]) else "rejected"
|
|
358
|
-
for key in ("decision", "type"):
|
|
359
|
-
if key in payload:
|
|
360
|
-
return KsadkAGUIAgent._approval_decision_for_audit(status, payload[key])
|
|
361
|
-
return "rejected"
|
|
362
|
-
if isinstance(payload, str) and payload.strip().lower() in {"approve", "approved"}:
|
|
363
|
-
return "approved"
|
|
364
|
-
return "rejected"
|
|
365
|
-
|
|
366
500
|
async def _project(
|
|
367
501
|
self,
|
|
368
502
|
event: RuntimeEvent,
|
|
369
503
|
wire: _WireState,
|
|
370
504
|
run: _ThreadRun,
|
|
371
505
|
) -> AsyncIterator[BaseEvent]:
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if event_type in (EventType.TEXT_DELTA, EventType.TEXT_COMPLETED):
|
|
506
|
+
# ---- message (text) ----
|
|
507
|
+
if isinstance(event, (ItemUpdated, ItemSnapshotReplaced)) and event.item_kind == "message":
|
|
376
508
|
if not wire.text_open:
|
|
377
509
|
wire.text_open = True
|
|
378
510
|
yield TextMessageStartEvent(message_id=wire.message_id)
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
511
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
512
|
+
# atomic snapshot replace: close and reopen with full text
|
|
513
|
+
wire.text_open = False
|
|
514
|
+
wire.text_content = ""
|
|
515
|
+
yield TextMessageEndEvent(message_id=wire.message_id)
|
|
516
|
+
wire.text_open = True
|
|
517
|
+
yield TextMessageStartEvent(message_id=wire.message_id)
|
|
518
|
+
text = self._extract_text(event.snapshot)
|
|
519
|
+
elif event.op == "replace":
|
|
520
|
+
wire.text_open = False
|
|
521
|
+
wire.text_content = ""
|
|
522
|
+
yield TextMessageEndEvent(message_id=wire.message_id)
|
|
523
|
+
wire.text_open = True
|
|
524
|
+
yield TextMessageStartEvent(message_id=wire.message_id)
|
|
525
|
+
text = event.update.text if isinstance(event.update, TextContent) else ""
|
|
526
|
+
else:
|
|
527
|
+
text = event.update.text if isinstance(event.update, TextContent) else ""
|
|
382
528
|
if text:
|
|
383
529
|
yield TextMessageContentEvent(message_id=wire.message_id, delta=text)
|
|
384
530
|
wire.text_content += text
|
|
385
|
-
if event_type == EventType.TEXT_COMPLETED:
|
|
386
|
-
wire.text_open = False
|
|
387
|
-
yield TextMessageEndEvent(message_id=wire.message_id)
|
|
388
531
|
return
|
|
389
532
|
|
|
390
|
-
if
|
|
533
|
+
if isinstance(event, ItemCompleted) and event.item_kind == "message":
|
|
534
|
+
if not wire.text_open:
|
|
535
|
+
wire.text_open = True
|
|
536
|
+
yield TextMessageStartEvent(message_id=wire.message_id)
|
|
537
|
+
# ItemCompleted is the authoritative snapshot; do NOT re-append
|
|
538
|
+
# the full text when deltas already covered the content.
|
|
539
|
+
if not wire.text_content:
|
|
540
|
+
text = self._extract_text(event.snapshot)
|
|
541
|
+
if text:
|
|
542
|
+
yield TextMessageContentEvent(message_id=wire.message_id, delta=text)
|
|
543
|
+
wire.text_content += text
|
|
544
|
+
wire.text_open = False
|
|
545
|
+
yield TextMessageEndEvent(message_id=wire.message_id)
|
|
546
|
+
return
|
|
547
|
+
|
|
548
|
+
if isinstance(event, ItemStarted) and event.item_kind == "message":
|
|
549
|
+
# ItemStarted for messages is a tracking signal; the text message
|
|
550
|
+
# opens lazily on the first content delta or completed snapshot.
|
|
551
|
+
return
|
|
552
|
+
|
|
553
|
+
# ---- reasoning ----
|
|
554
|
+
if (
|
|
555
|
+
isinstance(event, (ItemUpdated, ItemSnapshotReplaced))
|
|
556
|
+
and event.item_kind == "reasoning"
|
|
557
|
+
):
|
|
391
558
|
if not wire.reasoning_open:
|
|
392
559
|
wire.reasoning_open = True
|
|
393
560
|
yield ReasoningStartEvent(message_id=wire.reasoning_id)
|
|
394
561
|
yield ReasoningMessageStartEvent(message_id=wire.reasoning_id, role="reasoning")
|
|
395
|
-
|
|
562
|
+
if isinstance(event, ItemSnapshotReplaced):
|
|
563
|
+
wire.reasoning_content = ""
|
|
564
|
+
text = self._extract_text(event.snapshot)
|
|
565
|
+
else:
|
|
566
|
+
text = event.update.text if isinstance(event.update, TextContent) else ""
|
|
396
567
|
if text:
|
|
397
568
|
yield ReasoningMessageContentEvent(message_id=wire.reasoning_id, delta=text)
|
|
398
|
-
|
|
399
|
-
wire.reasoning_open = False
|
|
400
|
-
yield ReasoningMessageEndEvent(message_id=wire.reasoning_id)
|
|
401
|
-
yield ReasoningEndEvent(message_id=wire.reasoning_id)
|
|
569
|
+
wire.reasoning_content += text
|
|
402
570
|
return
|
|
403
571
|
|
|
404
|
-
if
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
572
|
+
if isinstance(event, ItemCompleted) and event.item_kind == "reasoning":
|
|
573
|
+
if not wire.reasoning_open:
|
|
574
|
+
wire.reasoning_open = True
|
|
575
|
+
yield ReasoningStartEvent(message_id=wire.reasoning_id)
|
|
576
|
+
yield ReasoningMessageStartEvent(message_id=wire.reasoning_id, role="reasoning")
|
|
577
|
+
if not wire.reasoning_content:
|
|
578
|
+
text = self._extract_text(event.snapshot)
|
|
579
|
+
if text:
|
|
580
|
+
yield ReasoningMessageContentEvent(message_id=wire.reasoning_id, delta=text)
|
|
581
|
+
wire.reasoning_content += text
|
|
582
|
+
wire.reasoning_open = False
|
|
583
|
+
yield ReasoningMessageEndEvent(message_id=wire.reasoning_id)
|
|
584
|
+
yield ReasoningEndEvent(message_id=wire.reasoning_id)
|
|
585
|
+
return
|
|
586
|
+
|
|
587
|
+
if isinstance(event, ItemStarted) and event.item_kind == "reasoning":
|
|
588
|
+
return
|
|
589
|
+
|
|
590
|
+
# ---- tool call ----
|
|
591
|
+
if isinstance(event, ItemStarted) and event.item_kind == "tool_call":
|
|
592
|
+
part = self._first_part(event.initial)
|
|
593
|
+
if isinstance(part, ToolCallContent):
|
|
594
|
+
call_id = part.call_id
|
|
595
|
+
yield ToolCallStartEvent(
|
|
596
|
+
tool_call_id=call_id,
|
|
597
|
+
tool_call_name=part.name,
|
|
598
|
+
parent_message_id=wire.message_id,
|
|
599
|
+
)
|
|
412
600
|
yield ToolCallArgsEvent(
|
|
413
601
|
tool_call_id=call_id,
|
|
414
|
-
delta=json.dumps(
|
|
602
|
+
delta=json.dumps(part.arguments, ensure_ascii=False, default=str),
|
|
415
603
|
)
|
|
416
604
|
return
|
|
417
605
|
|
|
418
|
-
if
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
payload.get("result") if payload.get("error") is None else payload.get("error")
|
|
422
|
-
)
|
|
423
|
-
# AG-UI closes the active call at TOOL_CALL_END. Sending a result
|
|
424
|
-
# first makes official clients discard the call, then reject this
|
|
425
|
-
# end event as orphaned.
|
|
606
|
+
if isinstance(event, ItemCompleted) and event.item_kind == "tool_call":
|
|
607
|
+
part = self._first_part(event.snapshot)
|
|
608
|
+
call_id = part.call_id if isinstance(part, ToolCallContent) else "tool"
|
|
426
609
|
yield ToolCallEndEvent(tool_call_id=call_id)
|
|
427
|
-
yield ToolCallResultEvent(
|
|
428
|
-
message_id=f"{wire.run_id}:tool:{call_id}",
|
|
429
|
-
tool_call_id=call_id,
|
|
430
|
-
content=json.dumps(content, ensure_ascii=False, default=str),
|
|
431
|
-
role="tool",
|
|
432
|
-
)
|
|
433
610
|
return
|
|
434
611
|
|
|
435
|
-
if
|
|
436
|
-
|
|
612
|
+
if isinstance(event, ItemCompleted) and event.item_kind == "tool_result":
|
|
613
|
+
part = self._first_part(event.snapshot)
|
|
614
|
+
if isinstance(part, ToolResultContent):
|
|
615
|
+
call_id = part.call_id
|
|
616
|
+
content = part.result
|
|
617
|
+
yield ToolCallResultEvent(
|
|
618
|
+
message_id=f"{wire.run_id}:tool:{call_id}",
|
|
619
|
+
tool_call_id=call_id,
|
|
620
|
+
content=json.dumps(content, ensure_ascii=False, default=str),
|
|
621
|
+
role="tool",
|
|
622
|
+
)
|
|
437
623
|
return
|
|
438
624
|
|
|
439
|
-
if
|
|
440
|
-
interrupt_id = str(payload.get("approval_id") or payload.get("call_id") or "")
|
|
441
|
-
checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
|
|
442
|
-
if not checkpoint_id:
|
|
443
|
-
known = run.handle.native_ref.get("known_checkpoint_ids") or []
|
|
444
|
-
checkpoint_id = str(known[-1]) if known else ""
|
|
445
|
-
raw_detail = payload.get("detail")
|
|
446
|
-
detail: dict[str, Any] = raw_detail if isinstance(raw_detail, dict) else {}
|
|
447
|
-
interrupt = Interrupt(
|
|
448
|
-
id=interrupt_id,
|
|
449
|
-
reason=str(detail.get("reason") or payload.get("kind") or "approval"),
|
|
450
|
-
message=self._approval_message(detail, payload),
|
|
451
|
-
tool_call_id=str(payload.get("call_id") or "") or None,
|
|
452
|
-
response_schema=detail.get("response_schema"),
|
|
453
|
-
metadata=self._approval_metadata(detail, payload),
|
|
454
|
-
)
|
|
455
|
-
run.pending[interrupt_id] = _PendingInterrupt(interrupt, checkpoint_id)
|
|
625
|
+
if isinstance(event, ItemStarted) and event.item_kind == "tool_result":
|
|
456
626
|
return
|
|
457
627
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
628
|
+
# ---- A2UI surface (item_kind="data" + source.protocol="a2ui") ----
|
|
629
|
+
if (
|
|
630
|
+
isinstance(event, (ItemStarted, ItemUpdated, ItemCompleted))
|
|
631
|
+
and event.item_kind == "data"
|
|
632
|
+
and event.source.protocol == "a2ui"
|
|
633
|
+
):
|
|
634
|
+
surface_id = str(event.source.metadata.get("surface_id") or "")
|
|
635
|
+
operations = self._a2ui_operations(event, surface_id)
|
|
464
636
|
if operations:
|
|
465
|
-
surface_id = str(payload.get("surface_id") or payload.get("surfaceId") or "")
|
|
466
637
|
yield ActivitySnapshotEvent(
|
|
467
638
|
message_id=f"{wire.run_id}:a2ui:{surface_id}",
|
|
468
639
|
activity_type="a2ui-surface",
|
|
469
|
-
# The client renderer addresses a surface by this value.
|
|
470
|
-
# ``message_id`` is a transport id, not the A2UI surface id.
|
|
471
640
|
content={
|
|
472
641
|
"surfaceId": surface_id,
|
|
473
642
|
"a2ui_operations": operations,
|
|
@@ -476,18 +645,62 @@ class KsadkAGUIAgent:
|
|
|
476
645
|
)
|
|
477
646
|
return
|
|
478
647
|
|
|
479
|
-
|
|
648
|
+
# ---- checkpoint ----
|
|
649
|
+
if isinstance(event, ContinuationCreated):
|
|
650
|
+
# Track checkpoint id in handle native_ref for downstream approval
|
|
651
|
+
# resolution (pending interrupts need a resumable checkpoint_id).
|
|
652
|
+
ckpt_id = str(event.ref.get("checkpoint_id") or "")
|
|
653
|
+
if ckpt_id:
|
|
654
|
+
run.handle.native_ref["checkpoint_id"] = ckpt_id
|
|
655
|
+
known = run.handle.native_ref.setdefault("known_checkpoint_ids", [])
|
|
656
|
+
if ckpt_id not in known:
|
|
657
|
+
known.append(ckpt_id)
|
|
658
|
+
yield StateSnapshotEvent(snapshot={"checkpoint": copy.deepcopy(event.ref)})
|
|
659
|
+
return
|
|
660
|
+
|
|
661
|
+
# ---- approval ----
|
|
662
|
+
if isinstance(event, InteractionRequested):
|
|
663
|
+
interrupt = self._interrupt_from_interaction(event)
|
|
664
|
+
checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
|
|
665
|
+
if not checkpoint_id:
|
|
666
|
+
known = run.handle.native_ref.get("known_checkpoint_ids") or []
|
|
667
|
+
checkpoint_id = str(known[-1]) if known else ""
|
|
668
|
+
run.pending[interrupt.id] = _PendingInterrupt(interrupt, checkpoint_id)
|
|
669
|
+
return
|
|
670
|
+
|
|
671
|
+
# ---- run lifecycle ----
|
|
672
|
+
if isinstance(event, RunInterrupted):
|
|
480
673
|
async for close_event in self._close_open_messages(wire):
|
|
481
674
|
yield close_event
|
|
482
675
|
if not run.pending:
|
|
483
676
|
raise ValueError("runtime interrupted without a pending approval")
|
|
484
|
-
checkpoint_id
|
|
677
|
+
# If checkpoint_id wasn't set by ContinuationCreated (e.g. langgraph
|
|
678
|
+
# canonical stream without checkpoint_ref on first run), try to
|
|
679
|
+
# extract it from the RunInterrupted event's continuation_id or
|
|
680
|
+
# the executor's checkpoint descriptor.
|
|
681
|
+
if event.continuation_id:
|
|
682
|
+
checkpoint_id = str(event.continuation_id)
|
|
683
|
+
else:
|
|
684
|
+
checkpoint_id = str(run.handle.native_ref.get("checkpoint_id") or "")
|
|
485
685
|
if not checkpoint_id:
|
|
486
686
|
known = run.handle.native_ref.get("known_checkpoint_ids") or []
|
|
487
687
|
checkpoint_id = str(known[-1]) if known else ""
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
688
|
+
if not checkpoint_id:
|
|
689
|
+
# Last resort: query the executor for the native checkpoint.
|
|
690
|
+
try:
|
|
691
|
+
descriptor = await self._shared.executor.checkpoint(run.handle)
|
|
692
|
+
checkpoint_id = str(descriptor.checkpoint_id or "")
|
|
693
|
+
if checkpoint_id:
|
|
694
|
+
run.handle.native_ref["checkpoint_id"] = checkpoint_id
|
|
695
|
+
known = run.handle.native_ref.setdefault("known_checkpoint_ids", [])
|
|
696
|
+
if checkpoint_id not in known:
|
|
697
|
+
known.append(checkpoint_id)
|
|
698
|
+
except Exception:
|
|
699
|
+
pass
|
|
700
|
+
if checkpoint_id:
|
|
701
|
+
for pending in run.pending.values():
|
|
702
|
+
if not pending.checkpoint_id:
|
|
703
|
+
pending.checkpoint_id = checkpoint_id
|
|
491
704
|
run.interrupted = True
|
|
492
705
|
wire.terminal = True
|
|
493
706
|
yield RunFinishedEvent(
|
|
@@ -499,23 +712,30 @@ class KsadkAGUIAgent:
|
|
|
499
712
|
)
|
|
500
713
|
return
|
|
501
714
|
|
|
502
|
-
if
|
|
715
|
+
if isinstance(event, RunCompleted):
|
|
503
716
|
async for finish_event in self._finish_success(wire):
|
|
504
717
|
yield finish_event
|
|
505
718
|
return
|
|
506
719
|
|
|
507
|
-
if
|
|
720
|
+
if isinstance(event, RunCanceled):
|
|
508
721
|
async for close_event in self._close_open_messages(wire):
|
|
509
722
|
yield close_event
|
|
510
723
|
wire.terminal = True
|
|
511
724
|
yield RunErrorEvent(
|
|
512
|
-
message=
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
725
|
+
message=event.reason or "Runtime run was cancelled",
|
|
726
|
+
code="CANCELLED",
|
|
727
|
+
)
|
|
728
|
+
return
|
|
729
|
+
|
|
730
|
+
if isinstance(event, RunFailed):
|
|
731
|
+
async for close_event in self._close_open_messages(wire):
|
|
732
|
+
yield close_event
|
|
733
|
+
wire.terminal = True
|
|
734
|
+
yield RunErrorEvent(
|
|
735
|
+
message=event.error.message or "Runtime execution failed",
|
|
736
|
+
code="RUNTIME_ERROR",
|
|
518
737
|
)
|
|
738
|
+
return
|
|
519
739
|
|
|
520
740
|
async def _finish_success(self, wire: _WireState) -> AsyncIterator[BaseEvent]:
|
|
521
741
|
async for event in self._close_open_messages(wire):
|
|
@@ -538,14 +758,17 @@ class KsadkAGUIAgent:
|
|
|
538
758
|
wire.text_open = False
|
|
539
759
|
yield TextMessageEndEvent(message_id=wire.message_id)
|
|
540
760
|
|
|
541
|
-
async def _persist(self, event: RuntimeEvent) -> RuntimeEvent:
|
|
761
|
+
async def _persist(self, event: RuntimeEvent, *, session_id: str = "") -> RuntimeEvent:
|
|
542
762
|
factory = self._shared.event_store_factory
|
|
543
763
|
if factory is None:
|
|
544
764
|
return event
|
|
545
765
|
store = factory()
|
|
546
|
-
|
|
766
|
+
sid = str(event.source.metadata.get("session_id") or session_id or "")
|
|
767
|
+
return cast(RuntimeEvent, await store.append_one(sid, event))
|
|
547
768
|
|
|
548
|
-
async def _reserve(
|
|
769
|
+
async def _reserve(
|
|
770
|
+
self, event: RuntimeEvent, *, session_id: str = ""
|
|
771
|
+
) -> tuple[RuntimeEvent, bool]:
|
|
549
772
|
factory = self._shared.event_store_factory
|
|
550
773
|
if factory is None:
|
|
551
774
|
return event, True
|
|
@@ -554,7 +777,8 @@ class KsadkAGUIAgent:
|
|
|
554
777
|
if callable(reserve):
|
|
555
778
|
persisted, created = await reserve(event)
|
|
556
779
|
return cast(RuntimeEvent, persisted), bool(created)
|
|
557
|
-
|
|
780
|
+
sid = str(event.source.metadata.get("session_id") or session_id or "")
|
|
781
|
+
return cast(RuntimeEvent, await store.append_one(sid, event)), True
|
|
558
782
|
|
|
559
783
|
async def _persist_user_input(
|
|
560
784
|
self,
|
|
@@ -564,21 +788,27 @@ class KsadkAGUIAgent:
|
|
|
564
788
|
) -> None:
|
|
565
789
|
event_key = json.dumps([input.thread_id, input.run_id, "user"], ensure_ascii=False)
|
|
566
790
|
await self._persist(
|
|
567
|
-
|
|
568
|
-
|
|
791
|
+
RunStarted(
|
|
792
|
+
schema_version=2,
|
|
569
793
|
event_id=f"evt_agui_input_{hashlib.sha256(event_key.encode()).hexdigest()}",
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
794
|
+
seq=0,
|
|
795
|
+
timestamp=time.time(),
|
|
796
|
+
run_id=input.run_id,
|
|
797
|
+
scope_id=f"ksadk:{input.run_id}",
|
|
798
|
+
source=SourceRef(
|
|
799
|
+
framework="ksadk",
|
|
800
|
+
metadata={
|
|
801
|
+
"agent_id": self.name,
|
|
802
|
+
"user_id": request.user_id,
|
|
803
|
+
"session_id": input.thread_id,
|
|
804
|
+
"input": self._json_safe(request.input),
|
|
805
|
+
"source": "ag-ui",
|
|
806
|
+
"runtime_type": handle.runtime_type,
|
|
807
|
+
},
|
|
808
|
+
),
|
|
809
|
+
status="running",
|
|
810
|
+
),
|
|
811
|
+
session_id=input.thread_id,
|
|
582
812
|
)
|
|
583
813
|
await self._prime_session_metadata_for_user_turn(
|
|
584
814
|
session_id=input.thread_id,
|
|
@@ -626,21 +856,22 @@ class KsadkAGUIAgent:
|
|
|
626
856
|
logger.debug("failed to update AG-UI session metadata", exc_info=True)
|
|
627
857
|
|
|
628
858
|
def _event_for_persistence(self, event: RuntimeEvent, run: _ThreadRun) -> RuntimeEvent:
|
|
629
|
-
if event
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return event.model_copy(update={"
|
|
634
|
-
if event
|
|
859
|
+
if isinstance(event, (InteractionRequested, InteractionResolved)):
|
|
860
|
+
new_source = event.source.model_copy(
|
|
861
|
+
update={"metadata": {**event.source.metadata, "protocol": "ag-ui"}}
|
|
862
|
+
)
|
|
863
|
+
return event.model_copy(update={"source": new_source})
|
|
864
|
+
if not isinstance(event, RunInterrupted):
|
|
635
865
|
return event
|
|
636
|
-
|
|
866
|
+
new_source = event.source.model_copy(
|
|
637
867
|
update={
|
|
638
|
-
"
|
|
639
|
-
**event.
|
|
868
|
+
"metadata": {
|
|
869
|
+
**event.source.metadata,
|
|
640
870
|
"runtime_handle": self._durable_handle(run.handle),
|
|
641
871
|
}
|
|
642
872
|
}
|
|
643
873
|
)
|
|
874
|
+
return event.model_copy(update={"source": new_source})
|
|
644
875
|
|
|
645
876
|
async def _restore_durable_run(
|
|
646
877
|
self,
|
|
@@ -651,13 +882,15 @@ class KsadkAGUIAgent:
|
|
|
651
882
|
if not events:
|
|
652
883
|
return None, False
|
|
653
884
|
resolved = {
|
|
654
|
-
str(event.
|
|
885
|
+
str(event.interaction_id): event
|
|
655
886
|
for event in events
|
|
656
|
-
if event
|
|
887
|
+
if isinstance(event, InteractionResolved)
|
|
657
888
|
}
|
|
658
889
|
if fingerprints and all(interrupt_id in resolved for interrupt_id in fingerprints):
|
|
659
890
|
for interrupt_id, fingerprint in fingerprints.items():
|
|
660
|
-
persisted = str(
|
|
891
|
+
persisted = str(
|
|
892
|
+
resolved[interrupt_id].source.metadata.get("resume_fingerprint") or ""
|
|
893
|
+
)
|
|
661
894
|
if persisted and persisted != fingerprint:
|
|
662
895
|
raise ValueError(f"interrupt {interrupt_id!r} was resolved differently")
|
|
663
896
|
return None, True
|
|
@@ -665,22 +898,21 @@ class KsadkAGUIAgent:
|
|
|
665
898
|
raise ValueError("resume set is only partially resolved")
|
|
666
899
|
|
|
667
900
|
interrupted = next(
|
|
668
|
-
(event for event in reversed(events) if event
|
|
901
|
+
(event for event in reversed(events) if isinstance(event, RunInterrupted)),
|
|
669
902
|
None,
|
|
670
903
|
)
|
|
671
904
|
if interrupted is None:
|
|
672
905
|
return None, False
|
|
673
|
-
raw_handle = interrupted.
|
|
906
|
+
raw_handle = interrupted.source.metadata.get("runtime_handle")
|
|
674
907
|
if not isinstance(raw_handle, dict):
|
|
675
908
|
return None, False
|
|
676
909
|
handle = RunHandle.model_validate(raw_handle)
|
|
677
910
|
requests = [
|
|
678
911
|
event
|
|
679
912
|
for event in events
|
|
680
|
-
if event
|
|
681
|
-
and event.
|
|
682
|
-
and str(event.
|
|
683
|
-
not in resolved
|
|
913
|
+
if isinstance(event, InteractionRequested)
|
|
914
|
+
and event.run_id == interrupted.run_id
|
|
915
|
+
and str(event.interaction_id) not in resolved
|
|
684
916
|
]
|
|
685
917
|
pending: dict[str, _PendingInterrupt] = {}
|
|
686
918
|
checkpoint_id = str(handle.native_ref.get("checkpoint_id") or "")
|
|
@@ -688,12 +920,15 @@ class KsadkAGUIAgent:
|
|
|
688
920
|
known = handle.native_ref.get("known_checkpoint_ids") or []
|
|
689
921
|
checkpoint_id = str(known[-1]) if known else ""
|
|
690
922
|
for request in requests:
|
|
691
|
-
interrupt = self.
|
|
923
|
+
interrupt = self._interrupt_from_interaction(request)
|
|
692
924
|
pending[interrupt.id] = _PendingInterrupt(interrupt, checkpoint_id)
|
|
693
925
|
if not pending:
|
|
694
926
|
return None, False
|
|
695
|
-
if not self._shared.
|
|
696
|
-
handle = await self._shared.
|
|
927
|
+
if not self._shared.executor.is_attached(handle):
|
|
928
|
+
handle = await self._shared.executor.attach(
|
|
929
|
+
self._shared.launch_context,
|
|
930
|
+
handle,
|
|
931
|
+
)
|
|
697
932
|
return _ThreadRun(handle=handle, interrupted=True, pending=pending), False
|
|
698
933
|
|
|
699
934
|
async def _durable_events(self, session_id: str) -> list[RuntimeEvent]:
|
|
@@ -706,65 +941,16 @@ class KsadkAGUIAgent:
|
|
|
706
941
|
return []
|
|
707
942
|
return list(await list_events(session_id))
|
|
708
943
|
|
|
709
|
-
@staticmethod
|
|
710
|
-
def _durable_handle(handle: RunHandle) -> dict[str, Any]:
|
|
711
|
-
allowed = {
|
|
712
|
-
"agent_id",
|
|
713
|
-
"user_id",
|
|
714
|
-
"checkpoint_id",
|
|
715
|
-
"known_checkpoint_ids",
|
|
716
|
-
"pending_approval_ids",
|
|
717
|
-
"framework_ref",
|
|
718
|
-
"thread_id",
|
|
719
|
-
"checkpoint_ns",
|
|
720
|
-
"resume_thread_id",
|
|
721
|
-
}
|
|
722
|
-
native_ref = {key: value for key, value in handle.native_ref.items() if key in allowed}
|
|
723
|
-
return {
|
|
724
|
-
"run_id": handle.run_id,
|
|
725
|
-
"session_id": handle.session_id,
|
|
726
|
-
"runtime_type": handle.runtime_type,
|
|
727
|
-
"native_ref": KsadkAGUIAgent._json_safe(native_ref),
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
@staticmethod
|
|
731
|
-
def _interrupt_from_payload(payload: Mapping[str, Any]) -> Interrupt:
|
|
732
|
-
interrupt_id = str(payload.get("approval_id") or payload.get("call_id") or "")
|
|
733
|
-
raw_detail = payload.get("detail")
|
|
734
|
-
detail = raw_detail if isinstance(raw_detail, dict) else {}
|
|
735
|
-
return Interrupt(
|
|
736
|
-
id=interrupt_id,
|
|
737
|
-
reason=str(detail.get("reason") or payload.get("kind") or "approval"),
|
|
738
|
-
message=KsadkAGUIAgent._approval_message(detail, payload),
|
|
739
|
-
tool_call_id=str(payload.get("call_id") or "") or None,
|
|
740
|
-
response_schema=detail.get("response_schema"),
|
|
741
|
-
metadata=KsadkAGUIAgent._approval_metadata(detail, payload),
|
|
742
|
-
)
|
|
743
|
-
|
|
744
|
-
@staticmethod
|
|
745
|
-
def _duplicate_run(input: RunAgentInput) -> _ThreadRun:
|
|
746
|
-
return _ThreadRun(
|
|
747
|
-
handle=RunHandle(
|
|
748
|
-
run_id=input.run_id,
|
|
749
|
-
session_id=input.thread_id,
|
|
750
|
-
runtime_type="ag-ui-duplicate",
|
|
751
|
-
)
|
|
752
|
-
)
|
|
753
|
-
|
|
754
|
-
@staticmethod
|
|
755
|
-
def _json_safe(value: Any) -> Any:
|
|
756
|
-
return json.loads(json.dumps(value, ensure_ascii=False, default=str))
|
|
757
|
-
|
|
758
944
|
async def _close_thread(self, thread_id: str, run: _ThreadRun) -> None:
|
|
759
945
|
try:
|
|
760
|
-
await self._shared.
|
|
946
|
+
await self._shared.executor.close(run.handle)
|
|
761
947
|
finally:
|
|
762
948
|
async with self._shared.lock:
|
|
763
949
|
if self._shared.threads.get(thread_id) is run:
|
|
764
950
|
self._shared.threads.pop(thread_id, None)
|
|
765
951
|
|
|
766
952
|
async def _cancel_and_close(self, thread_id: str, run: _ThreadRun) -> CancelResult:
|
|
767
|
-
result = await self._shared.
|
|
953
|
+
result = await self._shared.executor.cancel(run.handle)
|
|
768
954
|
if result in {
|
|
769
955
|
CancelResult.INTERRUPTED_ACTIVE_TURN,
|
|
770
956
|
CancelResult.PENDING_CANCEL_RECORDED,
|
|
@@ -778,80 +964,93 @@ class KsadkAGUIAgent:
|
|
|
778
964
|
run.active = True
|
|
779
965
|
return result
|
|
780
966
|
|
|
967
|
+
@staticmethod
|
|
968
|
+
def _approval_decision_for_audit(status: str, payload: Any) -> str:
|
|
969
|
+
return _agent_helpers.approval_decision_for_audit(status, payload)
|
|
970
|
+
|
|
971
|
+
@staticmethod
|
|
972
|
+
def _durable_handle(handle: RunHandle) -> dict[str, Any]:
|
|
973
|
+
return _agent_helpers.durable_handle(handle)
|
|
974
|
+
|
|
975
|
+
@staticmethod
|
|
976
|
+
def _interrupt_from_payload(payload: Mapping[str, Any]) -> Interrupt:
|
|
977
|
+
return _agent_helpers.interrupt_from_payload(payload)
|
|
978
|
+
|
|
979
|
+
@staticmethod
|
|
980
|
+
def _interrupt_from_interaction(event: InteractionRequested) -> Interrupt:
|
|
981
|
+
return _agent_helpers.interrupt_from_interaction(event)
|
|
982
|
+
|
|
983
|
+
@staticmethod
|
|
984
|
+
def _extract_text(snapshot: ContentSnapshot | None) -> str:
|
|
985
|
+
return _agent_helpers.extract_text(snapshot)
|
|
986
|
+
|
|
987
|
+
@staticmethod
|
|
988
|
+
def _first_part(snapshot: ContentSnapshot | None) -> Any:
|
|
989
|
+
return _agent_helpers.first_part(snapshot)
|
|
990
|
+
|
|
991
|
+
@staticmethod
|
|
992
|
+
def _a2ui_operations(
|
|
993
|
+
event: ItemStarted | ItemUpdated | ItemCompleted,
|
|
994
|
+
surface_id: str,
|
|
995
|
+
) -> list[dict[str, Any]]:
|
|
996
|
+
return _agent_helpers.a2ui_operations(event, surface_id)
|
|
997
|
+
|
|
998
|
+
@staticmethod
|
|
999
|
+
def _duplicate_run(input: RunAgentInput) -> _ThreadRun:
|
|
1000
|
+
return _agent_helpers.duplicate_run(input)
|
|
1001
|
+
|
|
1002
|
+
@staticmethod
|
|
1003
|
+
def _json_safe(value: Any) -> Any:
|
|
1004
|
+
return _agent_helpers.json_safe(value)
|
|
1005
|
+
|
|
781
1006
|
@staticmethod
|
|
782
1007
|
def _latest_user_input(input: RunAgentInput) -> Any:
|
|
783
|
-
|
|
784
|
-
if getattr(message, "role", None) == "user":
|
|
785
|
-
return getattr(message, "content", "")
|
|
786
|
-
return ""
|
|
1008
|
+
return _agent_helpers.latest_user_input(input)
|
|
787
1009
|
|
|
788
1010
|
@staticmethod
|
|
789
1011
|
def _input_text(value: Any) -> str:
|
|
790
|
-
|
|
791
|
-
return value.strip()
|
|
792
|
-
if isinstance(value, Mapping):
|
|
793
|
-
return str(value.get("text") or value.get("content") or "").strip()
|
|
794
|
-
return str(value or "").strip()
|
|
1012
|
+
return _agent_helpers.input_text(value)
|
|
795
1013
|
|
|
796
1014
|
@staticmethod
|
|
797
1015
|
def _approval_action(detail: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
798
|
-
|
|
799
|
-
actions = (
|
|
800
|
-
nested_request.get("action_requests")
|
|
801
|
-
if isinstance(nested_request, Mapping)
|
|
802
|
-
else detail.get("action_requests")
|
|
803
|
-
)
|
|
804
|
-
if isinstance(actions, list):
|
|
805
|
-
for action in actions:
|
|
806
|
-
if isinstance(action, Mapping):
|
|
807
|
-
return action
|
|
808
|
-
return {}
|
|
1016
|
+
return _agent_helpers.approval_action(detail)
|
|
809
1017
|
|
|
810
1018
|
@staticmethod
|
|
811
1019
|
def _approval_metadata(
|
|
812
1020
|
detail: Mapping[str, Any],
|
|
813
1021
|
payload: Mapping[str, Any],
|
|
814
1022
|
) -> dict[str, Any]:
|
|
815
|
-
|
|
816
|
-
arguments = (
|
|
817
|
-
action.get("args")
|
|
818
|
-
or action.get("arguments")
|
|
819
|
-
or detail.get("arguments")
|
|
820
|
-
or detail.get("args")
|
|
821
|
-
or payload.get("args")
|
|
822
|
-
)
|
|
823
|
-
metadata: dict[str, Any] = {
|
|
824
|
-
"tool_name": str(
|
|
825
|
-
action.get("name")
|
|
826
|
-
or detail.get("tool_name")
|
|
827
|
-
or payload.get("name")
|
|
828
|
-
or payload.get("kind")
|
|
829
|
-
or "approval"
|
|
830
|
-
),
|
|
831
|
-
"arguments": arguments if arguments is not None else {},
|
|
832
|
-
}
|
|
833
|
-
approval_level = (
|
|
834
|
-
action.get("approval_level")
|
|
835
|
-
or detail.get("approval_level")
|
|
836
|
-
or payload.get("approval_level")
|
|
837
|
-
)
|
|
838
|
-
if approval_level:
|
|
839
|
-
metadata["approval_level"] = str(approval_level)
|
|
840
|
-
return metadata
|
|
1023
|
+
return _agent_helpers.approval_metadata(detail, payload)
|
|
841
1024
|
|
|
842
1025
|
@staticmethod
|
|
843
1026
|
def _approval_message(detail: Mapping[str, Any], payload: Mapping[str, Any]) -> str:
|
|
844
|
-
|
|
845
|
-
return str(
|
|
846
|
-
action.get("description")
|
|
847
|
-
or detail.get("message")
|
|
848
|
-
or payload.get("message")
|
|
849
|
-
or "Approval required"
|
|
850
|
-
)
|
|
1027
|
+
return _agent_helpers.approval_message(detail, payload)
|
|
851
1028
|
|
|
852
1029
|
@staticmethod
|
|
853
1030
|
def _resume_fingerprint(status: str, payload: Any) -> Any:
|
|
854
|
-
return
|
|
1031
|
+
return _agent_helpers.resume_fingerprint(status, payload)
|
|
855
1032
|
|
|
856
1033
|
|
|
857
1034
|
__all__ = ["KsadkAGUIAgent"]
|
|
1035
|
+
|
|
1036
|
+
def _agui_user_text(input: RunAgentInput) -> str:
|
|
1037
|
+
parts = []
|
|
1038
|
+
for message in input.messages or []:
|
|
1039
|
+
content = getattr(message, "content", "")
|
|
1040
|
+
if isinstance(content, str):
|
|
1041
|
+
parts.append(content)
|
|
1042
|
+
elif content is not None:
|
|
1043
|
+
parts.append(str(content))
|
|
1044
|
+
return "\n".join(parts)
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
def _agui_envelope_payload(envelope) -> tuple[str, str] | None:
|
|
1048
|
+
"""Session envelope -> AG-UI 文本投影;cursor 仍用 envelope.seq。"""
|
|
1049
|
+
|
|
1050
|
+
payload = envelope.payload or {}
|
|
1051
|
+
if envelope.event_type == "run.completed":
|
|
1052
|
+
return "completed", str(payload.get("output_text") or "")
|
|
1053
|
+
text = str(payload.get("delta") or payload.get("text") or "")
|
|
1054
|
+
if text:
|
|
1055
|
+
return "delta", text
|
|
1056
|
+
return None
|