agentengine-sdk-python 0.8.0__py3-none-any.whl → 0.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/METADATA +43 -7
- agentengine_sdk_python-0.8.2.dist-info/RECORD +778 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/WHEEL +1 -1
- ksadk/a2a/__init__.py +2 -0
- ksadk/a2a/_space_client_events.py +381 -0
- ksadk/a2a/bootstrap.py +0 -2
- ksadk/a2a/card.py +6 -111
- ksadk/a2a/control_plane.py +239 -1
- ksadk/a2a/event_adapter.py +156 -64
- ksadk/a2a/executor.py +195 -172
- ksadk/a2a/routes.py +12 -5
- ksadk/a2a/server.py +1 -8
- ksadk/a2a/service_env.py +33 -0
- ksadk/a2a/space_client.py +43 -349
- ksadk/a2a_card.py +101 -0
- ksadk/a2ui/core.py +222 -53
- ksadk/agui/_agent_helpers.py +243 -0
- ksadk/agui/a2ui_projection.py +12 -5
- ksadk/agui/agent.py +474 -275
- ksadk/agui/config.py +11 -5
- ksadk/agui/routes.py +7 -15
- ksadk/api/client.py +530 -40
- ksadk/api/environment.py +27 -0
- ksadk/builders/code_builder.py +352 -53
- ksadk/builders/container_builder.py +71 -44
- ksadk/builders/framework_requirements.py +2 -1
- ksadk/builders/ks3_uploader.py +2 -2
- ksadk/builders/managed_runtime_builder.py +60 -28
- ksadk/cli/__init__.py +25 -0
- ksadk/cli/cmd_a2a.py +18 -31
- ksadk/cli/cmd_create.py +13 -26
- ksadk/cli/cmd_dashboard.py +15 -1
- ksadk/cli/cmd_deploy.py +28 -3
- ksadk/cli/cmd_eval.py +443 -0
- ksadk/cli/cmd_evalset.py +284 -0
- ksadk/cli/cmd_files.py +5 -1
- ksadk/cli/cmd_hermes.py +137 -163
- ksadk/cli/cmd_invoke.py +28 -38
- ksadk/cli/cmd_launch.py +12 -0
- ksadk/cli/cmd_managed_runtime.py +95 -0
- ksadk/cli/cmd_observe.py +85 -0
- ksadk/cli/cmd_openclaw.py +85 -479
- ksadk/cli/cmd_replay.py +28 -4
- ksadk/cli/cmd_run.py +29 -67
- ksadk/cli/cmd_studio.py +201 -0
- ksadk/cli/cmd_web.py +15 -6
- ksadk/cli/dry_run.py +2 -1
- ksadk/cli/env_options.py +83 -0
- ksadk/cli/global_options.py +3 -1
- ksadk/cli/hermes_env.py +151 -0
- ksadk/cli/invoke_payload.py +49 -0
- ksadk/cli/network_options.py +7 -5
- ksadk/cli/openclaw_env.py +458 -0
- ksadk/cli/runtime_bootstrap.py +51 -0
- ksadk/cli/ui.py +6 -0
- ksadk/cli/workflow_common.py +5 -5
- ksadk/codex/__init__.py +3 -3
- ksadk/codex/client.py +833 -49
- ksadk/codex/phase.py +1 -1
- ksadk/codex/runtime.py +720 -127
- ksadk/common/kop_client.py +232 -0
- ksadk/configs/__init__.py +1 -3
- ksadk/configs/env_registry.py +244 -45
- ksadk/configs/env_registry_pcm.py +181 -0
- ksadk/configs/env_var_spec.py +18 -0
- ksadk/configs/global_config.py +6 -1
- ksadk/configs/settings.py +5 -108
- ksadk/context_engine/__init__.py +98 -0
- ksadk/context_engine/assembler.py +176 -0
- ksadk/context_engine/baseline.py +419 -0
- ksadk/context_engine/cache_observability.py +228 -0
- ksadk/context_engine/capabilities.py +443 -0
- ksadk/context_engine/contributors.py +344 -0
- ksadk/context_engine/hosted_pipeline.py +417 -0
- ksadk/context_engine/models.py +117 -0
- ksadk/context_engine/planner.py +698 -0
- ksadk/context_engine/policies.py +319 -0
- ksadk/context_engine/projection.py +31 -0
- ksadk/context_engine/shadow_plan.py +266 -0
- ksadk/context_engine/tokenizer.py +164 -0
- ksadk/conversations/__init__.py +85 -94
- ksadk/conversations/context.py +126 -6
- ksadk/conversations/message_projection.py +292 -28
- ksadk/conversations/model_context.py +49 -3
- ksadk/conversations/runtime_compaction.py +207 -5
- ksadk/conversations/runtime_input.py +193 -3
- ksadk/conversations/runtime_invocation.py +81 -3
- ksadk/conversations/runtime_observability.py +157 -4
- ksadk/conversations/runtime_payloads.py +42 -0
- ksadk/conversations/runtime_preparation.py +280 -2
- ksadk/conversations/runtime_resume.py +71 -32
- ksadk/conversations/runtime_stream_events.py +94 -9
- ksadk/conversations/runtime_streaming.py +175 -22
- ksadk/conversations/semantic_summary.py +311 -1
- ksadk/conversations/session_lock.py +51 -0
- ksadk/deployment/env_forward.py +72 -0
- ksadk/deployment/managed_runtime.py +38 -0
- ksadk/deployment/manager.py +24 -8
- ksadk/deployment/providers/serverless.py +228 -92
- ksadk/evaluation/__init__.py +116 -0
- ksadk/evaluation/a2a_adapter.py +452 -0
- ksadk/evaluation/adapters.py +67 -0
- ksadk/evaluation/agent_eval_client.py +395 -0
- ksadk/evaluation/cloud_binding.py +80 -0
- ksadk/evaluation/cloud_converter.py +194 -0
- ksadk/evaluation/cloud_service.py +199 -0
- ksadk/evaluation/contracts.py +478 -0
- ksadk/evaluation/evalset.py +351 -0
- ksadk/evaluation/evaluators.py +627 -0
- ksadk/evaluation/evidence.py +258 -0
- ksadk/evaluation/executor.py +143 -0
- ksadk/evaluation/local_adapter.py +550 -0
- ksadk/evaluation/service_env.py +27 -0
- ksadk/evaluation/storage.py +68 -0
- ksadk/evaluation/studio_build_adapter.py +253 -0
- ksadk/evaluation/target.py +82 -0
- ksadk/events/__init__.py +13 -13
- ksadk/events/_v1_compat/__init__.py +1 -0
- ksadk/events/_v1_compat/models.py +299 -0
- ksadk/events/_v1_compat/parser.py +247 -0
- ksadk/events/_v1_compat/projection.py +753 -0
- ksadk/events/adapters/__init__.py +34 -0
- ksadk/events/adapters/_a2a_snapshot.py +622 -0
- ksadk/events/adapters/_a2a_support.py +275 -0
- ksadk/events/adapters/_codex_interactions.py +375 -0
- ksadk/events/adapters/_codex_items.py +801 -0
- ksadk/events/adapters/_codex_validators.py +311 -0
- ksadk/events/adapters/_langgraph_support.py +785 -0
- ksadk/events/adapters/a2a.py +841 -0
- ksadk/events/adapters/adk.py +503 -0
- ksadk/events/adapters/codex.py +717 -0
- ksadk/events/adapters/langgraph.py +745 -0
- ksadk/events/canonical.py +440 -0
- ksadk/events/canonical_replay.py +497 -0
- ksadk/events/canonical_store.py +468 -0
- ksadk/events/cold_recovery.py +257 -0
- ksadk/events/content.py +89 -0
- ksadk/events/identity.py +86 -0
- ksadk/events/pipeline.py +455 -0
- ksadk/events/projections.py +66 -0
- ksadk/events/reducer.py +661 -0
- ksadk/events/replay.py +3 -36
- ksadk/events/runtime_event.py +20 -256
- ksadk/events/session_event.py +324 -0
- ksadk/events/store.py +3 -316
- ksadk/events/v1_compat.py +41 -0
- ksadk/harness/__init__.py +3 -2
- ksadk/harness/app.py +114 -123
- ksadk/harness/config.py +1 -1
- ksadk/harness/runtime.py +467 -0
- ksadk/hermes_terminal.py +5 -0
- ksadk/identity/resolver.py +4 -3
- ksadk/interaction/__init__.py +28 -0
- ksadk/interaction/contracts.py +136 -0
- ksadk/interaction/ledger.py +189 -0
- ksadk/interaction/provider.py +122 -0
- ksadk/interaction/providers/__init__.py +52 -0
- ksadk/interaction/providers/adk.py +40 -0
- ksadk/interaction/providers/codex.py +94 -0
- ksadk/interaction/providers/langgraph.py +58 -0
- ksadk/kernel/__init__.py +117 -0
- ksadk/kernel/authorization.py +258 -0
- ksadk/kernel/bootstrap.py +1074 -0
- ksadk/kernel/contract_fingerprints.py +61 -0
- ksadk/kernel/contracts.py +362 -0
- ksadk/kernel/control.py +219 -0
- ksadk/kernel/errors.py +79 -0
- ksadk/kernel/ingress.py +1102 -0
- ksadk/kernel/mapping.py +111 -0
- ksadk/kernel/memory_store.py +1133 -0
- ksadk/kernel/postgres_store.py +1756 -0
- ksadk/kernel/recovery.py +452 -0
- ksadk/kernel/runtime_identity.py +103 -0
- ksadk/kernel/sql/001_agent_kernel.sql +120 -0
- ksadk/kernel/sqlite_store.py +1410 -0
- ksadk/kernel/state.py +145 -0
- ksadk/kernel/store.py +232 -0
- ksadk/kernel/worker.py +953 -0
- ksadk/knowledge_base/client.py +22 -4
- ksadk/knowledge_base/service.py +32 -5
- ksadk/managed_a2a_card.py +160 -0
- ksadk/managed_runtime.py +16 -9
- ksadk/memory/__init__.py +61 -0
- ksadk/memory/adk/backends/base_ltm_backend.py +96 -1
- ksadk/memory/adk/backends/http_ltm_backend.py +14 -5
- ksadk/memory/adk/backends/inmemory_ltm_backend.py +136 -3
- ksadk/memory/adk/backends/sdk_ltm_backend.py +394 -5
- ksadk/memory/adk/backends/sqlite_ltm_backend.py +95 -0
- ksadk/memory/adk/long_term_memory.py +3 -2
- ksadk/memory/coordinator.py +461 -0
- ksadk/memory/events.py +202 -0
- ksadk/memory/extraction.py +228 -0
- ksadk/memory/ltm_backend_factory.py +16 -3
- ksadk/memory/models.py +316 -0
- ksadk/memory/policy.py +215 -0
- ksadk/memory/provider.py +47 -0
- ksadk/memory/provider_adapter.py +159 -0
- ksadk/memory/provider_resolver.py +71 -0
- ksadk/memory/providers/__init__.py +5 -0
- ksadk/memory/providers/local_sqlite.py +490 -0
- ksadk/memory/resolved_policy.py +145 -0
- ksadk/memory/service.py +198 -8
- ksadk/memory/tool.py +4 -0
- ksadk/model_proxy/bootstrap.py +16 -9
- ksadk/model_proxy/config.py +22 -1
- ksadk/model_proxy/detect.py +202 -9
- ksadk/model_proxy/namespace.py +67 -15
- ksadk/model_proxy/server.py +168 -6
- ksadk/model_proxy/transform.py +105 -3
- ksadk/observability/__init__.py +25 -0
- ksadk/observability/session_log.py +420 -0
- ksadk/observability/trajectory.py +105 -0
- ksadk/prompts/__init__.py +71 -0
- ksadk/prompts/compiler.py +215 -0
- ksadk/prompts/models.py +82 -0
- ksadk/prompts/projection.py +89 -0
- ksadk/prompts/resolved.py +137 -0
- ksadk/prompts/sources.py +233 -0
- ksadk/runners/_langgraph_runner_streams.py +822 -0
- ksadk/runners/adk_runner.py +14 -31
- ksadk/runners/base_runner.py +44 -3
- ksadk/runners/factory.py +3 -3
- ksadk/runners/langgraph_runner.py +252 -433
- ksadk/runners/utils/__init__.py +0 -10
- ksadk/runners/utils/loader.py +16 -0
- ksadk/runtime/__init__.py +67 -41
- ksadk/runtime/_runner_adapter/__init__.py +1 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +788 -0
- ksadk/runtime/adapter.py +199 -16
- ksadk/runtime/conversation_execution.py +687 -0
- ksadk/runtime/executor.py +392 -0
- ksadk/runtime/factory.py +342 -0
- ksadk/runtime/framework_adapters.py +6 -12
- ksadk/runtime/hosted_finalizer.py +268 -0
- ksadk/runtime/launch.py +61 -0
- ksadk/runtime/preprocessing.py +49 -14
- ksadk/runtime/runner_adapter.py +330 -391
- ksadk/runtime/runner_loading.py +36 -0
- ksadk/runtime/usage.py +33 -0
- ksadk/sandbox/backends/e2b.py +36 -3
- ksadk/server/__init__.py +39 -4
- ksadk/server/app.py +18 -492
- ksadk/server/composition.py +36 -2
- ksadk/server/factory.py +210 -149
- ksadk/server/routes/common.py +15 -46
- ksadk/server/routes/control.py +13 -9
- ksadk/server/routes/kernel_ingress.py +258 -0
- ksadk/server/routes/misc.py +10 -33
- ksadk/server/routes/models.py +14 -6
- ksadk/server/routes/openai_compat.py +129 -27
- ksadk/server/routes/projection.py +84 -16
- ksadk/server/routes/run.py +347 -460
- ksadk/server/routes/sessions.py +37 -40
- ksadk/server/routes/streaming.py +52 -7
- ksadk/server/routes/workspace.py +54 -21
- ksadk/server/static/assets/{ArtifactsPanel-Cjnqt-8W.js → ArtifactsPanel-DSU1sWD_.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-BqyqZfuB.js → CodeBlock-DOH6MVcn.js} +4 -4
- ksadk/server/static/assets/{MathMessageMarkdown-BpH7jiFM.js → MathMessageMarkdown-BL8my1R2.js} +4 -4
- ksadk/server/static/assets/MathMessageMarkdown-BorAY7qD.css +1 -0
- ksadk/server/static/assets/MermaidBlock-Dz4IP-Tx.js +312 -0
- ksadk/server/static/assets/NativeTerminalPanel-DUrK0JpZ.js +1 -0
- ksadk/server/static/assets/abnfDiagram-VCTEODGH-g20pFzNV.js +1 -0
- ksadk/server/static/assets/arc-C4FzinUA.js +1 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +1 -0
- ksadk/server/static/assets/architectureDiagram-5GKGNRK7-DpIqL5h4.js +36 -0
- ksadk/server/static/assets/blockDiagram-NRAW4CY4-BjkljTNz.js +129 -0
- ksadk/server/static/assets/c4Diagram-UCG6FXSJ-Dk_ieq2X.js +38 -0
- ksadk/server/static/assets/channel-4cQHKtx1.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +1 -0
- ksadk/server/static/assets/{chunk-FMBD7UC4-BGhvzDYt.js → chunk-5VM5RSS4-BVHAchFb.js} +1 -1
- ksadk/server/static/assets/{chunk-ND2GUHAM-D98vPd-E.js → chunk-F27PBJKO-C-ipQzuS.js} +1 -1
- ksadk/server/static/assets/chunk-G27WJ6UU-C2EyJbIK.js +231 -0
- ksadk/server/static/assets/{chunk-4BX2VUAB-CsWIQRhc.js → chunk-JWPE2WC7-vYvVJb_M.js} +1 -1
- ksadk/server/static/assets/chunk-LCL6LL3I-BcI6ysPT.js +206 -0
- ksadk/server/static/assets/chunk-POPQ4Y6H-C030x_Z1.js +1 -0
- ksadk/server/static/assets/chunk-RHFEMEQ7-yyGpsz4n.js +168 -0
- ksadk/server/static/assets/chunk-SVP7TREG-BLTlmMU7.js +88 -0
- ksadk/server/static/assets/chunk-XXDRQBXY-C_32ArgP.js +1 -0
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-S5V4N54A-CX3yotHq.js → cose-bilkent-JH36ORCC-9YQYwdl0.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +1 -0
- ksadk/server/static/assets/cynefinDiagram-5FMLGOSQ-ErLF5N13.js +62 -0
- ksadk/server/static/assets/cytoscape.esm-CyCl8rPi.js +321 -0
- ksadk/server/static/assets/dagre-3AP2YEHR-DFiQF-6f.js +4 -0
- ksadk/server/static/assets/dagre-BuhGnRI1.js +1 -0
- ksadk/server/static/assets/diagram-S7CK7UJ4-Bt1v8-GC.js +30 -0
- ksadk/server/static/assets/diagram-UQ7AKVKN-DSCxJdBK.js +41 -0
- ksadk/server/static/assets/diagram-VSXAHHWV-DHfYwp_9.js +3 -0
- ksadk/server/static/assets/diagram-VX7I27RA-DdzD-4Le.js +24 -0
- ksadk/server/static/assets/diagram-Z3DM3KII-Du-nAJ9F.js +24 -0
- ksadk/server/static/assets/{dist-D82mtD2s.js → dist-8hqcx0sU.js} +1 -1
- ksadk/server/static/assets/dist-B7seoj3d.js +1 -0
- ksadk/server/static/assets/{dist-DHn6nBzr.js → dist-BE7bu-DL.js} +1 -1
- ksadk/server/static/assets/{dist-eoW6tZXA.js → dist-BVDffZ0U.js} +1 -1
- ksadk/server/static/assets/{dist-C2xjE7cO.js → dist-BX8z72IC.js} +1 -1
- ksadk/server/static/assets/{dist-CgF3fj15.js → dist-Bf2M8m3N.js} +1 -1
- ksadk/server/static/assets/{dist-Bs-jQcRX.js → dist-BjU6y-A2.js} +1 -1
- ksadk/server/static/assets/{dist-Djgl2wVZ.js → dist-BytlxIDT.js} +1 -1
- ksadk/server/static/assets/{dist-CVQRZjPu.js → dist-CSh_DE14.js} +1 -1
- ksadk/server/static/assets/{dist-6CVKuTAe.js → dist-CXYYBw3_.js} +1 -1
- ksadk/server/static/assets/{dist-DlzCRy0S.js → dist-C_wsv-Qd.js} +1 -1
- ksadk/server/static/assets/{dist-DF06ORQo.js → dist-ClxGviKw.js} +1 -1
- ksadk/server/static/assets/{dist-Cf23NY4L.js → dist-CttYUqzS.js} +1 -1
- ksadk/server/static/assets/{dist-ivOya1LD.js → dist-DNp6rLRA.js} +1 -1
- ksadk/server/static/assets/{dist-BibcG1V9.js → dist-DUX-id_F.js} +1 -1
- ksadk/server/static/assets/{dist-BUHRxvDG.js → dist-DmldrHd_.js} +1 -1
- ksadk/server/static/assets/{dist-BZ9n9AjO.js → dist-DnfXs8Vn.js} +2 -2
- ksadk/server/static/assets/{dist-DqNnNFrw.js → dist-Dq9gLD7L.js} +1 -1
- ksadk/server/static/assets/{dist-CGcp2ex8.js → dist-W-TIVntx.js} +1 -1
- ksadk/server/static/assets/{dist-Cwt7koer.js → dist-dDdADKFA.js} +1 -1
- ksadk/server/static/assets/{dist-C7-3jInC.js → dist-dydu68Fl.js} +1 -1
- ksadk/server/static/assets/{dist-C99THtIA.js → dist-ngtN0DJB.js} +1 -1
- ksadk/server/static/assets/ebnfDiagram-PWID7BFC-Da9C9NO1.js +1 -0
- ksadk/server/static/assets/erDiagram-SSCWMZ5O-EAGqqR79.js +99 -0
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +1 -0
- ksadk/server/static/assets/ganttDiagram-EL5Y4UJY-DqJsKb59.js +292 -0
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +1 -0
- ksadk/server/static/assets/gitGraphDiagram-WWUBYQGX-B6g4dtDi.js +106 -0
- ksadk/server/static/assets/index-8ipRcQ-M.js +240 -0
- ksadk/server/static/assets/index-ByFCqjlh.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +1 -0
- ksadk/server/static/assets/infoDiagram-RXCK75RN-Djm_nbd5.js +2 -0
- ksadk/server/static/assets/{ishikawaDiagram-YF4QCWOH-DLOHGvWw.js → ishikawaDiagram-5VMMS53U-DWya9SG2.js} +6 -6
- ksadk/server/static/assets/{journeyDiagram-JHISSGLW-BIzKeejT.js → journeyDiagram-EYS64GPL-DutxhSNI.js} +6 -6
- ksadk/server/static/assets/{kanban-definition-UN3LZRKU-BWHoFSw2.js → kanban-definition-3QL26DDD-DJdOF8Fm.js} +10 -10
- ksadk/server/static/assets/katex-vFWytM5c.js +257 -0
- ksadk/server/static/assets/{linear-CvMBw9cA.js → linear-BHjG8b-J.js} +1 -1
- ksadk/server/static/assets/mermaid-parser.core-KGSy4jWT.js +166 -0
- ksadk/server/static/assets/{mindmap-definition-RKZ34NQL-CSAQxEAe.js → mindmap-definition-FBJOCRG2-9-HC88D4.js} +29 -29
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +1 -0
- ksadk/server/static/assets/pegDiagram-XKGWAZYB-DrEZd4fD.js +1 -0
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +1 -0
- ksadk/server/static/assets/pieDiagram-E7YTZNPT-DpjqOFFp.js +39 -0
- ksadk/server/static/assets/{quadrantDiagram-W4KKPZXB-CxIR4JXI.js → quadrantDiagram-AXDQQJYC-BiNhgOXX.js} +6 -6
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +1 -0
- ksadk/server/static/assets/railroadDiagram-O6MQD6OU-_Y3Ojg6G.js +1 -0
- ksadk/server/static/assets/requirementDiagram-EFPCY7ZU-DeCFdg9K.js +84 -0
- ksadk/server/static/assets/{sankeyDiagram-5OEKKPKP-DpGa6EAV.js → sankeyDiagram-P5KCCOFB-CPH75rhw.js} +7 -7
- ksadk/server/static/assets/{sequenceDiagram-3UESZ5HK-NTKNGGe5.js → sequenceDiagram-WJ2MYXX4-OEpQQdr4.js} +10 -10
- ksadk/server/static/assets/sizeCapture-X5ZJPWSS-heUErzhI.js +1 -0
- ksadk/server/static/assets/stateDiagram-HBIQ2CUA-DvA3jSMB.js +1 -0
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +1 -0
- ksadk/server/static/assets/swimlanes-XN3QIQJK-CR-dfN_t.js +1 -0
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +8 -0
- ksadk/server/static/assets/{timeline-definition-PNZ67QCA-jqoYs3jQ.js → timeline-definition-24CTP7MA-DAVJf1TX.js} +7 -7
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +1 -0
- ksadk/server/static/assets/vennDiagram-4TSXK5OY-DwM8eDkh.js +34 -0
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +1 -0
- ksadk/server/static/assets/wardleyDiagram-VM6X3IG4-DZL-Zz2t.js +78 -0
- ksadk/server/static/assets/xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js +7 -0
- ksadk/server/static/index.html +2 -2
- ksadk/sessions/__init__.py +26 -9
- ksadk/sessions/_local_service_sync.py +688 -0
- ksadk/sessions/_local_tables.py +21 -0
- ksadk/sessions/_postgres_schema.py +305 -0
- ksadk/sessions/_postgres_tables.py +15 -0
- ksadk/sessions/base.py +80 -1
- ksadk/sessions/in_memory.py +53 -2
- ksadk/sessions/local_service.py +63 -604
- ksadk/sessions/postgres_service.py +58 -148
- ksadk/sessions/resilient.py +35 -1
- ksadk/skills/runtime/backends/e2b.py +1 -1
- ksadk/skills/service_client.py +13 -3
- ksadk/studio/__init__.py +5 -0
- ksadk/studio/agent_avatar_assets.py +120 -0
- ksadk/studio/agent_lifecycle.py +51 -0
- ksadk/studio/api.py +1598 -0
- ksadk/studio/api_catalog_routes.py +324 -0
- ksadk/studio/api_contracts.py +286 -0
- ksadk/studio/api_helpers.py +132 -0
- ksadk/studio/api_memory_routes.py +82 -0
- ksadk/studio/authoring.py +749 -0
- ksadk/studio/authoring_coordinator.py +1017 -0
- ksadk/studio/builder.py +397 -0
- ksadk/studio/capabilities.py +368 -0
- ksadk/studio/cloud.py +2099 -0
- ksadk/studio/codex_agent_service.py +694 -0
- ksadk/studio/codex_authoring.py +469 -0
- ksadk/studio/codex_builder.py +437 -0
- ksadk/studio/codex_manifest.py +307 -0
- ksadk/studio/codex_run.py +395 -0
- ksadk/studio/compiler.py +190 -0
- ksadk/studio/contracts.py +755 -0
- ksadk/studio/errors.py +47 -0
- ksadk/studio/event_store.py +214 -0
- ksadk/studio/framework_run.py +342 -0
- ksadk/studio/hosted_kernel.py +317 -0
- ksadk/studio/identifiers.py +33 -0
- ksadk/studio/manifest_resolver.py +131 -0
- ksadk/studio/mcp_runtime.py +229 -0
- ksadk/studio/model_client.py +629 -0
- ksadk/studio/model_profile_service.py +214 -0
- ksadk/studio/operations.py +275 -0
- ksadk/studio/otel_trace.py +1060 -0
- ksadk/studio/pagination.py +182 -0
- ksadk/studio/pcm_memory.py +85 -0
- ksadk/studio/python_tool_inspection.py +183 -0
- ksadk/studio/repository.py +327 -0
- ksadk/studio/resource_catalog.py +1260 -0
- ksadk/studio/run_service.py +1133 -0
- ksadk/studio/runtime_catalog.py +74 -0
- ksadk/studio/runtime_source.py +365 -0
- ksadk/studio/service.py +2249 -0
- ksadk/studio/shared_web.py +1004 -0
- ksadk/studio/skill_discovery.py +628 -0
- ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +3 -0
- ksadk/studio/static/assets/index-BLpcdrgW.css +1 -0
- ksadk/studio/static/assets/index-CYekR2Xv.js +260 -0
- ksadk/studio/static/assets/react-vendor-BNmTiJ-I.js +9 -0
- ksadk/studio/static/assets/rolldown-runtime-hePW80VL.js +1 -0
- ksadk/studio/static/index.html +15 -0
- ksadk/studio/templates.py +722 -0
- ksadk/studio/validator.py +265 -0
- ksadk/studio/workspace.py +135 -0
- ksadk/tools/gateway.py +9 -0
- ksadk/toolsets/__init__.py +27 -1
- ksadk/toolsets/a2a.py +426 -0
- ksadk/tracing/__init__.py +19 -21
- ksadk/tracing/setup.py +317 -403
- ksadk/tracing/span_utils.py +0 -44
- ksadk/version.py +1 -1
- ksadk_runtime_common/memory_backend/registry.py +56 -56
- ksadk_runtime_common/schemas/runtime_event_v1.json +37 -0
- ksadk_runtime_common/schemas/runtime_event_v2.json +271 -0
- ksadk_runtime_common/workspace_files/router.py +8 -2
- agentengine_sdk_python-0.8.0.dist-info/RECORD +0 -578
- ksadk/a2a/card_builder.py +0 -64
- ksadk/a2a/client.py +0 -309
- ksadk/events/parser.py +0 -191
- ksadk/harness/runner.py +0 -211
- ksadk/runners/codex_runner.py +0 -132
- ksadk/runners/utils/langfuse.py +0 -230
- ksadk/server/static/assets/MathMessageMarkdown-DeYh8QPr.css +0 -1
- ksadk/server/static/assets/MermaidBlock-DWuxETaJ.js +0 -303
- ksadk/server/static/assets/NativeTerminalPanel-MDTopWMO.js +0 -1
- ksadk/server/static/assets/arc-CFKwSk_B.js +0 -1
- ksadk/server/static/assets/architecture-7EHR7CIX-CynqOWjZ.js +0 -1
- ksadk/server/static/assets/architectureDiagram-3BPJPVTR-Dej8jX8c.js +0 -36
- ksadk/server/static/assets/blockDiagram-GPEHLZMM-1F64jqvy.js +0 -132
- ksadk/server/static/assets/c4Diagram-AAUBKEIU-9q7AUAKb.js +0 -10
- ksadk/server/static/assets/channel-iUGv2N24.js +0 -1
- ksadk/server/static/assets/chunk-2J33WTMH-6qgwJm7Q.js +0 -1
- ksadk/server/static/assets/chunk-55IACEB6-BK8paA20.js +0 -1
- ksadk/server/static/assets/chunk-727SXJPM-B-JEhy7h.js +0 -206
- ksadk/server/static/assets/chunk-AQP2D5EJ-DYBvMHAa.js +0 -231
- ksadk/server/static/assets/chunk-QZHKN3VN-YQIEXeF6.js +0 -1
- ksadk/server/static/assets/classDiagram-4FO5ZUOK-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-Q7XG4LA2-CDAUuoXK.js +0 -1
- ksadk/server/static/assets/cytoscape.esm-DelgaX4f.js +0 -321
- ksadk/server/static/assets/dagre-BM42HDAG-C7TguAWo.js +0 -4
- ksadk/server/static/assets/dagre-Bx709z4p.js +0 -1
- ksadk/server/static/assets/diagram-2AECGRRQ-Dd17_kws.js +0 -43
- ksadk/server/static/assets/diagram-5GNKFQAL-DVIClIil.js +0 -10
- ksadk/server/static/assets/diagram-KO2AKTUF-Df_3gYQa.js +0 -3
- ksadk/server/static/assets/diagram-LMA3HP47-BhLk6ZtA.js +0 -24
- ksadk/server/static/assets/diagram-OG6HWLK6-D4GNGvuu.js +0 -24
- ksadk/server/static/assets/dist-DyvYLMW9.js +0 -1
- ksadk/server/static/assets/erDiagram-TEJ5UH35-CnfRcY2M.js +0 -85
- ksadk/server/static/assets/eventmodeling-FCH6USID-ChYO-ijM.js +0 -1
- ksadk/server/static/assets/flowDiagram-I6XJVG4X-DGaJjGNJ.js +0 -162
- ksadk/server/static/assets/ganttDiagram-6RSMTGT7-DpCoB2g9.js +0 -292
- ksadk/server/static/assets/gitGraph-WXDBUCRP-BN_0Fk-j.js +0 -1
- ksadk/server/static/assets/gitGraphDiagram-PVQCEYII-9IKVFBVT.js +0 -106
- ksadk/server/static/assets/graphlib-B8gBHxth.js +0 -1
- ksadk/server/static/assets/index-QSwCHuB8.js +0 -177
- ksadk/server/static/assets/index-jOPmTOZH.css +0 -2
- ksadk/server/static/assets/info-J43DQDTF-Cp6o3vId.js +0 -1
- ksadk/server/static/assets/infoDiagram-5YYISTIA-CYIIsb8y.js +0 -2
- ksadk/server/static/assets/katex-DATssjp1.js +0 -265
- ksadk/server/static/assets/mermaid-parser.core-mGAcEwcq.js +0 -161
- ksadk/server/static/assets/packet-YPE3B663-wQzct3cT.js +0 -1
- ksadk/server/static/assets/pie-LRSECV5Y-BgTQiv-9.js +0 -1
- ksadk/server/static/assets/pieDiagram-4H26LBE5-By-ra07M.js +0 -30
- ksadk/server/static/assets/radar-GUYGQ44K-BIq5fXsn.js +0 -1
- ksadk/server/static/assets/requirementDiagram-4Y6WPE33-DpW90iu3.js +0 -84
- ksadk/server/static/assets/stateDiagram-AJRCARHV-DGpd9yFG.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-BHNVJYJU-B3o579IQ.js +0 -1
- ksadk/server/static/assets/treeView-BLDUP644-Dqi-E0EM.js +0 -1
- ksadk/server/static/assets/treemap-LRROVOQU-ClQP9CJ9.js +0 -1
- ksadk/server/static/assets/vennDiagram-CIIHVFJN-l3Z7-wbP.js +0 -34
- ksadk/server/static/assets/wardley-L42UT6IY-8XLvnNIs.js +0 -1
- ksadk/server/static/assets/wardleyDiagram-YWT4CUSO-BR54GPmr.js +0 -78
- ksadk/server/static/assets/xychartDiagram-2RQKCTM6-SkiH8GsK.js +0 -7
- ksadk/tracing/exporters/langfuse_exporter.py +0 -460
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.0.dist-info → agentengine_sdk_python-0.8.2.dist-info}/top_level.txt +0 -0
ksadk/memory/service.py
CHANGED
|
@@ -8,15 +8,25 @@ import os
|
|
|
8
8
|
from typing import Any, cast
|
|
9
9
|
|
|
10
10
|
from ksadk.common.aicp_env import resolve_aicp_connection
|
|
11
|
-
from ksadk.memory.adk.backends.base_ltm_backend import
|
|
11
|
+
from ksadk.memory.adk.backends.base_ltm_backend import (
|
|
12
|
+
CAP_SESSION_STATUS,
|
|
13
|
+
CAP_STRUCTURED_SEARCH,
|
|
14
|
+
BaseLongTermMemoryBackend,
|
|
15
|
+
)
|
|
12
16
|
from ksadk.memory.ltm_backend_factory import get_long_term_memory_backend_cls
|
|
17
|
+
from ksadk.memory.models import (
|
|
18
|
+
LongTermMemoryRecord,
|
|
19
|
+
MemoryExtractionStatus,
|
|
20
|
+
MemoryMutationResult,
|
|
21
|
+
UnsupportedMemoryOperation,
|
|
22
|
+
)
|
|
13
23
|
|
|
14
24
|
logger = logging.getLogger(__name__)
|
|
15
25
|
|
|
16
26
|
|
|
17
27
|
def format_memory_entries(entries: list[str]) -> str:
|
|
18
28
|
if not entries:
|
|
19
|
-
return "
|
|
29
|
+
return "" # empty → "" not "未找到"(§10.8)
|
|
20
30
|
|
|
21
31
|
formatted_entries: list[str] = []
|
|
22
32
|
for index, entry in enumerate(entries, 1):
|
|
@@ -35,6 +45,11 @@ def format_memory_entries(entries: list[str]) -> str:
|
|
|
35
45
|
return "\n\n".join(formatted_entries)
|
|
36
46
|
|
|
37
47
|
|
|
48
|
+
def _normalize_content(text: str) -> str:
|
|
49
|
+
"""归一化正文,用于写后确认的可见性匹配(去空白,小写)。"""
|
|
50
|
+
return "".join(str(text or "").split()).lower()
|
|
51
|
+
|
|
52
|
+
|
|
38
53
|
class LongTermMemoryService:
|
|
39
54
|
def __init__(
|
|
40
55
|
self,
|
|
@@ -77,10 +92,18 @@ class LongTermMemoryService:
|
|
|
77
92
|
connection = resolve_aicp_connection("KSADK_LTM")
|
|
78
93
|
backend_config = {
|
|
79
94
|
"access_key": (
|
|
80
|
-
os.environ.get("KSADK_LTM_ACCESS_KEY")
|
|
95
|
+
os.environ.get("KSADK_LTM_ACCESS_KEY")
|
|
96
|
+
or os.environ.get("KSYUN_ACCESS_KEY")
|
|
97
|
+
or os.environ.get("KSYUN_ACCESS_KEY_ID", "")
|
|
81
98
|
),
|
|
82
99
|
"secret_key": (
|
|
83
|
-
os.environ.get("KSADK_LTM_SECRET_KEY")
|
|
100
|
+
os.environ.get("KSADK_LTM_SECRET_KEY")
|
|
101
|
+
or os.environ.get("KSYUN_SECRET_KEY")
|
|
102
|
+
or os.environ.get("KSYUN_SECRET_ACCESS_KEY", "")
|
|
103
|
+
),
|
|
104
|
+
"session_token": (
|
|
105
|
+
os.environ.get("KSADK_LTM_SESSION_TOKEN")
|
|
106
|
+
or os.environ.get("KSYUN_SESSION_TOKEN", "")
|
|
84
107
|
),
|
|
85
108
|
"region": connection["region"],
|
|
86
109
|
"endpoint": connection["endpoint"],
|
|
@@ -118,14 +141,137 @@ class LongTermMemoryService:
|
|
|
118
141
|
top_k=top_k if top_k is not None else self.top_k,
|
|
119
142
|
)
|
|
120
143
|
|
|
144
|
+
def search_records(
|
|
145
|
+
self, *, user_id: str, query: str, top_k: int | None = None
|
|
146
|
+
) -> list[LongTermMemoryRecord]:
|
|
147
|
+
"""结构化检索(§7.5):优先走 backend.search_records,返回带服务端 ID 的记录。
|
|
148
|
+
|
|
149
|
+
旧 backend 不支持时抛出 UnsupportedMemoryOperation,
|
|
150
|
+
由上层降级为只读 search/add,不得伪造 ID。
|
|
151
|
+
"""
|
|
152
|
+
return self._backend.search_records(
|
|
153
|
+
user_id=user_id,
|
|
154
|
+
query=query,
|
|
155
|
+
top_k=top_k if top_k is not None else self.top_k,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def update_memory(
|
|
159
|
+
self,
|
|
160
|
+
*,
|
|
161
|
+
user_id: str,
|
|
162
|
+
memory_id: str,
|
|
163
|
+
content: str,
|
|
164
|
+
) -> MemoryMutationResult:
|
|
165
|
+
"""按 ID 原地更新记忆(§7.4);不支持的 backend 抛稳定异常。"""
|
|
166
|
+
return self._backend.update_memory(
|
|
167
|
+
user_id=user_id,
|
|
168
|
+
memory_id=memory_id,
|
|
169
|
+
content=content,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def delete_memory(self, *, user_id: str, memory_id: str) -> MemoryMutationResult:
|
|
173
|
+
"""按 ID 软删除记忆(§7.4);重复删除归一为 already_absent。"""
|
|
174
|
+
return self._backend.delete_memory(user_id=user_id, memory_id=memory_id)
|
|
175
|
+
|
|
176
|
+
def list_memory_records(
|
|
177
|
+
self,
|
|
178
|
+
*,
|
|
179
|
+
user_id: str,
|
|
180
|
+
query: str = "",
|
|
181
|
+
page: int = 1,
|
|
182
|
+
page_size: int = 20,
|
|
183
|
+
) -> list[LongTermMemoryRecord]:
|
|
184
|
+
"""ListMemories 透传:写后确认可见性 / 取当前 MemoryId。"""
|
|
185
|
+
return self._backend.list_memory_records(
|
|
186
|
+
user_id=user_id, query=query, page=page, page_size=page_size
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def get_extraction_status(
|
|
190
|
+
self,
|
|
191
|
+
*,
|
|
192
|
+
user_id: str,
|
|
193
|
+
session_id: str,
|
|
194
|
+
confirm_searchable: bool = False,
|
|
195
|
+
expected_content: str = "",
|
|
196
|
+
) -> MemoryExtractionStatus:
|
|
197
|
+
"""写后确认(§7.7):查询 Session 后台提取状态。
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
confirm_searchable: True 且 State=100 时,进一步通过
|
|
201
|
+
ListMemories 确认目标记录可见(目标达成后 searchable=True)。
|
|
202
|
+
expected_content: 用于在 ListMemories 中定位目标记录的归一化正文。
|
|
203
|
+
"""
|
|
204
|
+
if CAP_SESSION_STATUS not in self._backend.capabilities():
|
|
205
|
+
raise UnsupportedMemoryOperation(
|
|
206
|
+
f"{type(self._backend).__name__} does not support session status"
|
|
207
|
+
)
|
|
208
|
+
status = self._backend.get_extraction_status(user_id=user_id, session_id=session_id)
|
|
209
|
+
if (
|
|
210
|
+
confirm_searchable
|
|
211
|
+
and status.status == "extracted"
|
|
212
|
+
and CAP_STRUCTURED_SEARCH in self._backend.capabilities()
|
|
213
|
+
and expected_content.strip()
|
|
214
|
+
):
|
|
215
|
+
# 用 expected_content 作为 Query 语义过滤,避免大记忆库时目标不在首页。
|
|
216
|
+
records = self.list_memory_records(
|
|
217
|
+
user_id=user_id, query=expected_content, page_size=50
|
|
218
|
+
)
|
|
219
|
+
if self._find_matching_record(records, expected_content) is not None:
|
|
220
|
+
status = MemoryExtractionStatus(
|
|
221
|
+
session_id=status.session_id,
|
|
222
|
+
state=status.state,
|
|
223
|
+
status=status.status,
|
|
224
|
+
searchable=True,
|
|
225
|
+
message=status.message,
|
|
226
|
+
)
|
|
227
|
+
return status
|
|
228
|
+
|
|
229
|
+
@staticmethod
|
|
230
|
+
def _find_matching_record(
|
|
231
|
+
records: list[LongTermMemoryRecord], expected_content: str
|
|
232
|
+
) -> LongTermMemoryRecord | None:
|
|
233
|
+
"""按归一化正文等值/包含匹配目标记录(方案 N3:可见性判定规则)。
|
|
234
|
+
|
|
235
|
+
expected_content 为空时不作匹配(返回 None),避免误判任意记录为可见。
|
|
236
|
+
"""
|
|
237
|
+
normalized = _normalize_content(expected_content)
|
|
238
|
+
if not normalized:
|
|
239
|
+
return None
|
|
240
|
+
for record in records:
|
|
241
|
+
if normalized == _normalize_content(record.content):
|
|
242
|
+
return record
|
|
243
|
+
for record in records:
|
|
244
|
+
if normalized in _normalize_content(record.content):
|
|
245
|
+
return record
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
def capabilities(self) -> set[str]:
|
|
249
|
+
"""透传 backend 能力声明(§7.3)。"""
|
|
250
|
+
return set(self._backend.capabilities())
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def last_error(self) -> str:
|
|
254
|
+
"""最近一次后端失败原因(成功调用前置空,失败时填充)。
|
|
255
|
+
|
|
256
|
+
后端(SDK/HTTP)失败时可能吞掉异常返空列表而非抛错,这里把该信号暴露给
|
|
257
|
+
``build_context``,以区分"后端吞错返空"与"真无记忆"。
|
|
258
|
+
"""
|
|
259
|
+
return str(getattr(self._backend, "last_error", "") or "")
|
|
260
|
+
|
|
121
261
|
def search_text(self, *, user_id: str, query: str, top_k: int | None = None) -> str:
|
|
262
|
+
"""检索长期记忆并格式化为文本(方案 §10.8:错误不得混入正文)。
|
|
263
|
+
|
|
264
|
+
Provider 异常时返回空字符串而非错误文本——错误文本会被当作记忆正文注入模型上下文,
|
|
265
|
+
污染回答。需要区分"真无记忆"与"后端失败"的调用方应改用 ``build_context()``
|
|
266
|
+
或检查 ``self.last_error``。
|
|
267
|
+
"""
|
|
122
268
|
try:
|
|
123
269
|
return format_memory_entries(
|
|
124
270
|
self.search_entries(user_id=user_id, query=query, top_k=top_k)
|
|
125
271
|
)
|
|
126
272
|
except Exception as exc:
|
|
127
273
|
logger.error("load_memory failed: %s", exc)
|
|
128
|
-
return
|
|
274
|
+
return ""
|
|
129
275
|
|
|
130
276
|
def save_event_strings(
|
|
131
277
|
self,
|
|
@@ -133,18 +279,52 @@ class LongTermMemoryService:
|
|
|
133
279
|
user_id: str,
|
|
134
280
|
event_strings: list[str],
|
|
135
281
|
metadata: dict[str, Any] | None = None,
|
|
282
|
+
session_id: str | None = None,
|
|
283
|
+
flush: bool | None = None,
|
|
136
284
|
) -> bool:
|
|
285
|
+
"""保存事件字符串。
|
|
286
|
+
|
|
287
|
+
显式参数优先于 metadata(方案 §7.6):
|
|
288
|
+
flush: None 表示未指定,回退到 metadata["flush"];
|
|
289
|
+
True/False 显式覆盖 metadata。
|
|
290
|
+
session_id: None 回退到 metadata["session_id"]。
|
|
291
|
+
兼容期旧调用(仅 metadata)行为不变。
|
|
292
|
+
"""
|
|
293
|
+
base_metadata = dict(metadata or {})
|
|
294
|
+
effective_flush = flush if flush is not None else base_metadata.get("flush")
|
|
295
|
+
if session_id is not None:
|
|
296
|
+
base_metadata["session_id"] = session_id
|
|
297
|
+
effective_session_id = base_metadata.get("session_id")
|
|
298
|
+
# 只有显式为 True 时才携带 flush;False/未携带时不传,
|
|
299
|
+
# 让服务端走默认累积策略(§5.2)。
|
|
300
|
+
if effective_flush is True:
|
|
301
|
+
base_metadata["flush"] = True
|
|
302
|
+
else:
|
|
303
|
+
base_metadata.pop("flush", None)
|
|
137
304
|
return bool(
|
|
138
305
|
self._backend.save_memory(
|
|
139
306
|
user_id=user_id,
|
|
140
307
|
event_strings=event_strings,
|
|
141
|
-
metadata=
|
|
308
|
+
metadata=base_metadata,
|
|
309
|
+
session_id=effective_session_id,
|
|
310
|
+
flush=effective_flush,
|
|
142
311
|
)
|
|
143
312
|
)
|
|
144
313
|
|
|
145
314
|
def save_text(
|
|
146
|
-
self,
|
|
315
|
+
self,
|
|
316
|
+
*,
|
|
317
|
+
user_id: str,
|
|
318
|
+
content: str,
|
|
319
|
+
metadata: dict[str, Any] | None = None,
|
|
320
|
+
session_id: str | None = None,
|
|
321
|
+
flush: bool | None = None,
|
|
147
322
|
) -> bool:
|
|
323
|
+
"""保存自包含事实文本。
|
|
324
|
+
|
|
325
|
+
显式 flush=True 用于显式、内容自包含的持久事实保存
|
|
326
|
+
(如 ksadk_memory_add);普通 sync_turn 不传 flush(§3.1/§8.7)。
|
|
327
|
+
"""
|
|
148
328
|
payload = {
|
|
149
329
|
"role": "user",
|
|
150
330
|
"parts": [{"text": content}],
|
|
@@ -154,6 +334,8 @@ class LongTermMemoryService:
|
|
|
154
334
|
user_id=user_id,
|
|
155
335
|
event_strings=[json.dumps(payload, ensure_ascii=False)],
|
|
156
336
|
metadata=metadata,
|
|
337
|
+
session_id=session_id,
|
|
338
|
+
flush=flush,
|
|
157
339
|
)
|
|
158
340
|
|
|
159
341
|
def build_context(
|
|
@@ -168,7 +350,15 @@ class LongTermMemoryService:
|
|
|
168
350
|
return None
|
|
169
351
|
if not self.is_configured():
|
|
170
352
|
return None
|
|
353
|
+
try:
|
|
354
|
+
entries = self.search_entries(user_id=user_id, query=normalized, top_k=top_k)
|
|
355
|
+
except Exception as exc:
|
|
356
|
+
logger.error("load_memory failed: %s", exc)
|
|
357
|
+
return {"query": normalized, "formatted_text": "", "error": str(exc)}
|
|
358
|
+
backend_error = self.last_error
|
|
359
|
+
if not entries and backend_error:
|
|
360
|
+
return {"query": normalized, "formatted_text": "", "error": backend_error}
|
|
171
361
|
return {
|
|
172
362
|
"query": normalized,
|
|
173
|
-
"formatted_text":
|
|
363
|
+
"formatted_text": format_memory_entries(entries),
|
|
174
364
|
}
|
ksadk/memory/tool.py
CHANGED
|
@@ -78,6 +78,10 @@ def save_memory(content: str) -> dict:
|
|
|
78
78
|
"agent_id": context.agent_id,
|
|
79
79
|
"session_id": context.session_id,
|
|
80
80
|
"runner_type": context.runner_type,
|
|
81
|
+
# Explicit user saves must become searchable promptly. The
|
|
82
|
+
# SDK backend maps this to CreateMemorySdk.Flush; background
|
|
83
|
+
# turn persistence keeps the service's batched default.
|
|
84
|
+
"flush": True,
|
|
81
85
|
},
|
|
82
86
|
)
|
|
83
87
|
if ok:
|
ksadk/model_proxy/bootstrap.py
CHANGED
|
@@ -21,6 +21,7 @@ from .server import ProxyServer
|
|
|
21
21
|
# 进程级单例:setup_environment 多次调用只起一个 proxy
|
|
22
22
|
_proxy: Optional[ProxyServer] = None
|
|
23
23
|
_original_base: Optional[str] = None
|
|
24
|
+
_original_base_env: Optional[dict[str, str | None]] = None
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
def setup_proxy_redirect_if_enabled(
|
|
@@ -35,7 +36,7 @@ def setup_proxy_redirect_if_enabled(
|
|
|
35
36
|
返回 proxy base_url(已重定向)或 None(未启用)。多次调用幂等(单例)。
|
|
36
37
|
上游凭证来自 ProxyConfig(从 env 读),不下发给子进程(凭证闭合)。
|
|
37
38
|
"""
|
|
38
|
-
global _proxy, _original_base
|
|
39
|
+
global _proxy, _original_base, _original_base_env
|
|
39
40
|
if _proxy is not None:
|
|
40
41
|
return _proxy.base_url # 幂等:已起
|
|
41
42
|
gate = gate or ProxyGate.from_env()
|
|
@@ -48,9 +49,7 @@ def setup_proxy_redirect_if_enabled(
|
|
|
48
49
|
or os.environ.get("OPENAI_API_BASE")
|
|
49
50
|
or ""
|
|
50
51
|
)
|
|
51
|
-
key = (
|
|
52
|
-
api_key or os.environ.get("OPENAI_API_KEY") or os.environ.get("LLM_API_KEY") or ""
|
|
53
|
-
)
|
|
52
|
+
key = api_key or os.environ.get("OPENAI_API_KEY") or os.environ.get("LLM_API_KEY") or ""
|
|
54
53
|
token = local_token or os.environ.get("KSADK_PROXY_TOKEN") or ""
|
|
55
54
|
if not upstream or not key:
|
|
56
55
|
return None # 缺凭证/上游,不启用(保持原 env)
|
|
@@ -59,7 +58,11 @@ def setup_proxy_redirect_if_enabled(
|
|
|
59
58
|
srv.start()
|
|
60
59
|
_proxy = srv
|
|
61
60
|
# 记录原 base 并重定向(双别名都指向 proxy)
|
|
62
|
-
|
|
61
|
+
_original_base_env = {
|
|
62
|
+
"OPENAI_BASE_URL": os.environ.get("OPENAI_BASE_URL"),
|
|
63
|
+
"OPENAI_API_BASE": os.environ.get("OPENAI_API_BASE"),
|
|
64
|
+
}
|
|
65
|
+
_original_base = _original_base_env["OPENAI_BASE_URL"] or _original_base_env["OPENAI_API_BASE"]
|
|
63
66
|
os.environ["OPENAI_BASE_URL"] = srv.base_url
|
|
64
67
|
os.environ["OPENAI_API_BASE"] = srv.base_url
|
|
65
68
|
if not token:
|
|
@@ -70,11 +73,15 @@ def setup_proxy_redirect_if_enabled(
|
|
|
70
73
|
|
|
71
74
|
def teardown_proxy_redirect() -> None:
|
|
72
75
|
"""回收 proxy 并恢复原 OPENAI_BASE_URL(进程退出/卸载时调)。"""
|
|
73
|
-
global _proxy, _original_base
|
|
76
|
+
global _proxy, _original_base, _original_base_env
|
|
74
77
|
if _proxy is not None:
|
|
75
78
|
_proxy.stop()
|
|
76
79
|
_proxy = None
|
|
77
|
-
if
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
if _original_base_env is not None:
|
|
81
|
+
for key, value in _original_base_env.items():
|
|
82
|
+
if value is None:
|
|
83
|
+
os.environ.pop(key, None)
|
|
84
|
+
else:
|
|
85
|
+
os.environ[key] = value
|
|
86
|
+
_original_base_env = None
|
|
80
87
|
_original_base = None
|
ksadk/model_proxy/config.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""ProxyConfig:转换 proxy 的配置(显式注入,不在模块导入时读 env,便于内化与测试)。"""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
from dataclasses import dataclass
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any, Callable
|
|
5
6
|
from urllib.parse import urlsplit
|
|
6
7
|
|
|
7
8
|
# HTTPS(凭证安全):不再用明文 HTTP 携带 Bearer key。
|
|
@@ -15,17 +16,37 @@ class ProxyConfig:
|
|
|
15
16
|
upstream_base: str = DEFAULT_UPSTREAM_BASE
|
|
16
17
|
api_key: str = "" # 上游凭证(proxy -> 上游)
|
|
17
18
|
local_token: str = "" # 本地 proxy 鉴权 token(codex -> proxy);空则不校验(仅本地调试)
|
|
19
|
+
# 非空时 responses 转换路径强制改写 model(Codex 可能发送内部伪模型名)。
|
|
20
|
+
upstream_model: str = ""
|
|
18
21
|
timeout: float = 180.0
|
|
22
|
+
event_callback: Callable[[str, dict[str, Any]], None] | None = field(
|
|
23
|
+
default=None,
|
|
24
|
+
repr=False,
|
|
25
|
+
compare=False,
|
|
26
|
+
)
|
|
19
27
|
|
|
20
28
|
def __post_init__(self) -> None:
|
|
21
29
|
self.upstream_base = _require_secure_upstream(self.upstream_base.rstrip("/"))
|
|
22
30
|
|
|
31
|
+
def emit(self, event: str, data: dict[str, Any]) -> None:
|
|
32
|
+
callback = self.event_callback
|
|
33
|
+
if callback is None:
|
|
34
|
+
return
|
|
35
|
+
try:
|
|
36
|
+
callback(event, data)
|
|
37
|
+
except Exception:
|
|
38
|
+
# Observability must never break model traffic.
|
|
39
|
+
return
|
|
40
|
+
|
|
23
41
|
@classmethod
|
|
24
42
|
def from_env(cls) -> "ProxyConfig":
|
|
25
43
|
return cls(
|
|
26
44
|
upstream_base=os.environ.get("UPSTREAM_BASE", DEFAULT_UPSTREAM_BASE),
|
|
27
45
|
api_key=os.environ.get("KSPMAS_API_KEY", ""),
|
|
28
46
|
local_token=os.environ.get("KSADK_PROXY_TOKEN", ""),
|
|
47
|
+
upstream_model=os.environ.get("OPENAI_MODEL_NAME")
|
|
48
|
+
or os.environ.get("MODEL_NAME")
|
|
49
|
+
or "",
|
|
29
50
|
timeout=float(os.environ.get("UPSTREAM_TIMEOUT", "180")),
|
|
30
51
|
)
|
|
31
52
|
|
ksadk/model_proxy/detect.py
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
超时/5xx/429/401/403 一律 "unknown",不改变判定(故障 ≠ 能力缺失)。
|
|
13
13
|
- ``stream_delta_ok`` 需真发流式请求才能判定,成本高,本模块默认 None(不探),
|
|
14
14
|
由调用方按需触发或默认走转换层(转换层自己生成完整 delta)。
|
|
15
|
+
- Codex 直连还需功能性 tool probes:真实发送当前 Codex 会声明的
|
|
16
|
+
``additional_tools`` 工具面。任一必需类型被拒时保留
|
|
17
|
+
``responses_supported=True``,同时推荐经 Chat 转换层执行。
|
|
15
18
|
"""
|
|
16
19
|
|
|
17
20
|
from __future__ import annotations
|
|
@@ -24,6 +27,12 @@ import httpx
|
|
|
24
27
|
|
|
25
28
|
Verdict = Literal["supported", "unsupported", "unknown"]
|
|
26
29
|
|
|
30
|
+
# These are Codex wire-contract capabilities, not provider/model allowlists.
|
|
31
|
+
# namespace/custom are required for a native Responses turn; web_search is an
|
|
32
|
+
# optional built-in that may be disabled without downgrading the whole protocol.
|
|
33
|
+
CODEX_DIRECT_REQUIRED_TOOL_TYPES = frozenset({"namespace", "custom"})
|
|
34
|
+
CODEX_OPTIONAL_TOOL_TYPES = frozenset({"web_search"})
|
|
35
|
+
|
|
27
36
|
|
|
28
37
|
@dataclass
|
|
29
38
|
class ModelCapabilities:
|
|
@@ -31,7 +40,7 @@ class ModelCapabilities:
|
|
|
31
40
|
|
|
32
41
|
responses_supported: bool | None = None # None = 未知(未探/不确定)
|
|
33
42
|
stream_delta_ok: bool | None = None # 流式增量 delta;None = 未探
|
|
34
|
-
tool_types: set[str] = field(default_factory=set) #
|
|
43
|
+
tool_types: set[str] = field(default_factory=set) # 已实测支持的 Codex 工具类型
|
|
35
44
|
preferred_protocol: str = "chat" # "responses" | "chat":路由该走哪条
|
|
36
45
|
checked_at: float = 0.0
|
|
37
46
|
verdict: Verdict = "unknown" # 最近一次探测结论
|
|
@@ -65,7 +74,10 @@ def probe_responses_capability(
|
|
|
65
74
|
):
|
|
66
75
|
"""功能性 probe /v1/responses,返回能力矩阵(sync) 或 coroutine(async)。
|
|
67
76
|
|
|
68
|
-
- 200
|
|
77
|
+
- 纯文本 200 且结构合法后,再逐个探测真实 Codex 工具类型
|
|
78
|
+
- namespace/custom 成功→ preferred_protocol=responses
|
|
79
|
+
- 仅 web_search 被拒→仍为 responses,但不把 web_search 记入 tool_types
|
|
80
|
+
- namespace/custom 被拒→ supported,preferred_protocol=chat
|
|
69
81
|
- 200 但非 responses 结构(网关伪 200)→ unsupported,preferred_protocol=chat
|
|
70
82
|
- 404/405/400 unknown → unsupported,preferred_protocol=chat
|
|
71
83
|
- 超时/5xx/429/401/403 → unknown,preferred_protocol 保持默认 chat(保守走转换层)
|
|
@@ -86,16 +98,47 @@ def _probe_sync(
|
|
|
86
98
|
caps = ModelCapabilities(checked_at=time.time(), verdict="unknown")
|
|
87
99
|
url = f"{base.rstrip('/')}/responses"
|
|
88
100
|
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
|
89
|
-
payload = {"model": model, "input": "hi", "max_output_tokens": 1, "stream": False}
|
|
90
101
|
try:
|
|
91
|
-
r = client.post(
|
|
102
|
+
r = client.post(
|
|
103
|
+
url,
|
|
104
|
+
json=_base_probe_payload(model),
|
|
105
|
+
headers=headers,
|
|
106
|
+
timeout=timeout,
|
|
107
|
+
)
|
|
92
108
|
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
93
109
|
return _finalize(caps)
|
|
94
110
|
try:
|
|
95
111
|
data = r.json()
|
|
96
112
|
except ValueError:
|
|
97
113
|
data = None
|
|
98
|
-
|
|
114
|
+
caps = _apply_response(caps, r.status_code, r.text, data)
|
|
115
|
+
if not caps.responses_supported:
|
|
116
|
+
return caps
|
|
117
|
+
for tool_type, payload in _codex_tool_probe_payloads(model):
|
|
118
|
+
try:
|
|
119
|
+
tool_response = client.post(
|
|
120
|
+
url,
|
|
121
|
+
json=payload,
|
|
122
|
+
headers=headers,
|
|
123
|
+
timeout=timeout,
|
|
124
|
+
)
|
|
125
|
+
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
126
|
+
caps.verdict = "unknown"
|
|
127
|
+
return _finalize(caps)
|
|
128
|
+
try:
|
|
129
|
+
tool_data = tool_response.json()
|
|
130
|
+
except ValueError:
|
|
131
|
+
tool_data = None
|
|
132
|
+
caps = _apply_tool_response(
|
|
133
|
+
caps,
|
|
134
|
+
tool_type,
|
|
135
|
+
tool_response.status_code,
|
|
136
|
+
tool_response.text,
|
|
137
|
+
tool_data,
|
|
138
|
+
)
|
|
139
|
+
if tool_type not in caps.tool_types:
|
|
140
|
+
return caps
|
|
141
|
+
return _finalize(caps)
|
|
99
142
|
|
|
100
143
|
|
|
101
144
|
async def _probe_async(
|
|
@@ -104,16 +147,162 @@ async def _probe_async(
|
|
|
104
147
|
caps = ModelCapabilities(checked_at=time.time(), verdict="unknown")
|
|
105
148
|
url = f"{base.rstrip('/')}/responses"
|
|
106
149
|
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
|
107
|
-
payload = {"model": model, "input": "hi", "max_output_tokens": 1, "stream": False}
|
|
108
150
|
try:
|
|
109
|
-
r = await client.post(
|
|
151
|
+
r = await client.post(
|
|
152
|
+
url,
|
|
153
|
+
json=_base_probe_payload(model),
|
|
154
|
+
headers=headers,
|
|
155
|
+
timeout=timeout,
|
|
156
|
+
)
|
|
110
157
|
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
111
158
|
return _finalize(caps)
|
|
112
159
|
try:
|
|
113
160
|
data = r.json()
|
|
114
161
|
except ValueError:
|
|
115
162
|
data = None
|
|
116
|
-
|
|
163
|
+
caps = _apply_response(caps, r.status_code, r.text, data)
|
|
164
|
+
if not caps.responses_supported:
|
|
165
|
+
return caps
|
|
166
|
+
for tool_type, payload in _codex_tool_probe_payloads(model):
|
|
167
|
+
try:
|
|
168
|
+
tool_response = await client.post(
|
|
169
|
+
url,
|
|
170
|
+
json=payload,
|
|
171
|
+
headers=headers,
|
|
172
|
+
timeout=timeout,
|
|
173
|
+
)
|
|
174
|
+
except (httpx.TimeoutException, httpx.ConnectError, httpx.HTTPError):
|
|
175
|
+
caps.verdict = "unknown"
|
|
176
|
+
return _finalize(caps)
|
|
177
|
+
try:
|
|
178
|
+
tool_data = tool_response.json()
|
|
179
|
+
except ValueError:
|
|
180
|
+
tool_data = None
|
|
181
|
+
caps = _apply_tool_response(
|
|
182
|
+
caps,
|
|
183
|
+
tool_type,
|
|
184
|
+
tool_response.status_code,
|
|
185
|
+
tool_response.text,
|
|
186
|
+
tool_data,
|
|
187
|
+
)
|
|
188
|
+
if tool_type not in caps.tool_types:
|
|
189
|
+
return caps
|
|
190
|
+
return _finalize(caps)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _base_probe_payload(model: str) -> dict[str, Any]:
|
|
194
|
+
return {"model": model, "input": "hi", "max_output_tokens": 1, "stream": False}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _namespace_probe_payload(model: str) -> dict[str, Any]:
|
|
198
|
+
"""Return the smallest real Codex 0.147 dynamic-tool declaration."""
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
"model": model,
|
|
202
|
+
"input": [
|
|
203
|
+
{
|
|
204
|
+
"type": "additional_tools",
|
|
205
|
+
"role": "developer",
|
|
206
|
+
"tools": [
|
|
207
|
+
{
|
|
208
|
+
"type": "namespace",
|
|
209
|
+
"name": "functions",
|
|
210
|
+
"description": "KsADK Codex capability probe",
|
|
211
|
+
"tools": [
|
|
212
|
+
{
|
|
213
|
+
"type": "function",
|
|
214
|
+
"name": "probe",
|
|
215
|
+
"description": "Probe Codex namespace tool support",
|
|
216
|
+
"parameters": {
|
|
217
|
+
"type": "object",
|
|
218
|
+
"properties": {},
|
|
219
|
+
"additionalProperties": False,
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
],
|
|
223
|
+
}
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"type": "message",
|
|
228
|
+
"role": "user",
|
|
229
|
+
"content": [{"type": "input_text", "text": "Reply with OK."}],
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
"max_output_tokens": 1,
|
|
233
|
+
"stream": False,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _custom_probe_payload(model: str) -> dict[str, Any]:
|
|
238
|
+
"""Return the smallest Codex namespaced freeform-tool declaration."""
|
|
239
|
+
|
|
240
|
+
payload = _namespace_probe_payload(model)
|
|
241
|
+
payload["input"][0]["tools"][0]["tools"] = [
|
|
242
|
+
{
|
|
243
|
+
"type": "custom",
|
|
244
|
+
"name": "probe",
|
|
245
|
+
"description": "Probe Codex custom tool support",
|
|
246
|
+
"format": {
|
|
247
|
+
"type": "grammar",
|
|
248
|
+
"syntax": "lark",
|
|
249
|
+
"definition": 'start: "OK"',
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
return payload
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _web_search_probe_payload(model: str) -> dict[str, Any]:
|
|
257
|
+
"""Return Codex's ``additional_tools`` built-in web-search declaration."""
|
|
258
|
+
|
|
259
|
+
payload = _namespace_probe_payload(model)
|
|
260
|
+
payload["input"][0]["tools"] = [{"type": "web_search"}]
|
|
261
|
+
return payload
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _codex_tool_probe_payloads(model: str) -> tuple[tuple[str, dict[str, Any]], ...]:
|
|
265
|
+
"""Return the model-agnostic direct tool surface required by Codex."""
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
("namespace", _namespace_probe_payload(model)),
|
|
269
|
+
("custom", _custom_probe_payload(model)),
|
|
270
|
+
("web_search", _web_search_probe_payload(model)),
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _apply_tool_response(
|
|
275
|
+
caps: ModelCapabilities, tool_type: str, status: int, text: str, data: Any
|
|
276
|
+
) -> ModelCapabilities:
|
|
277
|
+
valid_envelope = isinstance(data, dict) and "output" in data and "status" in data
|
|
278
|
+
envelope_failed = valid_envelope and (
|
|
279
|
+
str(data.get("status") or "").lower() == "failed" or bool(data.get("error"))
|
|
280
|
+
)
|
|
281
|
+
if status == 200 and valid_envelope and not envelope_failed:
|
|
282
|
+
caps.tool_types.add(tool_type)
|
|
283
|
+
caps.verdict = "supported"
|
|
284
|
+
return _finalize(caps)
|
|
285
|
+
|
|
286
|
+
low = (text or "").lower()
|
|
287
|
+
dialect_marker = any(
|
|
288
|
+
marker in low
|
|
289
|
+
for marker in (
|
|
290
|
+
tool_type.lower(),
|
|
291
|
+
"additional_tools",
|
|
292
|
+
"invalid value",
|
|
293
|
+
"supported values",
|
|
294
|
+
"not supported",
|
|
295
|
+
"unrecognized",
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
dialect_rejected = (
|
|
299
|
+
status in (400, 404, 405, 422) and (status in (404, 405) or dialect_marker)
|
|
300
|
+
) or (status == 200 and envelope_failed and dialect_marker)
|
|
301
|
+
if not dialect_rejected:
|
|
302
|
+
# Transient failures do not establish direct compatibility and should
|
|
303
|
+
# not be cached as a native Codex tool-capable endpoint.
|
|
304
|
+
caps.verdict = "unknown"
|
|
305
|
+
return _finalize(caps)
|
|
117
306
|
|
|
118
307
|
|
|
119
308
|
def _apply_response(
|
|
@@ -136,7 +325,11 @@ def _apply_response(
|
|
|
136
325
|
|
|
137
326
|
def _finalize(caps: ModelCapabilities) -> ModelCapabilities:
|
|
138
327
|
"""根据 verdict 定 preferred_protocol(保守:不确定也走转换层 chat)。"""
|
|
139
|
-
if
|
|
328
|
+
if (
|
|
329
|
+
caps.verdict == "supported"
|
|
330
|
+
and caps.responses_supported
|
|
331
|
+
and CODEX_DIRECT_REQUIRED_TOOL_TYPES.issubset(caps.tool_types)
|
|
332
|
+
):
|
|
140
333
|
caps.preferred_protocol = "responses"
|
|
141
334
|
else:
|
|
142
335
|
# unsupported 或 unknown 都默认 chat(走转换层):unknown 时走转换层更安全,
|