agentengine-sdk-python 0.8.1__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.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +22 -2
- {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/RECORD +356 -222
- ksadk/a2a/_space_client_events.py +381 -0
- ksadk/a2a/event_adapter.py +156 -64
- ksadk/a2a/executor.py +179 -63
- ksadk/a2a/space_client.py +6 -333
- ksadk/a2ui/core.py +222 -53
- ksadk/agui/_agent_helpers.py +243 -0
- ksadk/agui/a2ui_projection.py +12 -5
- ksadk/agui/agent.py +443 -259
- ksadk/api/client.py +525 -27
- ksadk/builders/code_builder.py +284 -8
- ksadk/builders/container_builder.py +8 -1
- ksadk/builders/managed_runtime_builder.py +39 -35
- ksadk/cli/__init__.py +17 -0
- ksadk/cli/cmd_dashboard.py +15 -1
- ksadk/cli/cmd_deploy.py +10 -2
- ksadk/cli/cmd_eval.py +66 -9
- ksadk/cli/cmd_evalset.py +284 -0
- ksadk/cli/cmd_files.py +5 -1
- ksadk/cli/cmd_hermes.py +1 -126
- ksadk/cli/cmd_invoke.py +28 -38
- ksadk/cli/cmd_managed_runtime.py +95 -0
- ksadk/cli/cmd_observe.py +85 -0
- ksadk/cli/cmd_openclaw.py +1 -435
- ksadk/cli/cmd_replay.py +28 -4
- ksadk/cli/cmd_studio.py +99 -8
- ksadk/cli/cmd_web.py +10 -2
- ksadk/cli/hermes_env.py +151 -0
- ksadk/cli/invoke_payload.py +49 -0
- ksadk/cli/openclaw_env.py +458 -0
- ksadk/codex/client.py +180 -30
- ksadk/codex/runtime.py +428 -326
- ksadk/configs/env_registry.py +66 -12
- ksadk/configs/env_registry_pcm.py +181 -0
- ksadk/configs/env_var_spec.py +18 -0
- ksadk/configs/global_config.py +5 -0
- 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/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 +184 -2
- ksadk/conversations/runtime_invocation.py +81 -3
- ksadk/conversations/runtime_observability.py +141 -0
- ksadk/conversations/runtime_payloads.py +42 -0
- ksadk/conversations/runtime_preparation.py +272 -2
- ksadk/conversations/runtime_resume.py +20 -1
- ksadk/conversations/runtime_stream_events.py +94 -9
- 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 +5 -0
- ksadk/deployment/providers/serverless.py +143 -69
- ksadk/evaluation/__init__.py +32 -0
- ksadk/evaluation/a2a_adapter.py +9 -1
- ksadk/evaluation/adapters.py +18 -5
- 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 +73 -4
- ksadk/evaluation/evaluators.py +183 -17
- ksadk/evaluation/evidence.py +258 -0
- ksadk/evaluation/executor.py +31 -6
- ksadk/evaluation/local_adapter.py +550 -0
- ksadk/evaluation/service_env.py +27 -0
- ksadk/evaluation/studio_build_adapter.py +253 -0
- ksadk/evaluation/target.py +15 -6
- 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 -265
- ksadk/events/session_event.py +324 -0
- ksadk/events/store.py +3 -316
- ksadk/events/v1_compat.py +41 -0
- ksadk/harness/runtime.py +160 -57
- 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 +7 -0
- ksadk/knowledge_base/service.py +32 -5
- 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 +384 -2
- ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
- 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 +188 -6
- ksadk/model_proxy/bootstrap.py +16 -9
- ksadk/model_proxy/detect.py +202 -9
- ksadk/model_proxy/namespace.py +39 -15
- ksadk/model_proxy/server.py +24 -5
- ksadk/model_proxy/transform.py +60 -2
- 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 +5 -5
- ksadk/runners/base_runner.py +16 -0
- ksadk/runners/factory.py +1 -2
- ksadk/runners/langgraph_runner.py +198 -437
- ksadk/runtime/_runner_adapter/__init__.py +1 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
- ksadk/runtime/adapter.py +118 -2
- ksadk/runtime/conversation_execution.py +316 -182
- ksadk/runtime/executor.py +144 -3
- ksadk/runtime/factory.py +193 -7
- ksadk/runtime/hosted_finalizer.py +268 -0
- ksadk/runtime/launch.py +14 -1
- ksadk/runtime/preprocessing.py +25 -3
- ksadk/runtime/runner_adapter.py +288 -508
- ksadk/runtime/usage.py +33 -0
- ksadk/sandbox/backends/e2b.py +35 -2
- ksadk/server/composition.py +8 -0
- ksadk/server/factory.py +69 -6
- ksadk/server/routes/kernel_ingress.py +258 -0
- ksadk/server/routes/openai_compat.py +88 -8
- ksadk/server/routes/projection.py +35 -20
- ksadk/server/routes/run.py +94 -0
- ksadk/server/routes/sessions.py +2 -0
- ksadk/server/routes/streaming.py +5 -2
- ksadk/server/static/assets/{ArtifactsPanel-CakCqxEN.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-CynLknyO.js → CodeBlock-DOH6MVcn.js} +4 -4
- ksadk/server/static/assets/{MathMessageMarkdown-3sQdOysS.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-B_fH2YuH.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-D6rFLaVV.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
- ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
- ksadk/server/static/assets/{chunk-4BX2VUAB-B9drTgOW.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-ChNs_Mdk.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-Dli7qW-B.js → dist-8hqcx0sU.js} +1 -1
- ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
- ksadk/server/static/assets/{dist-C1sz5Eo3.js → dist-BE7bu-DL.js} +1 -1
- ksadk/server/static/assets/{dist-fhOuWds5.js → dist-BVDffZ0U.js} +1 -1
- ksadk/server/static/assets/{dist-BjOdlDjj.js → dist-BX8z72IC.js} +1 -1
- ksadk/server/static/assets/{dist-DsHPdk3W.js → dist-Bf2M8m3N.js} +1 -1
- ksadk/server/static/assets/{dist-o2OVmKvt.js → dist-BjU6y-A2.js} +1 -1
- ksadk/server/static/assets/{dist-DWKByxWV.js → dist-BytlxIDT.js} +1 -1
- ksadk/server/static/assets/{dist-DJN_6Y39.js → dist-CSh_DE14.js} +1 -1
- ksadk/server/static/assets/{dist-DQU9EWw-.js → dist-CXYYBw3_.js} +1 -1
- ksadk/server/static/assets/{dist-4N2NMVYg.js → dist-C_wsv-Qd.js} +1 -1
- ksadk/server/static/assets/{dist-gLnrGsoU.js → dist-ClxGviKw.js} +1 -1
- ksadk/server/static/assets/{dist-j6Dxmf_j.js → dist-CttYUqzS.js} +1 -1
- ksadk/server/static/assets/{dist-D6MpCZtz.js → dist-DNp6rLRA.js} +1 -1
- ksadk/server/static/assets/{dist-BB3-OwTQ.js → dist-DUX-id_F.js} +1 -1
- ksadk/server/static/assets/{dist-_pHPTyZ-.js → dist-DmldrHd_.js} +1 -1
- ksadk/server/static/assets/{dist-CWV4lDr1.js → dist-DnfXs8Vn.js} +2 -2
- ksadk/server/static/assets/{dist-B5oS1zcj.js → dist-Dq9gLD7L.js} +1 -1
- ksadk/server/static/assets/{dist-B-jNR6Vn.js → dist-W-TIVntx.js} +1 -1
- ksadk/server/static/assets/{dist-BIlKoW0k.js → dist-dDdADKFA.js} +1 -1
- ksadk/server/static/assets/{dist-X4TnqwOK.js → dist-dydu68Fl.js} +1 -1
- ksadk/server/static/assets/{dist-CmZHzlwZ.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-K0OOfVna.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-8LeOJaZp.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-C6uCgZrW.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
- ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
- ksadk/server/static/assets/{linear-hdBcYzM8.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-Bjy_2v4_.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-BmkRbwCg.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-l6iXmU65.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-Cq6UBeQB.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-DEz24vV0.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/studio/api.py +577 -25
- ksadk/studio/api_contracts.py +114 -5
- ksadk/studio/api_memory_routes.py +82 -0
- ksadk/studio/authoring.py +252 -27
- ksadk/studio/authoring_coordinator.py +799 -67
- ksadk/studio/builder.py +88 -11
- ksadk/studio/capabilities.py +17 -0
- ksadk/studio/cloud.py +1916 -95
- ksadk/studio/codex_agent_service.py +125 -14
- ksadk/studio/codex_authoring.py +469 -0
- ksadk/studio/codex_builder.py +138 -25
- ksadk/studio/codex_manifest.py +51 -22
- ksadk/studio/codex_run.py +46 -3
- ksadk/studio/compiler.py +1 -0
- ksadk/studio/contracts.py +114 -3
- ksadk/studio/event_store.py +25 -95
- ksadk/studio/framework_run.py +231 -3
- ksadk/studio/hosted_kernel.py +317 -0
- ksadk/studio/manifest_resolver.py +131 -0
- ksadk/studio/model_client.py +95 -9
- ksadk/studio/model_profile_service.py +1 -1
- ksadk/studio/operations.py +37 -5
- ksadk/studio/otel_trace.py +348 -42
- ksadk/studio/pcm_memory.py +85 -0
- ksadk/studio/repository.py +23 -2
- ksadk/studio/resource_catalog.py +43 -0
- ksadk/studio/run_service.py +563 -137
- ksadk/studio/runtime_source.py +42 -16
- ksadk/studio/service.py +1180 -72
- ksadk/studio/shared_web.py +32 -22
- ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
- ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
- ksadk/studio/static/index.html +2 -2
- ksadk/studio/templates.py +100 -8
- ksadk/studio/validator.py +19 -0
- ksadk/studio/workspace.py +30 -32
- ksadk/tracing/setup.py +304 -3
- ksadk/version.py +1 -1
- ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
- ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
- ksadk/events/parser.py +0 -191
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
- ksadk/server/static/assets/MermaidBlock-NERD_ef7.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-CiHWf82q.js +0 -1
- ksadk/server/static/assets/arc-DrgjcKhl.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CpZLRCcY.js +0 -1
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-BXoVRbQ6.js +0 -36
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-BnaB3Ywv.js +0 -132
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-Dw4weZcp.js +0 -10
- ksadk/server/static/assets/channel-Dt3rQTFI.js +0 -1
- ksadk/server/static/assets/chunk-2J33WTMH-ChjpLK7j.js +0 -1
- ksadk/server/static/assets/chunk-55IACEB6-CK4ROATy.js +0 -1
- ksadk/server/static/assets/chunk-727SXJPM-B9KtTTgw.js +0 -206
- ksadk/server/static/assets/chunk-AQP2D5EJ-1O1mki3m.js +0 -231
- ksadk/server/static/assets/chunk-QZHKN3VN-iXEZtKQc.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-DIveV17Q.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-DIveV17Q.js +0 -1
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
- ksadk/server/static/assets/dagre-BM42HDAG-D0QXg_MQ.js +0 -4
- ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
- ksadk/server/static/assets/diagram-2AECGRRQ-DBDDKwBQ.js +0 -43
- ksadk/server/static/assets/diagram-5GNKFQAL-BkwDOxmO.js +0 -10
- ksadk/server/static/assets/diagram-KO2AKTUF-Bv8waYvY.js +0 -3
- ksadk/server/static/assets/diagram-LMA3HP47-e1VECDdu.js +0 -24
- ksadk/server/static/assets/diagram-OG6HWLK6-Ds9adfRl.js +0 -24
- ksadk/server/static/assets/dist-B5J2uhNk.js +0 -1
- ksadk/server/static/assets/erDiagram-TEJ5UH35-BPItFKH6.js +0 -85
- ksadk/server/static/assets/eventmodeling-FCH6USID-DYFSxbqr.js +0 -1
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-BbYB9w5Y.js +0 -162
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-TQXa0KXv.js +0 -292
- ksadk/server/static/assets/gitGraph-WXDBUCRP-DyNYp6BN.js +0 -1
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-bKblCnpa.js +0 -106
- ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
- ksadk/server/static/assets/index-R52pJJvg.js +0 -177
- ksadk/server/static/assets/index-jJr3_955.css +0 -2
- ksadk/server/static/assets/info-J43DQDTF-WUx7qTde.js +0 -1
- ksadk/server/static/assets/infoDiagram-5YYISTIA-BGVT7J_i.js +0 -2
- ksadk/server/static/assets/katex-CYWseY5E.js +0 -265
- ksadk/server/static/assets/mermaid-parser.core-BWrDjSZM.js +0 -161
- ksadk/server/static/assets/packet-YPE3B663-BN13y_xl.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-ftSLXhhc.js +0 -1
- ksadk/server/static/assets/pieDiagram-4H26LBE5-GmmqNiVH.js +0 -30
- ksadk/server/static/assets/radar-GUYGQ44K-jaICkIeO.js +0 -1
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DSWFqL7c.js +0 -84
- ksadk/server/static/assets/stateDiagram-AJRCARHV-qzTQpg3Y.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-BYCoYGAN.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-Cpib_vlz.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-DQxfmVHK.js +0 -1
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-CMCixki2.js +0 -34
- ksadk/server/static/assets/wardley-L42UT6IY-BQYHnnkU.js +0 -1
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-CVzB8F9K.js +0 -78
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-BFBqBLc1.js +0 -7
- ksadk/studio/evaluation.py +0 -192
- ksadk/studio/static/assets/index-CaEN0eTR.css +0 -1
- ksadk/studio/static/assets/index-DI2eY_NH.js +0 -252
- {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.1.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,10 @@ LangGraphRunner - LangGraph 框架运行时
|
|
|
4
4
|
直接透传 LangGraph 原生能力,最小化封装
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
7
10
|
import base64
|
|
8
|
-
import inspect
|
|
9
11
|
import os
|
|
10
12
|
import re
|
|
11
13
|
import uuid
|
|
@@ -14,14 +16,13 @@ from typing import Any, AsyncIterator, Dict, Mapping
|
|
|
14
16
|
from langgraph.types import Command
|
|
15
17
|
|
|
16
18
|
from ksadk.conversations.attachments import classify_attachment_kind, read_attachment_uri_bytes
|
|
17
|
-
from ksadk.
|
|
19
|
+
from ksadk.runners._langgraph_runner_streams import _LangGraphStreamMixin
|
|
18
20
|
from ksadk.runners.base_runner import BaseRunner
|
|
19
|
-
from ksadk.runners.usage_accumulator import accumulate_usage
|
|
20
21
|
from ksadk.runners.utils import load_agent_module
|
|
21
22
|
from ksadk.sessions.continuity import LangGraphSessionAdapter
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
class LangGraphRunner(BaseRunner):
|
|
25
|
+
class LangGraphRunner(_LangGraphStreamMixin, BaseRunner):
|
|
25
26
|
"""LangGraph 框架运行时
|
|
26
27
|
|
|
27
28
|
透传原生 LangGraph 功能,支持任意 State 格式
|
|
@@ -31,6 +32,14 @@ class LangGraphRunner(BaseRunner):
|
|
|
31
32
|
# this runner opts into the runtime's semantic follow-up continuation.
|
|
32
33
|
supports_gateway_approval_semantic_resume = True
|
|
33
34
|
|
|
35
|
+
def __init__(self, detection_result: Any, project_dir: str):
|
|
36
|
+
super().__init__(detection_result, project_dir)
|
|
37
|
+
self._managed_checkpoint_lock = asyncio.Lock()
|
|
38
|
+
self._managed_checkpoint_prepared = False
|
|
39
|
+
self._managed_checkpoint_error: tuple[str, str] | None = None
|
|
40
|
+
self._managed_checkpoint_pool: Any = None
|
|
41
|
+
self._managed_checkpoint_namespace = ""
|
|
42
|
+
|
|
34
43
|
def load_agent(self) -> None:
|
|
35
44
|
self._load_agent(force_reload=False)
|
|
36
45
|
|
|
@@ -53,7 +62,13 @@ class LangGraphRunner(BaseRunner):
|
|
|
53
62
|
normalized = self.sync_process_model_env(model)
|
|
54
63
|
if normalized is None or self._agent is None:
|
|
55
64
|
return
|
|
56
|
-
|
|
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
|
+
):
|
|
57
72
|
return
|
|
58
73
|
self._load_agent(force_reload=True)
|
|
59
74
|
|
|
@@ -66,24 +81,23 @@ class LangGraphRunner(BaseRunner):
|
|
|
66
81
|
if checkpointer is None:
|
|
67
82
|
checkpointer = getattr(agent, "_checkpointer", None)
|
|
68
83
|
if checkpointer is None:
|
|
84
|
+
error_code, error_reason = self._managed_checkpoint_error or ("", "")
|
|
69
85
|
return {
|
|
70
86
|
"Supported": False,
|
|
71
87
|
"Backend": "none",
|
|
72
88
|
"Scope": "unknown",
|
|
73
89
|
"Durable": False,
|
|
74
90
|
"SharedAcrossPods": False,
|
|
75
|
-
"
|
|
91
|
+
"ResumeMode": "none",
|
|
92
|
+
**({"ReasonCode": error_code} if error_code else {}),
|
|
93
|
+
"Reason": error_reason or "LangGraph graph has no configured checkpointer",
|
|
76
94
|
}
|
|
77
95
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
backend = "sqlite"
|
|
84
|
-
elif "postgres" in type_name:
|
|
85
|
-
backend = "postgres"
|
|
86
|
-
else:
|
|
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.
|
|
87
101
|
backend = str(os.getenv("KSADK_CHECKPOINT_BACKEND") or "").strip().lower()
|
|
88
102
|
if backend == "local":
|
|
89
103
|
backend = "sqlite"
|
|
@@ -112,17 +126,28 @@ class LangGraphRunner(BaseRunner):
|
|
|
112
126
|
reason = "In-memory checkpoint cannot be recovered after process restart or across pods"
|
|
113
127
|
|
|
114
128
|
return {
|
|
115
|
-
|
|
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", ""},
|
|
116
132
|
"Backend": backend,
|
|
117
133
|
"Scope": scope,
|
|
118
134
|
"Durable": durable,
|
|
119
135
|
"SharedAcrossPods": shared,
|
|
120
|
-
"ResumeMode": "time_travel",
|
|
136
|
+
"ResumeMode": "time_travel" if durable else "none",
|
|
137
|
+
**(
|
|
138
|
+
{"ReasonCode": "CHECKPOINTER_NOT_DURABLE"}
|
|
139
|
+
if backend in {"memory", "inmemory", "unknown", ""}
|
|
140
|
+
else {}
|
|
141
|
+
),
|
|
121
142
|
"Reason": reason,
|
|
122
143
|
}
|
|
123
144
|
|
|
124
145
|
def get_runtime_capabilities(self) -> dict[str, Any]:
|
|
125
146
|
capabilities = super().get_runtime_capabilities()
|
|
147
|
+
capabilities["model_call_boundaries"] = True
|
|
148
|
+
reason_code = str(capabilities["Checkpoint"].get("ReasonCode") or "")
|
|
149
|
+
if reason_code:
|
|
150
|
+
capabilities["ResumeRun"]["ReasonCode"] = reason_code
|
|
126
151
|
capabilities["SessionContinuity"] = {
|
|
127
152
|
"Supported": True,
|
|
128
153
|
"Type": (
|
|
@@ -133,9 +158,150 @@ class LangGraphRunner(BaseRunner):
|
|
|
133
158
|
}
|
|
134
159
|
return capabilities
|
|
135
160
|
|
|
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
|
+
@staticmethod
|
|
179
|
+
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}"
|
|
191
|
+
|
|
192
|
+
async def _create_managed_postgres_saver(self, dsn: str) -> tuple[Any, Any]:
|
|
193
|
+
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
|
194
|
+
from psycopg.rows import dict_row
|
|
195
|
+
from psycopg_pool import AsyncConnectionPool
|
|
196
|
+
|
|
197
|
+
timeout = max(0.1, float(os.getenv("KSADK_SESSION_CONNECT_TIMEOUT") or "5"))
|
|
198
|
+
pool = AsyncConnectionPool(
|
|
199
|
+
conninfo=dsn,
|
|
200
|
+
min_size=1,
|
|
201
|
+
max_size=10,
|
|
202
|
+
open=False,
|
|
203
|
+
timeout=timeout,
|
|
204
|
+
kwargs={
|
|
205
|
+
"autocommit": True,
|
|
206
|
+
"prepare_threshold": 0,
|
|
207
|
+
"row_factory": dict_row,
|
|
208
|
+
},
|
|
209
|
+
)
|
|
210
|
+
try:
|
|
211
|
+
await pool.open(wait=True, timeout=timeout)
|
|
212
|
+
saver = AsyncPostgresSaver(pool)
|
|
213
|
+
await saver.setup()
|
|
214
|
+
return saver, pool
|
|
215
|
+
except Exception:
|
|
216
|
+
await pool.close()
|
|
217
|
+
raise
|
|
218
|
+
|
|
219
|
+
async def prepare_runtime_capabilities(self) -> None:
|
|
220
|
+
"""Install the managed saver before a graph can begin an interaction.
|
|
221
|
+
|
|
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.
|
|
226
|
+
"""
|
|
227
|
+
if self._managed_checkpoint_prepared:
|
|
228
|
+
return
|
|
229
|
+
async with self._managed_checkpoint_lock:
|
|
230
|
+
if self._managed_checkpoint_prepared:
|
|
231
|
+
return
|
|
232
|
+
|
|
233
|
+
checkpointer = getattr(self._agent, "checkpointer", None)
|
|
234
|
+
if checkpointer is None:
|
|
235
|
+
checkpointer = getattr(self._agent, "_checkpointer", None)
|
|
236
|
+
if self._checkpoint_backend_from_saver(checkpointer) == "postgres":
|
|
237
|
+
self._managed_checkpoint_namespace = self._resolve_checkpoint_namespace()
|
|
238
|
+
self._managed_checkpoint_prepared = True
|
|
239
|
+
return
|
|
240
|
+
|
|
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:
|
|
247
|
+
self._managed_checkpoint_prepared = True
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
factory = getattr(self._module, "ksadk_graph_factory", None)
|
|
251
|
+
if not callable(factory):
|
|
252
|
+
self._managed_checkpoint_error = (
|
|
253
|
+
"LANGGRAPH_FACTORY_REQUIRED",
|
|
254
|
+
"LangGraph graph has no durable checkpointer; export "
|
|
255
|
+
"ksadk_graph_factory(*, checkpointer) for managed PostgreSQL checkpoints",
|
|
256
|
+
)
|
|
257
|
+
self._managed_checkpoint_prepared = True
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
pool = None
|
|
261
|
+
try:
|
|
262
|
+
saver, pool = await self._create_managed_postgres_saver(dsn)
|
|
263
|
+
managed_graph = factory(checkpointer=saver)
|
|
264
|
+
if not callable(getattr(managed_graph, "invoke", None)):
|
|
265
|
+
raise TypeError("ksadk_graph_factory must return a compiled LangGraph graph")
|
|
266
|
+
self._agent = managed_graph
|
|
267
|
+
self._managed_checkpoint_pool = pool
|
|
268
|
+
self._managed_checkpoint_namespace = self._resolve_checkpoint_namespace()
|
|
269
|
+
self._managed_checkpoint_error = None
|
|
270
|
+
except (ModuleNotFoundError, ImportError):
|
|
271
|
+
self._managed_checkpoint_error = (
|
|
272
|
+
"DEPENDENCY_MISSING",
|
|
273
|
+
"langgraph-checkpoint-postgres and psycopg are required "
|
|
274
|
+
"for managed checkpoints",
|
|
275
|
+
)
|
|
276
|
+
except Exception as exc: # noqa: BLE001
|
|
277
|
+
error_name = type(exc).__name__.lower()
|
|
278
|
+
self._managed_checkpoint_error = (
|
|
279
|
+
"SCHEMA_PERMISSION_DENIED"
|
|
280
|
+
if "privilege" in error_name or "permission" in error_name
|
|
281
|
+
else "DB_UNREACHABLE",
|
|
282
|
+
"Managed LangGraph PostgreSQL checkpointer initialization failed",
|
|
283
|
+
)
|
|
284
|
+
finally:
|
|
285
|
+
if pool is not None and self._managed_checkpoint_pool is None:
|
|
286
|
+
try:
|
|
287
|
+
await pool.close()
|
|
288
|
+
except Exception: # noqa: BLE001
|
|
289
|
+
pass
|
|
290
|
+
self._managed_checkpoint_prepared = True
|
|
291
|
+
|
|
292
|
+
async def close(self) -> None:
|
|
293
|
+
pool = self._managed_checkpoint_pool
|
|
294
|
+
self._managed_checkpoint_pool = None
|
|
295
|
+
if pool is not None:
|
|
296
|
+
await pool.close()
|
|
297
|
+
await super().close()
|
|
298
|
+
|
|
136
299
|
def _get_config(self, session_id: str) -> dict:
|
|
137
300
|
"""获取运行配置"""
|
|
138
|
-
|
|
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
|
|
139
305
|
|
|
140
306
|
@staticmethod
|
|
141
307
|
def _extract_langgraph_checkpoint_ref(payload: Dict[str, Any]) -> dict[str, Any]:
|
|
@@ -407,6 +573,12 @@ class LangGraphRunner(BaseRunner):
|
|
|
407
573
|
for msg in history:
|
|
408
574
|
role = msg.get("role")
|
|
409
575
|
content = msg.get("content", "")
|
|
576
|
+
# Runtime-owned tool/approval records are preserved in the durable
|
|
577
|
+
# transcript, but must not be taught back to LangGraph as plain text.
|
|
578
|
+
if isinstance(content, str) and content.startswith(
|
|
579
|
+
("[tool_call]", "[tool_result]", "[approval_request]", "[approval_response]")
|
|
580
|
+
):
|
|
581
|
+
continue
|
|
410
582
|
if role == "user":
|
|
411
583
|
messages.append(HumanMessage(content=content))
|
|
412
584
|
elif role in ("assistant", "model"):
|
|
@@ -604,6 +776,7 @@ class LangGraphRunner(BaseRunner):
|
|
|
604
776
|
1. 简化格式: {"input": "hello"} - 自动转换为 messages
|
|
605
777
|
2. 原生格式: {"messages": [...]} 或自定义 State - 直接透传
|
|
606
778
|
"""
|
|
779
|
+
await self.prepare_runtime_capabilities()
|
|
607
780
|
payload = dict(input_data)
|
|
608
781
|
force_graph_invoke = bool(payload.pop("_ksadk_force_graph_invoke", False))
|
|
609
782
|
if not force_graph_invoke and hasattr(self._agent, "astream_events"):
|
|
@@ -878,428 +1051,16 @@ class LangGraphRunner(BaseRunner):
|
|
|
878
1051
|
)
|
|
879
1052
|
return events
|
|
880
1053
|
|
|
881
|
-
async def stream(self, input_data: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
|
|
882
|
-
"""流式调用 LangGraph 图"""
|
|
883
|
-
payload = dict(input_data)
|
|
884
|
-
payload.pop("_ksadk_force_graph_invoke", None)
|
|
885
|
-
session_id = payload.pop("session_id", None) or str(uuid.uuid4())[:8]
|
|
886
|
-
history = payload.pop("history", [])
|
|
887
|
-
is_resume = payload.pop("resume", False)
|
|
888
|
-
is_checkpoint_resume = bool(payload.pop("checkpoint_resume", False))
|
|
889
|
-
resume_payload_provided = bool(payload.pop("resume_payload_provided", False))
|
|
890
|
-
resume_interrupt_id = str(payload.pop("resume_interrupt_id", "") or "")
|
|
891
|
-
resume_value = payload.get("input")
|
|
892
|
-
is_gateway_approval_resume = bool(
|
|
893
|
-
is_resume and self._is_gateway_approval_semantic_resume(resume_value)
|
|
894
|
-
)
|
|
895
|
-
if is_gateway_approval_resume:
|
|
896
|
-
# See ``invoke``: the graph did not suspend at a native interrupt,
|
|
897
|
-
# so use the durable transcript to run the post-tool answer turn.
|
|
898
|
-
payload["input"] = self._gateway_approval_follow_up_input()
|
|
899
|
-
resume_value = payload["input"]
|
|
900
|
-
checkpoint_ref = self._extract_langgraph_checkpoint_ref(payload)
|
|
901
|
-
native_context = self.build_native_context(payload.get("platform_context"))
|
|
902
|
-
invoke_payload = dict(payload)
|
|
903
|
-
invoke_payload["session_id"] = session_id
|
|
904
|
-
if history:
|
|
905
|
-
invoke_payload["history"] = history
|
|
906
|
-
if is_resume and not is_gateway_approval_resume:
|
|
907
|
-
invoke_payload["resume"] = True
|
|
908
|
-
if is_checkpoint_resume:
|
|
909
|
-
invoke_payload["checkpoint_resume"] = True
|
|
910
|
-
invoke_payload["resume_payload_provided"] = resume_payload_provided
|
|
911
|
-
invoke_payload["resume_interrupt_id"] = resume_interrupt_id
|
|
912
|
-
|
|
913
|
-
config = self._get_config(session_id)
|
|
914
|
-
if is_checkpoint_resume:
|
|
915
|
-
config = self._apply_checkpoint_resume_config(
|
|
916
|
-
config,
|
|
917
|
-
session_id=session_id,
|
|
918
|
-
checkpoint_ref=checkpoint_ref,
|
|
919
|
-
)
|
|
920
|
-
|
|
921
|
-
if is_checkpoint_resume:
|
|
922
|
-
state = resume_value
|
|
923
|
-
elif is_resume and not is_gateway_approval_resume:
|
|
924
|
-
# Keep the interrupt value intact for ``Command(resume=...)``;
|
|
925
|
-
# prepare-state hooks only shape fresh user turns.
|
|
926
|
-
state = resume_value
|
|
927
|
-
elif self._has_prepare_state_hook():
|
|
928
|
-
state = self._prepare_state_with_hook(
|
|
929
|
-
payload,
|
|
930
|
-
session_id,
|
|
931
|
-
history,
|
|
932
|
-
is_resume=is_gateway_approval_resume,
|
|
933
|
-
)
|
|
934
|
-
else:
|
|
935
|
-
state = self._to_state(payload, history)
|
|
936
|
-
|
|
937
|
-
accumulated_text = ""
|
|
938
|
-
accumulated_reasoning = ""
|
|
939
|
-
inline_reasoning_parser = ReasoningMarkupParser()
|
|
940
|
-
emitted_non_text_event = False
|
|
941
|
-
final_output_text = ""
|
|
942
|
-
final_output_usage: dict[str, Any] = {}
|
|
943
|
-
final_output_last_usage: dict[str, Any] = {}
|
|
944
|
-
model_run_usages: dict[str, dict[str, Any]] = {}
|
|
945
|
-
model_run_order: list[str] = []
|
|
946
|
-
stream_usage_run_keys: set[str] = set()
|
|
947
|
-
latest_stream_usage: dict[str, Any] = {}
|
|
948
|
-
|
|
949
|
-
def model_run_key(
|
|
950
|
-
event: Mapping[str, Any],
|
|
951
|
-
*,
|
|
952
|
-
fallback_key: str | None = None,
|
|
953
|
-
) -> str:
|
|
954
|
-
raw_run_id = event.get("run_id")
|
|
955
|
-
return (
|
|
956
|
-
str(raw_run_id)
|
|
957
|
-
if raw_run_id
|
|
958
|
-
else fallback_key or f"model-event-{len(model_run_order)}"
|
|
959
|
-
)
|
|
960
|
-
|
|
961
|
-
def record_model_usage(
|
|
962
|
-
event: Mapping[str, Any],
|
|
963
|
-
usage: dict[str, Any],
|
|
964
|
-
*,
|
|
965
|
-
fallback_key: str | None = None,
|
|
966
|
-
) -> None:
|
|
967
|
-
if not usage:
|
|
968
|
-
return
|
|
969
|
-
run_key = model_run_key(event, fallback_key=fallback_key)
|
|
970
|
-
if run_key not in model_run_usages:
|
|
971
|
-
model_run_order.append(run_key)
|
|
972
|
-
model_run_usages[run_key] = dict(usage)
|
|
973
|
-
|
|
974
|
-
def accumulated_model_usage() -> dict[str, Any]:
|
|
975
|
-
if len(model_run_order) == 1:
|
|
976
|
-
return dict(model_run_usages.get(model_run_order[0]) or {})
|
|
977
|
-
usage: dict[str, Any] = {}
|
|
978
|
-
for run_key in model_run_order:
|
|
979
|
-
usage = accumulate_usage(usage, model_run_usages.get(run_key) or {})
|
|
980
|
-
return usage
|
|
981
|
-
|
|
982
|
-
def latest_model_usage() -> dict[str, Any]:
|
|
983
|
-
for run_key in reversed(model_run_order):
|
|
984
|
-
usage = model_run_usages.get(run_key)
|
|
985
|
-
if usage:
|
|
986
|
-
return dict(usage)
|
|
987
|
-
return {}
|
|
988
|
-
|
|
989
|
-
if is_checkpoint_resume and callable(getattr(self._agent, "astream", None)):
|
|
990
|
-
try:
|
|
991
|
-
async for chunk in self._stream_checkpoint_resume_updates(
|
|
992
|
-
stream_input=self._checkpoint_resume_input(
|
|
993
|
-
state,
|
|
994
|
-
payload_provided=resume_payload_provided,
|
|
995
|
-
interrupt_id=resume_interrupt_id,
|
|
996
|
-
),
|
|
997
|
-
config=config,
|
|
998
|
-
context=native_context,
|
|
999
|
-
):
|
|
1000
|
-
yield chunk
|
|
1001
|
-
return
|
|
1002
|
-
except Exception as e:
|
|
1003
|
-
yield {
|
|
1004
|
-
"type": "error",
|
|
1005
|
-
"message": str(e) or "LangGraph checkpoint resume failed",
|
|
1006
|
-
"checkpoint_id": str(checkpoint_ref.get("checkpoint_id") or ""),
|
|
1007
|
-
"exception_type": type(e).__name__,
|
|
1008
|
-
}
|
|
1009
|
-
return
|
|
1010
|
-
|
|
1011
|
-
if not hasattr(self._agent, "astream_events"):
|
|
1012
|
-
result = await self.invoke(invoke_payload)
|
|
1013
|
-
final_chunk = {"output": result.get("output", ""), "type": "final"}
|
|
1014
|
-
usage = self._extract_usage(result)
|
|
1015
|
-
if usage:
|
|
1016
|
-
final_chunk["usage"] = usage
|
|
1017
|
-
last_usage = self._extract_last_usage(result)
|
|
1018
|
-
if last_usage:
|
|
1019
|
-
final_chunk.setdefault("metadata", {})["last_usage"] = last_usage
|
|
1020
|
-
yield final_chunk
|
|
1021
|
-
return
|
|
1022
|
-
|
|
1023
|
-
try:
|
|
1024
|
-
stream_input = (
|
|
1025
|
-
self._checkpoint_resume_input(
|
|
1026
|
-
state,
|
|
1027
|
-
payload_provided=resume_payload_provided,
|
|
1028
|
-
interrupt_id=resume_interrupt_id,
|
|
1029
|
-
)
|
|
1030
|
-
if is_checkpoint_resume
|
|
1031
|
-
else (
|
|
1032
|
-
Command(resume=state) if is_resume and not is_gateway_approval_resume else state
|
|
1033
|
-
)
|
|
1034
|
-
)
|
|
1035
|
-
# stream_mode 含 "custom" 才会产生 on_custom_stream 事件(custom writer);
|
|
1036
|
-
# 保留默认 "values" 以兼容既有 on_chain_end/graph_update 消费。
|
|
1037
|
-
stream_kwargs = {"version": "v2", "config": config}
|
|
1038
|
-
if self._callable_accepts_keyword(self._agent.astream_events, "stream_mode"):
|
|
1039
|
-
stream_kwargs["stream_mode"] = ["values", "custom"]
|
|
1040
|
-
if native_context and self._callable_accepts_keyword(
|
|
1041
|
-
self._agent.astream_events, "context"
|
|
1042
|
-
):
|
|
1043
|
-
stream_kwargs["context"] = native_context
|
|
1044
|
-
async for event in self._agent.astream_events(stream_input, **stream_kwargs):
|
|
1045
|
-
event_kind = event.get("event", "")
|
|
1046
|
-
|
|
1047
|
-
if event_kind == "on_chat_model_stream":
|
|
1048
|
-
chunk = event.get("data", {}).get("chunk")
|
|
1049
|
-
if not chunk:
|
|
1050
|
-
continue
|
|
1051
|
-
chunk_usage = self._extract_usage(chunk)
|
|
1052
|
-
if chunk_usage:
|
|
1053
|
-
# Some LangChain providers attach cumulative usage to
|
|
1054
|
-
# every stream chunk, and LangChain may then sum those
|
|
1055
|
-
# cumulative snapshots into an inflated
|
|
1056
|
-
# on_chat_model_end usage. For a concrete model run,
|
|
1057
|
-
# keep the latest stream snapshot and ignore the later
|
|
1058
|
-
# end usage for that same run_id.
|
|
1059
|
-
latest_stream_usage = dict(chunk_usage)
|
|
1060
|
-
if event.get("run_id"):
|
|
1061
|
-
run_key = model_run_key(event)
|
|
1062
|
-
stream_usage_run_keys.add(run_key)
|
|
1063
|
-
record_model_usage(event, latest_stream_usage)
|
|
1064
|
-
|
|
1065
|
-
# 推理内容
|
|
1066
|
-
reasoning = getattr(chunk, "reasoning_content", None)
|
|
1067
|
-
if not reasoning and hasattr(chunk, "additional_kwargs"):
|
|
1068
|
-
reasoning = chunk.additional_kwargs.get("reasoning_content")
|
|
1069
|
-
|
|
1070
|
-
if reasoning:
|
|
1071
|
-
accumulated_reasoning += reasoning
|
|
1072
|
-
yield {"delta": reasoning, "type": "thinking"}
|
|
1073
|
-
|
|
1074
|
-
# 常规内容
|
|
1075
|
-
if hasattr(chunk, "content") and chunk.content:
|
|
1076
|
-
content = self._filter_tool_tags(chunk.content)
|
|
1077
|
-
if isinstance(content, str):
|
|
1078
|
-
if accumulated_reasoning and content.startswith(accumulated_reasoning):
|
|
1079
|
-
content = content[len(accumulated_reasoning) :]
|
|
1080
|
-
elif reasoning and content.startswith(reasoning):
|
|
1081
|
-
content = content[len(reasoning) :]
|
|
1082
|
-
if content:
|
|
1083
|
-
for part in inline_reasoning_parser.feed(content):
|
|
1084
|
-
if not part.text or not part.text.strip():
|
|
1085
|
-
continue
|
|
1086
|
-
if part.kind == "thinking":
|
|
1087
|
-
accumulated_reasoning += part.text
|
|
1088
|
-
yield {"delta": part.text, "type": "thinking"}
|
|
1089
|
-
else:
|
|
1090
|
-
accumulated_text += part.text
|
|
1091
|
-
yield {"delta": part.text, "type": "text"}
|
|
1092
|
-
|
|
1093
|
-
elif event_kind == "on_chat_model_end":
|
|
1094
|
-
data = event.get("data") or {}
|
|
1095
|
-
output = data.get("output") if isinstance(data, Mapping) else None
|
|
1096
|
-
usage = self._extract_usage(output) or self._extract_usage(data)
|
|
1097
|
-
last_usage = self._extract_last_usage(output) or self._extract_last_usage(data)
|
|
1098
|
-
run_key = model_run_key(event)
|
|
1099
|
-
if run_key not in stream_usage_run_keys:
|
|
1100
|
-
record_model_usage(event, last_usage or usage)
|
|
1101
|
-
|
|
1102
|
-
elif event_kind == "on_chain_stream":
|
|
1103
|
-
# node 内 get_stream_writer() 写入的自定义数据,经 stream_mode 含
|
|
1104
|
-
# "custom" 时,astream_events 包成 on_chain_stream,chunk 为
|
|
1105
|
-
# (mode, value) tuple:("custom", value) 是 writer 透传内容,
|
|
1106
|
-
# ("values", state) 是 state 快照(忽略,终态走 on_chain_end)。
|
|
1107
|
-
# 编排方常用 custom writer 把"调远端 agent/子图"的流式增量透传出来。
|
|
1108
|
-
chunk = event.get("data", {}).get("chunk")
|
|
1109
|
-
if not (isinstance(chunk, tuple) and len(chunk) == 2 and chunk[0] == "custom"):
|
|
1110
|
-
continue
|
|
1111
|
-
data = chunk[1]
|
|
1112
|
-
if isinstance(data, str):
|
|
1113
|
-
accumulated_text += data
|
|
1114
|
-
yield {"delta": data, "type": "text"}
|
|
1115
|
-
continue
|
|
1116
|
-
if isinstance(data, Mapping):
|
|
1117
|
-
custom_type = str(data.get("type") or "text")
|
|
1118
|
-
if custom_type in ("tool_call", "tool_result"):
|
|
1119
|
-
# 结构化工具事件:透传完整 payload(tool_name/tool_args/
|
|
1120
|
-
# tool_output 等),不计入正文,供 UI 渲染工具卡片。
|
|
1121
|
-
out = {"type": custom_type}
|
|
1122
|
-
out.update({k: v for k, v in data.items() if k != "type"})
|
|
1123
|
-
yield out
|
|
1124
|
-
continue
|
|
1125
|
-
custom_delta = ""
|
|
1126
|
-
for key in ("delta", "text", "content", "output", "data"):
|
|
1127
|
-
value = data.get(key)
|
|
1128
|
-
if isinstance(value, str) and value:
|
|
1129
|
-
custom_delta = value
|
|
1130
|
-
break
|
|
1131
|
-
if not custom_delta:
|
|
1132
|
-
continue
|
|
1133
|
-
replace = bool(data.get("replace"))
|
|
1134
|
-
if custom_type == "thinking":
|
|
1135
|
-
accumulated_reasoning = (
|
|
1136
|
-
custom_delta if replace else accumulated_reasoning + custom_delta
|
|
1137
|
-
)
|
|
1138
|
-
else:
|
|
1139
|
-
accumulated_text = (
|
|
1140
|
-
custom_delta if replace else accumulated_text + custom_delta
|
|
1141
|
-
)
|
|
1142
|
-
custom_event: dict[str, Any] = {
|
|
1143
|
-
"delta": custom_delta,
|
|
1144
|
-
"type": custom_type,
|
|
1145
|
-
}
|
|
1146
|
-
if replace:
|
|
1147
|
-
custom_event["replace"] = True
|
|
1148
|
-
yield custom_event
|
|
1149
|
-
continue
|
|
1150
|
-
if data is not None:
|
|
1151
|
-
accumulated_text += str(data)
|
|
1152
|
-
yield {"delta": str(data), "type": "text"}
|
|
1153
|
-
|
|
1154
|
-
elif event_kind == "on_tool_start":
|
|
1155
|
-
emitted_non_text_event = True
|
|
1156
|
-
yield {
|
|
1157
|
-
"type": "tool_call",
|
|
1158
|
-
"tool_name": event.get("name", "unknown"),
|
|
1159
|
-
"tool_args": event.get("data", {}).get("input", {}),
|
|
1160
|
-
"run_id": event.get("run_id"),
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
elif event_kind == "on_tool_end":
|
|
1164
|
-
emitted_non_text_event = True
|
|
1165
|
-
tool_output = event.get("data", {}).get("output", "")
|
|
1166
|
-
# LangGraph returns a ToolMessage here for normal tools.
|
|
1167
|
-
# Preserve its content instead of serializing the repr,
|
|
1168
|
-
# otherwise structured output such as A2UI envelopes becomes
|
|
1169
|
-
# unparsable. Keep the callback run_id below: it is paired
|
|
1170
|
-
# with the preceding ``on_tool_start`` event on this stream.
|
|
1171
|
-
normalized_output = getattr(tool_output, "content", tool_output)
|
|
1172
|
-
if isinstance(tool_output, Mapping) and "content" in tool_output:
|
|
1173
|
-
normalized_output = tool_output["content"]
|
|
1174
|
-
yield {
|
|
1175
|
-
"type": "tool_result",
|
|
1176
|
-
"tool_name": event.get("name", "unknown"),
|
|
1177
|
-
"tool_args": event.get("data", {}).get("input", {}),
|
|
1178
|
-
"tool_output": normalized_output,
|
|
1179
|
-
"run_id": event.get("run_id"),
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
elif event_kind == "on_chain_end":
|
|
1183
|
-
output = event.get("data", {}).get("output", {})
|
|
1184
|
-
if isinstance(output, dict) and "__interrupt__" in output:
|
|
1185
|
-
emitted_non_text_event = True
|
|
1186
|
-
yield {
|
|
1187
|
-
"type": "interrupt",
|
|
1188
|
-
"interrupt_info": output["__interrupt__"],
|
|
1189
|
-
"session_id": session_id,
|
|
1190
|
-
}
|
|
1191
|
-
return
|
|
1192
|
-
extracted_output = self._extract_output(output)
|
|
1193
|
-
if extracted_output:
|
|
1194
|
-
final_output_text = strip_reasoning_markup(str(extracted_output))
|
|
1195
|
-
final_output_usage = self._extract_usage(output)
|
|
1196
|
-
final_output_last_usage = self._extract_last_usage(output)
|
|
1197
|
-
|
|
1198
|
-
except Exception as e:
|
|
1199
|
-
if "Interrupt" in type(e).__name__:
|
|
1200
|
-
yield {
|
|
1201
|
-
"type": "interrupt",
|
|
1202
|
-
"interrupt_info": self._get_interrupt_info(self._agent.get_state(config)),
|
|
1203
|
-
"session_id": session_id,
|
|
1204
|
-
}
|
|
1205
|
-
return
|
|
1206
|
-
raise
|
|
1207
|
-
|
|
1208
|
-
# goal-18(ksadk-web 人机交互):图因审批门(HITL)在流式中静默暂停时,
|
|
1209
|
-
# 这里把审批详情(action_requests)作为 approval 事件冒出,供 UI 渲染审批卡。
|
|
1210
|
-
# 此前流式路径只在 checkpoint 标 resumable,UI 拿不到"该批哪个工具/什么参数/允许哪些决定"。
|
|
1211
|
-
# 注:get_state 在部分 agent 上是 async,统一按 awaitable 处理;取不到则跳过,不破坏事件流。
|
|
1212
|
-
pending_approval = None
|
|
1213
|
-
try:
|
|
1214
|
-
_get_state = getattr(self._agent, "aget_state", None) or getattr(
|
|
1215
|
-
self._agent, "get_state", None
|
|
1216
|
-
)
|
|
1217
|
-
if _get_state is not None:
|
|
1218
|
-
_maybe_state = _get_state(config)
|
|
1219
|
-
if inspect.isawaitable(_maybe_state):
|
|
1220
|
-
_maybe_state = await _maybe_state
|
|
1221
|
-
pending_approval = self._get_interrupt_info(_maybe_state)
|
|
1222
|
-
except Exception:
|
|
1223
|
-
pending_approval = None
|
|
1224
|
-
if pending_approval:
|
|
1225
|
-
yield {
|
|
1226
|
-
"type": "approval",
|
|
1227
|
-
"interrupt_info": pending_approval,
|
|
1228
|
-
"session_id": session_id,
|
|
1229
|
-
}
|
|
1230
|
-
metadata = await self._latest_checkpoint_metadata(config)
|
|
1231
|
-
if metadata:
|
|
1232
|
-
yield {"type": "checkpoint", "metadata": metadata}
|
|
1233
|
-
return
|
|
1234
|
-
|
|
1235
|
-
for part in inline_reasoning_parser.flush():
|
|
1236
|
-
if not part.text or not part.text.strip():
|
|
1237
|
-
continue
|
|
1238
|
-
if part.kind == "thinking":
|
|
1239
|
-
accumulated_reasoning += part.text
|
|
1240
|
-
yield {"delta": part.text, "type": "thinking"}
|
|
1241
|
-
else:
|
|
1242
|
-
accumulated_text += part.text
|
|
1243
|
-
yield {"delta": part.text, "type": "text"}
|
|
1244
|
-
|
|
1245
|
-
if not accumulated_text:
|
|
1246
|
-
if final_output_text:
|
|
1247
|
-
final_chunk = {"output": final_output_text, "type": "final"}
|
|
1248
|
-
usage = accumulated_model_usage() or final_output_usage or latest_stream_usage
|
|
1249
|
-
last_usage = (
|
|
1250
|
-
latest_model_usage() or final_output_last_usage or latest_stream_usage or usage
|
|
1251
|
-
)
|
|
1252
|
-
if usage:
|
|
1253
|
-
final_chunk["usage"] = usage
|
|
1254
|
-
if last_usage:
|
|
1255
|
-
final_chunk.setdefault("metadata", {})["last_usage"] = last_usage
|
|
1256
|
-
yield final_chunk
|
|
1257
|
-
elif not emitted_non_text_event:
|
|
1258
|
-
result = await self.invoke({**invoke_payload, "_ksadk_force_graph_invoke": True})
|
|
1259
|
-
fallback_chunk: dict[str, Any] = {
|
|
1260
|
-
"output": result.get("output", ""),
|
|
1261
|
-
"type": "final",
|
|
1262
|
-
}
|
|
1263
|
-
usage = self._extract_usage(result)
|
|
1264
|
-
if usage:
|
|
1265
|
-
fallback_chunk["usage"] = usage
|
|
1266
|
-
last_usage = self._extract_last_usage(result)
|
|
1267
|
-
if last_usage:
|
|
1268
|
-
fallback_chunk.setdefault("metadata", {})["last_usage"] = last_usage
|
|
1269
|
-
yield fallback_chunk
|
|
1270
|
-
checkpoint_metadata = result.get("metadata") if isinstance(result, dict) else None
|
|
1271
|
-
if isinstance(checkpoint_metadata, dict) and checkpoint_metadata.get("agentengine"):
|
|
1272
|
-
yield {"type": "checkpoint", "metadata": checkpoint_metadata}
|
|
1273
|
-
return
|
|
1274
|
-
else:
|
|
1275
|
-
final_chunk = {"output": accumulated_text, "type": "final"}
|
|
1276
|
-
state_usage = await self._latest_state_usage(config)
|
|
1277
|
-
usage = (
|
|
1278
|
-
accumulated_model_usage()
|
|
1279
|
-
or state_usage
|
|
1280
|
-
or final_output_usage
|
|
1281
|
-
or latest_stream_usage
|
|
1282
|
-
)
|
|
1283
|
-
if usage:
|
|
1284
|
-
final_chunk["usage"] = usage
|
|
1285
|
-
last_usage = (
|
|
1286
|
-
latest_model_usage()
|
|
1287
|
-
or state_usage
|
|
1288
|
-
or final_output_last_usage
|
|
1289
|
-
or latest_stream_usage
|
|
1290
|
-
or usage
|
|
1291
|
-
)
|
|
1292
|
-
final_chunk.setdefault("metadata", {})["last_usage"] = last_usage
|
|
1293
|
-
yield final_chunk
|
|
1294
|
-
|
|
1295
|
-
metadata = await self._latest_checkpoint_metadata(config)
|
|
1296
|
-
if metadata:
|
|
1297
|
-
yield {"type": "checkpoint", "metadata": metadata}
|
|
1298
|
-
|
|
1299
1054
|
def _filter_tool_tags(self, content: str) -> str:
|
|
1300
|
-
"""
|
|
1055
|
+
"""过滤完整的 XML tool_call 标签。"""
|
|
1301
1056
|
if not isinstance(content, str):
|
|
1302
1057
|
return content
|
|
1303
1058
|
content = re.sub(r"<tool_call>.*?</tool_call>", "", content, flags=re.DOTALL)
|
|
1304
1059
|
content = re.sub(r"</?(?:tool_call|arg_key|arg_value)>", "", content)
|
|
1305
1060
|
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
|