enya-agent 0.1.0
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.
- package/.env.example +20 -0
- package/.github/workflows/ci.yml +70 -0
- package/.github/workflows/publish.yml +250 -0
- package/.gitmodules +3 -0
- package/Cargo.lock +3584 -0
- package/Cargo.toml +97 -0
- package/crates/enact/Cargo.toml +27 -0
- package/crates/enact/src/lib.rs +60 -0
- package/crates/enact-a2a/Cargo.toml +25 -0
- package/crates/enact-a2a/src/lib.rs +411 -0
- package/crates/enact-channels/Cargo.toml +64 -0
- package/crates/enact-channels/examples/README.md +80 -0
- package/crates/enact-channels/examples/channel_bot.rs +169 -0
- package/crates/enact-channels/examples/telegram-echo.rs +34 -0
- package/crates/enact-channels/examples/whatsapp-echo.rs +142 -0
- package/crates/enact-channels/src/config.rs +213 -0
- package/crates/enact-channels/src/lib.rs +25 -0
- package/crates/enact-channels/src/runtime.rs +237 -0
- package/crates/enact-channels/src/security/mod.rs +5 -0
- package/crates/enact-channels/src/security/pairing.rs +205 -0
- package/crates/enact-channels/src/teams.rs +601 -0
- package/crates/enact-channels/src/telegram.rs +2833 -0
- package/crates/enact-channels/src/traits.rs +200 -0
- package/crates/enact-channels/src/webhook.rs +262 -0
- package/crates/enact-channels/src/whatsapp.rs +310 -0
- package/crates/enact-cli/Cargo.toml +40 -0
- package/crates/enact-cli/src/commands/doctor.rs +62 -0
- package/crates/enact-cli/src/commands/mod.rs +3 -0
- package/crates/enact-cli/src/commands/run.rs +69 -0
- package/crates/enact-cli/src/commands/serve.rs +81 -0
- package/crates/enact-cli/src/config.rs +2 -0
- package/crates/enact-cli/src/main.rs +79 -0
- package/crates/enact-config/Cargo.toml +36 -0
- package/crates/enact-config/ENV_VAR_MAPPING.md +135 -0
- package/crates/enact-config/QUICK_REFERENCE.md +92 -0
- package/crates/enact-config/README.md +107 -0
- package/crates/enact-config/TESTING.md +161 -0
- package/crates/enact-config/examples/test-env-vars.rs +100 -0
- package/crates/enact-config/src/config.rs +399 -0
- package/crates/enact-config/src/encrypted_store.rs +211 -0
- package/crates/enact-config/src/lib.rs +298 -0
- package/crates/enact-config/src/secrets.rs +149 -0
- package/crates/enact-config/src/sync.rs +260 -0
- package/crates/enact-config/test-env-vars.sh +34 -0
- package/crates/enact-config/tests/README.md +99 -0
- package/crates/enact-config/tests/config_integration_test.rs +202 -0
- package/crates/enact-config/tests/security_test.rs +140 -0
- package/crates/enact-context/Cargo.toml +41 -0
- package/crates/enact-context/src/budget.rs +314 -0
- package/crates/enact-context/src/calibrator.rs +535 -0
- package/crates/enact-context/src/compactor.rs +392 -0
- package/crates/enact-context/src/condenser.rs +826 -0
- package/crates/enact-context/src/lib.rs +94 -0
- package/crates/enact-context/src/segment.rs +238 -0
- package/crates/enact-context/src/step_context.rs +645 -0
- package/crates/enact-context/src/token_counter.rs +148 -0
- package/crates/enact-context/src/window.rs +372 -0
- package/crates/enact-core/Cargo.toml +42 -0
- package/crates/enact-core/README.md +98 -0
- package/crates/enact-core/src/background/executor.rs +524 -0
- package/crates/enact-core/src/background/mod.rs +48 -0
- package/crates/enact-core/src/background/target_binding.rs +390 -0
- package/crates/enact-core/src/background/trigger.rs +511 -0
- package/crates/enact-core/src/callable/callable.rs +152 -0
- package/crates/enact-core/src/callable/composite.rs +817 -0
- package/crates/enact-core/src/callable/graph.rs +104 -0
- package/crates/enact-core/src/callable/llm.rs +211 -0
- package/crates/enact-core/src/callable/mod.rs +64 -0
- package/crates/enact-core/src/callable/registry.rs +206 -0
- package/crates/enact-core/src/context/execution_context.rs +757 -0
- package/crates/enact-core/src/context/invocation.rs +99 -0
- package/crates/enact-core/src/context/mod.rs +50 -0
- package/crates/enact-core/src/context/tenant.rs +175 -0
- package/crates/enact-core/src/context/trace.rs +127 -0
- package/crates/enact-core/src/flow/conditional.rs +293 -0
- package/crates/enact-core/src/flow/mod.rs +43 -0
- package/crates/enact-core/src/flow/parallel.rs +437 -0
- package/crates/enact-core/src/flow/repeat.rs +534 -0
- package/crates/enact-core/src/flow/sequential.rs +248 -0
- package/crates/enact-core/src/graph/checkpoint.rs +79 -0
- package/crates/enact-core/src/graph/checkpoint_store.rs +76 -0
- package/crates/enact-core/src/graph/compiled.rs +189 -0
- package/crates/enact-core/src/graph/edge.rs +59 -0
- package/crates/enact-core/src/graph/graph_schema.rs +218 -0
- package/crates/enact-core/src/graph/loader.rs +155 -0
- package/crates/enact-core/src/graph/mod.rs +18 -0
- package/crates/enact-core/src/graph/node/function.rs +49 -0
- package/crates/enact-core/src/graph/node/mod.rs +48 -0
- package/crates/enact-core/src/graph/schema.rs +62 -0
- package/crates/enact-core/src/inbox/message.rs +405 -0
- package/crates/enact-core/src/inbox/mod.rs +31 -0
- package/crates/enact-core/src/inbox/store.rs +355 -0
- package/crates/enact-core/src/kernel/artifact/filesystem.rs +546 -0
- package/crates/enact-core/src/kernel/artifact/metadata.rs +283 -0
- package/crates/enact-core/src/kernel/artifact/mod.rs +27 -0
- package/crates/enact-core/src/kernel/artifact/store.rs +427 -0
- package/crates/enact-core/src/kernel/enforcement.rs +1315 -0
- package/crates/enact-core/src/kernel/error.rs +1200 -0
- package/crates/enact-core/src/kernel/event.rs +1394 -0
- package/crates/enact-core/src/kernel/execution_model.rs +831 -0
- package/crates/enact-core/src/kernel/execution_state.rs +189 -0
- package/crates/enact-core/src/kernel/execution_strategy.rs +117 -0
- package/crates/enact-core/src/kernel/ids.rs +2086 -0
- package/crates/enact-core/src/kernel/interrupt.rs +125 -0
- package/crates/enact-core/src/kernel/kernel.rs +1283 -0
- package/crates/enact-core/src/kernel/mod.rs +205 -0
- package/crates/enact-core/src/kernel/persistence/event_store.rs +270 -0
- package/crates/enact-core/src/kernel/persistence/message_store.rs +908 -0
- package/crates/enact-core/src/kernel/persistence/mod.rs +102 -0
- package/crates/enact-core/src/kernel/persistence/state_store.rs +228 -0
- package/crates/enact-core/src/kernel/persistence/vector_store.rs +299 -0
- package/crates/enact-core/src/kernel/reducer.rs +808 -0
- package/crates/enact-core/src/kernel/replay.rs +153 -0
- package/crates/enact-core/src/lib.rs +413 -0
- package/crates/enact-core/src/memory/episodic.rs +0 -0
- package/crates/enact-core/src/memory/mod.rs +6 -0
- package/crates/enact-core/src/memory/semantic.rs +0 -0
- package/crates/enact-core/src/memory/trait.rs +0 -0
- package/crates/enact-core/src/memory/vector_db.rs +0 -0
- package/crates/enact-core/src/memory/working.rs +0 -0
- package/crates/enact-core/src/policy/execution_policy.rs +292 -0
- package/crates/enact-core/src/policy/filters.rs +458 -0
- package/crates/enact-core/src/policy/input_processor.rs +407 -0
- package/crates/enact-core/src/policy/long_running.rs +134 -0
- package/crates/enact-core/src/policy/mod.rs +193 -0
- package/crates/enact-core/src/policy/pii_input.rs +274 -0
- package/crates/enact-core/src/policy/tenant_policy.rs +453 -0
- package/crates/enact-core/src/policy/tool_policy.rs +407 -0
- package/crates/enact-core/src/providers/mod.rs +63 -0
- package/crates/enact-core/src/providers/trait.rs +292 -0
- package/crates/enact-core/src/runner/callbacks.rs +6 -0
- package/crates/enact-core/src/runner/execution_runner.rs +476 -0
- package/crates/enact-core/src/runner/loop.rs +117 -0
- package/crates/enact-core/src/runner/mod.rs +58 -0
- package/crates/enact-core/src/runner/protected_runner.rs +280 -0
- package/crates/enact-core/src/signal/inmemory.rs +231 -0
- package/crates/enact-core/src/signal/mod.rs +108 -0
- package/crates/enact-core/src/streaming/event_logger.rs +195 -0
- package/crates/enact-core/src/streaming/event_stream.rs +1423 -0
- package/crates/enact-core/src/streaming/mod.rs +108 -0
- package/crates/enact-core/src/streaming/pause_cancel.rs +0 -0
- package/crates/enact-core/src/streaming/protected_emitter.rs +173 -0
- package/crates/enact-core/src/streaming/protection/context.rs +136 -0
- package/crates/enact-core/src/streaming/protection/encryption.rs +289 -0
- package/crates/enact-core/src/streaming/protection/mod.rs +43 -0
- package/crates/enact-core/src/streaming/protection/pii_protection.rs +243 -0
- package/crates/enact-core/src/streaming/protection/processor.rs +166 -0
- package/crates/enact-core/src/streaming/sse.rs +0 -0
- package/crates/enact-core/src/telemetry/exporter.rs +0 -0
- package/crates/enact-core/src/telemetry/init.rs +0 -0
- package/crates/enact-core/src/telemetry/mod.rs +49 -0
- package/crates/enact-core/src/telemetry/spans.rs +245 -0
- package/crates/enact-core/src/tool/agent_tool.rs +177 -0
- package/crates/enact-core/src/tool/browser/mod.rs +0 -0
- package/crates/enact-core/src/tool/browser/webdriver.rs +0 -0
- package/crates/enact-core/src/tool/cost.rs +247 -0
- package/crates/enact-core/src/tool/discovery.rs +0 -0
- package/crates/enact-core/src/tool/dispatcher.rs +347 -0
- package/crates/enact-core/src/tool/filesystem.rs +231 -0
- package/crates/enact-core/src/tool/function.rs +99 -0
- package/crates/enact-core/src/tool/git.rs +162 -0
- package/crates/enact-core/src/tool/http.rs +214 -0
- package/crates/enact-core/src/tool/mcp/client.rs +0 -0
- package/crates/enact-core/src/tool/mcp/mod.rs +0 -0
- package/crates/enact-core/src/tool/mod.rs +51 -0
- package/crates/enact-core/src/tool/reasoning/debugging.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mcts.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mod.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/sequential.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/dagger.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/mod.rs +0 -0
- package/crates/enact-core/src/tool/shell.rs +147 -0
- package/crates/enact-core/src/tool/trait.rs +33 -0
- package/crates/enact-core/src/tool/web_search.rs +277 -0
- package/crates/enact-core/src/util/config.rs +0 -0
- package/crates/enact-core/src/util/errors.rs +0 -0
- package/crates/enact-core/src/util/mod.rs +6 -0
- package/crates/enact-core/tests/airgapped_e2e_test.rs +291 -0
- package/crates/enact-core/tests/e2e_agentic_loop.rs +119 -0
- package/crates/enact-core/tests/e2e_test.rs +259 -0
- package/crates/enact-core/tests/graph_test.rs +130 -0
- package/crates/enact-core/tests/stream_event_id_validation.rs +435 -0
- package/crates/enact-cron/Cargo.toml +28 -0
- package/crates/enact-cron/src/lib.rs +44 -0
- package/crates/enact-cron/src/schedule.rs +156 -0
- package/crates/enact-cron/src/store.rs +589 -0
- package/crates/enact-cron/src/types.rs +148 -0
- package/crates/enact-gateway/Cargo.toml +31 -0
- package/crates/enact-gateway/README.md +30 -0
- package/crates/enact-gateway/examples/whatsapp-gateway-runner-mock.rs +59 -0
- package/crates/enact-gateway/examples/whatsapp-gateway.rs +42 -0
- package/crates/enact-gateway/src/lib.rs +582 -0
- package/crates/enact-mcp/Cargo.toml +24 -0
- package/crates/enact-mcp/src/lib.rs +178 -0
- package/crates/enact-memory/Cargo.toml +25 -0
- package/crates/enact-memory/src/backend.rs +20 -0
- package/crates/enact-memory/src/chunker.rs +230 -0
- package/crates/enact-memory/src/embeddings.rs +221 -0
- package/crates/enact-memory/src/lib.rs +67 -0
- package/crates/enact-memory/src/markdown.rs +127 -0
- package/crates/enact-memory/src/none.rs +61 -0
- package/crates/enact-memory/src/sqlite.rs +276 -0
- package/crates/enact-memory/src/traits.rs +65 -0
- package/crates/enact-memory/src/vector.rs +198 -0
- package/crates/enact-oauth/Cargo.toml +27 -0
- package/crates/enact-oauth/src/lib.rs +584 -0
- package/crates/enact-observability/Cargo.toml +22 -0
- package/crates/enact-observability/src/lib.rs +197 -0
- package/crates/enact-providers/Cargo.toml +33 -0
- package/crates/enact-providers/examples/hello-agent.rs +33 -0
- package/crates/enact-providers/src/anthropic.rs +182 -0
- package/crates/enact-providers/src/azure.rs +96 -0
- package/crates/enact-providers/src/bridge.rs +221 -0
- package/crates/enact-providers/src/gemini.rs +227 -0
- package/crates/enact-providers/src/http.rs +78 -0
- package/crates/enact-providers/src/lib.rs +53 -0
- package/crates/enact-providers/src/openai_compatible.rs +167 -0
- package/crates/enact-providers/src/openrouter.rs +33 -0
- package/crates/enact-runner/Cargo.toml +24 -0
- package/crates/enact-runner/README.md +76 -0
- package/crates/enact-runner/src/compaction.rs +225 -0
- package/crates/enact-runner/src/config.rs +118 -0
- package/crates/enact-runner/src/lib.rs +63 -0
- package/crates/enact-runner/src/loop_driver.rs +414 -0
- package/crates/enact-runner/src/parser.rs +421 -0
- package/crates/enact-runner/src/retry.rs +262 -0
- package/crates/enact-runner/tests/integration.rs +278 -0
- package/crates/enact-security/Cargo.toml +22 -0
- package/crates/enact-security/src/audit.rs +375 -0
- package/crates/enact-security/src/lib.rs +37 -0
- package/crates/enact-security/src/policy.rs +406 -0
- package/crates/enact-skills/Cargo.toml +25 -0
- package/crates/enact-skills/src/lib.rs +506 -0
- package/crates/enact-tools/Cargo.toml +22 -0
- package/crates/enact-tools/src/file_read.rs +166 -0
- package/crates/enact-tools/src/file_write.rs +216 -0
- package/crates/enact-tools/src/git_operations.rs +513 -0
- package/crates/enact-tools/src/http_request.rs +417 -0
- package/crates/enact-tools/src/lib.rs +104 -0
- package/crates/enact-tools/src/security.rs +227 -0
- package/crates/enact-tools/src/shell.rs +191 -0
- package/crates/enact-tools/src/traits.rs +159 -0
- package/docs/Makefile +74 -0
- package/docs/config.toml +62 -0
- package/docs/content/_index.md +174 -0
- package/docs/content/a2a/_index.md +431 -0
- package/docs/content/api/_index.md +323 -0
- package/docs/content/channels/_index.md +160 -0
- package/docs/content/channels/teams.md +205 -0
- package/docs/content/channels/telegram.md +182 -0
- package/docs/content/channels/webhook.md +423 -0
- package/docs/content/channels/whatsapp.md +240 -0
- package/docs/content/cli/_index.md +261 -0
- package/docs/content/concepts/_index.md +273 -0
- package/docs/content/configuration/_index.md +241 -0
- package/docs/content/cron/_index.md +248 -0
- package/docs/content/developers/_index.md +278 -0
- package/docs/content/getting-started/_index.md +180 -0
- package/docs/content/installation/_index.md +186 -0
- package/docs/content/installation/uninstall.md +101 -0
- package/docs/content/installation/updating.md +120 -0
- package/docs/content/mcp/_index.md +215 -0
- package/docs/content/memory/_index.md +163 -0
- package/docs/content/oauth/_index.md +515 -0
- package/docs/content/providers/_index.md +206 -0
- package/docs/content/roadmap/_index.md +199 -0
- package/docs/content/security/_index.md +219 -0
- package/docs/content/skills/_index.md +228 -0
- package/docs/content/tools/_index.md +485 -0
- package/docs/content/troubleshooting/_index.md +259 -0
- package/docs/content/yaml-schema/_index.md +294 -0
- package/docs/static/giallo-dark.css +91 -0
- package/docs/static/giallo-light.css +91 -0
- package/docs/themes/tanuki/.github/workflows/deploy.yml +44 -0
- package/docs/themes/tanuki/LICENSE +21 -0
- package/docs/themes/tanuki/README.md +166 -0
- package/docs/themes/tanuki/examples/blog/config.toml +58 -0
- package/docs/themes/tanuki/examples/blog/content/_index.md +4 -0
- package/docs/themes/tanuki/examples/blog/content/about.md +33 -0
- package/docs/themes/tanuki/examples/blog/content/blog/_index.md +7 -0
- package/docs/themes/tanuki/examples/blog/content/blog/api-design-best-practices.md +245 -0
- package/docs/themes/tanuki/examples/blog/content/blog/building-accessible-websites.md +147 -0
- package/docs/themes/tanuki/examples/blog/content/blog/css-grid-vs-flexbox.md +165 -0
- package/docs/themes/tanuki/examples/blog/content/blog/customizing-catppuccin-colors.md +137 -0
- package/docs/themes/tanuki/examples/blog/content/blog/dark-mode-best-practices.md +82 -0
- package/docs/themes/tanuki/examples/blog/content/blog/docker-essentials.md +301 -0
- package/docs/themes/tanuki/examples/blog/content/blog/getting-started-with-zola.md +129 -0
- package/docs/themes/tanuki/examples/blog/content/blog/git-workflow-for-content.md +112 -0
- package/docs/themes/tanuki/examples/blog/content/blog/introduction-to-webassembly.md +183 -0
- package/docs/themes/tanuki/examples/blog/content/blog/modern-javascript-features.md +234 -0
- package/docs/themes/tanuki/examples/blog/content/blog/testing-strategies.md +311 -0
- package/docs/themes/tanuki/examples/blog/content/blog/typography-for-developers.md +104 -0
- package/docs/themes/tanuki/examples/blog/content/blog/welcome-to-tanuki.md +67 -0
- package/docs/themes/tanuki/examples/blog/content/blog/why-static-sites.md +85 -0
- package/docs/themes/tanuki/examples/blog/content/projects.md +64 -0
- package/docs/themes/tanuki/examples/book/config.toml +17 -0
- package/docs/themes/tanuki/examples/book/content/_index.md +12 -0
- package/docs/themes/tanuki/examples/book/content/chapter-1.md +90 -0
- package/docs/themes/tanuki/examples/book/content/chapter-2.md +143 -0
- package/docs/themes/tanuki/examples/book/content/chapter-3.md +217 -0
- package/docs/themes/tanuki/examples/book/content/chapter-4.md +224 -0
- package/docs/themes/tanuki/examples/book/content/chapter-5.md +297 -0
- package/docs/themes/tanuki/examples/book/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/config.toml +28 -0
- package/docs/themes/tanuki/examples/docs/content/_index.md +20 -0
- package/docs/themes/tanuki/examples/docs/content/components.md +156 -0
- package/docs/themes/tanuki/examples/docs/content/configuration.md +94 -0
- package/docs/themes/tanuki/examples/docs/content/customization.md +202 -0
- package/docs/themes/tanuki/examples/docs/content/deployment.md +204 -0
- package/docs/themes/tanuki/examples/docs/content/installation.md +59 -0
- package/docs/themes/tanuki/examples/docs/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/examples/index.html +2104 -0
- package/docs/themes/tanuki/mise.toml +108 -0
- package/docs/themes/tanuki/sass/base/_catppuccin.scss +164 -0
- package/docs/themes/tanuki/sass/base/_fonts.scss +64 -0
- package/docs/themes/tanuki/sass/base/_reset.scss +152 -0
- package/docs/themes/tanuki/sass/base/_typography.scss +523 -0
- package/docs/themes/tanuki/sass/components/_buttons.scss +209 -0
- package/docs/themes/tanuki/sass/components/_code.scss +457 -0
- package/docs/themes/tanuki/sass/components/_landing.scss +633 -0
- package/docs/themes/tanuki/sass/components/_layout.scss +294 -0
- package/docs/themes/tanuki/sass/components/_navigation.scss +1200 -0
- package/docs/themes/tanuki/sass/components/_print.scss +237 -0
- package/docs/themes/tanuki/sass/components/_search.scss +224 -0
- package/docs/themes/tanuki/sass/components/_sidebar.scss +473 -0
- package/docs/themes/tanuki/sass/components/_theme-toggle.scss +186 -0
- package/docs/themes/tanuki/sass/modes/_blog.scss +366 -0
- package/docs/themes/tanuki/sass/modes/_product.scss +875 -0
- package/docs/themes/tanuki/sass/modes/_raskell.scss +1696 -0
- package/docs/themes/tanuki/sass/patterns/_buttons.scss +183 -0
- package/docs/themes/tanuki/sass/patterns/_cards.scss +144 -0
- package/docs/themes/tanuki/sass/patterns/_index.scss +9 -0
- package/docs/themes/tanuki/sass/patterns/_lists.scss +259 -0
- package/docs/themes/tanuki/sass/patterns/_sections.scss +243 -0
- package/docs/themes/tanuki/sass/style.scss +47 -0
- package/docs/themes/tanuki/sass/tokens/_colors.scss +139 -0
- package/docs/themes/tanuki/sass/tokens/_spacing.scss +100 -0
- package/docs/themes/tanuki/sass/tokens/_typography.scss +186 -0
- package/docs/themes/tanuki/screenshot.png +0 -0
- package/docs/themes/tanuki/sentinel.kdl +59 -0
- package/docs/themes/tanuki/static/elasticlunr.min.js +10 -0
- package/docs/themes/tanuki/static/fonts/GEIST-LICENSE.txt +92 -0
- package/docs/themes/tanuki/static/fonts/Geist-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/fonts/GeistMono-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.png +0 -0
- package/docs/themes/tanuki/static/js/anchors.js +18 -0
- package/docs/themes/tanuki/static/js/app.js +274 -0
- package/docs/themes/tanuki/static/js/code.js +394 -0
- package/docs/themes/tanuki/static/js/navigation.js +778 -0
- package/docs/themes/tanuki/static/js/scroll-to-top.js +33 -0
- package/docs/themes/tanuki/static/js/search-raskell.js +240 -0
- package/docs/themes/tanuki/static/js/search.js +215 -0
- package/docs/themes/tanuki/static/js/theme.js +169 -0
- package/docs/themes/tanuki/static/syntax-dark.css +151 -0
- package/docs/themes/tanuki/static/syntax-light.css +151 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm.js +486 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm_bg.wasm +0 -0
- package/docs/themes/tanuki/templates/404.html +52 -0
- package/docs/themes/tanuki/templates/base.html +428 -0
- package/docs/themes/tanuki/templates/blog.html +66 -0
- package/docs/themes/tanuki/templates/home.html +108 -0
- package/docs/themes/tanuki/templates/index.html +178 -0
- package/docs/themes/tanuki/templates/landing.html +168 -0
- package/docs/themes/tanuki/templates/macros/nav.html +128 -0
- package/docs/themes/tanuki/templates/macros/posts.html +101 -0
- package/docs/themes/tanuki/templates/macros/ui.html +159 -0
- package/docs/themes/tanuki/templates/page.html +135 -0
- package/docs/themes/tanuki/templates/partials/footer.html +38 -0
- package/docs/themes/tanuki/templates/partials/header.html +366 -0
- package/docs/themes/tanuki/templates/partials/nav-buttons.html +55 -0
- package/docs/themes/tanuki/templates/partials/nav-overlay.html +81 -0
- package/docs/themes/tanuki/templates/partials/page-toc-panel.html +43 -0
- package/docs/themes/tanuki/templates/partials/search.html +52 -0
- package/docs/themes/tanuki/templates/partials/sidebar.html +107 -0
- package/docs/themes/tanuki/templates/partials/theme-toggle.html +35 -0
- package/docs/themes/tanuki/templates/partials/toc-overlay.html +146 -0
- package/docs/themes/tanuki/templates/partials/version-picker.html +38 -0
- package/docs/themes/tanuki/templates/print.html +244 -0
- package/docs/themes/tanuki/templates/section.html +186 -0
- package/docs/themes/tanuki/templates/taxonomy_list.html +18 -0
- package/docs/themes/tanuki/templates/taxonomy_single.html +31 -0
- package/docs/themes/tanuki/theme.toml +58 -0
- package/examples/hello-agent.rs +55 -0
- package/package.json +36 -0
- package/proto/config.proto +60 -0
- package/proto/events.proto +0 -0
- package/proto/runtime.proto +215 -0
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
//! Result Condenser
|
|
2
|
+
//!
|
|
3
|
+
//! Condenses child execution traces to 1-2k token summaries.
|
|
4
|
+
//! Used to compress child callable results back into parent context.
|
|
5
|
+
//!
|
|
6
|
+
//! @see packages/enact-schemas/src/context.schemas.ts
|
|
7
|
+
|
|
8
|
+
use crate::segment::{ContextPriority, ContextSegment, ContextSegmentType};
|
|
9
|
+
use crate::token_counter::TokenCounter;
|
|
10
|
+
use chrono::{DateTime, Utc};
|
|
11
|
+
use enact_core::kernel::{ExecutionId, StepId};
|
|
12
|
+
use serde::{Deserialize, Serialize};
|
|
13
|
+
use std::collections::HashMap;
|
|
14
|
+
use std::sync::atomic::{AtomicU64, Ordering};
|
|
15
|
+
|
|
16
|
+
/// Global sequence counter for segments
|
|
17
|
+
static CONDENSE_SEQUENCE: AtomicU64 = AtomicU64::new(3000);
|
|
18
|
+
|
|
19
|
+
fn next_sequence() -> u64 {
|
|
20
|
+
CONDENSE_SEQUENCE.fetch_add(1, Ordering::SeqCst)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Condensation configuration
|
|
24
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
25
|
+
#[serde(rename_all = "camelCase")]
|
|
26
|
+
pub struct CondenserConfig {
|
|
27
|
+
/// Target token count for condensed result
|
|
28
|
+
pub target_tokens: usize,
|
|
29
|
+
|
|
30
|
+
/// Maximum token count (hard limit)
|
|
31
|
+
pub max_tokens: usize,
|
|
32
|
+
|
|
33
|
+
/// Include step summaries
|
|
34
|
+
pub include_steps: bool,
|
|
35
|
+
|
|
36
|
+
/// Maximum steps to summarize
|
|
37
|
+
pub max_steps: usize,
|
|
38
|
+
|
|
39
|
+
/// Include tool call summaries
|
|
40
|
+
pub include_tools: bool,
|
|
41
|
+
|
|
42
|
+
/// Include error summaries
|
|
43
|
+
pub include_errors: bool,
|
|
44
|
+
|
|
45
|
+
/// Include timing information
|
|
46
|
+
pub include_timing: bool,
|
|
47
|
+
|
|
48
|
+
/// Preserve key decisions
|
|
49
|
+
pub preserve_decisions: bool,
|
|
50
|
+
|
|
51
|
+
/// Maximum decision count
|
|
52
|
+
pub max_decisions: usize,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
impl Default for CondenserConfig {
|
|
56
|
+
fn default() -> Self {
|
|
57
|
+
Self {
|
|
58
|
+
target_tokens: 1500,
|
|
59
|
+
max_tokens: 2000,
|
|
60
|
+
include_steps: true,
|
|
61
|
+
max_steps: 10,
|
|
62
|
+
include_tools: true,
|
|
63
|
+
include_errors: true,
|
|
64
|
+
include_timing: true,
|
|
65
|
+
preserve_decisions: true,
|
|
66
|
+
max_decisions: 5,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
impl CondenserConfig {
|
|
72
|
+
/// Minimal config for brief summaries
|
|
73
|
+
pub fn minimal() -> Self {
|
|
74
|
+
Self {
|
|
75
|
+
target_tokens: 500,
|
|
76
|
+
max_tokens: 750,
|
|
77
|
+
include_steps: false,
|
|
78
|
+
max_steps: 3,
|
|
79
|
+
include_tools: false,
|
|
80
|
+
include_errors: true,
|
|
81
|
+
include_timing: false,
|
|
82
|
+
preserve_decisions: true,
|
|
83
|
+
max_decisions: 2,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Detailed config for comprehensive summaries
|
|
88
|
+
pub fn detailed() -> Self {
|
|
89
|
+
Self {
|
|
90
|
+
target_tokens: 3000,
|
|
91
|
+
max_tokens: 4000,
|
|
92
|
+
include_steps: true,
|
|
93
|
+
max_steps: 20,
|
|
94
|
+
include_tools: true,
|
|
95
|
+
include_errors: true,
|
|
96
|
+
include_timing: true,
|
|
97
|
+
preserve_decisions: true,
|
|
98
|
+
max_decisions: 10,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Summary of a step for condensation
|
|
104
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
105
|
+
pub struct StepSummary {
|
|
106
|
+
/// Step ID
|
|
107
|
+
pub step_id: StepId,
|
|
108
|
+
|
|
109
|
+
/// Step type/name
|
|
110
|
+
pub step_type: String,
|
|
111
|
+
|
|
112
|
+
/// Brief description of what happened
|
|
113
|
+
pub summary: String,
|
|
114
|
+
|
|
115
|
+
/// Whether step succeeded
|
|
116
|
+
pub success: bool,
|
|
117
|
+
|
|
118
|
+
/// Duration in milliseconds
|
|
119
|
+
pub duration_ms: Option<u64>,
|
|
120
|
+
|
|
121
|
+
/// Key output (truncated if needed)
|
|
122
|
+
pub key_output: Option<String>,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Summary of a decision made during execution
|
|
126
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
127
|
+
pub struct DecisionSummary {
|
|
128
|
+
/// What decision was made
|
|
129
|
+
pub decision: String,
|
|
130
|
+
|
|
131
|
+
/// Rationale for the decision
|
|
132
|
+
pub rationale: String,
|
|
133
|
+
|
|
134
|
+
/// Confidence level
|
|
135
|
+
pub confidence: f64,
|
|
136
|
+
|
|
137
|
+
/// Step where decision was made
|
|
138
|
+
pub step_id: StepId,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/// Input for condensation - represents a child execution trace
|
|
142
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
143
|
+
pub struct ExecutionTrace {
|
|
144
|
+
/// Execution ID
|
|
145
|
+
pub execution_id: ExecutionId,
|
|
146
|
+
|
|
147
|
+
/// Parent execution ID (if any)
|
|
148
|
+
pub parent_execution_id: Option<ExecutionId>,
|
|
149
|
+
|
|
150
|
+
/// Parent step that spawned this execution
|
|
151
|
+
pub parent_step_id: Option<StepId>,
|
|
152
|
+
|
|
153
|
+
/// Execution start time
|
|
154
|
+
pub started_at: DateTime<Utc>,
|
|
155
|
+
|
|
156
|
+
/// Execution end time
|
|
157
|
+
pub ended_at: Option<DateTime<Utc>>,
|
|
158
|
+
|
|
159
|
+
/// Final status
|
|
160
|
+
pub status: ExecutionStatus,
|
|
161
|
+
|
|
162
|
+
/// Step summaries
|
|
163
|
+
pub steps: Vec<StepSummary>,
|
|
164
|
+
|
|
165
|
+
/// Key decisions made
|
|
166
|
+
pub decisions: Vec<DecisionSummary>,
|
|
167
|
+
|
|
168
|
+
/// Final output/result
|
|
169
|
+
pub final_output: Option<String>,
|
|
170
|
+
|
|
171
|
+
/// Error message if failed
|
|
172
|
+
pub error: Option<String>,
|
|
173
|
+
|
|
174
|
+
/// Metadata
|
|
175
|
+
pub metadata: HashMap<String, String>,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// Execution status for trace
|
|
179
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
180
|
+
#[serde(rename_all = "snake_case")]
|
|
181
|
+
pub enum ExecutionStatus {
|
|
182
|
+
/// Completed successfully
|
|
183
|
+
Completed,
|
|
184
|
+
/// Failed with error
|
|
185
|
+
Failed,
|
|
186
|
+
/// Cancelled by user/system
|
|
187
|
+
Cancelled,
|
|
188
|
+
/// Timed out
|
|
189
|
+
TimedOut,
|
|
190
|
+
/// Still running
|
|
191
|
+
Running,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
impl ExecutionTrace {
|
|
195
|
+
/// Create a new trace
|
|
196
|
+
pub fn new(execution_id: ExecutionId) -> Self {
|
|
197
|
+
Self {
|
|
198
|
+
execution_id,
|
|
199
|
+
parent_execution_id: None,
|
|
200
|
+
parent_step_id: None,
|
|
201
|
+
started_at: Utc::now(),
|
|
202
|
+
ended_at: None,
|
|
203
|
+
status: ExecutionStatus::Running,
|
|
204
|
+
steps: Vec::new(),
|
|
205
|
+
decisions: Vec::new(),
|
|
206
|
+
final_output: None,
|
|
207
|
+
error: None,
|
|
208
|
+
metadata: HashMap::new(),
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/// Create with parent context
|
|
213
|
+
pub fn with_parent(
|
|
214
|
+
execution_id: ExecutionId,
|
|
215
|
+
parent_execution_id: ExecutionId,
|
|
216
|
+
parent_step_id: StepId,
|
|
217
|
+
) -> Self {
|
|
218
|
+
Self {
|
|
219
|
+
execution_id,
|
|
220
|
+
parent_execution_id: Some(parent_execution_id),
|
|
221
|
+
parent_step_id: Some(parent_step_id),
|
|
222
|
+
started_at: Utc::now(),
|
|
223
|
+
ended_at: None,
|
|
224
|
+
status: ExecutionStatus::Running,
|
|
225
|
+
steps: Vec::new(),
|
|
226
|
+
decisions: Vec::new(),
|
|
227
|
+
final_output: None,
|
|
228
|
+
error: None,
|
|
229
|
+
metadata: HashMap::new(),
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/// Mark as completed
|
|
234
|
+
pub fn complete(mut self, output: impl Into<String>) -> Self {
|
|
235
|
+
self.ended_at = Some(Utc::now());
|
|
236
|
+
self.status = ExecutionStatus::Completed;
|
|
237
|
+
self.final_output = Some(output.into());
|
|
238
|
+
self
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// Mark as failed
|
|
242
|
+
pub fn fail(mut self, error: impl Into<String>) -> Self {
|
|
243
|
+
self.ended_at = Some(Utc::now());
|
|
244
|
+
self.status = ExecutionStatus::Failed;
|
|
245
|
+
self.error = Some(error.into());
|
|
246
|
+
self
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// Add a step summary
|
|
250
|
+
pub fn add_step(mut self, step: StepSummary) -> Self {
|
|
251
|
+
self.steps.push(step);
|
|
252
|
+
self
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/// Add a decision
|
|
256
|
+
pub fn add_decision(mut self, decision: DecisionSummary) -> Self {
|
|
257
|
+
self.decisions.push(decision);
|
|
258
|
+
self
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/// Get duration in milliseconds
|
|
262
|
+
pub fn duration_ms(&self) -> Option<i64> {
|
|
263
|
+
self.ended_at.map(|end| {
|
|
264
|
+
(end - self.started_at).num_milliseconds()
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/// Result of condensation
|
|
270
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
271
|
+
#[serde(rename_all = "camelCase")]
|
|
272
|
+
pub struct CondensedResult {
|
|
273
|
+
/// Source execution ID
|
|
274
|
+
pub execution_id: ExecutionId,
|
|
275
|
+
|
|
276
|
+
/// Condensed summary text
|
|
277
|
+
pub summary: String,
|
|
278
|
+
|
|
279
|
+
/// Key outcomes
|
|
280
|
+
pub outcomes: Vec<String>,
|
|
281
|
+
|
|
282
|
+
/// Important learnings
|
|
283
|
+
pub learnings: Vec<String>,
|
|
284
|
+
|
|
285
|
+
/// Context segment for parent
|
|
286
|
+
pub context_segment: ContextSegment,
|
|
287
|
+
|
|
288
|
+
/// Token count of condensed result
|
|
289
|
+
pub token_count: usize,
|
|
290
|
+
|
|
291
|
+
/// Original trace token estimate
|
|
292
|
+
pub original_tokens: usize,
|
|
293
|
+
|
|
294
|
+
/// Compression ratio
|
|
295
|
+
pub compression_ratio: f64,
|
|
296
|
+
|
|
297
|
+
/// Condensation timestamp
|
|
298
|
+
pub condensed_at: DateTime<Utc>,
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// Result Condenser - compresses execution traces for parent context
|
|
302
|
+
pub struct ResultCondenser {
|
|
303
|
+
token_counter: TokenCounter,
|
|
304
|
+
config: CondenserConfig,
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
impl ResultCondenser {
|
|
308
|
+
/// Create with default config
|
|
309
|
+
pub fn new() -> Self {
|
|
310
|
+
Self {
|
|
311
|
+
token_counter: TokenCounter::default(),
|
|
312
|
+
config: CondenserConfig::default(),
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// Create with custom config
|
|
317
|
+
pub fn with_config(config: CondenserConfig) -> Self {
|
|
318
|
+
Self {
|
|
319
|
+
token_counter: TokenCounter::default(),
|
|
320
|
+
config,
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/// Condense an execution trace
|
|
325
|
+
pub fn condense(&self, trace: &ExecutionTrace) -> CondensedResult {
|
|
326
|
+
let mut parts: Vec<String> = Vec::new();
|
|
327
|
+
let mut outcomes: Vec<String> = Vec::new();
|
|
328
|
+
let mut learnings: Vec<String> = Vec::new();
|
|
329
|
+
|
|
330
|
+
// Header with execution info
|
|
331
|
+
let header = self.build_header(trace);
|
|
332
|
+
parts.push(header);
|
|
333
|
+
|
|
334
|
+
// Status and result
|
|
335
|
+
let status_section = self.build_status_section(trace, &mut outcomes);
|
|
336
|
+
parts.push(status_section);
|
|
337
|
+
|
|
338
|
+
// Steps summary (if enabled)
|
|
339
|
+
if self.config.include_steps && !trace.steps.is_empty() {
|
|
340
|
+
let steps_section = self.build_steps_section(&trace.steps);
|
|
341
|
+
parts.push(steps_section);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Decisions (if enabled)
|
|
345
|
+
if self.config.preserve_decisions && !trace.decisions.is_empty() {
|
|
346
|
+
let decisions_section = self.build_decisions_section(&trace.decisions, &mut learnings);
|
|
347
|
+
parts.push(decisions_section);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Error details (if any)
|
|
351
|
+
if self.config.include_errors {
|
|
352
|
+
if let Some(error) = &trace.error {
|
|
353
|
+
parts.push(format!("Error: {}", self.truncate(error, 200)));
|
|
354
|
+
learnings.push(format!("Failure mode: {}", self.truncate(error, 100)));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Combine and check token count
|
|
359
|
+
let mut summary = parts.join("\n\n");
|
|
360
|
+
let mut token_count = self.token_counter.count(&summary);
|
|
361
|
+
|
|
362
|
+
// Truncate if over limit
|
|
363
|
+
if token_count > self.config.max_tokens {
|
|
364
|
+
let (truncated, new_count) = self.token_counter.truncate(&summary, self.config.target_tokens);
|
|
365
|
+
summary = truncated;
|
|
366
|
+
token_count = new_count;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Estimate original token count
|
|
370
|
+
let original_tokens = self.estimate_original_tokens(trace);
|
|
371
|
+
let compression_ratio = if original_tokens > 0 {
|
|
372
|
+
token_count as f64 / original_tokens as f64
|
|
373
|
+
} else {
|
|
374
|
+
1.0
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// Create context segment for parent
|
|
378
|
+
let segment_content = format!(
|
|
379
|
+
"[Child Execution: {}]\n{}",
|
|
380
|
+
trace.execution_id.as_str(),
|
|
381
|
+
summary
|
|
382
|
+
);
|
|
383
|
+
let segment_tokens = self.token_counter.count(&segment_content);
|
|
384
|
+
let context_segment = ContextSegment::child_summary(
|
|
385
|
+
segment_content,
|
|
386
|
+
segment_tokens,
|
|
387
|
+
next_sequence(),
|
|
388
|
+
trace.parent_step_id.clone().unwrap_or_else(StepId::new),
|
|
389
|
+
).with_priority(
|
|
390
|
+
if trace.status == ExecutionStatus::Completed {
|
|
391
|
+
ContextPriority::Medium
|
|
392
|
+
} else {
|
|
393
|
+
ContextPriority::High
|
|
394
|
+
}
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
CondensedResult {
|
|
398
|
+
execution_id: trace.execution_id.clone(),
|
|
399
|
+
summary,
|
|
400
|
+
outcomes,
|
|
401
|
+
learnings,
|
|
402
|
+
context_segment,
|
|
403
|
+
token_count,
|
|
404
|
+
original_tokens,
|
|
405
|
+
compression_ratio,
|
|
406
|
+
condensed_at: Utc::now(),
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/// Build header section
|
|
411
|
+
fn build_header(&self, trace: &ExecutionTrace) -> String {
|
|
412
|
+
let mut header = format!("Execution: {}", trace.execution_id.as_str());
|
|
413
|
+
|
|
414
|
+
if self.config.include_timing {
|
|
415
|
+
if let Some(duration) = trace.duration_ms() {
|
|
416
|
+
header.push_str(&format!(" ({}ms)", duration));
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if let Some(parent) = &trace.parent_step_id {
|
|
421
|
+
header.push_str(&format!("\nSpawned from: {}", parent.as_str()));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
header
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/// Build status section
|
|
428
|
+
fn build_status_section(&self, trace: &ExecutionTrace, outcomes: &mut Vec<String>) -> String {
|
|
429
|
+
let status_str = match trace.status {
|
|
430
|
+
ExecutionStatus::Completed => "COMPLETED",
|
|
431
|
+
ExecutionStatus::Failed => "FAILED",
|
|
432
|
+
ExecutionStatus::Cancelled => "CANCELLED",
|
|
433
|
+
ExecutionStatus::TimedOut => "TIMED_OUT",
|
|
434
|
+
ExecutionStatus::Running => "RUNNING",
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
let mut section = format!("Status: {}", status_str);
|
|
438
|
+
|
|
439
|
+
if let Some(output) = &trace.final_output {
|
|
440
|
+
let truncated = self.truncate(output, 300);
|
|
441
|
+
section.push_str(&format!("\nResult: {}", truncated));
|
|
442
|
+
outcomes.push(format!("Output: {}", self.truncate(output, 100)));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
section
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/// Build steps section
|
|
449
|
+
fn build_steps_section(&self, steps: &[StepSummary]) -> String {
|
|
450
|
+
let steps_to_show: Vec<_> = steps.iter().take(self.config.max_steps).collect();
|
|
451
|
+
let total = steps.len();
|
|
452
|
+
let shown = steps_to_show.len();
|
|
453
|
+
|
|
454
|
+
let mut lines: Vec<String> = vec![format!("Steps ({}/{}):", shown, total)];
|
|
455
|
+
|
|
456
|
+
for (i, step) in steps_to_show.iter().enumerate() {
|
|
457
|
+
let status = if step.success { "✓" } else { "✗" };
|
|
458
|
+
let mut line = format!(
|
|
459
|
+
" {}. {} {} - {}",
|
|
460
|
+
i + 1,
|
|
461
|
+
status,
|
|
462
|
+
step.step_type,
|
|
463
|
+
self.truncate(&step.summary, 50)
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
if self.config.include_timing {
|
|
467
|
+
if let Some(ms) = step.duration_ms {
|
|
468
|
+
line.push_str(&format!(" ({}ms)", ms));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
lines.push(line);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if total > shown {
|
|
476
|
+
lines.push(format!(" ... and {} more steps", total - shown));
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
lines.join("\n")
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/// Build decisions section
|
|
483
|
+
fn build_decisions_section(
|
|
484
|
+
&self,
|
|
485
|
+
decisions: &[DecisionSummary],
|
|
486
|
+
learnings: &mut Vec<String>,
|
|
487
|
+
) -> String {
|
|
488
|
+
let decisions_to_show: Vec<_> = decisions.iter().take(self.config.max_decisions).collect();
|
|
489
|
+
|
|
490
|
+
let mut lines: Vec<String> = vec!["Key Decisions:".to_string()];
|
|
491
|
+
|
|
492
|
+
for decision in decisions_to_show {
|
|
493
|
+
lines.push(format!(
|
|
494
|
+
" • {} (confidence: {:.0}%)",
|
|
495
|
+
self.truncate(&decision.decision, 80),
|
|
496
|
+
decision.confidence * 100.0
|
|
497
|
+
));
|
|
498
|
+
|
|
499
|
+
learnings.push(format!(
|
|
500
|
+
"Decision: {} - Rationale: {}",
|
|
501
|
+
self.truncate(&decision.decision, 50),
|
|
502
|
+
self.truncate(&decision.rationale, 50)
|
|
503
|
+
));
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
lines.join("\n")
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// Estimate original token count from trace
|
|
510
|
+
fn estimate_original_tokens(&self, trace: &ExecutionTrace) -> usize {
|
|
511
|
+
let mut estimate = 0;
|
|
512
|
+
|
|
513
|
+
// Estimate from steps
|
|
514
|
+
for step in &trace.steps {
|
|
515
|
+
estimate += self.token_counter.count(&step.summary);
|
|
516
|
+
if let Some(output) = &step.key_output {
|
|
517
|
+
estimate += self.token_counter.count(output);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Estimate from decisions
|
|
522
|
+
for decision in &trace.decisions {
|
|
523
|
+
estimate += self.token_counter.count(&decision.decision);
|
|
524
|
+
estimate += self.token_counter.count(&decision.rationale);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Final output
|
|
528
|
+
if let Some(output) = &trace.final_output {
|
|
529
|
+
estimate += self.token_counter.count(output);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Error
|
|
533
|
+
if let Some(error) = &trace.error {
|
|
534
|
+
estimate += self.token_counter.count(error);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
estimate
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/// Truncate text to max length
|
|
541
|
+
fn truncate(&self, text: &str, max_len: usize) -> String {
|
|
542
|
+
if text.len() <= max_len {
|
|
543
|
+
text.to_string()
|
|
544
|
+
} else {
|
|
545
|
+
format!("{}...", &text[..max_len.saturating_sub(3)])
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/// Condense multiple traces (e.g., parallel child executions)
|
|
550
|
+
pub fn condense_multiple(&self, traces: &[ExecutionTrace]) -> CondensedResult {
|
|
551
|
+
if traces.is_empty() {
|
|
552
|
+
let empty_segment = ContextSegment::child_summary(
|
|
553
|
+
"No child executions".to_string(),
|
|
554
|
+
3,
|
|
555
|
+
next_sequence(),
|
|
556
|
+
StepId::new(),
|
|
557
|
+
).with_priority(ContextPriority::Low);
|
|
558
|
+
|
|
559
|
+
return CondensedResult {
|
|
560
|
+
execution_id: ExecutionId::new(),
|
|
561
|
+
summary: "No executions to condense".to_string(),
|
|
562
|
+
outcomes: Vec::new(),
|
|
563
|
+
learnings: Vec::new(),
|
|
564
|
+
context_segment: empty_segment,
|
|
565
|
+
token_count: 0,
|
|
566
|
+
original_tokens: 0,
|
|
567
|
+
compression_ratio: 1.0,
|
|
568
|
+
condensed_at: Utc::now(),
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if traces.len() == 1 {
|
|
573
|
+
return self.condense(&traces[0]);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Multi-trace condensation
|
|
577
|
+
let mut parts: Vec<String> = Vec::new();
|
|
578
|
+
let mut all_outcomes: Vec<String> = Vec::new();
|
|
579
|
+
let mut all_learnings: Vec<String> = Vec::new();
|
|
580
|
+
let mut total_original = 0;
|
|
581
|
+
|
|
582
|
+
parts.push(format!("Parallel Executions: {} total", traces.len()));
|
|
583
|
+
|
|
584
|
+
// Summarize each trace briefly
|
|
585
|
+
let tokens_per_trace = self.config.target_tokens / traces.len();
|
|
586
|
+
for (i, trace) in traces.iter().enumerate() {
|
|
587
|
+
let brief_config = CondenserConfig {
|
|
588
|
+
target_tokens: tokens_per_trace,
|
|
589
|
+
max_tokens: tokens_per_trace + 100,
|
|
590
|
+
include_steps: false,
|
|
591
|
+
max_steps: 3,
|
|
592
|
+
..self.config.clone()
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
let condenser = ResultCondenser::with_config(brief_config);
|
|
596
|
+
let condensed = condenser.condense(trace);
|
|
597
|
+
|
|
598
|
+
parts.push(format!(
|
|
599
|
+
"\n[{}/{}] {}",
|
|
600
|
+
i + 1,
|
|
601
|
+
traces.len(),
|
|
602
|
+
condensed.summary
|
|
603
|
+
));
|
|
604
|
+
all_outcomes.extend(condensed.outcomes);
|
|
605
|
+
all_learnings.extend(condensed.learnings);
|
|
606
|
+
total_original += condensed.original_tokens;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
let summary = parts.join("\n");
|
|
610
|
+
let token_count = self.token_counter.count(&summary);
|
|
611
|
+
|
|
612
|
+
let segment_content = format!("[Parallel Executions]\n{}", summary);
|
|
613
|
+
let segment_tokens = self.token_counter.count(&segment_content);
|
|
614
|
+
let context_segment = ContextSegment::child_summary(
|
|
615
|
+
segment_content,
|
|
616
|
+
segment_tokens,
|
|
617
|
+
next_sequence(),
|
|
618
|
+
traces[0].parent_step_id.clone().unwrap_or_else(StepId::new),
|
|
619
|
+
).with_priority(ContextPriority::Medium);
|
|
620
|
+
|
|
621
|
+
CondensedResult {
|
|
622
|
+
execution_id: traces[0].execution_id.clone(),
|
|
623
|
+
summary,
|
|
624
|
+
outcomes: all_outcomes,
|
|
625
|
+
learnings: all_learnings,
|
|
626
|
+
context_segment,
|
|
627
|
+
token_count,
|
|
628
|
+
original_tokens: total_original,
|
|
629
|
+
compression_ratio: if total_original > 0 {
|
|
630
|
+
token_count as f64 / total_original as f64
|
|
631
|
+
} else {
|
|
632
|
+
1.0
|
|
633
|
+
},
|
|
634
|
+
condensed_at: Utc::now(),
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
impl Default for ResultCondenser {
|
|
640
|
+
fn default() -> Self {
|
|
641
|
+
Self::new()
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
#[cfg(test)]
|
|
646
|
+
mod tests {
|
|
647
|
+
use super::*;
|
|
648
|
+
|
|
649
|
+
fn test_execution_id() -> ExecutionId {
|
|
650
|
+
ExecutionId::new()
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
fn test_step_id() -> StepId {
|
|
654
|
+
StepId::new()
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
#[test]
|
|
658
|
+
fn test_condenser_config_defaults() {
|
|
659
|
+
let config = CondenserConfig::default();
|
|
660
|
+
assert_eq!(config.target_tokens, 1500);
|
|
661
|
+
assert!(config.include_steps);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
#[test]
|
|
665
|
+
fn test_condense_simple_trace() {
|
|
666
|
+
let condenser = ResultCondenser::new();
|
|
667
|
+
let trace = ExecutionTrace::new(test_execution_id())
|
|
668
|
+
.complete("Task completed successfully");
|
|
669
|
+
|
|
670
|
+
let result = condenser.condense(&trace);
|
|
671
|
+
|
|
672
|
+
assert!(result.summary.contains("COMPLETED"));
|
|
673
|
+
assert!(result.token_count > 0);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
#[test]
|
|
677
|
+
fn test_condense_with_steps() {
|
|
678
|
+
let condenser = ResultCondenser::new();
|
|
679
|
+
let trace = ExecutionTrace::new(test_execution_id())
|
|
680
|
+
.add_step(StepSummary {
|
|
681
|
+
step_id: test_step_id(),
|
|
682
|
+
step_type: "llm_call".to_string(),
|
|
683
|
+
summary: "Generated response".to_string(),
|
|
684
|
+
success: true,
|
|
685
|
+
duration_ms: Some(500),
|
|
686
|
+
key_output: Some("Response text".to_string()),
|
|
687
|
+
})
|
|
688
|
+
.add_step(StepSummary {
|
|
689
|
+
step_id: test_step_id(),
|
|
690
|
+
step_type: "tool_call".to_string(),
|
|
691
|
+
summary: "Called search API".to_string(),
|
|
692
|
+
success: true,
|
|
693
|
+
duration_ms: Some(200),
|
|
694
|
+
key_output: None,
|
|
695
|
+
})
|
|
696
|
+
.complete("Done");
|
|
697
|
+
|
|
698
|
+
let result = condenser.condense(&trace);
|
|
699
|
+
|
|
700
|
+
assert!(result.summary.contains("Steps"));
|
|
701
|
+
assert!(result.summary.contains("llm_call"));
|
|
702
|
+
assert!(result.summary.contains("tool_call"));
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
#[test]
|
|
706
|
+
fn test_condense_failed_trace() {
|
|
707
|
+
let condenser = ResultCondenser::new();
|
|
708
|
+
let trace = ExecutionTrace::new(test_execution_id())
|
|
709
|
+
.fail("Connection timeout after 30 seconds");
|
|
710
|
+
|
|
711
|
+
let result = condenser.condense(&trace);
|
|
712
|
+
|
|
713
|
+
assert!(result.summary.contains("FAILED"));
|
|
714
|
+
assert!(result.summary.contains("timeout"));
|
|
715
|
+
assert!(!result.learnings.is_empty());
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
#[test]
|
|
719
|
+
fn test_condense_with_decisions() {
|
|
720
|
+
let condenser = ResultCondenser::new();
|
|
721
|
+
let trace = ExecutionTrace::new(test_execution_id())
|
|
722
|
+
.add_decision(DecisionSummary {
|
|
723
|
+
decision: "Use caching strategy".to_string(),
|
|
724
|
+
rationale: "Reduce API calls".to_string(),
|
|
725
|
+
confidence: 0.85,
|
|
726
|
+
step_id: test_step_id(),
|
|
727
|
+
})
|
|
728
|
+
.complete("Done");
|
|
729
|
+
|
|
730
|
+
let result = condenser.condense(&trace);
|
|
731
|
+
|
|
732
|
+
assert!(result.summary.contains("Key Decisions"));
|
|
733
|
+
assert!(result.summary.contains("caching"));
|
|
734
|
+
assert!(!result.learnings.is_empty());
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
#[test]
|
|
738
|
+
fn test_condense_respects_token_limit() {
|
|
739
|
+
let config = CondenserConfig {
|
|
740
|
+
max_tokens: 100,
|
|
741
|
+
target_tokens: 50,
|
|
742
|
+
..Default::default()
|
|
743
|
+
};
|
|
744
|
+
let condenser = ResultCondenser::with_config(config);
|
|
745
|
+
|
|
746
|
+
// Create trace with lots of content
|
|
747
|
+
let mut trace = ExecutionTrace::new(test_execution_id());
|
|
748
|
+
for i in 0..20 {
|
|
749
|
+
trace = trace.add_step(StepSummary {
|
|
750
|
+
step_id: test_step_id(),
|
|
751
|
+
step_type: format!("step_{}", i),
|
|
752
|
+
summary: format!("This is a detailed summary of step {} with lots of information", i),
|
|
753
|
+
success: true,
|
|
754
|
+
duration_ms: Some(100),
|
|
755
|
+
key_output: Some(format!("Output from step {}", i)),
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
trace = trace.complete("Final result with lots of detail");
|
|
759
|
+
|
|
760
|
+
let result = condenser.condense(&trace);
|
|
761
|
+
|
|
762
|
+
assert!(result.token_count <= 150); // Some tolerance
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
#[test]
|
|
766
|
+
fn test_condense_multiple_traces() {
|
|
767
|
+
let condenser = ResultCondenser::new();
|
|
768
|
+
let traces = vec![
|
|
769
|
+
ExecutionTrace::new(test_execution_id()).complete("Result 1"),
|
|
770
|
+
ExecutionTrace::new(test_execution_id()).complete("Result 2"),
|
|
771
|
+
ExecutionTrace::new(test_execution_id()).fail("Error in trace 3"),
|
|
772
|
+
];
|
|
773
|
+
|
|
774
|
+
let result = condenser.condense_multiple(&traces);
|
|
775
|
+
|
|
776
|
+
assert!(result.summary.contains("Parallel Executions: 3"));
|
|
777
|
+
assert!(result.summary.contains("COMPLETED"));
|
|
778
|
+
assert!(result.summary.contains("FAILED"));
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
#[test]
|
|
782
|
+
fn test_compression_ratio() {
|
|
783
|
+
let condenser = ResultCondenser::new();
|
|
784
|
+
let mut trace = ExecutionTrace::new(test_execution_id());
|
|
785
|
+
|
|
786
|
+
// Add substantial content with long outputs
|
|
787
|
+
for i in 0..10 {
|
|
788
|
+
trace = trace.add_step(StepSummary {
|
|
789
|
+
step_id: test_step_id(),
|
|
790
|
+
step_type: "step".to_string(),
|
|
791
|
+
summary: format!("Detailed summary for step {} with additional context and more information to ensure we have enough content", i),
|
|
792
|
+
success: true,
|
|
793
|
+
duration_ms: Some(100),
|
|
794
|
+
key_output: Some(format!("Long output content for step {} that adds more tokens and even more details to increase the token count significantly beyond what will be included in the final summary. This should definitely be truncated.", i)),
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
trace = trace.complete("Comprehensive final output with all the details and extra information that extends the content significantly.");
|
|
798
|
+
|
|
799
|
+
let result = condenser.condense(&trace);
|
|
800
|
+
|
|
801
|
+
// Verify condensation happened (original should be larger due to key_output not being included)
|
|
802
|
+
assert!(result.original_tokens > 0);
|
|
803
|
+
assert!(result.token_count > 0);
|
|
804
|
+
// The condenser limits steps and truncates content, so we should see some compression
|
|
805
|
+
// Note: compression_ratio = token_count / original_tokens
|
|
806
|
+
// Due to formatting overhead, ratio might be close to 1.0 but original should still be larger
|
|
807
|
+
assert!(result.original_tokens >= result.token_count / 2,
|
|
808
|
+
"Original tokens ({}) should be at least half of final tokens ({})",
|
|
809
|
+
result.original_tokens, result.token_count);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
#[test]
|
|
813
|
+
fn test_context_segment_priority() {
|
|
814
|
+
let condenser = ResultCondenser::new();
|
|
815
|
+
|
|
816
|
+
// Successful execution should have medium priority
|
|
817
|
+
let success_trace = ExecutionTrace::new(test_execution_id()).complete("Done");
|
|
818
|
+
let success_result = condenser.condense(&success_trace);
|
|
819
|
+
assert_eq!(success_result.context_segment.priority, ContextPriority::Medium);
|
|
820
|
+
|
|
821
|
+
// Failed execution should have high priority
|
|
822
|
+
let fail_trace = ExecutionTrace::new(test_execution_id()).fail("Error");
|
|
823
|
+
let fail_result = condenser.condense(&fail_trace);
|
|
824
|
+
assert_eq!(fail_result.context_segment.priority, ContextPriority::High);
|
|
825
|
+
}
|
|
826
|
+
}
|