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
ksadk/studio/operations.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json
|
|
7
|
+
import logging
|
|
7
8
|
from datetime import datetime, timezone
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Awaitable, Callable, cast
|
|
@@ -20,6 +21,8 @@ from ksadk.studio.contracts import (
|
|
|
20
21
|
from ksadk.studio.errors import StudioError, not_found
|
|
21
22
|
from ksadk.studio.workspace import Workspace
|
|
22
23
|
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
23
26
|
|
|
24
27
|
class OperationManager:
|
|
25
28
|
def __init__(self, workspace: Workspace) -> None:
|
|
@@ -33,7 +36,8 @@ class OperationManager:
|
|
|
33
36
|
kind: OperationKind,
|
|
34
37
|
resource_id: str,
|
|
35
38
|
idempotency_key: str,
|
|
36
|
-
|
|
39
|
+
metadata: dict | None = None,
|
|
40
|
+
runner: Callable[[str], Awaitable[object]],
|
|
37
41
|
) -> Operation:
|
|
38
42
|
existing = self._find_by_idempotency_key(idempotency_key)
|
|
39
43
|
if existing is not None:
|
|
@@ -42,6 +46,7 @@ class OperationManager:
|
|
|
42
46
|
id=f"op_{uuid4().hex}",
|
|
43
47
|
kind=kind,
|
|
44
48
|
resource_id=resource_id,
|
|
49
|
+
metadata=metadata or {},
|
|
45
50
|
)
|
|
46
51
|
self._write(operation, [], idempotency_key)
|
|
47
52
|
self.append(operation.id, "operation.queued", {"kind": kind})
|
|
@@ -57,14 +62,14 @@ class OperationManager:
|
|
|
57
62
|
async def _run(
|
|
58
63
|
self,
|
|
59
64
|
operation_id: str,
|
|
60
|
-
runner: Callable[[], Awaitable[object]],
|
|
65
|
+
runner: Callable[[str], Awaitable[object]],
|
|
61
66
|
) -> None:
|
|
62
67
|
operation = self.get(operation_id)
|
|
63
68
|
operation.status = OperationStatus.RUNNING
|
|
64
69
|
self._save_record(operation)
|
|
65
70
|
self.append(operation_id, "operation.started", {})
|
|
66
71
|
try:
|
|
67
|
-
result = await runner()
|
|
72
|
+
result = await runner(operation_id)
|
|
68
73
|
result_id = getattr(result, "id", None)
|
|
69
74
|
if result_id:
|
|
70
75
|
operation.resource_id = str(result_id)
|
|
@@ -91,12 +96,22 @@ class OperationManager:
|
|
|
91
96
|
operation.completed_at = datetime.now(timezone.utc)
|
|
92
97
|
self._save_record(operation)
|
|
93
98
|
self.append(operation_id, "operation.failed", operation.error)
|
|
94
|
-
except Exception:
|
|
99
|
+
except Exception as exc:
|
|
100
|
+
# Keep the browser response generic so an exception cannot leak a
|
|
101
|
+
# credential, but retain the traceback in the local Studio log for
|
|
102
|
+
# an operator to diagnose a failed deployment.
|
|
103
|
+
logger.exception("Studio operation failed: operation_id=%s", operation_id)
|
|
95
104
|
operation.status = OperationStatus.FAILED
|
|
96
105
|
operation.error = {
|
|
97
106
|
"code": "INTERNAL_ERROR",
|
|
98
107
|
"message": "本地操作执行失败",
|
|
108
|
+
"exceptionType": type(exc).__name__,
|
|
99
109
|
}
|
|
110
|
+
# TypeError carries only Python call-shape information and is safe
|
|
111
|
+
# to surface to the local operator. Do not expose arbitrary
|
|
112
|
+
# exception text: it may include provider request data.
|
|
113
|
+
if isinstance(exc, TypeError):
|
|
114
|
+
operation.error["exceptionMessage"] = str(exc)
|
|
100
115
|
operation.completed_at = datetime.now(timezone.utc)
|
|
101
116
|
self._save_record(operation)
|
|
102
117
|
self.append(operation_id, "operation.failed", operation.error)
|
|
@@ -105,6 +120,18 @@ class OperationManager:
|
|
|
105
120
|
operation, _, _ = self._read(operation_id)
|
|
106
121
|
return operation
|
|
107
122
|
|
|
123
|
+
def list(self, *, kind: OperationKind | None = None) -> list[Operation]:
|
|
124
|
+
directory = self.workspace.resolve(".agentkit/operations")
|
|
125
|
+
operations: list[Operation] = []
|
|
126
|
+
for path in directory.glob("op_*.json"):
|
|
127
|
+
try:
|
|
128
|
+
operation = self.get(path.stem)
|
|
129
|
+
except StudioError:
|
|
130
|
+
continue
|
|
131
|
+
if kind is None or operation.kind == kind:
|
|
132
|
+
operations.append(operation)
|
|
133
|
+
return sorted(operations, key=lambda item: item.created_at, reverse=True)
|
|
134
|
+
|
|
108
135
|
def events(self, operation_id: str, *, after: int = 0) -> list[OperationEvent]:
|
|
109
136
|
_, events, _ = self._read(operation_id)
|
|
110
137
|
return [event for event in events if event.id > after]
|
|
@@ -133,7 +160,12 @@ class OperationManager:
|
|
|
133
160
|
task = self._tasks.get(operation_id)
|
|
134
161
|
if task is not None:
|
|
135
162
|
task.cancel()
|
|
136
|
-
|
|
163
|
+
if operation.status == OperationStatus.QUEUED:
|
|
164
|
+
operation.status = OperationStatus.CANCELLED
|
|
165
|
+
operation.completed_at = datetime.now(timezone.utc)
|
|
166
|
+
self._save_record(operation)
|
|
167
|
+
self.append(operation_id, "operation.cancelled", {})
|
|
168
|
+
return self.get(operation_id)
|
|
137
169
|
|
|
138
170
|
async def wait(self, operation_id: str, *, timeout: float = 30) -> Operation:
|
|
139
171
|
deadline = asyncio.get_running_loop().time() + timeout
|
ksadk/studio/otel_trace.py
CHANGED
|
@@ -149,6 +149,270 @@ def _enum_string(value: Any) -> str:
|
|
|
149
149
|
return str(getattr(value, "value", value))
|
|
150
150
|
|
|
151
151
|
|
|
152
|
+
def _token_value(attributes: dict[str, Any], *keys: str) -> int | None:
|
|
153
|
+
"""Read one non-negative token counter from known OTLP attribute names."""
|
|
154
|
+
|
|
155
|
+
for key in keys:
|
|
156
|
+
value = attributes.get(key)
|
|
157
|
+
if value is None or isinstance(value, bool):
|
|
158
|
+
continue
|
|
159
|
+
try:
|
|
160
|
+
normalized = int(value)
|
|
161
|
+
except (TypeError, ValueError):
|
|
162
|
+
continue
|
|
163
|
+
if normalized >= 0:
|
|
164
|
+
return normalized
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _usage_from_attributes(attributes: dict[str, Any]) -> dict[str, Any]:
|
|
169
|
+
"""Normalize AgentKit and standard GenAI usage without trusting a side flag."""
|
|
170
|
+
|
|
171
|
+
input_tokens = _token_value(
|
|
172
|
+
attributes,
|
|
173
|
+
"gen_ai.usage.input_tokens",
|
|
174
|
+
"agentkit.usage.input_tokens",
|
|
175
|
+
)
|
|
176
|
+
output_tokens = _token_value(
|
|
177
|
+
attributes,
|
|
178
|
+
"gen_ai.usage.output_tokens",
|
|
179
|
+
"agentkit.usage.output_tokens",
|
|
180
|
+
)
|
|
181
|
+
total_tokens = _token_value(
|
|
182
|
+
attributes,
|
|
183
|
+
"agentkit.usage.total_tokens",
|
|
184
|
+
"gen_ai.usage.total_tokens",
|
|
185
|
+
)
|
|
186
|
+
cached_input_tokens = _token_value(
|
|
187
|
+
attributes,
|
|
188
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
189
|
+
"gen_ai.usage.cached_input_tokens",
|
|
190
|
+
"llm.usage.cache_read.input_tokens",
|
|
191
|
+
"agentkit.usage.cached_input_tokens",
|
|
192
|
+
)
|
|
193
|
+
reasoning_output_tokens = _token_value(
|
|
194
|
+
attributes,
|
|
195
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
196
|
+
"gen_ai.usage.reasoning_tokens",
|
|
197
|
+
"gen_ai.usage.reasoning_output_tokens",
|
|
198
|
+
"llm.usage.reasoning_tokens",
|
|
199
|
+
"agentkit.usage.reasoning_output_tokens",
|
|
200
|
+
)
|
|
201
|
+
if total_tokens is None and input_tokens is not None and output_tokens is not None:
|
|
202
|
+
total_tokens = input_tokens + output_tokens
|
|
203
|
+
reported = any(
|
|
204
|
+
value is not None
|
|
205
|
+
for value in (
|
|
206
|
+
input_tokens,
|
|
207
|
+
output_tokens,
|
|
208
|
+
total_tokens,
|
|
209
|
+
cached_input_tokens,
|
|
210
|
+
reasoning_output_tokens,
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
source = attributes.get("agentkit.usage.source")
|
|
214
|
+
if not source and reported:
|
|
215
|
+
source = "gen_ai.usage"
|
|
216
|
+
return {
|
|
217
|
+
"inputTokens": input_tokens,
|
|
218
|
+
"outputTokens": output_tokens,
|
|
219
|
+
"totalTokens": total_tokens,
|
|
220
|
+
"cachedInputTokens": cached_input_tokens,
|
|
221
|
+
"reasoningOutputTokens": reasoning_output_tokens,
|
|
222
|
+
"usageCompleteness": {
|
|
223
|
+
"inputTokens": input_tokens is not None,
|
|
224
|
+
"outputTokens": output_tokens is not None,
|
|
225
|
+
"totalTokens": total_tokens is not None,
|
|
226
|
+
"cachedInputTokens": cached_input_tokens is not None,
|
|
227
|
+
"reasoningOutputTokens": reasoning_output_tokens is not None,
|
|
228
|
+
},
|
|
229
|
+
"usageReported": reported,
|
|
230
|
+
"usageSource": source,
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def _aggregate_span_usage(spans: Iterable[dict[str, Any]]) -> dict[str, Any]:
|
|
235
|
+
"""Aggregate billing spans and collapse only exact compatibility wrappers."""
|
|
236
|
+
|
|
237
|
+
span_list = list(spans)
|
|
238
|
+
usage_by_id: dict[str, dict[str, Any]] = {}
|
|
239
|
+
children_by_parent: dict[str, list[str]] = {}
|
|
240
|
+
parent_by_id: dict[str, str] = {}
|
|
241
|
+
anonymous_usages: list[dict[str, Any]] = []
|
|
242
|
+
for span in span_list:
|
|
243
|
+
span_id = str(span.get("spanId") or "")
|
|
244
|
+
parent_id = str(span.get("parentSpanId") or "")
|
|
245
|
+
usage = _usage_from_attributes(_decoded_attributes(span.get("attributes", [])))
|
|
246
|
+
if span_id:
|
|
247
|
+
usage_by_id[span_id] = usage
|
|
248
|
+
parent_by_id[span_id] = parent_id
|
|
249
|
+
if parent_id:
|
|
250
|
+
children_by_parent.setdefault(parent_id, []).append(span_id)
|
|
251
|
+
elif usage["usageReported"]:
|
|
252
|
+
anonymous_usages.append(usage)
|
|
253
|
+
|
|
254
|
+
usage_fields = (
|
|
255
|
+
"inputTokens",
|
|
256
|
+
"outputTokens",
|
|
257
|
+
"totalTokens",
|
|
258
|
+
"cachedInputTokens",
|
|
259
|
+
"reasoningOutputTokens",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def empty_aggregate() -> dict[str, Any]:
|
|
263
|
+
return {
|
|
264
|
+
**{key: None for key in usage_fields},
|
|
265
|
+
"usageCompleteness": {key: False for key in usage_fields},
|
|
266
|
+
"billingSpanCount": 0,
|
|
267
|
+
"usageReported": False,
|
|
268
|
+
"usageSource": None,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
def billed_usage(usage: dict[str, Any]) -> dict[str, Any]:
|
|
272
|
+
return {
|
|
273
|
+
**{key: usage[key] for key in usage_fields},
|
|
274
|
+
"usageCompleteness": dict(usage["usageCompleteness"]),
|
|
275
|
+
"billingSpanCount": 1,
|
|
276
|
+
"usageReported": True,
|
|
277
|
+
"usageSource": usage["usageSource"],
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
def combine(parts: Iterable[dict[str, Any]]) -> dict[str, Any]:
|
|
281
|
+
billed_parts = [part for part in parts if part["billingSpanCount"] > 0]
|
|
282
|
+
if not billed_parts:
|
|
283
|
+
return empty_aggregate()
|
|
284
|
+
aggregate = empty_aggregate()
|
|
285
|
+
aggregate["billingSpanCount"] = sum(part["billingSpanCount"] for part in billed_parts)
|
|
286
|
+
aggregate["usageReported"] = True
|
|
287
|
+
aggregate["usageSource"] = next(
|
|
288
|
+
(part["usageSource"] for part in billed_parts if part["usageSource"]),
|
|
289
|
+
"gen_ai.usage",
|
|
290
|
+
)
|
|
291
|
+
for key in usage_fields:
|
|
292
|
+
values = [part[key] for part in billed_parts if part[key] is not None]
|
|
293
|
+
aggregate[key] = sum(values) if values else None
|
|
294
|
+
aggregate["usageCompleteness"][key] = all(
|
|
295
|
+
part["usageCompleteness"][key] for part in billed_parts
|
|
296
|
+
)
|
|
297
|
+
return aggregate
|
|
298
|
+
|
|
299
|
+
def is_compatibility_wrapper(
|
|
300
|
+
own_usage: dict[str, Any], descendant_usage: dict[str, Any]
|
|
301
|
+
) -> bool:
|
|
302
|
+
if descendant_usage["billingSpanCount"] == 0:
|
|
303
|
+
return False
|
|
304
|
+
if own_usage["inputTokens"] is None or own_usage["outputTokens"] is None:
|
|
305
|
+
return False
|
|
306
|
+
return all(
|
|
307
|
+
descendant_usage["usageCompleteness"][key] and descendant_usage[key] == own_usage[key]
|
|
308
|
+
for key in ("inputTokens", "outputTokens")
|
|
309
|
+
) and all(
|
|
310
|
+
own_usage[key] is None
|
|
311
|
+
or (
|
|
312
|
+
descendant_usage["usageCompleteness"][key]
|
|
313
|
+
and descendant_usage[key] == own_usage[key]
|
|
314
|
+
)
|
|
315
|
+
for key in ("inputTokens", "outputTokens", "totalTokens")
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
memo: dict[str, dict[str, Any]] = {}
|
|
319
|
+
|
|
320
|
+
def aggregate_subtree(span_id: str, visiting: set[str] | None = None) -> dict[str, Any]:
|
|
321
|
+
if span_id in memo:
|
|
322
|
+
return memo[span_id]
|
|
323
|
+
active = set() if visiting is None else visiting
|
|
324
|
+
if span_id in active:
|
|
325
|
+
return empty_aggregate()
|
|
326
|
+
active.add(span_id)
|
|
327
|
+
descendants = combine(
|
|
328
|
+
aggregate_subtree(child_id, active) for child_id in children_by_parent.get(span_id, [])
|
|
329
|
+
)
|
|
330
|
+
active.remove(span_id)
|
|
331
|
+
own_usage = usage_by_id[span_id]
|
|
332
|
+
if not own_usage["usageReported"]:
|
|
333
|
+
result = descendants
|
|
334
|
+
elif is_compatibility_wrapper(own_usage, descendants):
|
|
335
|
+
result = descendants
|
|
336
|
+
for key in usage_fields:
|
|
337
|
+
if own_usage[key] is not None:
|
|
338
|
+
result[key] = own_usage[key]
|
|
339
|
+
result["usageCompleteness"][key] = True
|
|
340
|
+
else:
|
|
341
|
+
result = combine((billed_usage(own_usage), descendants))
|
|
342
|
+
memo[span_id] = result
|
|
343
|
+
return result
|
|
344
|
+
|
|
345
|
+
roots = [
|
|
346
|
+
span_id
|
|
347
|
+
for span_id in usage_by_id
|
|
348
|
+
if not parent_by_id[span_id] or parent_by_id[span_id] not in usage_by_id
|
|
349
|
+
]
|
|
350
|
+
aggregate = combine(aggregate_subtree(span_id) for span_id in roots)
|
|
351
|
+
for span_id in usage_by_id:
|
|
352
|
+
if span_id not in memo:
|
|
353
|
+
aggregate = combine((aggregate, aggregate_subtree(span_id)))
|
|
354
|
+
aggregate = combine((aggregate, *(billed_usage(usage) for usage in anonymous_usages)))
|
|
355
|
+
if aggregate["billingSpanCount"] == 0:
|
|
356
|
+
return _usage_from_attributes({})
|
|
357
|
+
if not aggregate["usageCompleteness"]["totalTokens"]:
|
|
358
|
+
aggregate["totalTokens"] = None
|
|
359
|
+
aggregate.pop("billingSpanCount", None)
|
|
360
|
+
return aggregate
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _merge_usage(primary: dict[str, Any], fallback: dict[str, Any]) -> dict[str, Any]:
|
|
364
|
+
"""Keep explicit root counters and fill only absent fields from leaf usage."""
|
|
365
|
+
|
|
366
|
+
merged: dict[str, Any] = {
|
|
367
|
+
key: primary[key] if primary[key] is not None else fallback[key]
|
|
368
|
+
for key in (
|
|
369
|
+
"inputTokens",
|
|
370
|
+
"outputTokens",
|
|
371
|
+
"cachedInputTokens",
|
|
372
|
+
"reasoningOutputTokens",
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
completeness = {
|
|
376
|
+
key: (
|
|
377
|
+
primary["usageCompleteness"][key]
|
|
378
|
+
if primary[key] is not None
|
|
379
|
+
else fallback["usageCompleteness"][key]
|
|
380
|
+
)
|
|
381
|
+
for key in (
|
|
382
|
+
"inputTokens",
|
|
383
|
+
"outputTokens",
|
|
384
|
+
"cachedInputTokens",
|
|
385
|
+
"reasoningOutputTokens",
|
|
386
|
+
)
|
|
387
|
+
}
|
|
388
|
+
if primary["totalTokens"] is not None:
|
|
389
|
+
merged["totalTokens"] = primary["totalTokens"]
|
|
390
|
+
completeness["totalTokens"] = primary["usageCompleteness"]["totalTokens"]
|
|
391
|
+
elif (
|
|
392
|
+
merged["inputTokens"] is not None
|
|
393
|
+
and merged["outputTokens"] is not None
|
|
394
|
+
and completeness["inputTokens"]
|
|
395
|
+
and completeness["outputTokens"]
|
|
396
|
+
):
|
|
397
|
+
merged["totalTokens"] = merged["inputTokens"] + merged["outputTokens"]
|
|
398
|
+
completeness["totalTokens"] = True
|
|
399
|
+
elif primary["inputTokens"] is None and primary["outputTokens"] is None:
|
|
400
|
+
merged["totalTokens"] = (
|
|
401
|
+
fallback["totalTokens"] if fallback["usageCompleteness"]["totalTokens"] else None
|
|
402
|
+
)
|
|
403
|
+
completeness["totalTokens"] = fallback["usageCompleteness"]["totalTokens"]
|
|
404
|
+
else:
|
|
405
|
+
merged["totalTokens"] = None
|
|
406
|
+
completeness["totalTokens"] = False
|
|
407
|
+
reported = primary["usageReported"] or fallback["usageReported"]
|
|
408
|
+
return {
|
|
409
|
+
**merged,
|
|
410
|
+
"usageCompleteness": completeness,
|
|
411
|
+
"usageReported": reported,
|
|
412
|
+
"usageSource": primary["usageSource"] or fallback["usageSource"],
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
|
|
152
416
|
class OtlpTraceStore:
|
|
153
417
|
"""Persist one canonical OTLP JSON document per local Trace."""
|
|
154
418
|
|
|
@@ -188,37 +452,15 @@ class OtlpTraceStore:
|
|
|
188
452
|
root_attributes = _decoded_attributes(root.get("attributes", []))
|
|
189
453
|
canonical = root["traceId"]
|
|
190
454
|
duration = root_attributes.get("agentkit.duration.ms")
|
|
191
|
-
|
|
455
|
+
root_usage = _usage_from_attributes(root_attributes)
|
|
456
|
+
leaf_usage = _aggregate_span_usage(
|
|
457
|
+
span for span in spans if span.get("spanId") != root.get("spanId")
|
|
458
|
+
)
|
|
459
|
+
usage = _merge_usage(root_usage, leaf_usage)
|
|
192
460
|
metrics = {
|
|
193
461
|
"durationMs": int(duration) if duration is not None else None,
|
|
194
462
|
"durationSource": root_attributes.get("agentkit.duration.source"),
|
|
195
|
-
|
|
196
|
-
int(root_attributes["gen_ai.usage.input_tokens"])
|
|
197
|
-
if usage_reported and "gen_ai.usage.input_tokens" in root_attributes
|
|
198
|
-
else None
|
|
199
|
-
),
|
|
200
|
-
"outputTokens": (
|
|
201
|
-
int(root_attributes["gen_ai.usage.output_tokens"])
|
|
202
|
-
if usage_reported and "gen_ai.usage.output_tokens" in root_attributes
|
|
203
|
-
else None
|
|
204
|
-
),
|
|
205
|
-
"totalTokens": (
|
|
206
|
-
int(root_attributes["agentkit.usage.total_tokens"])
|
|
207
|
-
if usage_reported and "agentkit.usage.total_tokens" in root_attributes
|
|
208
|
-
else None
|
|
209
|
-
),
|
|
210
|
-
"cachedInputTokens": (
|
|
211
|
-
int(root_attributes.get("gen_ai.usage.cached_input_tokens", 0))
|
|
212
|
-
if usage_reported
|
|
213
|
-
else None
|
|
214
|
-
),
|
|
215
|
-
"reasoningOutputTokens": (
|
|
216
|
-
int(root_attributes.get("gen_ai.usage.reasoning_tokens", 0))
|
|
217
|
-
if usage_reported
|
|
218
|
-
else None
|
|
219
|
-
),
|
|
220
|
-
"usageReported": usage_reported,
|
|
221
|
-
"usageSource": root_attributes.get("agentkit.usage.source"),
|
|
463
|
+
**usage,
|
|
222
464
|
}
|
|
223
465
|
first_resource = (raw.get("resourceSpans") or [{}])[0]
|
|
224
466
|
first_scope = (first_resource.get("scopeSpans") or [{}])[0]
|
|
@@ -343,6 +585,7 @@ class OtlpTraceStore:
|
|
|
343
585
|
"outputTokens": metrics["outputTokens"],
|
|
344
586
|
"totalTokens": metrics["totalTokens"],
|
|
345
587
|
"usageReported": metrics["usageReported"],
|
|
588
|
+
"usageCompleteness": metrics["usageCompleteness"],
|
|
346
589
|
"spanCount": len(view["spans"]),
|
|
347
590
|
"target": view["target"],
|
|
348
591
|
}
|
|
@@ -451,11 +694,13 @@ class OtlpTraceStore:
|
|
|
451
694
|
root_end = (
|
|
452
695
|
root_start + record.duration_ms * 1_000_000
|
|
453
696
|
if record.duration_ms is not None
|
|
454
|
-
else
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
697
|
+
else (
|
|
698
|
+
_unix_nano(record.completed_at)
|
|
699
|
+
if record.completed_at is not None
|
|
700
|
+
else _unix_nano(events[-1].created_at)
|
|
701
|
+
if events
|
|
702
|
+
else root_start
|
|
703
|
+
)
|
|
459
704
|
)
|
|
460
705
|
run_status = _enum_string(record.status)
|
|
461
706
|
root_attributes: dict[str, Any] = {
|
|
@@ -546,15 +791,76 @@ class OtlpTraceStore:
|
|
|
546
791
|
"tool.requested",
|
|
547
792
|
"tool.completed",
|
|
548
793
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
794
|
+
content_families = {
|
|
795
|
+
"thinking.delta": "thinking",
|
|
796
|
+
"thinking.completed": "thinking",
|
|
797
|
+
"message.delta": "message",
|
|
798
|
+
"message.completed": "message",
|
|
799
|
+
}
|
|
800
|
+
projected: list[dict[str, Any]] = []
|
|
801
|
+
content_groups: dict[tuple[str, str, str, str], list[RunEvent]] = {}
|
|
802
|
+
current_turn = ""
|
|
803
|
+
current_step = ""
|
|
804
|
+
|
|
805
|
+
for event in events:
|
|
806
|
+
runtime_event = event.data.get("runtimeEvent")
|
|
807
|
+
correlation = runtime_event if isinstance(runtime_event, dict) else {}
|
|
808
|
+
turn_id = str(correlation.get("turn_id") or "")
|
|
809
|
+
step_id = str(correlation.get("step_id") or "")
|
|
810
|
+
if turn_id:
|
|
811
|
+
current_turn = turn_id
|
|
812
|
+
if step_id and event.type in {"step.started", "model.call.begin"}:
|
|
813
|
+
current_step = step_id
|
|
814
|
+
|
|
815
|
+
family = content_families.get(event.type)
|
|
816
|
+
if family:
|
|
817
|
+
key = (
|
|
818
|
+
event.run_id,
|
|
819
|
+
turn_id or current_turn,
|
|
820
|
+
step_id or current_step,
|
|
821
|
+
family,
|
|
822
|
+
)
|
|
823
|
+
content_groups.setdefault(key, []).append(event)
|
|
824
|
+
continue
|
|
825
|
+
if event.type in excluded:
|
|
826
|
+
continue
|
|
827
|
+
projected.append(
|
|
828
|
+
{
|
|
829
|
+
"timeUnixNano": str(_unix_nano(event.created_at)),
|
|
830
|
+
"name": event.type,
|
|
831
|
+
"attributes": _attributes(_safe_event_attributes(event.data)),
|
|
832
|
+
}
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
for grouped in content_groups.values():
|
|
836
|
+
completed = next(
|
|
837
|
+
(event for event in reversed(grouped) if event.type.endswith(".completed")),
|
|
838
|
+
None,
|
|
839
|
+
)
|
|
840
|
+
source = completed or grouped[-1]
|
|
841
|
+
completed_text = source.data.get("text") if completed is not None else None
|
|
842
|
+
text = (
|
|
843
|
+
completed_text
|
|
844
|
+
if isinstance(completed_text, str) and completed_text
|
|
845
|
+
else "".join(
|
|
846
|
+
str(event.data.get("text") or "")
|
|
847
|
+
for event in grouped
|
|
848
|
+
if event.type.endswith(".delta")
|
|
849
|
+
)
|
|
850
|
+
)
|
|
851
|
+
data = dict(source.data)
|
|
852
|
+
data["text"] = text
|
|
853
|
+
data["delta_count"] = sum(event.type.endswith(".delta") for event in grouped)
|
|
854
|
+
projected.append(
|
|
855
|
+
{
|
|
856
|
+
"timeUnixNano": str(_unix_nano(source.created_at)),
|
|
857
|
+
"name": source.type,
|
|
858
|
+
"attributes": _attributes(_safe_event_attributes(data)),
|
|
859
|
+
}
|
|
860
|
+
)
|
|
861
|
+
|
|
862
|
+
projected.sort(key=lambda event: int(event["timeUnixNano"]))
|
|
863
|
+
return projected
|
|
558
864
|
|
|
559
865
|
def _model_spans(
|
|
560
866
|
self, trace_id: str, root_id: str, events: list[RunEvent], root_end: int
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Studio-side projection helpers for platform-owned PCM memory."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ksadk.memory.coordinator import (
|
|
8
|
+
MemoryCoordinator,
|
|
9
|
+
agent_user_scope_id,
|
|
10
|
+
build_search_request,
|
|
11
|
+
recall_to_context_item,
|
|
12
|
+
)
|
|
13
|
+
from ksadk.memory.events import recall_completed, recall_empty, recall_failed
|
|
14
|
+
from ksadk.memory.provider_adapter import adapt_as_memory_provider
|
|
15
|
+
from ksadk.memory.provider_resolver import resolve_memory_provider
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def recall_platform_memory(
|
|
19
|
+
*,
|
|
20
|
+
run_id: str,
|
|
21
|
+
session_id: str,
|
|
22
|
+
agent_id: str,
|
|
23
|
+
user_id: str,
|
|
24
|
+
user_input: str,
|
|
25
|
+
request_config: dict[str, Any],
|
|
26
|
+
) -> tuple[dict[str, Any] | None, list[dict[str, Any]]]:
|
|
27
|
+
"""Recall agent-scoped memory and return its auditable lifecycle event."""
|
|
28
|
+
|
|
29
|
+
if not bool(request_config.get("memory_enabled")) or not bool(
|
|
30
|
+
request_config.get("memory_recall_enabled", True)
|
|
31
|
+
):
|
|
32
|
+
return None, []
|
|
33
|
+
|
|
34
|
+
provider_ref = str(request_config.get("provider_ref") or "local-default")
|
|
35
|
+
rollout = str(request_config.get("memory_write_rollout") or "enabled")
|
|
36
|
+
try:
|
|
37
|
+
provider = adapt_as_memory_provider(resolve_memory_provider(provider_ref))
|
|
38
|
+
result = MemoryCoordinator(provider).recall(
|
|
39
|
+
build_search_request(
|
|
40
|
+
query=user_input,
|
|
41
|
+
user_id=agent_user_scope_id(agent_id=agent_id, user_id=user_id),
|
|
42
|
+
top_k=int(request_config.get("memory_recall_top_k") or 8),
|
|
43
|
+
max_tokens=int(request_config.get("memory_recall_max_tokens") or 1600),
|
|
44
|
+
min_score=float(request_config.get("memory_recall_min_score") or 0.45),
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
context = recall_to_context_item(result)
|
|
48
|
+
if context is not None:
|
|
49
|
+
event = recall_completed(
|
|
50
|
+
run_id=run_id,
|
|
51
|
+
session_id=session_id,
|
|
52
|
+
provider=provider_ref,
|
|
53
|
+
rollout=rollout,
|
|
54
|
+
count=len(result.records),
|
|
55
|
+
)
|
|
56
|
+
elif result.status == "ok":
|
|
57
|
+
event = recall_empty(
|
|
58
|
+
run_id=run_id,
|
|
59
|
+
session_id=session_id,
|
|
60
|
+
provider=provider_ref,
|
|
61
|
+
rollout=rollout,
|
|
62
|
+
)
|
|
63
|
+
else:
|
|
64
|
+
event = recall_failed(
|
|
65
|
+
run_id=run_id,
|
|
66
|
+
session_id=session_id,
|
|
67
|
+
provider=provider_ref,
|
|
68
|
+
rollout=rollout,
|
|
69
|
+
error_code=str(result.error_code or result.status),
|
|
70
|
+
error_message="平台长期记忆召回失败",
|
|
71
|
+
retryable=result.status in {"timeout", "failed"},
|
|
72
|
+
)
|
|
73
|
+
return context, [event.to_dict()]
|
|
74
|
+
except Exception as exc: # noqa: BLE001 - recall failure must not break a run
|
|
75
|
+
return None, [
|
|
76
|
+
recall_failed(
|
|
77
|
+
run_id=run_id,
|
|
78
|
+
session_id=session_id,
|
|
79
|
+
provider=provider_ref,
|
|
80
|
+
rollout=rollout,
|
|
81
|
+
error_code="recall_exception",
|
|
82
|
+
error_message=str(exc)[:200],
|
|
83
|
+
retryable=True,
|
|
84
|
+
).to_dict()
|
|
85
|
+
]
|
ksadk/studio/repository.py
CHANGED
|
@@ -109,7 +109,14 @@ class AgentDraftRepository:
|
|
|
109
109
|
raise not_found("agent", agent_id)
|
|
110
110
|
return self._read(path)
|
|
111
111
|
|
|
112
|
-
def update(
|
|
112
|
+
def update(
|
|
113
|
+
self,
|
|
114
|
+
agent_id: str,
|
|
115
|
+
spec: AgentSpec,
|
|
116
|
+
*,
|
|
117
|
+
expected_revision: int,
|
|
118
|
+
name: str | None = None,
|
|
119
|
+
) -> AgentDraft:
|
|
113
120
|
current = self.get(agent_id)
|
|
114
121
|
if current.metadata.revision != expected_revision:
|
|
115
122
|
raise StudioError(
|
|
@@ -124,6 +131,8 @@ class AgentDraftRepository:
|
|
|
124
131
|
)
|
|
125
132
|
updated = cast(AgentDraft, current.model_copy(deep=True))
|
|
126
133
|
updated.metadata.revision += 1
|
|
134
|
+
if name is not None:
|
|
135
|
+
updated.metadata = updated.metadata.model_copy(update={"name": name})
|
|
127
136
|
updated.spec = spec
|
|
128
137
|
self._write(self._agent_file(agent_id), updated)
|
|
129
138
|
return updated
|
|
@@ -245,7 +254,19 @@ class BuildRepository:
|
|
|
245
254
|
continue
|
|
246
255
|
if record.agent_id == agent_id:
|
|
247
256
|
records.append(record)
|
|
248
|
-
return records
|
|
257
|
+
return sorted(records, key=lambda item: item.created_at, reverse=True)
|
|
258
|
+
|
|
259
|
+
def list(self) -> list[BuildRecord]:
|
|
260
|
+
records: list[BuildRecord] = []
|
|
261
|
+
directory = self.workspace.resolve(".agentkit/builds")
|
|
262
|
+
for path in directory.glob("build_*.json"):
|
|
263
|
+
try:
|
|
264
|
+
records.append(
|
|
265
|
+
BuildRecord.model_validate_json(path.read_text(encoding="utf-8"))
|
|
266
|
+
)
|
|
267
|
+
except (OSError, ValidationError):
|
|
268
|
+
continue
|
|
269
|
+
return sorted(records, key=lambda item: item.created_at, reverse=True)
|
|
249
270
|
|
|
250
271
|
def delete_for_agent(
|
|
251
272
|
self,
|