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
|
@@ -23,19 +23,19 @@
|
|
|
23
23
|
import json
|
|
24
24
|
import logging
|
|
25
25
|
import os
|
|
26
|
-
from typing import Any, List, Literal
|
|
26
|
+
from typing import Any, List, Literal, Optional, cast
|
|
27
27
|
|
|
28
|
-
from
|
|
29
|
-
from
|
|
28
|
+
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
|
|
29
|
+
from typing_extensions import Union, override
|
|
30
|
+
|
|
31
|
+
from ksadk.compat.adk_compat import (
|
|
30
32
|
BaseMemoryService,
|
|
33
|
+
Event,
|
|
34
|
+
MemoryEntry,
|
|
31
35
|
SearchMemoryResponse,
|
|
36
|
+
Session,
|
|
32
37
|
)
|
|
33
|
-
from
|
|
34
|
-
from google.adk.sessions import Session
|
|
35
|
-
from google.genai import types
|
|
36
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
37
|
-
from typing_extensions import Union, override
|
|
38
|
-
|
|
38
|
+
from ksadk.compat.adk_compat import genai_types as types
|
|
39
39
|
from ksadk.memory.adk.backends.base_ltm_backend import BaseLongTermMemoryBackend
|
|
40
40
|
from ksadk.memory.service import LongTermMemoryService
|
|
41
41
|
|
|
@@ -83,8 +83,8 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
83
83
|
index: str = ""
|
|
84
84
|
app_name: str = ""
|
|
85
85
|
|
|
86
|
-
_backend: BaseLongTermMemoryBackend = None
|
|
87
|
-
_service: LongTermMemoryService = None
|
|
86
|
+
_backend: Optional[BaseLongTermMemoryBackend] = PrivateAttr(default=None)
|
|
87
|
+
_service: Optional[LongTermMemoryService] = PrivateAttr(default=None)
|
|
88
88
|
|
|
89
89
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
90
90
|
|
|
@@ -105,14 +105,18 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
def _get_service(self) -> LongTermMemoryService:
|
|
108
|
-
|
|
108
|
+
service = self._service
|
|
109
|
+
if service is None:
|
|
109
110
|
self.model_post_init(None)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
service = self._service
|
|
112
|
+
if service is None:
|
|
113
|
+
raise RuntimeError("LongTermMemory service initialization failed")
|
|
114
|
+
if self._backend is not None and service._backend is not self._backend:
|
|
115
|
+
service.backend = self._backend
|
|
116
|
+
service._backend = self._backend
|
|
117
|
+
service.index = getattr(self._backend, "index", service.index)
|
|
118
|
+
self.index = service.index
|
|
119
|
+
return service
|
|
116
120
|
|
|
117
121
|
def _filter_and_convert_events(self, events: List[Event]) -> List[str]:
|
|
118
122
|
"""过滤并序列化 session 事件
|
|
@@ -157,9 +161,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
157
161
|
event_strings = self._filter_and_convert_events(session.events)
|
|
158
162
|
|
|
159
163
|
if not event_strings:
|
|
160
|
-
logger.info(
|
|
161
|
-
f"No user events to save for session={session.id}"
|
|
162
|
-
)
|
|
164
|
+
logger.info(f"No user events to save for session={session.id}")
|
|
163
165
|
return
|
|
164
166
|
|
|
165
167
|
logger.info(
|
|
@@ -200,9 +202,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
200
202
|
query=query, top_k=self.top_k, user_id=user_id
|
|
201
203
|
)
|
|
202
204
|
except Exception as e:
|
|
203
|
-
logger.error(
|
|
204
|
-
f"Error during memory search: {e}. Returning empty results."
|
|
205
|
-
)
|
|
205
|
+
logger.error(f"Error during memory search: {e}. Returning empty results.")
|
|
206
206
|
|
|
207
207
|
# 转换为 MemoryEntry 格式
|
|
208
208
|
memory_events = []
|
|
@@ -213,9 +213,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
213
213
|
text = memory_dict["parts"][0]["text"]
|
|
214
214
|
role = memory_dict.get("role", "user")
|
|
215
215
|
except (KeyError, IndexError):
|
|
216
|
-
logger.warning(
|
|
217
|
-
f"Non-standard memory format: {memory[:100]}. Skipping."
|
|
218
|
-
)
|
|
216
|
+
logger.warning(f"Non-standard memory format: {memory[:100]}. Skipping.")
|
|
219
217
|
continue
|
|
220
218
|
except json.JSONDecodeError:
|
|
221
219
|
# 非 JSON 格式的记忆字符串,直接作为 text
|
|
@@ -225,9 +223,7 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
225
223
|
memory_events.append(
|
|
226
224
|
MemoryEntry(
|
|
227
225
|
author="user",
|
|
228
|
-
content=types.Content(
|
|
229
|
-
parts=[types.Part(text=text)], role=role
|
|
230
|
-
),
|
|
226
|
+
content=types.Content(parts=[types.Part(text=text)], role=role),
|
|
231
227
|
)
|
|
232
228
|
)
|
|
233
229
|
|
|
@@ -256,16 +252,16 @@ class LongTermMemory(BaseMemoryService, BaseModel):
|
|
|
256
252
|
KSADK_LTM_INDEX: 索引名称
|
|
257
253
|
"""
|
|
258
254
|
service = LongTermMemoryService.from_env(app_name=app_name, backend=backend)
|
|
259
|
-
backend_name = (
|
|
260
|
-
backend
|
|
261
|
-
or os.environ.get("KSADK_LTM_BACKEND", "local")
|
|
262
|
-
)
|
|
255
|
+
backend_name = backend or os.environ.get("KSADK_LTM_BACKEND", "local")
|
|
263
256
|
backend_config = dict(service.backend_config)
|
|
264
257
|
if "index" in backend_config and backend_name != "local":
|
|
265
258
|
backend_config.pop("index", None)
|
|
266
259
|
|
|
260
|
+
if backend_name not in {"local", "http", "sdk"}:
|
|
261
|
+
raise ValueError(f"Unsupported long-term memory backend: {backend_name}")
|
|
262
|
+
normalized_backend = cast(Literal["local", "http", "sdk"], backend_name)
|
|
267
263
|
return cls(
|
|
268
|
-
backend=
|
|
264
|
+
backend=normalized_backend,
|
|
269
265
|
backend_config=backend_config,
|
|
270
266
|
top_k=service.top_k,
|
|
271
267
|
index=service.index,
|
|
@@ -4,15 +4,14 @@ import asyncio
|
|
|
4
4
|
import logging
|
|
5
5
|
from typing import Any, Optional
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
from google.adk.sessions import InMemorySessionService
|
|
9
|
-
from google.adk.sessions.base_session_service import (
|
|
7
|
+
from ksadk.compat.adk_compat import (
|
|
10
8
|
BaseSessionService,
|
|
9
|
+
Event,
|
|
11
10
|
GetSessionConfig,
|
|
11
|
+
InMemorySessionService,
|
|
12
12
|
ListSessionsResponse,
|
|
13
|
+
Session,
|
|
13
14
|
)
|
|
14
|
-
from google.adk.sessions.session import Session
|
|
15
|
-
|
|
16
15
|
from ksadk.sessions.resilience import is_session_backend_failure
|
|
17
16
|
|
|
18
17
|
logger = logging.getLogger(__name__)
|
|
@@ -24,14 +24,15 @@
|
|
|
24
24
|
|
|
25
25
|
import logging
|
|
26
26
|
import os
|
|
27
|
-
from typing import Any, Literal, Optional
|
|
27
|
+
from typing import Any, Literal, Optional, cast
|
|
28
28
|
|
|
29
|
-
from
|
|
29
|
+
from pydantic import BaseModel, PrivateAttr
|
|
30
|
+
|
|
31
|
+
from ksadk.compat.adk_compat import (
|
|
30
32
|
BaseSessionService,
|
|
31
33
|
InMemorySessionService,
|
|
32
34
|
Session,
|
|
33
35
|
)
|
|
34
|
-
from pydantic import BaseModel, PrivateAttr
|
|
35
36
|
|
|
36
37
|
logger = logging.getLogger(__name__)
|
|
37
38
|
|
|
@@ -119,14 +120,9 @@ class ShortTermMemory(BaseModel):
|
|
|
119
120
|
logger.info("ShortTermMemory: using InMemorySessionService")
|
|
120
121
|
|
|
121
122
|
case "sqlite":
|
|
122
|
-
db_url = _normalize_database_url(
|
|
123
|
-
f"sqlite:///{self.local_database_path}"
|
|
124
|
-
)
|
|
123
|
+
db_url = _normalize_database_url(f"sqlite:///{self.local_database_path}")
|
|
125
124
|
self._init_database_service(db_url)
|
|
126
|
-
logger.info(
|
|
127
|
-
f"ShortTermMemory: using SQLite at "
|
|
128
|
-
f"{self.local_database_path}"
|
|
129
|
-
)
|
|
125
|
+
logger.info(f"ShortTermMemory: using SQLite at " f"{self.local_database_path}")
|
|
130
126
|
|
|
131
127
|
case "database":
|
|
132
128
|
if not self.db_url:
|
|
@@ -148,8 +144,7 @@ class ShortTermMemory(BaseModel):
|
|
|
148
144
|
"""初始化数据库 SessionService"""
|
|
149
145
|
normalized_db_url = _normalize_database_url(db_url)
|
|
150
146
|
try:
|
|
151
|
-
from
|
|
152
|
-
|
|
147
|
+
from ksadk.compat.adk_compat import DatabaseSessionService
|
|
153
148
|
from ksadk.memory.adk.resilient_session_service import ResilientADKSessionService
|
|
154
149
|
from ksadk.sessions.resilience import session_backend_timeout_seconds
|
|
155
150
|
|
|
@@ -165,8 +160,7 @@ class ShortTermMemory(BaseModel):
|
|
|
165
160
|
DatabaseSessionService(db_url=normalized_db_url, **service_kwargs)
|
|
166
161
|
)
|
|
167
162
|
logger.info(
|
|
168
|
-
f"ShortTermMemory: using DatabaseSessionService "
|
|
169
|
-
f"({normalized_db_url[:30]}...)"
|
|
163
|
+
f"ShortTermMemory: using DatabaseSessionService " f"({normalized_db_url[:30]}...)"
|
|
170
164
|
)
|
|
171
165
|
except ImportError:
|
|
172
166
|
logger.warning(
|
|
@@ -218,8 +212,7 @@ class ShortTermMemory(BaseModel):
|
|
|
218
212
|
)
|
|
219
213
|
if session:
|
|
220
214
|
logger.debug(
|
|
221
|
-
f"Session {session_id} already exists "
|
|
222
|
-
f"(app={app_name}, user={user_id})"
|
|
215
|
+
f"Session {session_id} already exists " f"(app={app_name}, user={user_id})"
|
|
223
216
|
)
|
|
224
217
|
return session
|
|
225
218
|
except Exception as e:
|
|
@@ -238,10 +231,7 @@ class ShortTermMemory(BaseModel):
|
|
|
238
231
|
app_name=app_name,
|
|
239
232
|
user_id=user_id,
|
|
240
233
|
)
|
|
241
|
-
logger.info(
|
|
242
|
-
f"Created session: id={session.id}, "
|
|
243
|
-
f"app={app_name}, user={user_id}"
|
|
244
|
-
)
|
|
234
|
+
logger.info(f"Created session: id={session.id}, " f"app={app_name}, user={user_id}")
|
|
245
235
|
return session
|
|
246
236
|
except Exception as e:
|
|
247
237
|
logger.error(f"Failed to create session: {e}")
|
|
@@ -297,8 +287,9 @@ class ShortTermMemory(BaseModel):
|
|
|
297
287
|
else:
|
|
298
288
|
backend = "local"
|
|
299
289
|
|
|
290
|
+
backend_name = cast(Literal["local", "sqlite", "database"], backend)
|
|
300
291
|
return cls(
|
|
301
|
-
backend=
|
|
292
|
+
backend=backend_name,
|
|
302
293
|
db_url=db_url,
|
|
303
294
|
local_database_path=db_path,
|
|
304
295
|
)
|
ksadk/memory/adk_tool.py
CHANGED
|
@@ -21,11 +21,12 @@ def save_memory(content: str) -> dict:
|
|
|
21
21
|
|
|
22
22
|
def create_adk_tool():
|
|
23
23
|
try:
|
|
24
|
-
from
|
|
24
|
+
from ksadk.compat.adk_compat import FunctionTool
|
|
25
25
|
|
|
26
26
|
return FunctionTool(func=save_memory)
|
|
27
27
|
except ImportError:
|
|
28
28
|
logger.warning(
|
|
29
|
-
"google-adk not installed, returning raw function as tool.
|
|
29
|
+
"google-adk not installed, returning raw function as tool. "
|
|
30
|
+
"Install with: pip install ksadk[adk]"
|
|
30
31
|
)
|
|
31
32
|
return save_memory
|
ksadk/memory/backends/base.py
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
"""Base Memory Backend - 抽象基类"""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Any, Optional, List, Dict
|
|
5
4
|
from datetime import timedelta
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class BaseMemoryBackend(ABC):
|
|
9
9
|
"""记忆存储后端抽象基类
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
所有后端实现必须继承此类并实现以下方法。
|
|
12
12
|
"""
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
@abstractmethod
|
|
15
15
|
def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
|
|
16
16
|
"""获取值
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
Args:
|
|
19
19
|
key: 键名
|
|
20
20
|
session_id: 可选的会话 ID,用于隔离不同会话的数据
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
Returns:
|
|
23
23
|
存储的值,不存在返回 None
|
|
24
24
|
"""
|
|
25
25
|
pass
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
@abstractmethod
|
|
28
28
|
def set(
|
|
29
29
|
self,
|
|
@@ -33,43 +33,43 @@ class BaseMemoryBackend(ABC):
|
|
|
33
33
|
ttl: Optional[timedelta] = None,
|
|
34
34
|
) -> bool:
|
|
35
35
|
"""设置值
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
Args:
|
|
38
38
|
key: 键名
|
|
39
39
|
value: 值 (会自动序列化)
|
|
40
40
|
session_id: 可选的会话 ID
|
|
41
41
|
ttl: 可选的过期时间
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
Returns:
|
|
44
44
|
是否成功
|
|
45
45
|
"""
|
|
46
46
|
pass
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
@abstractmethod
|
|
49
49
|
def delete(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
50
50
|
"""删除键
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
Args:
|
|
53
53
|
key: 键名
|
|
54
54
|
session_id: 可选的会话 ID
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
Returns:
|
|
57
57
|
是否成功
|
|
58
58
|
"""
|
|
59
59
|
pass
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
@abstractmethod
|
|
62
62
|
def exists(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
63
63
|
"""检查键是否存在"""
|
|
64
64
|
pass
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
@abstractmethod
|
|
67
67
|
def clear_session(self, session_id: str) -> bool:
|
|
68
68
|
"""清除整个会话的所有数据"""
|
|
69
69
|
pass
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
# ===== 消息历史相关 (短期记忆) =====
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
@abstractmethod
|
|
74
74
|
def add_message(
|
|
75
75
|
self,
|
|
@@ -80,7 +80,7 @@ class BaseMemoryBackend(ABC):
|
|
|
80
80
|
) -> bool:
|
|
81
81
|
"""添加消息到会话历史"""
|
|
82
82
|
pass
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
@abstractmethod
|
|
85
85
|
def get_messages(
|
|
86
86
|
self,
|
|
@@ -88,16 +88,16 @@ class BaseMemoryBackend(ABC):
|
|
|
88
88
|
limit: Optional[int] = None,
|
|
89
89
|
) -> List[Dict]:
|
|
90
90
|
"""获取会话消息历史
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
Args:
|
|
93
93
|
session_id: 会话 ID
|
|
94
94
|
limit: 最近 N 条消息,None 表示全部
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
Returns:
|
|
97
97
|
消息列表 [{role, content, timestamp, ...}]
|
|
98
98
|
"""
|
|
99
99
|
pass
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
def close(self) -> None:
|
|
102
102
|
"""关闭连接 (可选实现)"""
|
|
103
103
|
pass
|
ksadk/memory/backends/memory.py
CHANGED
|
@@ -1,49 +1,48 @@
|
|
|
1
1
|
"""In-Memory Backend - 内存存储 (开发/测试用)"""
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
|
-
from datetime import datetime, timedelta
|
|
5
|
-
from typing import Any, Optional, List, Dict
|
|
6
3
|
from collections import defaultdict
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
7
6
|
|
|
8
7
|
from ksadk.memory.backends.base import BaseMemoryBackend
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class InMemoryBackend(BaseMemoryBackend):
|
|
12
11
|
"""内存存储后端
|
|
13
|
-
|
|
12
|
+
|
|
14
13
|
适用于开发和测试,数据在进程退出后丢失。
|
|
15
14
|
"""
|
|
16
|
-
|
|
15
|
+
|
|
17
16
|
def __init__(self):
|
|
18
17
|
# {session_id: {key: (value, expires_at)}}
|
|
19
18
|
self._data: Dict[str, Dict[str, tuple]] = defaultdict(dict)
|
|
20
19
|
# {session_id: [messages]}
|
|
21
20
|
self._messages: Dict[str, List[Dict]] = defaultdict(list)
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
def _make_key(self, key: str, session_id: Optional[str]) -> tuple:
|
|
24
23
|
"""生成复合键"""
|
|
25
24
|
sid = session_id or "__global__"
|
|
26
25
|
return sid, key
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
def _is_expired(self, expires_at: Optional[datetime]) -> bool:
|
|
29
28
|
if expires_at is None:
|
|
30
29
|
return False
|
|
31
30
|
return datetime.utcnow() > expires_at
|
|
32
|
-
|
|
31
|
+
|
|
33
32
|
def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
|
|
34
33
|
sid, k = self._make_key(key, session_id)
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
if sid not in self._data or k not in self._data[sid]:
|
|
37
36
|
return None
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
value, expires_at = self._data[sid][k]
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
if self._is_expired(expires_at):
|
|
42
41
|
del self._data[sid][k]
|
|
43
42
|
return None
|
|
44
|
-
|
|
43
|
+
|
|
45
44
|
return value
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
def set(
|
|
48
47
|
self,
|
|
49
48
|
key: str,
|
|
@@ -52,32 +51,32 @@ class InMemoryBackend(BaseMemoryBackend):
|
|
|
52
51
|
ttl: Optional[timedelta] = None,
|
|
53
52
|
) -> bool:
|
|
54
53
|
sid, k = self._make_key(key, session_id)
|
|
55
|
-
|
|
54
|
+
|
|
56
55
|
expires_at = None
|
|
57
56
|
if ttl:
|
|
58
57
|
expires_at = datetime.utcnow() + ttl
|
|
59
|
-
|
|
58
|
+
|
|
60
59
|
self._data[sid][k] = (value, expires_at)
|
|
61
60
|
return True
|
|
62
|
-
|
|
61
|
+
|
|
63
62
|
def delete(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
64
63
|
sid, k = self._make_key(key, session_id)
|
|
65
|
-
|
|
64
|
+
|
|
66
65
|
if sid in self._data and k in self._data[sid]:
|
|
67
66
|
del self._data[sid][k]
|
|
68
67
|
return True
|
|
69
68
|
return False
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
def exists(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
72
71
|
return self.get(key, session_id) is not None
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
def clear_session(self, session_id: str) -> bool:
|
|
75
74
|
if session_id in self._data:
|
|
76
75
|
del self._data[session_id]
|
|
77
76
|
if session_id in self._messages:
|
|
78
77
|
del self._messages[session_id]
|
|
79
78
|
return True
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
def add_message(
|
|
82
81
|
self,
|
|
83
82
|
session_id: str,
|
|
@@ -85,28 +84,28 @@ class InMemoryBackend(BaseMemoryBackend):
|
|
|
85
84
|
content: str,
|
|
86
85
|
metadata: Optional[Dict] = None,
|
|
87
86
|
) -> bool:
|
|
88
|
-
msg = {
|
|
87
|
+
msg: Dict[str, Any] = {
|
|
89
88
|
"role": role,
|
|
90
89
|
"content": content,
|
|
91
90
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
92
91
|
}
|
|
93
92
|
if metadata:
|
|
94
93
|
msg["metadata"] = metadata
|
|
95
|
-
|
|
94
|
+
|
|
96
95
|
self._messages[session_id].append(msg)
|
|
97
96
|
return True
|
|
98
|
-
|
|
97
|
+
|
|
99
98
|
def get_messages(
|
|
100
99
|
self,
|
|
101
100
|
session_id: str,
|
|
102
101
|
limit: Optional[int] = None,
|
|
103
102
|
) -> List[Dict]:
|
|
104
103
|
messages = self._messages.get(session_id, [])
|
|
105
|
-
|
|
104
|
+
|
|
106
105
|
if limit:
|
|
107
106
|
return messages[-limit:]
|
|
108
107
|
return messages.copy()
|
|
109
|
-
|
|
108
|
+
|
|
110
109
|
def close(self) -> None:
|
|
111
110
|
self._data.clear()
|
|
112
111
|
self._messages.clear()
|
ksadk/memory/backends/redis.py
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from datetime import datetime, timedelta
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
7
|
from ksadk.memory.backends.base import BaseMemoryBackend
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class RedisBackend(BaseMemoryBackend):
|
|
11
11
|
"""Redis 存储后端
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
适用于短期记忆和会话状态存储。
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
使用示例:
|
|
16
16
|
backend = RedisBackend(url="redis://localhost:6379/0")
|
|
17
17
|
"""
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
def __init__(
|
|
20
20
|
self,
|
|
21
21
|
url: str = "redis://localhost:6379/0",
|
|
@@ -26,39 +26,40 @@ class RedisBackend(BaseMemoryBackend):
|
|
|
26
26
|
self.prefix = prefix
|
|
27
27
|
self.default_ttl = default_ttl
|
|
28
28
|
self._client = None
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
@property
|
|
31
31
|
def client(self):
|
|
32
32
|
"""懒加载 Redis 客户端"""
|
|
33
33
|
if self._client is None:
|
|
34
34
|
try:
|
|
35
35
|
import redis
|
|
36
|
+
|
|
36
37
|
self._client = redis.from_url(self.url, decode_responses=True)
|
|
37
38
|
except ImportError:
|
|
38
39
|
raise ImportError("redis package required. Install with: pip install redis")
|
|
39
40
|
return self._client
|
|
40
|
-
|
|
41
|
+
|
|
41
42
|
def _make_key(self, key: str, session_id: Optional[str]) -> str:
|
|
42
43
|
"""生成 Redis 键"""
|
|
43
44
|
if session_id:
|
|
44
45
|
return f"{self.prefix}session:{session_id}:{key}"
|
|
45
46
|
return f"{self.prefix}global:{key}"
|
|
46
|
-
|
|
47
|
+
|
|
47
48
|
def _messages_key(self, session_id: str) -> str:
|
|
48
49
|
return f"{self.prefix}messages:{session_id}"
|
|
49
|
-
|
|
50
|
+
|
|
50
51
|
def get(self, key: str, session_id: Optional[str] = None) -> Optional[Any]:
|
|
51
52
|
redis_key = self._make_key(key, session_id)
|
|
52
53
|
value = self.client.get(redis_key)
|
|
53
|
-
|
|
54
|
+
|
|
54
55
|
if value is None:
|
|
55
56
|
return None
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
try:
|
|
58
59
|
return json.loads(value)
|
|
59
60
|
except json.JSONDecodeError:
|
|
60
61
|
return value
|
|
61
|
-
|
|
62
|
+
|
|
62
63
|
def set(
|
|
63
64
|
self,
|
|
64
65
|
key: str,
|
|
@@ -67,40 +68,40 @@ class RedisBackend(BaseMemoryBackend):
|
|
|
67
68
|
ttl: Optional[timedelta] = None,
|
|
68
69
|
) -> bool:
|
|
69
70
|
redis_key = self._make_key(key, session_id)
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
# 序列化
|
|
72
73
|
if not isinstance(value, str):
|
|
73
74
|
value = json.dumps(value, ensure_ascii=False)
|
|
74
|
-
|
|
75
|
+
|
|
75
76
|
# 设置过期时间
|
|
76
77
|
ex = None
|
|
77
78
|
if ttl:
|
|
78
79
|
ex = int(ttl.total_seconds())
|
|
79
80
|
elif self.default_ttl:
|
|
80
81
|
ex = int(self.default_ttl.total_seconds())
|
|
81
|
-
|
|
82
|
+
|
|
82
83
|
self.client.set(redis_key, value, ex=ex)
|
|
83
84
|
return True
|
|
84
|
-
|
|
85
|
+
|
|
85
86
|
def delete(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
86
87
|
redis_key = self._make_key(key, session_id)
|
|
87
|
-
return self.client.delete(redis_key) > 0
|
|
88
|
-
|
|
88
|
+
return bool(self.client.delete(redis_key) > 0)
|
|
89
|
+
|
|
89
90
|
def exists(self, key: str, session_id: Optional[str] = None) -> bool:
|
|
90
91
|
redis_key = self._make_key(key, session_id)
|
|
91
|
-
return self.client.exists(redis_key) > 0
|
|
92
|
-
|
|
92
|
+
return bool(self.client.exists(redis_key) > 0)
|
|
93
|
+
|
|
93
94
|
def clear_session(self, session_id: str) -> bool:
|
|
94
95
|
pattern = f"{self.prefix}session:{session_id}:*"
|
|
95
96
|
keys = list(self.client.scan_iter(match=pattern))
|
|
96
|
-
|
|
97
|
+
|
|
97
98
|
# 也删除消息
|
|
98
99
|
keys.append(self._messages_key(session_id))
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
if keys:
|
|
101
102
|
self.client.delete(*keys)
|
|
102
103
|
return True
|
|
103
|
-
|
|
104
|
+
|
|
104
105
|
def add_message(
|
|
105
106
|
self,
|
|
106
107
|
session_id: str,
|
|
@@ -108,38 +109,38 @@ class RedisBackend(BaseMemoryBackend):
|
|
|
108
109
|
content: str,
|
|
109
110
|
metadata: Optional[Dict] = None,
|
|
110
111
|
) -> bool:
|
|
111
|
-
msg = {
|
|
112
|
+
msg: dict[str, Any] = {
|
|
112
113
|
"role": role,
|
|
113
114
|
"content": content,
|
|
114
115
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
115
116
|
}
|
|
116
117
|
if metadata:
|
|
117
118
|
msg["metadata"] = metadata
|
|
118
|
-
|
|
119
|
+
|
|
119
120
|
redis_key = self._messages_key(session_id)
|
|
120
121
|
self.client.rpush(redis_key, json.dumps(msg, ensure_ascii=False))
|
|
121
|
-
|
|
122
|
+
|
|
122
123
|
# 可以设置消息历史的过期时间
|
|
123
124
|
if self.default_ttl:
|
|
124
125
|
self.client.expire(redis_key, int(self.default_ttl.total_seconds()))
|
|
125
|
-
|
|
126
|
+
|
|
126
127
|
return True
|
|
127
|
-
|
|
128
|
+
|
|
128
129
|
def get_messages(
|
|
129
130
|
self,
|
|
130
131
|
session_id: str,
|
|
131
132
|
limit: Optional[int] = None,
|
|
132
133
|
) -> List[Dict]:
|
|
133
134
|
redis_key = self._messages_key(session_id)
|
|
134
|
-
|
|
135
|
+
|
|
135
136
|
if limit:
|
|
136
137
|
# 获取最后 N 条
|
|
137
138
|
raw = self.client.lrange(redis_key, -limit, -1)
|
|
138
139
|
else:
|
|
139
140
|
raw = self.client.lrange(redis_key, 0, -1)
|
|
140
|
-
|
|
141
|
+
|
|
141
142
|
return [json.loads(m) for m in raw]
|
|
142
|
-
|
|
143
|
+
|
|
143
144
|
def close(self) -> None:
|
|
144
145
|
if self._client:
|
|
145
146
|
self._client.close()
|
ksadk/memory/langchain_tool.py
CHANGED
|
@@ -31,7 +31,8 @@ def create_langchain_tools():
|
|
|
31
31
|
return load_memory_tool, save_memory_tool
|
|
32
32
|
except ImportError:
|
|
33
33
|
logger.warning(
|
|
34
|
-
"langchain-core not installed, returning raw functions.
|
|
34
|
+
"langchain-core not installed, returning raw functions. "
|
|
35
|
+
"Install with: pip install langchain-core"
|
|
35
36
|
)
|
|
36
37
|
return _load_memory, _save_memory
|
|
37
38
|
|