agentengine-sdk-python 0.7.0__py3-none-any.whl → 0.8.0__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.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/METADATA +36 -20
- agentengine_sdk_python-0.8.0.dist-info/RECORD +578 -0
- ksadk/a2a/__init__.py +178 -11
- ksadk/a2a/bootstrap.py +334 -0
- ksadk/a2a/card.py +120 -0
- ksadk/a2a/context_store.py +203 -0
- ksadk/a2a/control_plane.py +818 -0
- ksadk/a2a/credential.py +99 -0
- ksadk/a2a/event_adapter.py +149 -0
- ksadk/a2a/executor.py +406 -89
- ksadk/a2a/external_transport.py +516 -0
- ksadk/a2a/identity.py +304 -0
- ksadk/a2a/ids.py +22 -0
- ksadk/a2a/langgraph.py +285 -0
- ksadk/a2a/resume_store.py +201 -0
- ksadk/a2a/routes.py +105 -0
- ksadk/a2a/server.py +107 -60
- ksadk/a2a/space_client.py +1101 -0
- ksadk/a2a/task_adapter.py +423 -0
- ksadk/a2a/task_event_dispatcher.py +167 -0
- ksadk/a2a/task_event_outbox.py +326 -0
- ksadk/a2a/task_store.py +206 -0
- ksadk/a2ui/__init__.py +27 -0
- ksadk/a2ui/core.py +186 -0
- ksadk/a2ui/models.py +166 -0
- ksadk/a2ui/renderer.py +198 -0
- ksadk/agui/__init__.py +9 -0
- ksadk/agui/a2ui_projection.py +92 -0
- ksadk/agui/agent.py +857 -0
- ksadk/agui/config.py +86 -0
- ksadk/agui/routes.py +55 -0
- ksadk/api/client.py +233 -191
- ksadk/builders/__init__.py +2 -0
- ksadk/builders/base.py +16 -14
- ksadk/builders/code_builder.py +318 -236
- ksadk/builders/container_builder.py +187 -167
- ksadk/builders/framework_requirements.py +29 -11
- ksadk/builders/ks3_uploader.py +58 -27
- ksadk/builders/managed_runtime_builder.py +145 -0
- ksadk/builders/mcp_builder.py +91 -92
- ksadk/builders/requirements_utils.py +1 -5
- ksadk/cli/__init__.py +89 -171
- ksadk/cli/cmd_a2a.py +254 -70
- ksadk/cli/cmd_agent.py +19 -5
- ksadk/cli/cmd_build.py +158 -29
- ksadk/cli/cmd_completion.py +47 -35
- ksadk/cli/cmd_config.py +267 -198
- ksadk/cli/cmd_create.py +500 -720
- ksadk/cli/cmd_dashboard.py +120 -45
- ksadk/cli/cmd_deploy.py +117 -58
- ksadk/cli/cmd_destroy.py +44 -14
- ksadk/cli/cmd_files.py +63 -24
- ksadk/cli/cmd_hermes.py +168 -89
- ksadk/cli/cmd_invoke.py +184 -122
- ksadk/cli/cmd_launch.py +64 -28
- ksadk/cli/cmd_mcp.py +98 -64
- ksadk/cli/cmd_model.py +14 -5
- ksadk/cli/cmd_openclaw.py +483 -227
- ksadk/cli/cmd_replay.py +71 -0
- ksadk/cli/cmd_run.py +33 -10
- ksadk/cli/cmd_status.py +80 -31
- ksadk/cli/cmd_version.py +20 -13
- ksadk/cli/cmd_web.py +89 -13
- ksadk/cli/deploy_utils.py +20 -20
- ksadk/cli/dry_run.py +5 -3
- ksadk/cli/error_utils.py +37 -12
- ksadk/cli/global_options.py +1 -2
- ksadk/cli/local_runtime.py +1 -2
- ksadk/cli/model_catalog.py +6 -2
- ksadk/cli/network_options.py +34 -14
- ksadk/cli/resource_common.py +6 -2
- ksadk/cli/storage.py +0 -1
- ksadk/cli/ui.py +5 -3
- ksadk/cli/workflow_common.py +51 -17
- ksadk/codex/__init__.py +12 -0
- ksadk/codex/client.py +408 -0
- ksadk/codex/phase.py +143 -0
- ksadk/codex/runtime.py +449 -0
- ksadk/common/aicp_env.py +0 -1
- ksadk/common/auth.py +2 -2
- ksadk/common/constants.py +1 -3
- ksadk/common/llm_utils.py +17 -13
- ksadk/compat/__init__.py +5 -0
- ksadk/compat/adk_compat.py +200 -0
- ksadk/compat/copilotkit_a2ui.py +330 -0
- ksadk/configs/__init__.py +12 -12
- ksadk/configs/env_registry.py +500 -100
- ksadk/configs/global_config.py +2 -1
- ksadk/configs/settings.py +151 -124
- ksadk/conversations/__init__.py +7 -5
- ksadk/conversations/attachment_storage.py +16 -11
- ksadk/conversations/attachments.py +44 -36
- ksadk/conversations/compaction_pipeline.py +12 -12
- ksadk/conversations/compaction_prompt.py +9 -5
- ksadk/conversations/context.py +221 -6
- ksadk/conversations/message_projection.py +438 -51
- ksadk/conversations/model_context.py +12 -6
- ksadk/conversations/model_options.py +0 -1
- ksadk/conversations/normalize.py +20 -16
- ksadk/conversations/reasoning_markup.py +1 -1
- ksadk/conversations/runtime.py +339 -5255
- ksadk/conversations/runtime_compaction.py +333 -0
- ksadk/conversations/runtime_constants.py +27 -0
- ksadk/conversations/runtime_governance.py +185 -0
- ksadk/conversations/runtime_input.py +652 -0
- ksadk/conversations/runtime_invocation.py +395 -0
- ksadk/conversations/runtime_metadata.py +475 -0
- ksadk/conversations/runtime_observability.py +355 -0
- ksadk/conversations/runtime_payloads.py +272 -0
- ksadk/conversations/runtime_persistence.py +440 -0
- ksadk/conversations/runtime_preparation.py +418 -0
- ksadk/conversations/runtime_resume.py +816 -0
- ksadk/conversations/runtime_stream_events.py +902 -0
- ksadk/conversations/runtime_streaming.py +547 -0
- ksadk/conversations/semantic_summary.py +17 -5
- ksadk/conversations/session_title.py +6 -3
- ksadk/deployment/__init__.py +15 -16
- ksadk/deployment/agent_access.py +12 -23
- ksadk/deployment/base.py +51 -38
- ksadk/deployment/manager.py +63 -65
- ksadk/deployment/providers/serverless.py +309 -202
- ksadk/deployment/registry.py +38 -32
- ksadk/deployment/state.py +11 -11
- ksadk/deployment/ui_config.py +1 -1
- ksadk/detection/__init__.py +1 -1
- ksadk/detection/detector.py +146 -83
- ksadk/detection/mcp_detector.py +9 -6
- ksadk/events/__init__.py +25 -0
- ksadk/events/parser.py +191 -0
- ksadk/events/replay.py +37 -0
- ksadk/events/runtime_event.py +264 -0
- ksadk/events/store.py +317 -0
- ksadk/harness/__init__.py +34 -0
- ksadk/harness/app.py +278 -0
- ksadk/harness/config.py +181 -0
- ksadk/harness/reasoner.py +105 -0
- ksadk/harness/runner.py +211 -0
- ksadk/harness/sandbox.py +141 -0
- ksadk/harness/tools.py +222 -0
- ksadk/hermes_terminal.py +23 -12
- ksadk/identity/resolver.py +15 -9
- ksadk/ids.py +32 -0
- ksadk/knowledge_base/adk_tool.py +1 -1
- ksadk/knowledge_base/client.py +23 -29
- ksadk/managed_runtime.py +188 -0
- ksadk/markdown.py +5 -2
- ksadk/mcp_runtime/__init__.py +9 -6
- ksadk/memory/__init__.py +1 -1
- ksadk/memory/adk/__init__.py +2 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +2 -6
- ksadk/memory/adk/backends/http_ltm_backend.py +13 -21
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +7 -13
- ksadk/memory/adk/backends/sdk_ltm_backend.py +26 -33
- ksadk/memory/adk/long_term_memory.py +31 -35
- ksadk/memory/adk/resilient_session_service.py +4 -5
- ksadk/memory/adk/short_term_memory.py +12 -21
- ksadk/memory/adk_tool.py +3 -2
- ksadk/memory/backends/base.py +19 -19
- ksadk/memory/backends/memory.py +24 -25
- ksadk/memory/backends/redis.py +31 -30
- ksadk/memory/langchain_tool.py +2 -1
- ksadk/memory/manager.py +52 -47
- ksadk/memory/service.py +10 -8
- ksadk/model_policy.py +15 -7
- ksadk/model_proxy/__init__.py +51 -0
- ksadk/model_proxy/bootstrap.py +80 -0
- ksadk/model_proxy/cache.py +165 -0
- ksadk/model_proxy/config.py +45 -0
- ksadk/model_proxy/demo_webui.py +115 -0
- ksadk/model_proxy/detect.py +145 -0
- ksadk/model_proxy/gate.py +68 -0
- ksadk/model_proxy/namespace.py +173 -0
- ksadk/model_proxy/protocol_proxy.py +22 -0
- ksadk/model_proxy/server.py +300 -0
- ksadk/model_proxy/transform.py +691 -0
- ksadk/openclaw_gateway.py +29 -14
- ksadk/runners/adk_runner.py +345 -120
- ksadk/runners/base_runner.py +46 -29
- ksadk/runners/codex_runner.py +132 -0
- ksadk/runners/deepagents_runner.py +0 -1
- ksadk/runners/factory.py +17 -5
- ksadk/runners/langchain_runner.py +29 -742
- ksadk/runners/langgraph_runner.py +352 -90
- ksadk/runners/patch_langchain.py +16 -16
- ksadk/runners/remote_runner.py +134 -33
- ksadk/runners/usage_accumulator.py +1 -0
- ksadk/runners/utils/langfuse.py +3 -3
- ksadk/runners/utils/loader.py +7 -7
- ksadk/runtime/__init__.py +41 -0
- ksadk/runtime/adapter.py +345 -0
- ksadk/runtime/framework_adapters.py +124 -0
- ksadk/runtime/preprocessing.py +118 -0
- ksadk/runtime/runner_adapter.py +873 -0
- ksadk/runtime_context.py +18 -3
- ksadk/runtime_state.py +0 -1
- ksadk/sandbox/__init__.py +4 -1
- ksadk/sandbox/backends/__init__.py +4 -1
- ksadk/sandbox/backends/e2b.py +13 -5
- ksadk/sandbox/backends/local_process.py +11 -3
- ksadk/sandbox/base.py +10 -15
- ksadk/sandbox/factory.py +14 -4
- ksadk/sandbox/registry.py +57 -6
- ksadk/server/api_models.py +15 -5
- ksadk/server/app.py +455 -3885
- ksadk/server/composition.py +21 -0
- ksadk/server/factory.py +624 -0
- ksadk/server/routes/__init__.py +1 -0
- ksadk/server/routes/checkpoint_resolution.py +116 -0
- ksadk/server/routes/common.py +713 -0
- ksadk/server/routes/control.py +327 -0
- ksadk/server/routes/dependencies.py +98 -0
- ksadk/server/routes/misc.py +448 -0
- ksadk/server/routes/models.py +443 -0
- ksadk/server/routes/openai_compat.py +207 -0
- ksadk/server/routes/projection.py +795 -0
- ksadk/server/routes/routers.py +52 -0
- ksadk/server/routes/run.py +726 -0
- ksadk/server/routes/sessions.py +649 -0
- ksadk/server/routes/streaming.py +223 -0
- ksadk/server/routes/workspace.py +381 -0
- ksadk/server/static/assets/{ArtifactsPanel-D-SSn2ee.js → ArtifactsPanel-Cjnqt-8W.js} +1 -1
- ksadk/server/static/assets/CodeBlock-BqyqZfuB.js +9 -0
- ksadk/server/static/assets/MathMessageMarkdown-BpH7jiFM.js +8 -0
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +303 -0
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +1 -0
- ksadk/server/static/assets/{arc-BA13sHc9.js → arc-CFKwSk_B.js} +1 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-3BPJPVTR-DzJzgVoL.js → architectureDiagram-3BPJPVTR-Dej8jX8c.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-GPEHLZMM-UTdVcZhn.js → blockDiagram-GPEHLZMM-1F64jqvy.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-AAUBKEIU-Dix0GD4m.js → c4Diagram-AAUBKEIU-9q7AUAKb.js} +1 -1
- ksadk/server/static/assets/channel-iUGv2N24.js +1 -0
- ksadk/server/static/assets/{chunk-2J33WTMH-C2JxuZ42.js → chunk-2J33WTMH-6qgwJm7Q.js} +1 -1
- ksadk/server/static/assets/{chunk-4BX2VUAB-Be57QPgD.js → chunk-4BX2VUAB-CsWIQRhc.js} +1 -1
- ksadk/server/static/assets/{chunk-55IACEB6-WjSuy4nv.js → chunk-55IACEB6-BK8paA20.js} +1 -1
- ksadk/server/static/assets/{chunk-727SXJPM-BOovP-b5.js → chunk-727SXJPM-B-JEhy7h.js} +1 -1
- ksadk/server/static/assets/{chunk-AQP2D5EJ-DOmZNmWj.js → chunk-AQP2D5EJ-DYBvMHAa.js} +1 -1
- ksadk/server/static/assets/{chunk-FMBD7UC4-DzwlodkU.js → chunk-FMBD7UC4-BGhvzDYt.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-DMqAikEU.js → chunk-ND2GUHAM-D98vPd-E.js} +1 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +1 -0
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-Zhy2GBnP.js → cose-bilkent-S5V4N54A-CX3yotHq.js} +1 -1
- ksadk/server/static/assets/{dagre-BM42HDAG-CbKrtIUz.js → dagre-BM42HDAG-C7TguAWo.js} +1 -1
- ksadk/server/static/assets/{diagram-2AECGRRQ-BRApgQRK.js → diagram-2AECGRRQ-Dd17_kws.js} +1 -1
- ksadk/server/static/assets/{diagram-5GNKFQAL-D0xbnDiK.js → diagram-5GNKFQAL-DVIClIil.js} +1 -1
- ksadk/server/static/assets/{diagram-KO2AKTUF-CVugVI9L.js → diagram-KO2AKTUF-Df_3gYQa.js} +1 -1
- ksadk/server/static/assets/{diagram-LMA3HP47-DozUGgee.js → diagram-LMA3HP47-BhLk6ZtA.js} +1 -1
- ksadk/server/static/assets/{diagram-OG6HWLK6-ZOYsKlru.js → diagram-OG6HWLK6-D4GNGvuu.js} +1 -1
- ksadk/server/static/assets/{dist-DmFaq_Iy.js → dist-6CVKuTAe.js} +1 -1
- ksadk/server/static/assets/{dist-8EEyGgDx.js → dist-BUHRxvDG.js} +1 -1
- ksadk/server/static/assets/{dist-B0NP_Z0z.js → dist-BZ9n9AjO.js} +1 -1
- ksadk/server/static/assets/{dist-DMezvBGJ.js → dist-BibcG1V9.js} +1 -1
- ksadk/server/static/assets/{dist-C3HIIaN5.js → dist-Bs-jQcRX.js} +1 -1
- ksadk/server/static/assets/{dist-BrCcQ47T.js → dist-C2xjE7cO.js} +1 -1
- ksadk/server/static/assets/{dist-Dp0k7bWI.js → dist-C7-3jInC.js} +1 -1
- ksadk/server/static/assets/{dist-D-xOD048.js → dist-C99THtIA.js} +1 -1
- ksadk/server/static/assets/{dist-CkEKJFtk.js → dist-CGcp2ex8.js} +1 -1
- ksadk/server/static/assets/{dist-DyOkZmze.js → dist-CVQRZjPu.js} +1 -1
- ksadk/server/static/assets/{dist-BssVmjIo.js → dist-Cf23NY4L.js} +1 -1
- ksadk/server/static/assets/{dist-BIJVDMuB.js → dist-CgF3fj15.js} +1 -1
- ksadk/server/static/assets/{dist-2hInLS_J.js → dist-Cwt7koer.js} +1 -1
- ksadk/server/static/assets/{dist-DyWsb78Q.js → dist-D82mtD2s.js} +1 -1
- ksadk/server/static/assets/{dist-D-JMdWPQ.js → dist-DF06ORQo.js} +1 -1
- ksadk/server/static/assets/{dist-BmlMPsCc.js → dist-DHn6nBzr.js} +1 -1
- ksadk/server/static/assets/{dist-gX6GOLKq.js → dist-Djgl2wVZ.js} +1 -1
- ksadk/server/static/assets/{dist-DpKtt4Bo.js → dist-DlzCRy0S.js} +1 -1
- ksadk/server/static/assets/{dist-8_SfK1IP.js → dist-DqNnNFrw.js} +1 -1
- ksadk/server/static/assets/{dist-D57wnGWd.js → dist-DyvYLMW9.js} +1 -1
- ksadk/server/static/assets/{dist-CPBtqRTW.js → dist-eoW6tZXA.js} +1 -1
- ksadk/server/static/assets/{dist-DL_NKc_z.js → dist-ivOya1LD.js} +1 -1
- ksadk/server/static/assets/{erDiagram-TEJ5UH35-Bk-9bgE5.js → erDiagram-TEJ5UH35-CnfRcY2M.js} +1 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +1 -0
- ksadk/server/static/assets/{flowDiagram-I6XJVG4X-Dn9kZVuZ.js → flowDiagram-I6XJVG4X-DGaJjGNJ.js} +1 -1
- ksadk/server/static/assets/{ganttDiagram-6RSMTGT7-BGxXlJqm.js → ganttDiagram-6RSMTGT7-DpCoB2g9.js} +1 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-PVQCEYII-C7Q0X-wi.js → gitGraphDiagram-PVQCEYII-9IKVFBVT.js} +1 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +177 -0
- ksadk/server/static/assets/index-jOPmTOZH.css +2 -0
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +1 -0
- ksadk/server/static/assets/{infoDiagram-5YYISTIA-BO_CSqq5.js → infoDiagram-5YYISTIA-CYIIsb8y.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-eYLPLd46.js → ishikawaDiagram-YF4QCWOH-DLOHGvWw.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-De9geSb0.js → journeyDiagram-JHISSGLW-BIzKeejT.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-Cs80kQto.js → kanban-definition-UN3LZRKU-BWHoFSw2.js} +1 -1
- ksadk/server/static/assets/{katex-DSrCFD8n.js → katex-DATssjp1.js} +1 -1
- ksadk/server/static/assets/{linear-CN9sbKTF.js → linear-CvMBw9cA.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-DlgSBU8l.js → mermaid-parser.core-mGAcEwcq.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-9afz7Oug.js → mindmap-definition-RKZ34NQL-CSAQxEAe.js} +1 -1
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +1 -0
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +1 -0
- ksadk/server/static/assets/{pieDiagram-4H26LBE5-DPv_VstN.js → pieDiagram-4H26LBE5-By-ra07M.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-o77wZ1XK.js → quadrantDiagram-W4KKPZXB-CxIR4JXI.js} +1 -1
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +1 -0
- ksadk/server/static/assets/{requirementDiagram-4Y6WPE33-BYVw81VC.js → requirementDiagram-4Y6WPE33-DpW90iu3.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-B7nZFMKT.js → sankeyDiagram-5OEKKPKP-DpGa6EAV.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-BGRRrFw5.js → sequenceDiagram-3UESZ5HK-NTKNGGe5.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-AJRCARHV-BUfHCoPs.js → stateDiagram-AJRCARHV-DGpd9yFG.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +1 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-FbCTGrf9.js → timeline-definition-PNZ67QCA-jqoYs3jQ.js} +1 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +1 -0
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +1 -0
- ksadk/server/static/assets/{vennDiagram-CIIHVFJN-DWgwtPsJ.js → vennDiagram-CIIHVFJN-l3Z7-wbP.js} +1 -1
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-YWT4CUSO-2x8G-tTM.js → wardleyDiagram-YWT4CUSO-BR54GPmr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-2RQKCTM6-Drma3AYl.js → xychartDiagram-2RQKCTM6-SkiH8GsK.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/server/terminal_sessions.py +111 -58
- ksadk/sessions/__init__.py +69 -19
- ksadk/sessions/base.py +31 -11
- ksadk/sessions/continuity.py +2 -3
- ksadk/sessions/in_memory.py +46 -2
- ksadk/sessions/local_service.py +148 -17
- ksadk/sessions/postgres_service.py +143 -25
- ksadk/sessions/resilient.py +36 -8
- ksadk/skills/models.py +17 -5
- ksadk/skills/package_store.py +5 -2
- ksadk/skills/runtime/agent.py +20 -5
- ksadk/skills/runtime/artifacts.py +1 -5
- ksadk/skills/runtime/backends/e2b.py +10 -4
- ksadk/skills/runtime/backends/local.py +15 -3
- ksadk/skills/runtime/base.py +1 -2
- ksadk/skills/runtime/executor.py +10 -3
- ksadk/skills/runtime/factory.py +4 -2
- ksadk/skills/runtime/loader.py +1 -2
- ksadk/skills/runtime/registry.py +15 -10
- ksadk/skills/runtime/request.py +3 -1
- ksadk/skills/service_client.py +38 -17
- ksadk/skills/tool_defs.py +15 -10
- ksadk/terminal_exec_policy.py +3 -4
- ksadk/tools/gateway.py +92 -15
- ksadk/tools/result_budget.py +12 -4
- ksadk/toolsets/__init__.py +134 -36
- ksadk/toolsets/platform.py +21 -5
- ksadk/toolsets/sandbox.py +82 -16
- ksadk/toolsets/skills.py +200 -39
- ksadk/toolsets/web.py +123 -26
- ksadk/toolsets/workspace.py +212 -101
- ksadk/tracing/exporters/inmemory_exporter.py +62 -51
- ksadk/tracing/exporters/langfuse_exporter.py +91 -76
- ksadk/tracing/setup.py +69 -53
- ksadk/tracing/span_utils.py +5 -2
- ksadk/tui/loop.py +78 -30
- ksadk/tui/stream_render.py +1 -0
- ksadk/ui_config.py +5 -3
- ksadk/version.py +1 -1
- ksadk_runtime_common/schemas/runtime_event_v1.json +95 -0
- agentengine_sdk_python-0.7.0.dist-info/RECORD +0 -482
- ksadk/server/static/assets/CodeBlock-P16VOLYi.js +0 -9
- ksadk/server/static/assets/MathMessageMarkdown-CdGiQWHR.js +0 -8
- ksadk/server/static/assets/MermaidBlock-IOcal8cm.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-DGSDWsei.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-BvUlsA6l.js +0 -1
- ksadk/server/static/assets/channel-CTuydARX.js +0 -1
- ksadk/server/static/assets/chunk-QZHKN3VN-BnCydivS.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-BNHg45Be.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-BNHg45Be.js +0 -1
- ksadk/server/static/assets/eventmodeling-FCH6USID-DsAgWnlf.js +0 -1
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BIao9Yjg.js +0 -1
- ksadk/server/static/assets/index-C00Lwg3L.js +0 -165
- ksadk/server/static/assets/index-DAURbCsP.css +0 -1
- ksadk/server/static/assets/info-J43DQDTF-CyipqGxU.js +0 -1
- ksadk/server/static/assets/packet-YPE3B663-CGkyRxlg.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-M0uWAf4n.js +0 -1
- ksadk/server/static/assets/radar-GUYGQ44K-Bdbm24-x.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-8xBN_gLM.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-npMo0ak1.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-CHdzrrdo.js +0 -1
- ksadk/server/static/assets/wardley-L42UT6IY-BEQz7wyy.js +0 -1
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.7.0.dist-info → agentengine_sdk_python-0.8.0.dist-info}/top_level.txt +0 -0
ksadk/tracing/setup.py
CHANGED
|
@@ -5,12 +5,17 @@ Tracing 初始化 - 支持多 Exporter (InMemory + Langfuse + OTLP)
|
|
|
5
5
|
|
|
6
6
|
import atexit
|
|
7
7
|
import base64
|
|
8
|
+
import importlib
|
|
8
9
|
import logging
|
|
9
10
|
import os
|
|
11
|
+
from collections.abc import Callable, Sequence
|
|
10
12
|
from dataclasses import dataclass
|
|
11
13
|
from typing import Any, Optional
|
|
12
14
|
from urllib.parse import unquote
|
|
13
15
|
|
|
16
|
+
from opentelemetry.sdk.trace import ReadableSpan
|
|
17
|
+
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
|
18
|
+
|
|
14
19
|
from ksadk.tracing.exporters.inmemory_exporter import InMemoryExporter
|
|
15
20
|
|
|
16
21
|
logger = logging.getLogger(__name__)
|
|
@@ -49,18 +54,18 @@ class _OtlpHttpConfig:
|
|
|
49
54
|
service_name: str
|
|
50
55
|
|
|
51
56
|
|
|
52
|
-
class _LoggingSpanExporter:
|
|
57
|
+
class _LoggingSpanExporter(SpanExporter):
|
|
53
58
|
"""Small delegating exporter that logs external trace export flow."""
|
|
54
59
|
|
|
55
60
|
def __init__(
|
|
56
61
|
self,
|
|
57
|
-
exporter:
|
|
62
|
+
exporter: SpanExporter,
|
|
58
63
|
*,
|
|
59
64
|
name: str,
|
|
60
65
|
endpoint: str,
|
|
61
66
|
service_name: str,
|
|
62
67
|
header_keys: list[str],
|
|
63
|
-
span_transform:
|
|
68
|
+
span_transform: Callable[[Sequence[ReadableSpan]], Sequence[ReadableSpan]] | None = None,
|
|
64
69
|
):
|
|
65
70
|
self._exporter = exporter
|
|
66
71
|
self._name = name
|
|
@@ -69,8 +74,8 @@ class _LoggingSpanExporter:
|
|
|
69
74
|
self._header_keys = header_keys
|
|
70
75
|
self._span_transform = span_transform
|
|
71
76
|
|
|
72
|
-
def export(self, spans):
|
|
73
|
-
span_count = len(spans)
|
|
77
|
+
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
|
78
|
+
span_count = len(spans)
|
|
74
79
|
logger.info(
|
|
75
80
|
"%s export started: endpoint=%s service_name=%s spans=%s headers=%s",
|
|
76
81
|
self._name,
|
|
@@ -101,24 +106,18 @@ class _LoggingSpanExporter:
|
|
|
101
106
|
)
|
|
102
107
|
return result
|
|
103
108
|
|
|
104
|
-
def shutdown(self):
|
|
105
|
-
shutdown = getattr(self._exporter, "shutdown", None)
|
|
106
|
-
if shutdown is None:
|
|
107
|
-
return None
|
|
109
|
+
def shutdown(self) -> None:
|
|
108
110
|
logger.info("%s exporter shutdown: endpoint=%s", self._name, self._endpoint)
|
|
109
|
-
|
|
111
|
+
self._exporter.shutdown()
|
|
110
112
|
|
|
111
113
|
def force_flush(self, timeout_millis: int = 30000) -> bool:
|
|
112
|
-
force_flush = getattr(self._exporter, "force_flush", None)
|
|
113
|
-
if force_flush is None:
|
|
114
|
-
return True
|
|
115
114
|
logger.info(
|
|
116
115
|
"%s exporter force_flush: endpoint=%s timeout_millis=%s",
|
|
117
116
|
self._name,
|
|
118
117
|
self._endpoint,
|
|
119
118
|
timeout_millis,
|
|
120
119
|
)
|
|
121
|
-
return force_flush(timeout_millis)
|
|
120
|
+
return self._exporter.force_flush(timeout_millis)
|
|
122
121
|
|
|
123
122
|
|
|
124
123
|
def _coerce_int(value: Any) -> int:
|
|
@@ -164,9 +163,7 @@ def _span_token_usage(span: Any) -> dict[str, int]:
|
|
|
164
163
|
"input": _coerce_int(attributes.get("gen_ai.usage.input_tokens")),
|
|
165
164
|
"output": _coerce_int(attributes.get("gen_ai.usage.output_tokens")),
|
|
166
165
|
"cache_read": _coerce_int(attributes.get("gen_ai.usage.cache_read.input_tokens")),
|
|
167
|
-
"reasoning_output": _coerce_int(
|
|
168
|
-
attributes.get("gen_ai.usage.reasoning.output_tokens")
|
|
169
|
-
),
|
|
166
|
+
"reasoning_output": _coerce_int(attributes.get("gen_ai.usage.reasoning.output_tokens")),
|
|
170
167
|
}
|
|
171
168
|
|
|
172
169
|
|
|
@@ -294,13 +291,16 @@ def _prepare_cloud_monitor_spans(spans: Any) -> Any:
|
|
|
294
291
|
|
|
295
292
|
def has_token_descendant(span: Any) -> bool:
|
|
296
293
|
sid = _span_id(span)
|
|
297
|
-
key = (_trace_id(span), sid)
|
|
298
294
|
if sid is None:
|
|
299
295
|
return False
|
|
296
|
+
key = (_trace_id(span), sid)
|
|
300
297
|
if key in has_token_descendant_cache:
|
|
301
298
|
return has_token_descendant_cache[key]
|
|
302
299
|
for child in children_by_parent.get(key, []):
|
|
303
|
-
|
|
300
|
+
child_sid = _span_id(child)
|
|
301
|
+
if child_sid is None:
|
|
302
|
+
continue
|
|
303
|
+
child_key = (_trace_id(child), child_sid)
|
|
304
304
|
if _has_nonzero_token_usage(token_usage_by_id.get(child_key, {})):
|
|
305
305
|
has_token_descendant_cache[key] = True
|
|
306
306
|
return True
|
|
@@ -312,6 +312,8 @@ def _prepare_cloud_monitor_spans(spans: Any) -> Any:
|
|
|
312
312
|
|
|
313
313
|
def collect_leaf_usage(span: Any, usage: dict[str, int]) -> None:
|
|
314
314
|
sid = _span_id(span)
|
|
315
|
+
if sid is None:
|
|
316
|
+
return
|
|
315
317
|
key = (_trace_id(span), sid)
|
|
316
318
|
own_usage = token_usage_by_id.get(key, {})
|
|
317
319
|
if _has_nonzero_token_usage(own_usage) and not has_token_descendant(span):
|
|
@@ -349,7 +351,9 @@ def _prepare_cloud_monitor_spans(spans: Any) -> Any:
|
|
|
349
351
|
return [replacements.get(id(span), span) for span in span_list]
|
|
350
352
|
|
|
351
353
|
|
|
352
|
-
def _build_langfuse_otlp_config(
|
|
354
|
+
def _build_langfuse_otlp_config(
|
|
355
|
+
langfuse_config: dict[str, Any] | None = None,
|
|
356
|
+
) -> dict[str, Any] | None:
|
|
353
357
|
"""Build Langfuse OTLP direct exporter config from explicit config or env."""
|
|
354
358
|
if langfuse_config:
|
|
355
359
|
public_key = langfuse_config.get("public_key") or ""
|
|
@@ -358,7 +362,9 @@ def _build_langfuse_otlp_config(langfuse_config: dict = None) -> Optional[dict]:
|
|
|
358
362
|
else:
|
|
359
363
|
public_key = os.getenv("LANGFUSE_PUBLIC_KEY", "")
|
|
360
364
|
secret_key = os.getenv("LANGFUSE_SECRET_KEY", "")
|
|
361
|
-
host =
|
|
365
|
+
host = (
|
|
366
|
+
os.getenv("LANGFUSE_BASE_URL") or os.getenv("LANGFUSE_HOST") or "http://localhost:3000"
|
|
367
|
+
)
|
|
362
368
|
|
|
363
369
|
if not public_key or not secret_key:
|
|
364
370
|
return None
|
|
@@ -561,9 +567,7 @@ def _apply_langfuse_auth_fallback(endpoint: str, headers: dict[str, str]) -> boo
|
|
|
561
567
|
langfuse_headers = _build_langfuse_otlp_headers(public_key, secret_key)
|
|
562
568
|
headers["Authorization"] = langfuse_headers["Authorization"]
|
|
563
569
|
if not _has_header(headers, "x-langfuse-ingestion-version"):
|
|
564
|
-
headers["x-langfuse-ingestion-version"] = langfuse_headers[
|
|
565
|
-
"x-langfuse-ingestion-version"
|
|
566
|
-
]
|
|
570
|
+
headers["x-langfuse-ingestion-version"] = langfuse_headers["x-langfuse-ingestion-version"]
|
|
567
571
|
return True
|
|
568
572
|
|
|
569
573
|
|
|
@@ -595,9 +599,8 @@ def _build_generic_otlp_http_config() -> Optional[dict]:
|
|
|
595
599
|
)
|
|
596
600
|
return None
|
|
597
601
|
|
|
598
|
-
raw_headers = (
|
|
599
|
-
|
|
600
|
-
or os.getenv("OTEL_EXPORTER_OTLP_HEADERS", "")
|
|
602
|
+
raw_headers = os.getenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "").strip() or os.getenv(
|
|
603
|
+
"OTEL_EXPORTER_OTLP_HEADERS", ""
|
|
601
604
|
)
|
|
602
605
|
headers = _parse_otlp_headers(raw_headers)
|
|
603
606
|
langfuse_auth_fallback = _apply_langfuse_auth_fallback(endpoint, headers)
|
|
@@ -618,13 +621,13 @@ def _build_generic_otlp_http_config() -> Optional[dict]:
|
|
|
618
621
|
|
|
619
622
|
def setup_tracing(
|
|
620
623
|
enable_inmemory: bool = True,
|
|
621
|
-
enable_langfuse: bool = None, # Auto-detect from env
|
|
622
|
-
langfuse_config: dict = None,
|
|
624
|
+
enable_langfuse: bool | None = None, # Auto-detect from env
|
|
625
|
+
langfuse_config: dict[str, Any] | None = None,
|
|
623
626
|
enable_otlp: bool = False,
|
|
624
627
|
otlp_endpoint: str = "localhost:4317",
|
|
625
628
|
enable_adk_instrumentation: bool = True, # Auto-instrument ADK
|
|
626
|
-
use_callback_only: bool = None, # Explicit override
|
|
627
|
-
**kwargs
|
|
629
|
+
use_callback_only: bool | None = None, # Explicit override
|
|
630
|
+
**kwargs,
|
|
628
631
|
) -> Optional[InMemoryExporter]:
|
|
629
632
|
"""初始化 Tracing (支持多 Exporter)
|
|
630
633
|
|
|
@@ -657,7 +660,7 @@ def setup_tracing(
|
|
|
657
660
|
|
|
658
661
|
# 检查是否已有 TracerProvider (避免覆盖)
|
|
659
662
|
existing_provider = trace.get_tracer_provider()
|
|
660
|
-
if existing_provider and hasattr(existing_provider,
|
|
663
|
+
if existing_provider and hasattr(existing_provider, "add_span_processor"):
|
|
661
664
|
# 使用现有 provider,直接添加 processor
|
|
662
665
|
provider = existing_provider
|
|
663
666
|
logger.debug("Using existing TracerProvider")
|
|
@@ -679,14 +682,16 @@ def setup_tracing(
|
|
|
679
682
|
generic_otlp_config = _build_generic_otlp_http_config()
|
|
680
683
|
if generic_otlp_config:
|
|
681
684
|
try:
|
|
682
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import
|
|
685
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
686
|
+
OTLPSpanExporter as HttpOTLPSpanExporter,
|
|
687
|
+
)
|
|
683
688
|
|
|
684
|
-
|
|
689
|
+
raw_otlp_exporter = HttpOTLPSpanExporter(
|
|
685
690
|
endpoint=generic_otlp_config["endpoint"],
|
|
686
691
|
headers=generic_otlp_config["headers"],
|
|
687
692
|
)
|
|
688
693
|
otlp_exporter = _LoggingSpanExporter(
|
|
689
|
-
|
|
694
|
+
raw_otlp_exporter,
|
|
690
695
|
name="Generic OTLP",
|
|
691
696
|
endpoint=generic_otlp_config["endpoint"],
|
|
692
697
|
service_name=_get_service_name(),
|
|
@@ -720,14 +725,16 @@ def setup_tracing(
|
|
|
720
725
|
cloud_monitor_config = _build_cloud_monitor_otlp_http_config()
|
|
721
726
|
if cloud_monitor_config:
|
|
722
727
|
try:
|
|
723
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import
|
|
728
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
729
|
+
OTLPSpanExporter as HttpOTLPSpanExporter,
|
|
730
|
+
)
|
|
724
731
|
|
|
725
|
-
|
|
732
|
+
raw_cloud_monitor_exporter = HttpOTLPSpanExporter(
|
|
726
733
|
endpoint=cloud_monitor_config.endpoint,
|
|
727
734
|
headers=cloud_monitor_config.headers,
|
|
728
735
|
)
|
|
729
736
|
cloud_monitor_exporter = _LoggingSpanExporter(
|
|
730
|
-
|
|
737
|
+
raw_cloud_monitor_exporter,
|
|
731
738
|
name="CloudMonitor OTLP",
|
|
732
739
|
endpoint=cloud_monitor_config.endpoint,
|
|
733
740
|
service_name=cloud_monitor_config.service_name,
|
|
@@ -757,9 +764,8 @@ def setup_tracing(
|
|
|
757
764
|
langfuse_enabled = enable_langfuse
|
|
758
765
|
if langfuse_enabled is None:
|
|
759
766
|
# Auto-detect from environment variables
|
|
760
|
-
langfuse_enabled = (
|
|
761
|
-
|
|
762
|
-
and bool(os.getenv("LANGFUSE_PUBLIC_KEY") or (langfuse_config or {}).get("public_key"))
|
|
767
|
+
langfuse_enabled = not generic_otlp_config and bool(
|
|
768
|
+
os.getenv("LANGFUSE_PUBLIC_KEY") or (langfuse_config or {}).get("public_key")
|
|
763
769
|
)
|
|
764
770
|
|
|
765
771
|
# 检查是否应该禁用 LangfuseExporter (当使用 LangChain/LangGraph 时)
|
|
@@ -769,16 +775,18 @@ def setup_tracing(
|
|
|
769
775
|
|
|
770
776
|
if langfuse_enabled and not use_callback_only:
|
|
771
777
|
try:
|
|
772
|
-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import
|
|
778
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
|
779
|
+
OTLPSpanExporter as HttpOTLPSpanExporter,
|
|
780
|
+
)
|
|
773
781
|
|
|
774
782
|
config = _build_langfuse_otlp_config(langfuse_config)
|
|
775
783
|
if config:
|
|
776
|
-
|
|
784
|
+
raw_langfuse_otlp_exporter = HttpOTLPSpanExporter(
|
|
777
785
|
endpoint=config["endpoint"],
|
|
778
786
|
headers=config["headers"],
|
|
779
787
|
)
|
|
780
788
|
otlp_exporter = _LoggingSpanExporter(
|
|
781
|
-
|
|
789
|
+
raw_langfuse_otlp_exporter,
|
|
782
790
|
name="Langfuse OTLP",
|
|
783
791
|
endpoint=config["endpoint"],
|
|
784
792
|
service_name=_get_service_name(),
|
|
@@ -786,11 +794,11 @@ def setup_tracing(
|
|
|
786
794
|
span_transform=_prepare_langfuse_spans,
|
|
787
795
|
)
|
|
788
796
|
provider.add_span_processor(
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
797
|
+
BatchSpanProcessor(
|
|
798
|
+
otlp_exporter,
|
|
799
|
+
**_batch_span_processor_kwargs(),
|
|
800
|
+
)
|
|
792
801
|
)
|
|
793
|
-
)
|
|
794
802
|
logger.info(
|
|
795
803
|
"Langfuse OTLP exporter enabled: %s (%s) headers=%s",
|
|
796
804
|
config["endpoint"],
|
|
@@ -810,11 +818,14 @@ def setup_tracing(
|
|
|
810
818
|
# 5. OTLP Exporter (optional)
|
|
811
819
|
if enable_otlp:
|
|
812
820
|
try:
|
|
813
|
-
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import
|
|
814
|
-
|
|
821
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
822
|
+
OTLPSpanExporter as GrpcOTLPSpanExporter,
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
grpc_otlp_exporter = GrpcOTLPSpanExporter(endpoint=otlp_endpoint)
|
|
815
826
|
provider.add_span_processor(
|
|
816
827
|
BatchSpanProcessor(
|
|
817
|
-
|
|
828
|
+
grpc_otlp_exporter,
|
|
818
829
|
**_batch_span_processor_kwargs(),
|
|
819
830
|
)
|
|
820
831
|
)
|
|
@@ -825,7 +836,10 @@ def setup_tracing(
|
|
|
825
836
|
# 6. ADK Auto-Instrumentation (for Google ADK projects)
|
|
826
837
|
if enable_adk_instrumentation and not _adk_instrumented:
|
|
827
838
|
try:
|
|
828
|
-
|
|
839
|
+
instrumentation_module = importlib.import_module(
|
|
840
|
+
"openinference.instrumentation.google_adk"
|
|
841
|
+
)
|
|
842
|
+
GoogleADKInstrumentor = getattr(instrumentation_module, "GoogleADKInstrumentor")
|
|
829
843
|
GoogleADKInstrumentor().instrument()
|
|
830
844
|
_adk_instrumented = True
|
|
831
845
|
logger.info("Google ADK instrumentation enabled")
|
|
@@ -841,6 +855,7 @@ def setup_tracing(
|
|
|
841
855
|
if enable_adk_instrumentation:
|
|
842
856
|
try:
|
|
843
857
|
from openinference.instrumentation.langchain import LangChainInstrumentor
|
|
858
|
+
|
|
844
859
|
LangChainInstrumentor().instrument()
|
|
845
860
|
logger.info("LangChain instrumentation enabled")
|
|
846
861
|
except ImportError:
|
|
@@ -864,7 +879,7 @@ def shutdown_tracing():
|
|
|
864
879
|
|
|
865
880
|
if _langfuse_exporter is not None:
|
|
866
881
|
try:
|
|
867
|
-
if hasattr(_langfuse_exporter,
|
|
882
|
+
if hasattr(_langfuse_exporter, "_exporter"):
|
|
868
883
|
_langfuse_exporter._exporter.shutdown()
|
|
869
884
|
logger.debug("Langfuse exporter shutdown gracefully")
|
|
870
885
|
except Exception:
|
|
@@ -887,6 +902,7 @@ def get_tracer(name: str = "ksadk"):
|
|
|
887
902
|
"""获取 Tracer"""
|
|
888
903
|
try:
|
|
889
904
|
from opentelemetry import trace
|
|
905
|
+
|
|
890
906
|
return trace.get_tracer(name)
|
|
891
907
|
except ImportError:
|
|
892
908
|
return None
|
ksadk/tracing/span_utils.py
CHANGED
|
@@ -93,9 +93,12 @@ def get_langfuse_callback(
|
|
|
93
93
|
Langfuse callback handler 或 None
|
|
94
94
|
"""
|
|
95
95
|
try:
|
|
96
|
-
|
|
96
|
+
import ksadk.tracing as tracing_module
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
factory = getattr(tracing_module, "get_langfuse_callback_handler", None)
|
|
99
|
+
if not callable(factory):
|
|
100
|
+
return None
|
|
101
|
+
handler = factory()
|
|
99
102
|
if handler:
|
|
100
103
|
# 设置 session 和 metadata
|
|
101
104
|
handler.session_id = session_id
|
ksadk/tui/loop.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Transcript 使用 ANSI 保留 rich 颜色和 Markdown 落定格式,composer 紧跟内容,
|
|
4
4
|
终端原生 scrollback 保留。支持键盘滚动、流式跟底和输入排队。
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
from __future__ import annotations
|
|
7
8
|
|
|
8
9
|
import asyncio
|
|
@@ -105,7 +106,11 @@ def _codex_surface_rgb(
|
|
|
105
106
|
# so 4% black on a light terminal is visually imperceptible; 8% gives the
|
|
106
107
|
# input surface a stable edge without introducing a border.
|
|
107
108
|
alpha = 0.08 if is_light and composer else 0.04 if is_light else 0.12
|
|
108
|
-
return
|
|
109
|
+
return (
|
|
110
|
+
int(top[0] * alpha + background[0] * (1.0 - alpha)),
|
|
111
|
+
int(top[1] * alpha + background[1] * (1.0 - alpha)),
|
|
112
|
+
int(top[2] * alpha + background[2] * (1.0 - alpha)),
|
|
113
|
+
)
|
|
109
114
|
|
|
110
115
|
|
|
111
116
|
def _codex_surface_style(background: tuple[int, int, int] | None) -> str:
|
|
@@ -319,12 +324,16 @@ class SlashCommandCompleter(Completer):
|
|
|
319
324
|
return
|
|
320
325
|
# /model <prefix> → 补全可选模型 id
|
|
321
326
|
if prefix.startswith("/model ") and self.runner is not None:
|
|
322
|
-
model_prefix = prefix[len("/model "):].strip()
|
|
327
|
+
model_prefix = prefix[len("/model ") :].strip()
|
|
323
328
|
available = getattr(self.runner, "available_models", None) or []
|
|
324
329
|
for m in available:
|
|
325
330
|
mid = str(m.get("id") or m.get("name") or "")
|
|
326
331
|
if mid and mid.startswith(model_prefix):
|
|
327
|
-
yield Completion(
|
|
332
|
+
yield Completion(
|
|
333
|
+
mid,
|
|
334
|
+
start_position=-len(model_prefix),
|
|
335
|
+
display_meta=m.get("display_name") or "",
|
|
336
|
+
)
|
|
328
337
|
return
|
|
329
338
|
for command, meta in self._COMMANDS.items():
|
|
330
339
|
if command.startswith(prefix):
|
|
@@ -372,7 +381,7 @@ class RichLiveRenderer:
|
|
|
372
381
|
self.assistant_entry.content = full_text
|
|
373
382
|
self.assistant_entry.status = "streaming"
|
|
374
383
|
if full_text.startswith(self._last_full_text):
|
|
375
|
-
delta = full_text[len(self._last_full_text):]
|
|
384
|
+
delta = full_text[len(self._last_full_text) :]
|
|
376
385
|
else:
|
|
377
386
|
# A final/snapshot event can replace the cumulative text. Preserve
|
|
378
387
|
# ordering when possible; without tools it is safe to replace the
|
|
@@ -398,7 +407,9 @@ class RichLiveRenderer:
|
|
|
398
407
|
self.assistant_entry.thinking = full_thinking
|
|
399
408
|
# thinking 不进动态区,落定时随 assistant 一起渲染(show_thinking)
|
|
400
409
|
|
|
401
|
-
async def on_tool_call(
|
|
410
|
+
async def on_tool_call(
|
|
411
|
+
self, tool_name: str, status: str, args: Any = None, call_id: str = ""
|
|
412
|
+
) -> None:
|
|
402
413
|
if self.loop is None:
|
|
403
414
|
return
|
|
404
415
|
content = f"{tool_name} [{status}]"
|
|
@@ -441,7 +452,7 @@ class RichLiveRenderer:
|
|
|
441
452
|
def final_entries(self, response: str) -> list[TranscriptEntry]:
|
|
442
453
|
"""Return finalized display cells in the original stream event order."""
|
|
443
454
|
if response and response.startswith(self._last_full_text):
|
|
444
|
-
delta = response[len(self._last_full_text):]
|
|
455
|
+
delta = response[len(self._last_full_text) :]
|
|
445
456
|
if delta:
|
|
446
457
|
if self._active_text_entry is None:
|
|
447
458
|
self._active_text_entry = TranscriptEntry(role="assistant")
|
|
@@ -507,7 +518,9 @@ class InteractionLoop:
|
|
|
507
518
|
self._pin_to_bottom = True
|
|
508
519
|
self._last_max_scroll = 0
|
|
509
520
|
self._history_pager_active = False
|
|
510
|
-
self._entry_ansi_cache: dict[int, str] =
|
|
521
|
+
self._entry_ansi_cache: dict[int, str] = (
|
|
522
|
+
{}
|
|
523
|
+
) # 历史 entries ANSI 缓存(避免 streaming 全量重渲)
|
|
511
524
|
self._last_usage: dict[str, Any] | None = None
|
|
512
525
|
self._showed_help = False # 首次运行显示帮助列表
|
|
513
526
|
self._welcome_ansi: str | None = None
|
|
@@ -600,6 +613,7 @@ class InteractionLoop:
|
|
|
600
613
|
multiline=True,
|
|
601
614
|
history=InMemoryHistory(),
|
|
602
615
|
)
|
|
616
|
+
input_buffer = self._input_buffer
|
|
603
617
|
|
|
604
618
|
# Codex uses an inline, content-first viewport: short transcripts keep
|
|
605
619
|
# the composer directly below the content and a filler absorbs the rest
|
|
@@ -771,13 +785,13 @@ class InteractionLoop:
|
|
|
771
785
|
|
|
772
786
|
@bindings.add("enter")
|
|
773
787
|
def _submit(event) -> None:
|
|
774
|
-
text =
|
|
775
|
-
|
|
788
|
+
text = input_buffer.text
|
|
789
|
+
input_buffer.reset(append_to_history=bool(text.strip()))
|
|
776
790
|
self._submit_text(text)
|
|
777
791
|
|
|
778
792
|
@bindings.add("escape", "enter")
|
|
779
793
|
def _newline(event) -> None:
|
|
780
|
-
|
|
794
|
+
input_buffer.insert_text("\n")
|
|
781
795
|
|
|
782
796
|
@bindings.add("c-c")
|
|
783
797
|
def _interrupt_or_exit(event) -> None:
|
|
@@ -796,7 +810,7 @@ class InteractionLoop:
|
|
|
796
810
|
|
|
797
811
|
@bindings.add("c-d")
|
|
798
812
|
def _exit_on_empty(event) -> None:
|
|
799
|
-
if not
|
|
813
|
+
if not input_buffer.text:
|
|
800
814
|
event.app.exit()
|
|
801
815
|
|
|
802
816
|
@bindings.add("pageup")
|
|
@@ -835,14 +849,18 @@ class InteractionLoop:
|
|
|
835
849
|
@bindings.add("up", filter=self._picker_condition)
|
|
836
850
|
def _picker_up(event) -> None:
|
|
837
851
|
if self._model_picker_models:
|
|
838
|
-
self._model_picker_index = (self._model_picker_index - 1) % len(
|
|
852
|
+
self._model_picker_index = (self._model_picker_index - 1) % len(
|
|
853
|
+
self._model_picker_models
|
|
854
|
+
)
|
|
839
855
|
self._scroll_picker_to_selected()
|
|
840
856
|
event.app.invalidate()
|
|
841
857
|
|
|
842
858
|
@bindings.add("down", filter=self._picker_condition)
|
|
843
859
|
def _picker_down(event) -> None:
|
|
844
860
|
if self._model_picker_models:
|
|
845
|
-
self._model_picker_index = (self._model_picker_index + 1) % len(
|
|
861
|
+
self._model_picker_index = (self._model_picker_index + 1) % len(
|
|
862
|
+
self._model_picker_models
|
|
863
|
+
)
|
|
846
864
|
self._scroll_picker_to_selected()
|
|
847
865
|
event.app.invalidate()
|
|
848
866
|
|
|
@@ -850,7 +868,11 @@ class InteractionLoop:
|
|
|
850
868
|
def _picker_select(event) -> None:
|
|
851
869
|
models = self._model_picker_models
|
|
852
870
|
if models and 0 <= self._model_picker_index < len(models):
|
|
853
|
-
mid = str(
|
|
871
|
+
mid = str(
|
|
872
|
+
models[self._model_picker_index].get("id")
|
|
873
|
+
or models[self._model_picker_index].get("name")
|
|
874
|
+
or ""
|
|
875
|
+
)
|
|
854
876
|
if mid:
|
|
855
877
|
self._apply_model_switch(mid)
|
|
856
878
|
self._close_model_picker()
|
|
@@ -980,7 +1002,9 @@ class InteractionLoop:
|
|
|
980
1002
|
for entry in renderer.final_entries(renderer._last_full_text):
|
|
981
1003
|
await self._commit_entry(entry)
|
|
982
1004
|
if is_resume:
|
|
983
|
-
await self._commit_entry(
|
|
1005
|
+
await self._commit_entry(
|
|
1006
|
+
TranscriptEntry(role="system", content="该 runtime 暂不支持审批续跑,已取消")
|
|
1007
|
+
)
|
|
984
1008
|
self._clear_current_task()
|
|
985
1009
|
self._drain_queue()
|
|
986
1010
|
else:
|
|
@@ -992,7 +1016,9 @@ class InteractionLoop:
|
|
|
992
1016
|
assistant_entry.status = ""
|
|
993
1017
|
for entry in renderer.final_entries(renderer._last_full_text):
|
|
994
1018
|
await self._commit_entry(entry)
|
|
995
|
-
await self._commit_entry(
|
|
1019
|
+
await self._commit_entry(
|
|
1020
|
+
TranscriptEntry(role="system", content="已取消(保留已产生内容)")
|
|
1021
|
+
)
|
|
996
1022
|
self._clear_current_task()
|
|
997
1023
|
self._drain_queue()
|
|
998
1024
|
return
|
|
@@ -1018,7 +1044,9 @@ class InteractionLoop:
|
|
|
1018
1044
|
|
|
1019
1045
|
async def _prompt():
|
|
1020
1046
|
await self._commit_entry(
|
|
1021
|
-
TranscriptEntry(
|
|
1047
|
+
TranscriptEntry(
|
|
1048
|
+
role="system", content=f"确认执行 {tool_name}? 输入 y 确认,其他内容取消"
|
|
1049
|
+
)
|
|
1022
1050
|
)
|
|
1023
1051
|
|
|
1024
1052
|
self._create_background_task(_prompt())
|
|
@@ -1032,7 +1060,9 @@ class InteractionLoop:
|
|
|
1032
1060
|
if user_input.lower() in {"y", "yes"}:
|
|
1033
1061
|
|
|
1034
1062
|
async def _resume():
|
|
1035
|
-
await self._commit_entry(
|
|
1063
|
+
await self._commit_entry(
|
|
1064
|
+
TranscriptEntry(role="system", content="已确认,尝试续跑...")
|
|
1065
|
+
)
|
|
1036
1066
|
self._start_turn(
|
|
1037
1067
|
"",
|
|
1038
1068
|
input_data={**input_data, "resume": True},
|
|
@@ -1049,7 +1079,11 @@ class InteractionLoop:
|
|
|
1049
1079
|
self._create_background_task(_cancel())
|
|
1050
1080
|
|
|
1051
1081
|
def _drain_queue(self) -> None:
|
|
1052
|
-
if
|
|
1082
|
+
if (
|
|
1083
|
+
self._pending_interrupt is not None
|
|
1084
|
+
or self._has_active_turn()
|
|
1085
|
+
or not self._queued_inputs
|
|
1086
|
+
):
|
|
1053
1087
|
return
|
|
1054
1088
|
item = self._queued_inputs.pop(0)
|
|
1055
1089
|
self._start_turn(item.text, user_entry=item.entry)
|
|
@@ -1167,7 +1201,7 @@ class InteractionLoop:
|
|
|
1167
1201
|
|
|
1168
1202
|
def _handle_model_command(self, user_input: str) -> None:
|
|
1169
1203
|
"""/model:弹出交互式选择器(↑↓ Enter Esc);/model <name>:直接切换(runnable 级,下轮生效)。"""
|
|
1170
|
-
arg = user_input[len("/model"):].strip()
|
|
1204
|
+
arg = user_input[len("/model") :].strip()
|
|
1171
1205
|
if arg:
|
|
1172
1206
|
# 直接切换:改 runner.model,下轮请求带新 model
|
|
1173
1207
|
self._apply_model_switch(arg)
|
|
@@ -1192,7 +1226,9 @@ class InteractionLoop:
|
|
|
1192
1226
|
"""
|
|
1193
1227
|
self.runner.model = model_id
|
|
1194
1228
|
available = getattr(self.runner, "available_models", None) or []
|
|
1195
|
-
matched = next(
|
|
1229
|
+
matched = next(
|
|
1230
|
+
(m for m in available if str(m.get("id") or m.get("name") or "") == model_id), None
|
|
1231
|
+
)
|
|
1196
1232
|
if matched:
|
|
1197
1233
|
self.runner.model_metadata = matched
|
|
1198
1234
|
# 清旧观察名,让 _current_model_name 用新 runner.model
|
|
@@ -1263,8 +1299,8 @@ class InteractionLoop:
|
|
|
1263
1299
|
frags: list[tuple[str, str]] = []
|
|
1264
1300
|
for i, m in enumerate(self._model_picker_models):
|
|
1265
1301
|
mid = str(m.get("id") or m.get("name") or "")
|
|
1266
|
-
is_cur_model =
|
|
1267
|
-
is_selected =
|
|
1302
|
+
is_cur_model = mid == current
|
|
1303
|
+
is_selected = i == self._model_picker_index
|
|
1268
1304
|
marker = "›" if is_selected else " "
|
|
1269
1305
|
line = f"{marker} {i + 1}. {mid}"
|
|
1270
1306
|
if is_cur_model:
|
|
@@ -1276,7 +1312,7 @@ class InteractionLoop:
|
|
|
1276
1312
|
# ---- streaming / transcript 渲染 ----
|
|
1277
1313
|
|
|
1278
1314
|
def _set_streaming(self, full_text: str) -> None:
|
|
1279
|
-
"""
|
|
1315
|
+
"""更新 transcript 末尾的 streaming entry。"""
|
|
1280
1316
|
if self._streaming_entry is not None:
|
|
1281
1317
|
self._streaming_entry.content = full_text
|
|
1282
1318
|
self._streaming_entry.status = "streaming"
|
|
@@ -1365,6 +1401,7 @@ class InteractionLoop:
|
|
|
1365
1401
|
height = int(getattr(ri, "window_height", 0) or 0)
|
|
1366
1402
|
if height <= 0:
|
|
1367
1403
|
import shutil
|
|
1404
|
+
|
|
1368
1405
|
height = max(10, (shutil.get_terminal_size(fallback=(80, 24)).lines or 24) - 6)
|
|
1369
1406
|
line_count = self._transcript_line_count()
|
|
1370
1407
|
return max(0, line_count - height)
|
|
@@ -1522,18 +1559,22 @@ def _resolve_model_name(runner) -> str:
|
|
|
1522
1559
|
return str(meta["id"])
|
|
1523
1560
|
observed = getattr(runner, "_observed_model", None)
|
|
1524
1561
|
if observed:
|
|
1525
|
-
return observed
|
|
1526
|
-
return getattr(runner, "model", None) or os.getenv("MODEL_NAME") or "unknown"
|
|
1562
|
+
return str(observed)
|
|
1563
|
+
return str(getattr(runner, "model", None) or os.getenv("MODEL_NAME") or "unknown")
|
|
1527
1564
|
|
|
1528
1565
|
|
|
1529
1566
|
def _help_text() -> str:
|
|
1530
|
-
return
|
|
1567
|
+
return (
|
|
1568
|
+
"命令: /new 新会话 · /clear 清屏 · /session 查看 · /tools 展开工具 "
|
|
1569
|
+
"· exit 退出 · Ctrl-C 中断/退出"
|
|
1570
|
+
)
|
|
1531
1571
|
|
|
1532
1572
|
|
|
1533
1573
|
def _welcome_block(session_id: str, model_name: str, project_dir: Path, *, show_help: bool) -> str:
|
|
1534
1574
|
"""Render the compact Codex-style session card and one-line tip."""
|
|
1535
1575
|
try:
|
|
1536
1576
|
from ksadk.version import VERSION
|
|
1577
|
+
|
|
1537
1578
|
version = VERSION
|
|
1538
1579
|
except Exception:
|
|
1539
1580
|
version = ""
|
|
@@ -1552,6 +1593,7 @@ def _welcome_block(session_id: str, model_name: str, project_dir: Path, *, show_
|
|
|
1552
1593
|
# 按终端宽度算框宽,留 transcript 左缩进 2 + 右 margin 2,上限 56(Codex 同款)。
|
|
1553
1594
|
try:
|
|
1554
1595
|
import shutil
|
|
1596
|
+
|
|
1555
1597
|
cols = shutil.get_terminal_size(fallback=(80, 24)).columns
|
|
1556
1598
|
except Exception:
|
|
1557
1599
|
cols = 80
|
|
@@ -1698,7 +1740,9 @@ def _render_entry_ansi(
|
|
|
1698
1740
|
else:
|
|
1699
1741
|
console.print(Markdown(_normalize_markdown(f"{body}{suffix}")))
|
|
1700
1742
|
else:
|
|
1701
|
-
console.print(
|
|
1743
|
+
console.print(
|
|
1744
|
+
Text(suffix.lstrip(), style="dim") if suffix else Text("...", style="dim")
|
|
1745
|
+
)
|
|
1702
1746
|
return _strip_ansi_backgrounds(console.export_text(styles=True)).rstrip() + "\n"
|
|
1703
1747
|
|
|
1704
1748
|
if entry.role == "tool":
|
|
@@ -1718,6 +1762,7 @@ def _render_entry_ansi(
|
|
|
1718
1762
|
display_output = output
|
|
1719
1763
|
try:
|
|
1720
1764
|
import json as _json
|
|
1765
|
+
|
|
1721
1766
|
parsed = _json.loads(output)
|
|
1722
1767
|
# Tool adapters often JSON-encode an already serialized result.
|
|
1723
1768
|
# Unwrap that second layer so structured output folds by fields
|
|
@@ -1729,7 +1774,7 @@ def _render_entry_ansi(
|
|
|
1729
1774
|
if nested.startswith("content="):
|
|
1730
1775
|
import ast as _ast
|
|
1731
1776
|
|
|
1732
|
-
quote = nested[len("content="):len("content=") + 1]
|
|
1777
|
+
quote = nested[len("content=") : len("content=") + 1]
|
|
1733
1778
|
if quote in {"'", '"'}:
|
|
1734
1779
|
body_start = len("content=") + 1
|
|
1735
1780
|
body_end = body_start
|
|
@@ -1756,6 +1801,7 @@ def _render_entry_ansi(
|
|
|
1756
1801
|
pass
|
|
1757
1802
|
# 估算显示行数:每行按 console width 折算(长字符串占多行)
|
|
1758
1803
|
import shutil as _su
|
|
1804
|
+
|
|
1759
1805
|
cw = max(40, (_su.get_terminal_size(fallback=(80, 24)).columns or 80) - 6)
|
|
1760
1806
|
logical_lines = display_output.split("\n")
|
|
1761
1807
|
# 估算显示行数:按显示宽度(CJK 占 2)折算,非 len
|
|
@@ -1864,7 +1910,9 @@ def _strip_ansi_backgrounds(text: str) -> str:
|
|
|
1864
1910
|
return re.sub(r"\x1b\[([0-9;]*)m", _clean, text)
|
|
1865
1911
|
|
|
1866
1912
|
|
|
1867
|
-
def run_tui(
|
|
1913
|
+
def run_tui(
|
|
1914
|
+
runner, *, show_thinking: bool = False, project_dir: str = ".", no_alt_screen: bool = False
|
|
1915
|
+
) -> None:
|
|
1868
1916
|
"""TUI 入口:被 cmd_invoke._invoke_tui / cmd_run._run_custom 调用。
|
|
1869
1917
|
|
|
1870
1918
|
``no_alt_screen`` 作为兼容参数保留;TUI 现在默认使用 Codex-style inline viewport。
|