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/runtime/factory.py
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
"""内置 RuntimeAdapter 的唯一默认 Factory Registry。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
import os
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ksadk.codex.client import AsyncCodexClient
|
|
12
|
+
from ksadk.codex.runtime import CodexRuntimeAdapter
|
|
13
|
+
from ksadk.runners.base_runner import BaseRunner
|
|
14
|
+
from ksadk.runtime.adapter import StartRequest
|
|
15
|
+
from ksadk.runtime.adapter import RuntimeAdapter, RuntimeRegistry
|
|
16
|
+
from ksadk.runtime.framework_adapters import ADKRuntimeAdapter, LangGraphRuntimeAdapter
|
|
17
|
+
from ksadk.runtime.launch import RuntimeLaunchContext
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def kernel_start_request_defaults(context: RuntimeLaunchContext) -> dict[str, Any]:
|
|
21
|
+
"""Project an admitted launch manifest into immutable Kernel turn defaults.
|
|
22
|
+
|
|
23
|
+
The durable Kernel owns enqueue ordering, while the deployment manifest
|
|
24
|
+
owns model, instructions, sandbox and approval policy. Keeping this
|
|
25
|
+
projection beside the RuntimeAdapter factory prevents the Kernel ingress
|
|
26
|
+
from trusting caller-supplied execution policy.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
config = dict(context.config)
|
|
30
|
+
defaults: dict[str, Any] = {}
|
|
31
|
+
detection_name = str(getattr(context.detection, "name", "") or "").strip()
|
|
32
|
+
if detection_name:
|
|
33
|
+
defaults["agent_id"] = detection_name
|
|
34
|
+
model = str(config.get("model") or "").strip()
|
|
35
|
+
if model:
|
|
36
|
+
defaults["model"] = model
|
|
37
|
+
raw_allowed_models = (
|
|
38
|
+
config.get("models") or config.get("allowed_models") or config.get("allowedModels") or []
|
|
39
|
+
)
|
|
40
|
+
allowed_models = (
|
|
41
|
+
{str(item).strip() for item in raw_allowed_models if str(item).strip()}
|
|
42
|
+
if isinstance(raw_allowed_models, (list, tuple, set))
|
|
43
|
+
else set()
|
|
44
|
+
)
|
|
45
|
+
# 不把默认 model 自动加进白名单:白名单只在显式声明 models/allowedModels
|
|
46
|
+
# 时才存在(显式声明 = 收紧;只配默认 = 不限制 run 级覆盖)。
|
|
47
|
+
if allowed_models:
|
|
48
|
+
defaults["allowed_models"] = sorted(allowed_models)
|
|
49
|
+
if context.runtime_type != "codex":
|
|
50
|
+
return defaults
|
|
51
|
+
|
|
52
|
+
prompt = str(config.get("prompt") or "").strip()
|
|
53
|
+
task_prompt = str(config.get("task_prompt") or "").strip()
|
|
54
|
+
base_instructions = prompt
|
|
55
|
+
if task_prompt:
|
|
56
|
+
base_instructions = f"{prompt}\n\n{task_prompt}" if prompt else task_prompt
|
|
57
|
+
|
|
58
|
+
raw_sandbox = str(config.get("sandbox") or "read_only").strip().lower()
|
|
59
|
+
raw_approval = str(config.get("approval_mode") or "").strip().lower()
|
|
60
|
+
approval_profiles = {
|
|
61
|
+
"ask": ("workspace-write", "manual"),
|
|
62
|
+
"risk": ("workspace-write", "auto_review"),
|
|
63
|
+
"full": ("full-access", "deny_all"),
|
|
64
|
+
}
|
|
65
|
+
sandbox_profiles = {
|
|
66
|
+
"read_only": ("read-only", "deny_all"),
|
|
67
|
+
"read-only": ("read-only", "deny_all"),
|
|
68
|
+
"workspace_write": ("workspace-write", "deny_all"),
|
|
69
|
+
"workspace-write": ("workspace-write", "deny_all"),
|
|
70
|
+
"workspace_write_auto": ("workspace-write", "auto_review"),
|
|
71
|
+
"workspace-write-auto": ("workspace-write", "auto_review"),
|
|
72
|
+
"full_access": ("full-access", "deny_all"),
|
|
73
|
+
"full-access": ("full-access", "deny_all"),
|
|
74
|
+
}
|
|
75
|
+
if raw_approval in approval_profiles:
|
|
76
|
+
sandbox, approval = approval_profiles[raw_approval]
|
|
77
|
+
else:
|
|
78
|
+
sandbox, default_approval = sandbox_profiles.get(raw_sandbox, ("read-only", "deny_all"))
|
|
79
|
+
approval = raw_approval or default_approval
|
|
80
|
+
|
|
81
|
+
request_config: dict[str, Any] = {
|
|
82
|
+
"sandbox_read_only": sandbox == "read-only",
|
|
83
|
+
"sandbox": sandbox,
|
|
84
|
+
"approval_mode": approval,
|
|
85
|
+
"cwd": str(context.project_dir),
|
|
86
|
+
"summary": "auto",
|
|
87
|
+
"ephemeral": False,
|
|
88
|
+
}
|
|
89
|
+
if base_instructions:
|
|
90
|
+
request_config["base_instructions"] = base_instructions
|
|
91
|
+
defaults["config"] = request_config
|
|
92
|
+
return defaults
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def apply_runtime_start_request_defaults(
|
|
96
|
+
context: RuntimeLaunchContext,
|
|
97
|
+
request: StartRequest,
|
|
98
|
+
) -> StartRequest:
|
|
99
|
+
"""Apply deployment-owned launch policy to a direct runtime start.
|
|
100
|
+
|
|
101
|
+
AgentKernelWorker already projects these defaults before ``adapter.start``.
|
|
102
|
+
Foreground RunAgent, ``/run_sse`` and OpenAI-compatible routes also create
|
|
103
|
+
``StartRequest`` objects directly, so they must use the same projection or
|
|
104
|
+
a deployed Codex agent silently falls back to the generic Codex role.
|
|
105
|
+
|
|
106
|
+
Request-local config is internal runtime state, not caller-owned policy;
|
|
107
|
+
retain it for local Studio builds while using the manifest model as the
|
|
108
|
+
fallback (and as the fail-closed fallback for an explicit allow-list).
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
defaults = kernel_start_request_defaults(context)
|
|
112
|
+
default_model = str(defaults.get("model") or "").strip() or None
|
|
113
|
+
requested_model = str(request.model or "").strip()
|
|
114
|
+
allowed_models = {
|
|
115
|
+
str(item).strip()
|
|
116
|
+
for item in (defaults.get("allowed_models") or [])
|
|
117
|
+
if str(item).strip()
|
|
118
|
+
}
|
|
119
|
+
selected_model = (
|
|
120
|
+
requested_model
|
|
121
|
+
if requested_model and (not allowed_models or requested_model in allowed_models)
|
|
122
|
+
else default_model
|
|
123
|
+
)
|
|
124
|
+
config = {
|
|
125
|
+
**dict(defaults.get("config") or {}),
|
|
126
|
+
**dict(request.config or {}),
|
|
127
|
+
}
|
|
128
|
+
return request.model_copy(
|
|
129
|
+
update={
|
|
130
|
+
"agent_id": request.agent_id or defaults.get("agent_id"),
|
|
131
|
+
"model": selected_model,
|
|
132
|
+
"config": config,
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _manifest_mcp_overrides(config: dict[str, Any]) -> list[str]:
|
|
138
|
+
"""Translate declarative MCP bindings into native Codex config keys."""
|
|
139
|
+
|
|
140
|
+
overrides: list[str] = []
|
|
141
|
+
servers = config.get("mcp_servers") or []
|
|
142
|
+
if not isinstance(servers, (list, tuple)):
|
|
143
|
+
return overrides
|
|
144
|
+
for server in servers:
|
|
145
|
+
if not isinstance(server, dict):
|
|
146
|
+
continue
|
|
147
|
+
name = str(server.get("name") or "").strip()
|
|
148
|
+
url = str(server.get("url") or "").strip()
|
|
149
|
+
if not name or not url:
|
|
150
|
+
continue
|
|
151
|
+
overrides.append(f"mcp_servers.{name}.url={url}")
|
|
152
|
+
env_key = str(server.get("env_key") or "").strip()
|
|
153
|
+
if env_key:
|
|
154
|
+
overrides.append(f"mcp_servers.{name}.bearer_token_env_var={env_key}")
|
|
155
|
+
return overrides
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _create_codex(context: RuntimeLaunchContext) -> RuntimeAdapter:
|
|
159
|
+
client_factory = context.services.codex_client_factory or AsyncCodexClient
|
|
160
|
+
config = dict(context.config)
|
|
161
|
+
overrides = list(config.get("codex_overrides") or [])
|
|
162
|
+
manifest_mcp_overrides = _manifest_mcp_overrides(config)
|
|
163
|
+
overrides.extend(item for item in manifest_mcp_overrides if item not in overrides)
|
|
164
|
+
projected_config = kernel_start_request_defaults(context).get("config") or {}
|
|
165
|
+
if manifest_mcp_overrides and projected_config.get("sandbox") == "workspace-write":
|
|
166
|
+
network_override = "sandbox_workspace_write.network_access=true"
|
|
167
|
+
if network_override not in overrides:
|
|
168
|
+
overrides.append(network_override)
|
|
169
|
+
# Studio's default collaboration mode must expose Codex's structured
|
|
170
|
+
# request_user_input tool; the upstream feature is intentionally off by
|
|
171
|
+
# default outside Plan mode. This stays process-local to the isolated
|
|
172
|
+
# runtime and does not mutate the user's global Codex configuration.
|
|
173
|
+
interaction_override = "features.default_mode_request_user_input=true"
|
|
174
|
+
if interaction_override not in overrides:
|
|
175
|
+
overrides.append(interaction_override)
|
|
176
|
+
try:
|
|
177
|
+
from openai_codex import CodexConfig
|
|
178
|
+
|
|
179
|
+
base_cfg = CodexConfig()
|
|
180
|
+
if overrides:
|
|
181
|
+
base_cfg = dataclasses.replace(
|
|
182
|
+
base_cfg,
|
|
183
|
+
config_overrides=tuple(getattr(base_cfg, "config_overrides", ()) or ())
|
|
184
|
+
+ tuple(str(o) for o in overrides),
|
|
185
|
+
)
|
|
186
|
+
env = dict(getattr(base_cfg, "env", None) or {})
|
|
187
|
+
isolated_home = _isolated_codex_home(context.project_dir)
|
|
188
|
+
env.setdefault("CODEX_HOME", str(isolated_home))
|
|
189
|
+
# HOME 级隔离:codex app-server 还会按约定扫 ~/.agents/skills、
|
|
190
|
+
# ~/.claude/skills 等宿主目录,仅设 CODEX_HOME 挡不住。隔离 HOME 后这些
|
|
191
|
+
# 路径全部落在工作区内,宿主 skills/MCP/凭证不再进入 Agent 上下文。
|
|
192
|
+
# 设 KSADK_CODEX_ISOLATE_HOME=0 可关闭(调试用)。
|
|
193
|
+
if os.environ.get("KSADK_CODEX_ISOLATE_HOME", "1") != "0":
|
|
194
|
+
env.setdefault("HOME", str(isolated_home))
|
|
195
|
+
# 运行期解析出的凭证值(如 MCP bearer_token_env_var 所需)注入子进程环境
|
|
196
|
+
env.update({str(k): str(v) for k, v in (context.config.get("env") or {}).items()})
|
|
197
|
+
base_cfg = dataclasses.replace(base_cfg, env=env)
|
|
198
|
+
try:
|
|
199
|
+
client: Any = client_factory(config=base_cfg)
|
|
200
|
+
except TypeError:
|
|
201
|
+
# 自定义/测试工厂可能不接受 config 参数:退化为无参构造,
|
|
202
|
+
# config_overrides 事后注入(自定义工厂自行承担 env 隔离)。
|
|
203
|
+
client = client_factory()
|
|
204
|
+
if overrides:
|
|
205
|
+
_apply_codex_overrides(client, overrides)
|
|
206
|
+
except ImportError:
|
|
207
|
+
client: Any = client_factory()
|
|
208
|
+
if overrides:
|
|
209
|
+
_apply_codex_overrides(client, overrides)
|
|
210
|
+
timeout = context.config.get("turn_timeout_seconds")
|
|
211
|
+
request_defaults = kernel_start_request_defaults(context)
|
|
212
|
+
request_config = request_defaults.get("config") or {}
|
|
213
|
+
sandbox_read_only = (
|
|
214
|
+
bool(context.config["sandbox_read_only"])
|
|
215
|
+
if "sandbox_read_only" in context.config
|
|
216
|
+
else bool(request_config.get("sandbox_read_only", True))
|
|
217
|
+
)
|
|
218
|
+
return CodexRuntimeAdapter(
|
|
219
|
+
client,
|
|
220
|
+
sandbox_read_only=sandbox_read_only,
|
|
221
|
+
turn_timeout_seconds=float(timeout) if timeout is not None else None,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _isolated_codex_home(project_dir: Any) -> Path:
|
|
226
|
+
"""Studio 运行 Agent 使用工作区级隔离 CODEX_HOME。
|
|
227
|
+
|
|
228
|
+
避免 codex app-server 继承宿主环境(~/.codex / ~/.wework/codex)里的
|
|
229
|
+
skills、MCP 配置、插件与凭证,污染 Agent 上下文甚至泄漏宿主能力。
|
|
230
|
+
可用 KSADK_CODEX_HOME 显式覆盖。
|
|
231
|
+
"""
|
|
232
|
+
override = os.environ.get("KSADK_CODEX_HOME")
|
|
233
|
+
if override:
|
|
234
|
+
home = Path(override).expanduser()
|
|
235
|
+
home.mkdir(parents=True, exist_ok=True)
|
|
236
|
+
return home
|
|
237
|
+
|
|
238
|
+
# Source bundles are deliberately mounted read-only in managed runtimes.
|
|
239
|
+
# Keep the preferred workspace-local isolation for local development, but
|
|
240
|
+
# never make a Codex turn depend on being able to mutate that bundle.
|
|
241
|
+
workspace_home = Path(str(project_dir)) / ".agentkit" / "codex-home"
|
|
242
|
+
try:
|
|
243
|
+
workspace_home.mkdir(parents=True, exist_ok=True)
|
|
244
|
+
return workspace_home
|
|
245
|
+
except OSError:
|
|
246
|
+
pass
|
|
247
|
+
|
|
248
|
+
# The managed runtime already provides a per-workload writable state
|
|
249
|
+
# volume. Derive from its explicit directory first, then from the
|
|
250
|
+
# session-store path for backward-compatible images. /tmp is a final
|
|
251
|
+
# process-local fallback for custom read-only launchers.
|
|
252
|
+
state_dir = os.environ.get("KSADK_RUNTIME_STATE_DIR")
|
|
253
|
+
session_path = os.environ.get("KSADK_SESSION_PATH")
|
|
254
|
+
fallback_root = (
|
|
255
|
+
Path(state_dir)
|
|
256
|
+
if state_dir
|
|
257
|
+
else Path(session_path).expanduser().parent
|
|
258
|
+
if session_path
|
|
259
|
+
else Path(tempfile.gettempdir()) / "ksadk-runtime-state"
|
|
260
|
+
)
|
|
261
|
+
fallback_home = fallback_root / "codex-home"
|
|
262
|
+
fallback_home.mkdir(parents=True, exist_ok=True)
|
|
263
|
+
return fallback_home
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _apply_codex_overrides(client: Any, overrides: Any) -> None:
|
|
267
|
+
"""Append MCP server --config overrides to the client's CodexConfig."""
|
|
268
|
+
try:
|
|
269
|
+
from openai_codex import CodexConfig
|
|
270
|
+
except ImportError:
|
|
271
|
+
return
|
|
272
|
+
# ksadk AsyncCodexClient -> AsyncCodex -> inner AsyncCodexClient.config
|
|
273
|
+
inner_codex = getattr(client, "_codex", None)
|
|
274
|
+
inner_client = getattr(inner_codex, "_client", None) or inner_codex
|
|
275
|
+
cfg = getattr(inner_client, "config", None)
|
|
276
|
+
if cfg is None or not isinstance(cfg, CodexConfig):
|
|
277
|
+
return
|
|
278
|
+
base_overrides = tuple(getattr(cfg, "config_overrides", ()) or ())
|
|
279
|
+
new_overrides = tuple(str(o) for o in overrides if o not in base_overrides)
|
|
280
|
+
if not new_overrides:
|
|
281
|
+
return
|
|
282
|
+
new_cfg = dataclasses.replace(cfg, config_overrides=base_overrides + new_overrides)
|
|
283
|
+
setattr(inner_client, "config", new_cfg)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _create_framework_runner(context: RuntimeLaunchContext, runtime_type: str) -> BaseRunner:
|
|
287
|
+
try:
|
|
288
|
+
from ksadk.runners.patch_langchain import apply_patch
|
|
289
|
+
|
|
290
|
+
apply_patch()
|
|
291
|
+
except ImportError:
|
|
292
|
+
pass
|
|
293
|
+
detection = context.detection
|
|
294
|
+
if detection is None:
|
|
295
|
+
raise ValueError(f"{runtime_type} runtime requires framework detection")
|
|
296
|
+
if context.services.runner_factory is not None:
|
|
297
|
+
runner = context.services.runner_factory(detection, str(context.project_dir))
|
|
298
|
+
else:
|
|
299
|
+
# 复用 runners.factory.create_runner:它优先读 detection.runner_class
|
|
300
|
+
# (agentengine.yaml 的 runner_class 字段),否则按 detection.type 分发到
|
|
301
|
+
# ADKRunner/LangGraphRunner 等。直接硬编码 LangGraphRunner 会绕过自定义
|
|
302
|
+
# runner,导致 root_agent=None 的项目在 preflight 阶段误报"不是有效 CompiledGraph"。
|
|
303
|
+
from ksadk.runners.factory import create_runner
|
|
304
|
+
|
|
305
|
+
runner = create_runner(detection, str(context.project_dir))
|
|
306
|
+
if not isinstance(runner, BaseRunner):
|
|
307
|
+
raise TypeError(
|
|
308
|
+
f"{runtime_type} runner factory must return BaseRunner, got {type(runner).__name__}"
|
|
309
|
+
)
|
|
310
|
+
return runner
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _create_adk(context: RuntimeLaunchContext) -> RuntimeAdapter:
|
|
314
|
+
return ADKRuntimeAdapter(_create_framework_runner(context, "adk"))
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _create_langgraph(context: RuntimeLaunchContext) -> RuntimeAdapter:
|
|
318
|
+
return LangGraphRuntimeAdapter(_create_framework_runner(context, "langgraph"))
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def build_default_runtime_registry() -> RuntimeRegistry:
|
|
322
|
+
"""注册内置 Codex、ADK 和 LangGraph Runtime Factory。"""
|
|
323
|
+
|
|
324
|
+
registry = RuntimeRegistry()
|
|
325
|
+
registry.register("codex", _create_codex)
|
|
326
|
+
registry.register("adk", _create_adk)
|
|
327
|
+
registry.register("langgraph", _create_langgraph)
|
|
328
|
+
return registry
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def create_runtime_adapter(context: RuntimeLaunchContext) -> RuntimeAdapter:
|
|
332
|
+
"""通过唯一默认 Registry 创建 RuntimeAdapter。"""
|
|
333
|
+
|
|
334
|
+
return build_default_runtime_registry().create(context)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
__all__ = [
|
|
338
|
+
"apply_runtime_start_request_defaults",
|
|
339
|
+
"build_default_runtime_registry",
|
|
340
|
+
"create_runtime_adapter",
|
|
341
|
+
"kernel_start_request_defaults",
|
|
342
|
+
]
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
- ADK:**forward-only**,resume 经 ``invocation_id``;不支持 time-travel/fork。
|
|
7
7
|
- LangGraph:**time-travel**,resume 经 ``checkpoint_id``;可按 turn 回滚/fork。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
默认注册由 :mod:`ksadk.runtime.factory` 统一负责。
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -19,7 +19,6 @@ from ksadk.runtime.adapter import (
|
|
|
19
19
|
ResumePayload,
|
|
20
20
|
ResumeTarget,
|
|
21
21
|
RunHandle,
|
|
22
|
-
RuntimeRegistry,
|
|
23
22
|
)
|
|
24
23
|
from ksadk.runtime.runner_adapter import RunnerRuntimeAdapter
|
|
25
24
|
|
|
@@ -88,10 +87,14 @@ class LangGraphRuntimeAdapter(RunnerRuntimeAdapter):
|
|
|
88
87
|
# ``checkpoint_resume`` + ``framework_ref.langgraph.{checkpoint_id,thread_id}``。
|
|
89
88
|
return {
|
|
90
89
|
"checkpoint_resume": True,
|
|
90
|
+
"run_id": handle.run_id,
|
|
91
91
|
"resume_payload_provided": payload is not None,
|
|
92
92
|
"resume_interrupt_id": payload.call_id if payload else None,
|
|
93
93
|
"framework_ref": {
|
|
94
|
-
"langgraph": {
|
|
94
|
+
"langgraph": {
|
|
95
|
+
"checkpoint_id": target.id,
|
|
96
|
+
"thread_id": str(handle.native_ref.get("thread_id") or handle.session_id),
|
|
97
|
+
}
|
|
95
98
|
},
|
|
96
99
|
"input": payload.data if payload else None,
|
|
97
100
|
}
|
|
@@ -109,16 +112,7 @@ class LangGraphRuntimeAdapter(RunnerRuntimeAdapter):
|
|
|
109
112
|
)
|
|
110
113
|
|
|
111
114
|
|
|
112
|
-
def build_default_registry() -> RuntimeRegistry:
|
|
113
|
-
"""构造默认 RuntimeRegistry 并注册 ADK/LangGraph adapter 类型。"""
|
|
114
|
-
registry = RuntimeRegistry()
|
|
115
|
-
registry.register("adk", ADKRuntimeAdapter)
|
|
116
|
-
registry.register("langgraph", LangGraphRuntimeAdapter)
|
|
117
|
-
return registry
|
|
118
|
-
|
|
119
|
-
|
|
120
115
|
__all__ = [
|
|
121
116
|
"ADKRuntimeAdapter",
|
|
122
117
|
"LangGraphRuntimeAdapter",
|
|
123
|
-
"build_default_registry",
|
|
124
118
|
]
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""HostedTurnFinalizer —— 统一 Studio 与 canonical Runtime 的 turn 收尾(方案 §11.1 / P0)。
|
|
2
|
+
|
|
3
|
+
之前 Studio `StudioRunService` 和 canonical `conversation_execution._finalize_hosted_turn`
|
|
4
|
+
各自维护一套收尾逻辑(usage 回填、Context evidence、Memory Candidate、Trace),导致两条路径
|
|
5
|
+
漂移(如 scope_id 硬编码 local-user、Memory 重复写)。本组件统一负责:
|
|
6
|
+
|
|
7
|
+
- actual usage 回填进 ContextPlan(planned vs actual 偏差可观测)。
|
|
8
|
+
- capability mismatch 证据检测(方案 §6.1)。
|
|
9
|
+
- Memory Candidate 抽取 + flush(据 MemoryPolicy,同一 Turn 不重复写)。
|
|
10
|
+
- 失败降级(best-effort,绝不阻断主链路,方案 §10.8)。
|
|
11
|
+
|
|
12
|
+
Studio 与 canonical Runtime 都调用本组件,不再各自实现收尾。
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from typing import Any, Callable, Mapping
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _memory_extract_enabled() -> bool:
|
|
23
|
+
return str(os.environ.get("KSADK_MEMORY_FLUSH_ENABLED", "")).strip().lower() in (
|
|
24
|
+
"1",
|
|
25
|
+
"true",
|
|
26
|
+
"yes",
|
|
27
|
+
"on",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _extract_input_tokens(usage: Mapping[str, Any] | None) -> int | None:
|
|
32
|
+
"""从 runtime usage 取 input tokens(兼容 OpenAI/Anthropic 字段)。"""
|
|
33
|
+
if not isinstance(usage, Mapping):
|
|
34
|
+
return None
|
|
35
|
+
for key in ("input_tokens", "prompt_tokens", "input_token_count"):
|
|
36
|
+
v = usage.get(key)
|
|
37
|
+
if isinstance(v, (int, float)) and v:
|
|
38
|
+
return int(v)
|
|
39
|
+
details = usage.get("input_token_details") or usage.get("input_tokens_details")
|
|
40
|
+
if isinstance(details, Mapping):
|
|
41
|
+
total = details.get("total") or details.get("input_tokens")
|
|
42
|
+
if isinstance(total, (int, float)) and total:
|
|
43
|
+
return int(total)
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(frozen=True)
|
|
48
|
+
class FinalizeContext:
|
|
49
|
+
"""turn 收尾所需的上下文(Studio 与 canonical 共用)。"""
|
|
50
|
+
|
|
51
|
+
session_id: str
|
|
52
|
+
invocation_id: str
|
|
53
|
+
user_id: str
|
|
54
|
+
context_plan: dict[str, Any] | None
|
|
55
|
+
shadow_context_plan: dict[str, Any] | None
|
|
56
|
+
usage: Mapping[str, Any] | None
|
|
57
|
+
runtime_type: str
|
|
58
|
+
agent_id: str = ""
|
|
59
|
+
prompt_integration_mode: str = ""
|
|
60
|
+
session_events: Any = None # 已取的 turn events(避免重复读 store)
|
|
61
|
+
memory_write_rollout: str = ""
|
|
62
|
+
memory_enabled: bool | None = None
|
|
63
|
+
memory_recall_enabled: bool | None = None
|
|
64
|
+
memory_write_mode: str = "candidate"
|
|
65
|
+
flush_before_compaction: bool = True
|
|
66
|
+
provider_ref: str = "local-default"
|
|
67
|
+
emit_event: Any = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def finalize_hosted_turn(
|
|
71
|
+
ctx: FinalizeContext,
|
|
72
|
+
*,
|
|
73
|
+
session_service_provider: Callable[[], Any] | None = None,
|
|
74
|
+
) -> None:
|
|
75
|
+
"""统一 hosted turn 收尾(方案 §11.1 步骤 15-16 / P0 收敛)。
|
|
76
|
+
|
|
77
|
+
Studio 与 canonical Runtime 都调用本函数,不再各自实现。失败不阻断主链路。
|
|
78
|
+
"""
|
|
79
|
+
# 1. usage 回填进 ContextPlan
|
|
80
|
+
plan = ctx.context_plan
|
|
81
|
+
if isinstance(plan, dict):
|
|
82
|
+
try:
|
|
83
|
+
actual = _extract_input_tokens(ctx.usage)
|
|
84
|
+
if actual is not None:
|
|
85
|
+
plan["runtime_reported_input_tokens"] = actual
|
|
86
|
+
except Exception: # noqa: BLE001
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
# 2. capability mismatch 证据检测
|
|
90
|
+
try:
|
|
91
|
+
_maybe_detect_capability_mismatch(ctx)
|
|
92
|
+
except Exception: # noqa: BLE001
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
# 3. Memory Candidate 抽取 + flush
|
|
96
|
+
# 统一解析 Memory 运行策略(方案 §2:ResolvedMemoryPolicy 统一入口)
|
|
97
|
+
from ksadk.memory.resolved_policy import resolve_memory_policy
|
|
98
|
+
|
|
99
|
+
policy = resolve_memory_policy(
|
|
100
|
+
memory_enabled=ctx.memory_enabled,
|
|
101
|
+
recall_enabled=ctx.memory_recall_enabled,
|
|
102
|
+
write_rollout=ctx.memory_write_rollout,
|
|
103
|
+
write_mode=ctx.memory_write_mode,
|
|
104
|
+
flush_before_compaction=ctx.flush_before_compaction,
|
|
105
|
+
provider_ref=ctx.provider_ref,
|
|
106
|
+
)
|
|
107
|
+
# shadow:生成 Candidate 和审计事件,但不提交 Provider(方案 §2)
|
|
108
|
+
# off/不启用:直接返回,连候选都不提取
|
|
109
|
+
if not policy.should_extract_candidates:
|
|
110
|
+
return
|
|
111
|
+
try:
|
|
112
|
+
from ksadk.memory.coordinator import MemoryCoordinator
|
|
113
|
+
from ksadk.memory.events import (
|
|
114
|
+
candidate_created,
|
|
115
|
+
candidate_rejected,
|
|
116
|
+
flush_completed,
|
|
117
|
+
flush_failed,
|
|
118
|
+
)
|
|
119
|
+
from ksadk.memory.extraction import propose_memory_candidates
|
|
120
|
+
from ksadk.memory.provider_resolver import resolve_memory_provider
|
|
121
|
+
|
|
122
|
+
turn_events = ctx.session_events
|
|
123
|
+
if turn_events is None and session_service_provider is not None:
|
|
124
|
+
try:
|
|
125
|
+
service = session_service_provider()
|
|
126
|
+
all_events = await service.get_events(ctx.session_id)
|
|
127
|
+
turn_events = [
|
|
128
|
+
e for e in all_events if getattr(e, "invocation_id", "") == ctx.invocation_id
|
|
129
|
+
]
|
|
130
|
+
except Exception: # noqa: BLE001
|
|
131
|
+
turn_events = None
|
|
132
|
+
if not turn_events:
|
|
133
|
+
return
|
|
134
|
+
from ksadk.memory.coordinator import agent_user_scope_id
|
|
135
|
+
|
|
136
|
+
candidates = propose_memory_candidates(
|
|
137
|
+
list(turn_events),
|
|
138
|
+
scope="user",
|
|
139
|
+
scope_id=agent_user_scope_id(
|
|
140
|
+
agent_id=ctx.agent_id,
|
|
141
|
+
user_id=ctx.user_id,
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
# explicit_only:只保留用户明确要求记住的内容(方案 §2)
|
|
145
|
+
if policy.is_explicit_only:
|
|
146
|
+
candidates = [c for c in candidates if c.reason.startswith("explicit_user_")]
|
|
147
|
+
provider_name = ctx.provider_ref or "local-default"
|
|
148
|
+
rollout = policy.write_rollout
|
|
149
|
+
if candidates:
|
|
150
|
+
# shadow:生成候选和审计事件,但不提交 Provider(方案 §2)
|
|
151
|
+
if policy.should_flush:
|
|
152
|
+
provider = resolve_memory_provider(ctx.provider_ref)
|
|
153
|
+
from ksadk.memory.provider_adapter import adapt_as_memory_provider
|
|
154
|
+
|
|
155
|
+
provider = adapt_as_memory_provider(provider)
|
|
156
|
+
coordinator = MemoryCoordinator(provider)
|
|
157
|
+
result = coordinator.flush_candidates(candidates)
|
|
158
|
+
else:
|
|
159
|
+
# shadow:不提交,构造一个不落库的 result
|
|
160
|
+
from ksadk.memory.coordinator import FlushResult
|
|
161
|
+
|
|
162
|
+
result = FlushResult(
|
|
163
|
+
status="shadow",
|
|
164
|
+
proposed=len(candidates),
|
|
165
|
+
committed=0,
|
|
166
|
+
rejected=0,
|
|
167
|
+
)
|
|
168
|
+
_emit(
|
|
169
|
+
ctx,
|
|
170
|
+
candidate_created(
|
|
171
|
+
run_id=ctx.invocation_id,
|
|
172
|
+
session_id=ctx.session_id,
|
|
173
|
+
provider=provider_name,
|
|
174
|
+
rollout=rollout,
|
|
175
|
+
count=len(candidates),
|
|
176
|
+
),
|
|
177
|
+
)
|
|
178
|
+
if result.rejected > 0:
|
|
179
|
+
_emit(
|
|
180
|
+
ctx,
|
|
181
|
+
candidate_rejected(
|
|
182
|
+
run_id=ctx.invocation_id,
|
|
183
|
+
session_id=ctx.session_id,
|
|
184
|
+
provider=provider_name,
|
|
185
|
+
rollout=rollout,
|
|
186
|
+
count=result.rejected,
|
|
187
|
+
),
|
|
188
|
+
)
|
|
189
|
+
# 检查 flush 结果:partial/failed 时发 flush.failed(方案 §3)
|
|
190
|
+
if result.status in ("succeeded", "shadow"):
|
|
191
|
+
_emit(
|
|
192
|
+
ctx,
|
|
193
|
+
flush_completed(
|
|
194
|
+
run_id=ctx.invocation_id,
|
|
195
|
+
session_id=ctx.session_id,
|
|
196
|
+
provider=provider_name,
|
|
197
|
+
rollout=rollout,
|
|
198
|
+
proposed=result.proposed,
|
|
199
|
+
committed=result.committed,
|
|
200
|
+
rejected=result.rejected,
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
# partial / failed → flush.failed
|
|
205
|
+
_emit(
|
|
206
|
+
ctx,
|
|
207
|
+
flush_failed(
|
|
208
|
+
run_id=ctx.invocation_id,
|
|
209
|
+
session_id=ctx.session_id,
|
|
210
|
+
provider=provider_name,
|
|
211
|
+
rollout=rollout,
|
|
212
|
+
error_code=f"flush_{result.status}",
|
|
213
|
+
error_message=f"{result.status}: {len(result.errors)} errors",
|
|
214
|
+
retryable=True,
|
|
215
|
+
),
|
|
216
|
+
)
|
|
217
|
+
except Exception as exc: # noqa: BLE001
|
|
218
|
+
_emit(
|
|
219
|
+
ctx,
|
|
220
|
+
flush_failed(
|
|
221
|
+
run_id=ctx.invocation_id,
|
|
222
|
+
session_id=ctx.session_id,
|
|
223
|
+
provider="sqlite",
|
|
224
|
+
rollout=ctx.memory_write_rollout or "enabled",
|
|
225
|
+
error_code="flush_exception",
|
|
226
|
+
error_message=str(exc)[:200],
|
|
227
|
+
retryable=True,
|
|
228
|
+
),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _maybe_detect_capability_mismatch(ctx: FinalizeContext) -> None:
|
|
233
|
+
"""证据驱动的 capability mismatch 熔断(方案 §6.1)。"""
|
|
234
|
+
from ksadk.context_engine.capabilities import (
|
|
235
|
+
capabilities_for_runtime_type,
|
|
236
|
+
detect_capability_mismatch,
|
|
237
|
+
is_capability_circuit_open,
|
|
238
|
+
mark_capability_mismatch,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
shadow = ctx.shadow_context_plan or {}
|
|
242
|
+
runtime_type = str(shadow.get("runtime_type") or "")
|
|
243
|
+
if not runtime_type:
|
|
244
|
+
return
|
|
245
|
+
if is_capability_circuit_open(runtime_type=runtime_type):
|
|
246
|
+
return
|
|
247
|
+
caps = capabilities_for_runtime_type(runtime_type)
|
|
248
|
+
has_usage = isinstance(ctx.usage, Mapping) and bool(ctx.usage)
|
|
249
|
+
reason = detect_capability_mismatch(
|
|
250
|
+
declared=caps,
|
|
251
|
+
runtime_reported_usage=has_usage if has_usage else False,
|
|
252
|
+
)
|
|
253
|
+
if reason and "runtime_reported" in reason:
|
|
254
|
+
mark_capability_mismatch(runtime_type=runtime_type)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
__all__ = ["FinalizeContext", "finalize_hosted_turn"]
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# 内存事件收集器(best-effort,不阻断主链路)
|
|
261
|
+
def _emit(ctx: Any, event: Any) -> None:
|
|
262
|
+
"""发送 Memory 事件到 ctx.emit_event(方案 §3)。"""
|
|
263
|
+
sink = getattr(ctx, "emit_event", None)
|
|
264
|
+
if callable(sink):
|
|
265
|
+
try:
|
|
266
|
+
sink(event.to_dict())
|
|
267
|
+
except Exception: # noqa: BLE001
|
|
268
|
+
pass
|