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,757 @@
|
|
|
1
|
+
//! Runtime Context - The spine of the enact-core runtime
|
|
2
|
+
//!
|
|
3
|
+
//! RuntimeContext carries all necessary context for execution, tracing,
|
|
4
|
+
//! and observability. It is created per Execution and inherited by child
|
|
5
|
+
//! executions (sub-agents) with appropriate field updates.
|
|
6
|
+
//!
|
|
7
|
+
//! ## Key Requirement: TenantContext is REQUIRED
|
|
8
|
+
//!
|
|
9
|
+
//! Every RuntimeContext must have a valid TenantContext. This ensures:
|
|
10
|
+
//! - Multi-tenant isolation
|
|
11
|
+
//! - Resource limit enforcement
|
|
12
|
+
//! - Audit compliance
|
|
13
|
+
//! - Billing attribution
|
|
14
|
+
//!
|
|
15
|
+
//! @see docs/TECHNICAL/01-EXECUTION-TELEMETRY.md
|
|
16
|
+
|
|
17
|
+
use crate::kernel::{CancellationPolicy, ExecutionId, ParentLink, ParentType, SpawnMode, StepId};
|
|
18
|
+
use super::tenant::TenantContext;
|
|
19
|
+
use super::trace::TraceContext;
|
|
20
|
+
use serde::{Deserialize, Serialize};
|
|
21
|
+
use std::collections::HashMap;
|
|
22
|
+
|
|
23
|
+
/// Session context for user-initiated flows
|
|
24
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
25
|
+
pub struct SessionContext {
|
|
26
|
+
/// Session ID
|
|
27
|
+
pub session_id: String,
|
|
28
|
+
/// Created timestamp
|
|
29
|
+
pub created_at: chrono::DateTime<chrono::Utc>,
|
|
30
|
+
/// Last active timestamp
|
|
31
|
+
pub last_active_at: Option<chrono::DateTime<chrono::Utc>>,
|
|
32
|
+
/// Session metadata
|
|
33
|
+
pub metadata: HashMap<String, serde_json::Value>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl SessionContext {
|
|
37
|
+
/// Create a new SessionContext
|
|
38
|
+
pub fn new(session_id: impl Into<String>) -> Self {
|
|
39
|
+
Self {
|
|
40
|
+
session_id: session_id.into(),
|
|
41
|
+
created_at: chrono::Utc::now(),
|
|
42
|
+
last_active_at: None,
|
|
43
|
+
metadata: HashMap::new(),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Touch the session (update last_active_at)
|
|
48
|
+
pub fn touch(&mut self) {
|
|
49
|
+
self.last_active_at = Some(chrono::Utc::now());
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// RuntimeContext - The context passed through all execution
|
|
54
|
+
///
|
|
55
|
+
/// Created per Execution, inherited by child executions (sub-agents)
|
|
56
|
+
/// with appropriate field updates.
|
|
57
|
+
///
|
|
58
|
+
/// ## Usage
|
|
59
|
+
/// ```ignore
|
|
60
|
+
/// let tenant = TenantContext::new(TenantId::from("tenant_acme"))
|
|
61
|
+
/// .with_user(UserId::from("usr_alice"));
|
|
62
|
+
///
|
|
63
|
+
/// let ctx = RuntimeContext::new(
|
|
64
|
+
/// ExecutionId::new(),
|
|
65
|
+
/// ParentLink::from_user_message("msg_123"),
|
|
66
|
+
/// tenant,
|
|
67
|
+
/// );
|
|
68
|
+
///
|
|
69
|
+
/// // For sub-agent invocation:
|
|
70
|
+
/// let child_ctx = ctx.child_context(ExecutionId::new(), &step_id);
|
|
71
|
+
/// ```
|
|
72
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
73
|
+
pub struct RuntimeContext {
|
|
74
|
+
// --- Execution Identity ---
|
|
75
|
+
/// The current execution ID
|
|
76
|
+
pub execution_id: ExecutionId,
|
|
77
|
+
/// Current step ID (if within a step)
|
|
78
|
+
pub step_id: Option<StepId>,
|
|
79
|
+
|
|
80
|
+
// --- Parent Linkage ---
|
|
81
|
+
/// What triggered this execution
|
|
82
|
+
pub parent: ParentLink,
|
|
83
|
+
|
|
84
|
+
// --- Tenant Context (REQUIRED) ---
|
|
85
|
+
/// Tenant context for multi-tenant isolation
|
|
86
|
+
pub tenant: TenantContext,
|
|
87
|
+
|
|
88
|
+
// --- Trace Context ---
|
|
89
|
+
/// OpenTelemetry trace context
|
|
90
|
+
pub trace: TraceContext,
|
|
91
|
+
|
|
92
|
+
// --- Session ---
|
|
93
|
+
/// Session context (for user-initiated flows)
|
|
94
|
+
pub session: Option<SessionContext>,
|
|
95
|
+
|
|
96
|
+
// --- Timestamps ---
|
|
97
|
+
/// When this context was created
|
|
98
|
+
pub created_at: chrono::DateTime<chrono::Utc>,
|
|
99
|
+
|
|
100
|
+
// --- SpawnMode (Execution Isolation Control) ---
|
|
101
|
+
/// How this context was spawned (for inbox routing decisions)
|
|
102
|
+
/// @see docs/TECHNICAL/32-SPAWN-MODE.md
|
|
103
|
+
pub spawn_mode: Option<SpawnMode>,
|
|
104
|
+
|
|
105
|
+
/// Cancellation policy for child executions spawned from this context
|
|
106
|
+
pub cancellation_policy: CancellationPolicy,
|
|
107
|
+
|
|
108
|
+
/// Parent execution ID (for Child spawn mode inbox routing)
|
|
109
|
+
pub parent_execution_id: Option<ExecutionId>,
|
|
110
|
+
|
|
111
|
+
// --- Metadata ---
|
|
112
|
+
/// Extensible metadata
|
|
113
|
+
pub metadata: HashMap<String, serde_json::Value>,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
impl RuntimeContext {
|
|
117
|
+
/// Create a new RuntimeContext for an execution
|
|
118
|
+
///
|
|
119
|
+
/// TenantContext is REQUIRED - this ensures every execution
|
|
120
|
+
/// runs within a tenant boundary.
|
|
121
|
+
pub fn new(execution_id: ExecutionId, parent: ParentLink, tenant: TenantContext) -> Self {
|
|
122
|
+
Self {
|
|
123
|
+
execution_id,
|
|
124
|
+
step_id: None,
|
|
125
|
+
parent,
|
|
126
|
+
tenant,
|
|
127
|
+
trace: TraceContext::new(),
|
|
128
|
+
session: None,
|
|
129
|
+
created_at: chrono::Utc::now(),
|
|
130
|
+
spawn_mode: None,
|
|
131
|
+
cancellation_policy: CancellationPolicy::default(),
|
|
132
|
+
parent_execution_id: None,
|
|
133
|
+
metadata: HashMap::new(),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// Create a RuntimeContext for a user message trigger
|
|
138
|
+
pub fn from_user_message(
|
|
139
|
+
execution_id: ExecutionId,
|
|
140
|
+
message_id: impl Into<String>,
|
|
141
|
+
tenant: TenantContext,
|
|
142
|
+
) -> Self {
|
|
143
|
+
Self::new(execution_id, ParentLink::from_user_message(message_id), tenant)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// --- Builder methods ---
|
|
147
|
+
|
|
148
|
+
/// Set the current step
|
|
149
|
+
pub fn with_step(mut self, step_id: StepId) -> Self {
|
|
150
|
+
self.step_id = Some(step_id);
|
|
151
|
+
self
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// Set trace context
|
|
155
|
+
pub fn with_trace(mut self, trace: TraceContext) -> Self {
|
|
156
|
+
self.trace = trace;
|
|
157
|
+
self
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// Set session context
|
|
161
|
+
pub fn with_session(mut self, session: SessionContext) -> Self {
|
|
162
|
+
self.session = Some(session);
|
|
163
|
+
self
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Add metadata
|
|
167
|
+
pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
|
|
168
|
+
self.metadata.insert(key.into(), value);
|
|
169
|
+
self
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// Set spawn mode
|
|
173
|
+
pub fn with_spawn_mode(mut self, spawn_mode: SpawnMode) -> Self {
|
|
174
|
+
self.spawn_mode = Some(spawn_mode);
|
|
175
|
+
self
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/// Set cancellation policy
|
|
179
|
+
pub fn with_cancellation_policy(mut self, policy: CancellationPolicy) -> Self {
|
|
180
|
+
self.cancellation_policy = policy;
|
|
181
|
+
self
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// --- Child context creation ---
|
|
185
|
+
|
|
186
|
+
/// Create a child RuntimeContext for a sub-agent invocation
|
|
187
|
+
///
|
|
188
|
+
/// The child context:
|
|
189
|
+
/// - Gets a new execution ID
|
|
190
|
+
/// - Has parent pointing to the current step
|
|
191
|
+
/// - Inherits tenant context (with same user or overridden)
|
|
192
|
+
/// - Inherits trace context (new span ID)
|
|
193
|
+
///
|
|
194
|
+
/// Uses default SpawnMode::Child with no background and no inbox inheritance.
|
|
195
|
+
/// For custom SpawnMode, use `child_context_with_spawn_mode`.
|
|
196
|
+
pub fn child_context(&self, child_execution_id: ExecutionId, parent_step_id: &StepId) -> Self {
|
|
197
|
+
self.child_context_with_spawn_mode(
|
|
198
|
+
child_execution_id,
|
|
199
|
+
parent_step_id,
|
|
200
|
+
SpawnMode::child(false, false),
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/// Create a child RuntimeContext with explicit SpawnMode
|
|
205
|
+
///
|
|
206
|
+
/// @see docs/TECHNICAL/32-SPAWN-MODE.md
|
|
207
|
+
pub fn child_context_with_spawn_mode(
|
|
208
|
+
&self,
|
|
209
|
+
child_execution_id: ExecutionId,
|
|
210
|
+
parent_step_id: &StepId,
|
|
211
|
+
spawn_mode: SpawnMode,
|
|
212
|
+
) -> Self {
|
|
213
|
+
Self {
|
|
214
|
+
execution_id: child_execution_id,
|
|
215
|
+
step_id: None,
|
|
216
|
+
parent: ParentLink::from_step(parent_step_id),
|
|
217
|
+
tenant: self.tenant.child_context(None),
|
|
218
|
+
trace: self.trace.child_span(),
|
|
219
|
+
session: self.session.clone(),
|
|
220
|
+
created_at: chrono::Utc::now(),
|
|
221
|
+
spawn_mode: Some(spawn_mode),
|
|
222
|
+
cancellation_policy: CancellationPolicy::default(),
|
|
223
|
+
parent_execution_id: Some(self.execution_id.clone()),
|
|
224
|
+
metadata: HashMap::new(), // Child starts with fresh metadata
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/// Enter a step (returns new context with step_id set)
|
|
229
|
+
pub fn enter_step(&self, step_id: StepId) -> Self {
|
|
230
|
+
let mut ctx = self.clone();
|
|
231
|
+
ctx.step_id = Some(step_id);
|
|
232
|
+
ctx.trace = ctx.trace.child_span();
|
|
233
|
+
ctx
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// --- Accessors ---
|
|
237
|
+
|
|
238
|
+
/// Get the execution ID
|
|
239
|
+
pub fn execution_id(&self) -> &ExecutionId {
|
|
240
|
+
&self.execution_id
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/// Get the step ID
|
|
244
|
+
pub fn step_id(&self) -> Option<&StepId> {
|
|
245
|
+
self.step_id.as_ref()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/// Get the tenant context
|
|
249
|
+
pub fn tenant(&self) -> &TenantContext {
|
|
250
|
+
&self.tenant
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// Get the trace ID
|
|
254
|
+
pub fn trace_id(&self) -> &str {
|
|
255
|
+
&self.trace.trace_id
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/// Get the span ID
|
|
259
|
+
pub fn span_id(&self) -> &str {
|
|
260
|
+
&self.trace.span_id
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/// Check if this is a root execution (not a sub-agent)
|
|
264
|
+
pub fn is_root(&self) -> bool {
|
|
265
|
+
!matches!(self.parent.parent_type, ParentType::StepExecution)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/// Builder for creating RuntimeContext with fluent API
|
|
270
|
+
pub struct RuntimeContextBuilder {
|
|
271
|
+
execution_id: ExecutionId,
|
|
272
|
+
parent: ParentLink,
|
|
273
|
+
tenant: TenantContext,
|
|
274
|
+
trace: TraceContext,
|
|
275
|
+
session: Option<SessionContext>,
|
|
276
|
+
spawn_mode: Option<SpawnMode>,
|
|
277
|
+
cancellation_policy: CancellationPolicy,
|
|
278
|
+
parent_execution_id: Option<ExecutionId>,
|
|
279
|
+
metadata: HashMap<String, serde_json::Value>,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
impl RuntimeContextBuilder {
|
|
283
|
+
/// Start building a new RuntimeContext
|
|
284
|
+
///
|
|
285
|
+
/// TenantContext is REQUIRED.
|
|
286
|
+
pub fn new(execution_id: ExecutionId, parent: ParentLink, tenant: TenantContext) -> Self {
|
|
287
|
+
Self {
|
|
288
|
+
execution_id,
|
|
289
|
+
parent,
|
|
290
|
+
tenant,
|
|
291
|
+
trace: TraceContext::new(),
|
|
292
|
+
session: None,
|
|
293
|
+
spawn_mode: None,
|
|
294
|
+
cancellation_policy: CancellationPolicy::default(),
|
|
295
|
+
parent_execution_id: None,
|
|
296
|
+
metadata: HashMap::new(),
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// Set trace context
|
|
301
|
+
pub fn trace(mut self, trace: TraceContext) -> Self {
|
|
302
|
+
self.trace = trace;
|
|
303
|
+
self
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// Set session
|
|
307
|
+
pub fn session(mut self, session: SessionContext) -> Self {
|
|
308
|
+
self.session = Some(session);
|
|
309
|
+
self
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/// Add metadata
|
|
313
|
+
pub fn metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
|
|
314
|
+
self.metadata.insert(key.into(), value);
|
|
315
|
+
self
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/// Set spawn mode
|
|
319
|
+
pub fn spawn_mode(mut self, spawn_mode: SpawnMode) -> Self {
|
|
320
|
+
self.spawn_mode = Some(spawn_mode);
|
|
321
|
+
self
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/// Set cancellation policy
|
|
325
|
+
pub fn cancellation_policy(mut self, policy: CancellationPolicy) -> Self {
|
|
326
|
+
self.cancellation_policy = policy;
|
|
327
|
+
self
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/// Set parent execution ID
|
|
331
|
+
pub fn parent_execution_id(mut self, parent_exec_id: ExecutionId) -> Self {
|
|
332
|
+
self.parent_execution_id = Some(parent_exec_id);
|
|
333
|
+
self
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/// Build the RuntimeContext
|
|
337
|
+
pub fn build(self) -> RuntimeContext {
|
|
338
|
+
RuntimeContext {
|
|
339
|
+
execution_id: self.execution_id,
|
|
340
|
+
step_id: None,
|
|
341
|
+
parent: self.parent,
|
|
342
|
+
tenant: self.tenant,
|
|
343
|
+
trace: self.trace,
|
|
344
|
+
session: self.session,
|
|
345
|
+
created_at: chrono::Utc::now(),
|
|
346
|
+
spawn_mode: self.spawn_mode,
|
|
347
|
+
cancellation_policy: self.cancellation_policy,
|
|
348
|
+
parent_execution_id: self.parent_execution_id,
|
|
349
|
+
metadata: self.metadata,
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
#[cfg(test)]
|
|
355
|
+
mod tests {
|
|
356
|
+
use super::*;
|
|
357
|
+
use crate::kernel::{TenantId, UserId};
|
|
358
|
+
|
|
359
|
+
// =========================================================================
|
|
360
|
+
// SessionContext Tests
|
|
361
|
+
// =========================================================================
|
|
362
|
+
|
|
363
|
+
#[test]
|
|
364
|
+
fn test_session_context_new() {
|
|
365
|
+
let session = SessionContext::new("sess_123");
|
|
366
|
+
assert_eq!(session.session_id, "sess_123");
|
|
367
|
+
assert!(session.last_active_at.is_none());
|
|
368
|
+
assert!(session.metadata.is_empty());
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
#[test]
|
|
372
|
+
fn test_session_context_new_owned_string() {
|
|
373
|
+
let session = SessionContext::new(String::from("sess_owned"));
|
|
374
|
+
assert_eq!(session.session_id, "sess_owned");
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
#[test]
|
|
378
|
+
fn test_session_context_touch() {
|
|
379
|
+
let mut session = SessionContext::new("sess_touch");
|
|
380
|
+
assert!(session.last_active_at.is_none());
|
|
381
|
+
|
|
382
|
+
session.touch();
|
|
383
|
+
assert!(session.last_active_at.is_some());
|
|
384
|
+
|
|
385
|
+
let first_touch = session.last_active_at.unwrap();
|
|
386
|
+
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
387
|
+
session.touch();
|
|
388
|
+
|
|
389
|
+
assert!(session.last_active_at.unwrap() >= first_touch);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
#[test]
|
|
393
|
+
fn test_session_context_metadata() {
|
|
394
|
+
let mut session = SessionContext::new("sess_meta");
|
|
395
|
+
session.metadata.insert("key".to_string(), serde_json::json!("value"));
|
|
396
|
+
|
|
397
|
+
assert_eq!(session.metadata.get("key"), Some(&serde_json::json!("value")));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
#[test]
|
|
401
|
+
fn test_session_context_serde() {
|
|
402
|
+
let session = SessionContext::new("sess_serde");
|
|
403
|
+
let json = serde_json::to_string(&session).unwrap();
|
|
404
|
+
let parsed: SessionContext = serde_json::from_str(&json).unwrap();
|
|
405
|
+
assert_eq!(session.session_id, parsed.session_id);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// =========================================================================
|
|
409
|
+
// RuntimeContext Tests
|
|
410
|
+
// =========================================================================
|
|
411
|
+
|
|
412
|
+
fn create_test_tenant() -> TenantContext {
|
|
413
|
+
TenantContext::new(TenantId::from_string("tenant_test"))
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
#[test]
|
|
417
|
+
fn test_runtime_context_new() {
|
|
418
|
+
let exec_id = ExecutionId::from_string("exec_test");
|
|
419
|
+
let parent = ParentLink::from_user_message("msg_123");
|
|
420
|
+
let tenant = create_test_tenant();
|
|
421
|
+
|
|
422
|
+
let ctx = RuntimeContext::new(exec_id.clone(), parent, tenant);
|
|
423
|
+
|
|
424
|
+
assert_eq!(ctx.execution_id.as_str(), "exec_test");
|
|
425
|
+
assert!(ctx.step_id.is_none());
|
|
426
|
+
assert!(ctx.session.is_none());
|
|
427
|
+
assert!(ctx.metadata.is_empty());
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
#[test]
|
|
431
|
+
fn test_runtime_context_from_user_message() {
|
|
432
|
+
let exec_id = ExecutionId::from_string("exec_msg");
|
|
433
|
+
let tenant = create_test_tenant();
|
|
434
|
+
|
|
435
|
+
let ctx = RuntimeContext::from_user_message(exec_id, "msg_456", tenant);
|
|
436
|
+
|
|
437
|
+
assert_eq!(ctx.parent.parent_type, ParentType::UserMessage);
|
|
438
|
+
assert_eq!(ctx.parent.parent_id, "msg_456");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#[test]
|
|
442
|
+
fn test_runtime_context_with_step() {
|
|
443
|
+
let exec_id = ExecutionId::from_string("exec_step");
|
|
444
|
+
let parent = ParentLink::system();
|
|
445
|
+
let tenant = create_test_tenant();
|
|
446
|
+
let step_id = StepId::from_string("step_ctx");
|
|
447
|
+
|
|
448
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
449
|
+
.with_step(step_id.clone());
|
|
450
|
+
|
|
451
|
+
assert!(ctx.step_id.is_some());
|
|
452
|
+
assert_eq!(ctx.step_id.unwrap().as_str(), "step_ctx");
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
#[test]
|
|
456
|
+
fn test_runtime_context_with_trace() {
|
|
457
|
+
let exec_id = ExecutionId::from_string("exec_trace");
|
|
458
|
+
let parent = ParentLink::system();
|
|
459
|
+
let tenant = create_test_tenant();
|
|
460
|
+
let trace = TraceContext::from_traceparent("00-0123456789abcdef0123456789abcdef-0123456789abcdef-01").unwrap();
|
|
461
|
+
|
|
462
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
463
|
+
.with_trace(trace);
|
|
464
|
+
|
|
465
|
+
assert_eq!(ctx.trace_id(), "0123456789abcdef0123456789abcdef");
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
#[test]
|
|
469
|
+
fn test_runtime_context_with_session() {
|
|
470
|
+
let exec_id = ExecutionId::from_string("exec_sess");
|
|
471
|
+
let parent = ParentLink::system();
|
|
472
|
+
let tenant = create_test_tenant();
|
|
473
|
+
let session = SessionContext::new("sess_runtime");
|
|
474
|
+
|
|
475
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
476
|
+
.with_session(session);
|
|
477
|
+
|
|
478
|
+
assert!(ctx.session.is_some());
|
|
479
|
+
assert_eq!(ctx.session.unwrap().session_id, "sess_runtime");
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
#[test]
|
|
483
|
+
fn test_runtime_context_with_metadata() {
|
|
484
|
+
let exec_id = ExecutionId::from_string("exec_meta");
|
|
485
|
+
let parent = ParentLink::system();
|
|
486
|
+
let tenant = create_test_tenant();
|
|
487
|
+
|
|
488
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
489
|
+
.with_metadata("key1", serde_json::json!("value1"))
|
|
490
|
+
.with_metadata("key2", serde_json::json!(42));
|
|
491
|
+
|
|
492
|
+
assert_eq!(ctx.metadata.len(), 2);
|
|
493
|
+
assert_eq!(ctx.metadata.get("key1"), Some(&serde_json::json!("value1")));
|
|
494
|
+
assert_eq!(ctx.metadata.get("key2"), Some(&serde_json::json!(42)));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
#[test]
|
|
498
|
+
fn test_runtime_context_child_context() {
|
|
499
|
+
let exec_id = ExecutionId::from_string("exec_parent");
|
|
500
|
+
let parent = ParentLink::from_user_message("msg_parent");
|
|
501
|
+
let tenant = TenantContext::new(TenantId::from_string("tenant_parent"))
|
|
502
|
+
.with_user(UserId::from_string("user_parent"));
|
|
503
|
+
|
|
504
|
+
let parent_ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
505
|
+
.with_session(SessionContext::new("sess_inherit"))
|
|
506
|
+
.with_metadata("parent_key", serde_json::json!("should_not_inherit"));
|
|
507
|
+
|
|
508
|
+
let child_exec_id = ExecutionId::from_string("exec_child");
|
|
509
|
+
let parent_step_id = StepId::from_string("step_that_spawned");
|
|
510
|
+
let child_ctx = parent_ctx.child_context(child_exec_id.clone(), &parent_step_id);
|
|
511
|
+
|
|
512
|
+
// Child should have new execution ID
|
|
513
|
+
assert_eq!(child_ctx.execution_id.as_str(), "exec_child");
|
|
514
|
+
|
|
515
|
+
// Child should have parent pointing to the step
|
|
516
|
+
assert_eq!(child_ctx.parent.parent_type, ParentType::StepExecution);
|
|
517
|
+
assert_eq!(child_ctx.parent.parent_id, "step_that_spawned");
|
|
518
|
+
|
|
519
|
+
// Child inherits tenant
|
|
520
|
+
assert_eq!(child_ctx.tenant.tenant_id().as_str(), "tenant_parent");
|
|
521
|
+
|
|
522
|
+
// Child inherits session
|
|
523
|
+
assert!(child_ctx.session.is_some());
|
|
524
|
+
assert_eq!(child_ctx.session.unwrap().session_id, "sess_inherit");
|
|
525
|
+
|
|
526
|
+
// Child has same trace ID but different span
|
|
527
|
+
assert_eq!(child_ctx.trace.trace_id, parent_ctx.trace.trace_id);
|
|
528
|
+
assert_ne!(child_ctx.trace.span_id, parent_ctx.trace.span_id);
|
|
529
|
+
|
|
530
|
+
// Child has fresh metadata
|
|
531
|
+
assert!(child_ctx.metadata.is_empty());
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
#[test]
|
|
535
|
+
fn test_runtime_context_enter_step() {
|
|
536
|
+
let exec_id = ExecutionId::from_string("exec_enter");
|
|
537
|
+
let parent = ParentLink::system();
|
|
538
|
+
let tenant = create_test_tenant();
|
|
539
|
+
let original_ctx = RuntimeContext::new(exec_id, parent, tenant);
|
|
540
|
+
|
|
541
|
+
let step_id = StepId::from_string("step_enter");
|
|
542
|
+
let step_ctx = original_ctx.enter_step(step_id.clone());
|
|
543
|
+
|
|
544
|
+
// Step context should have the step ID set
|
|
545
|
+
assert!(step_ctx.step_id.is_some());
|
|
546
|
+
assert_eq!(step_ctx.step_id.unwrap().as_str(), "step_enter");
|
|
547
|
+
|
|
548
|
+
// Same trace ID but different span
|
|
549
|
+
assert_eq!(step_ctx.trace.trace_id, original_ctx.trace.trace_id);
|
|
550
|
+
assert_ne!(step_ctx.trace.span_id, original_ctx.trace.span_id);
|
|
551
|
+
|
|
552
|
+
// Original context unchanged
|
|
553
|
+
assert!(original_ctx.step_id.is_none());
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
#[test]
|
|
557
|
+
fn test_runtime_context_accessors() {
|
|
558
|
+
let exec_id = ExecutionId::from_string("exec_access");
|
|
559
|
+
let step_id = StepId::from_string("step_access");
|
|
560
|
+
let parent = ParentLink::system();
|
|
561
|
+
let tenant = TenantContext::new(TenantId::from_string("tenant_access"))
|
|
562
|
+
.with_user(UserId::from_string("user_access"));
|
|
563
|
+
|
|
564
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant)
|
|
565
|
+
.with_step(step_id);
|
|
566
|
+
|
|
567
|
+
assert_eq!(ctx.execution_id().as_str(), "exec_access");
|
|
568
|
+
assert_eq!(ctx.step_id().unwrap().as_str(), "step_access");
|
|
569
|
+
assert_eq!(ctx.tenant().tenant_id().as_str(), "tenant_access");
|
|
570
|
+
assert!(!ctx.trace_id().is_empty());
|
|
571
|
+
assert!(!ctx.span_id().is_empty());
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
#[test]
|
|
575
|
+
fn test_runtime_context_is_root_user_message() {
|
|
576
|
+
let exec_id = ExecutionId::from_string("exec_root");
|
|
577
|
+
let parent = ParentLink::from_user_message("msg_root");
|
|
578
|
+
let tenant = create_test_tenant();
|
|
579
|
+
|
|
580
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant);
|
|
581
|
+
assert!(ctx.is_root());
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
#[test]
|
|
585
|
+
fn test_runtime_context_is_root_system() {
|
|
586
|
+
let exec_id = ExecutionId::from_string("exec_root");
|
|
587
|
+
let parent = ParentLink::system();
|
|
588
|
+
let tenant = create_test_tenant();
|
|
589
|
+
|
|
590
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant);
|
|
591
|
+
assert!(ctx.is_root());
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
#[test]
|
|
595
|
+
fn test_runtime_context_is_not_root_step_execution() {
|
|
596
|
+
let exec_id = ExecutionId::from_string("exec_child");
|
|
597
|
+
let parent_step = StepId::from_string("step_parent");
|
|
598
|
+
let parent = ParentLink::from_step(&parent_step);
|
|
599
|
+
let tenant = create_test_tenant();
|
|
600
|
+
|
|
601
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant);
|
|
602
|
+
assert!(!ctx.is_root());
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
#[test]
|
|
606
|
+
fn test_runtime_context_serde() {
|
|
607
|
+
let exec_id = ExecutionId::from_string("exec_serde");
|
|
608
|
+
let parent = ParentLink::system();
|
|
609
|
+
let tenant = create_test_tenant();
|
|
610
|
+
|
|
611
|
+
let ctx = RuntimeContext::new(exec_id, parent, tenant);
|
|
612
|
+
let json = serde_json::to_string(&ctx).unwrap();
|
|
613
|
+
let parsed: RuntimeContext = serde_json::from_str(&json).unwrap();
|
|
614
|
+
|
|
615
|
+
assert_eq!(ctx.execution_id.as_str(), parsed.execution_id.as_str());
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// =========================================================================
|
|
619
|
+
// RuntimeContextBuilder Tests
|
|
620
|
+
// =========================================================================
|
|
621
|
+
|
|
622
|
+
#[test]
|
|
623
|
+
fn test_builder_new() {
|
|
624
|
+
let exec_id = ExecutionId::from_string("exec_builder");
|
|
625
|
+
let parent = ParentLink::system();
|
|
626
|
+
let tenant = create_test_tenant();
|
|
627
|
+
|
|
628
|
+
let builder = RuntimeContextBuilder::new(exec_id.clone(), parent, tenant);
|
|
629
|
+
let ctx = builder.build();
|
|
630
|
+
|
|
631
|
+
assert_eq!(ctx.execution_id.as_str(), "exec_builder");
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
#[test]
|
|
635
|
+
fn test_builder_with_trace() {
|
|
636
|
+
let exec_id = ExecutionId::from_string("exec_builder_trace");
|
|
637
|
+
let parent = ParentLink::system();
|
|
638
|
+
let tenant = create_test_tenant();
|
|
639
|
+
let trace = TraceContext::from_traceparent("00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1-bbbbbbbbbbbbbb11-01").unwrap();
|
|
640
|
+
|
|
641
|
+
let ctx = RuntimeContextBuilder::new(exec_id, parent, tenant)
|
|
642
|
+
.trace(trace)
|
|
643
|
+
.build();
|
|
644
|
+
|
|
645
|
+
assert_eq!(ctx.trace.trace_id, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1");
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
#[test]
|
|
649
|
+
fn test_builder_with_session() {
|
|
650
|
+
let exec_id = ExecutionId::from_string("exec_builder_sess");
|
|
651
|
+
let parent = ParentLink::system();
|
|
652
|
+
let tenant = create_test_tenant();
|
|
653
|
+
let session = SessionContext::new("sess_builder");
|
|
654
|
+
|
|
655
|
+
let ctx = RuntimeContextBuilder::new(exec_id, parent, tenant)
|
|
656
|
+
.session(session)
|
|
657
|
+
.build();
|
|
658
|
+
|
|
659
|
+
assert!(ctx.session.is_some());
|
|
660
|
+
assert_eq!(ctx.session.unwrap().session_id, "sess_builder");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
#[test]
|
|
664
|
+
fn test_builder_with_metadata() {
|
|
665
|
+
let exec_id = ExecutionId::from_string("exec_builder_meta");
|
|
666
|
+
let parent = ParentLink::system();
|
|
667
|
+
let tenant = create_test_tenant();
|
|
668
|
+
|
|
669
|
+
let ctx = RuntimeContextBuilder::new(exec_id, parent, tenant)
|
|
670
|
+
.metadata("build_key", serde_json::json!("build_value"))
|
|
671
|
+
.build();
|
|
672
|
+
|
|
673
|
+
assert_eq!(ctx.metadata.get("build_key"), Some(&serde_json::json!("build_value")));
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
#[test]
|
|
677
|
+
fn test_builder_full_chain() {
|
|
678
|
+
let exec_id = ExecutionId::from_string("exec_full");
|
|
679
|
+
let parent = ParentLink::from_user_message("msg_full");
|
|
680
|
+
let tenant = TenantContext::new(TenantId::from_string("tenant_full"))
|
|
681
|
+
.with_user(UserId::from_string("user_full"));
|
|
682
|
+
let session = SessionContext::new("sess_full");
|
|
683
|
+
let trace = TraceContext::new();
|
|
684
|
+
|
|
685
|
+
let ctx = RuntimeContextBuilder::new(exec_id, parent, tenant)
|
|
686
|
+
.trace(trace.clone())
|
|
687
|
+
.session(session)
|
|
688
|
+
.metadata("key1", serde_json::json!(1))
|
|
689
|
+
.metadata("key2", serde_json::json!(2))
|
|
690
|
+
.build();
|
|
691
|
+
|
|
692
|
+
assert_eq!(ctx.execution_id.as_str(), "exec_full");
|
|
693
|
+
assert_eq!(ctx.parent.parent_id, "msg_full");
|
|
694
|
+
assert_eq!(ctx.tenant.tenant_id().as_str(), "tenant_full");
|
|
695
|
+
assert!(ctx.session.is_some());
|
|
696
|
+
assert_eq!(ctx.metadata.len(), 2);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// =========================================================================
|
|
700
|
+
// Integration Tests
|
|
701
|
+
// =========================================================================
|
|
702
|
+
|
|
703
|
+
#[test]
|
|
704
|
+
fn test_nested_execution_hierarchy() {
|
|
705
|
+
// Root execution from user message
|
|
706
|
+
let root_exec_id = ExecutionId::from_string("exec_root");
|
|
707
|
+
let tenant = TenantContext::new(TenantId::from_string("tenant_hier"))
|
|
708
|
+
.with_user(UserId::from_string("user_hier"));
|
|
709
|
+
let root_ctx = RuntimeContext::from_user_message(root_exec_id, "msg_root", tenant);
|
|
710
|
+
|
|
711
|
+
assert!(root_ctx.is_root());
|
|
712
|
+
|
|
713
|
+
// First-level child (sub-agent)
|
|
714
|
+
let step1_id = StepId::from_string("step_1");
|
|
715
|
+
let child1_ctx = root_ctx.child_context(
|
|
716
|
+
ExecutionId::from_string("exec_child1"),
|
|
717
|
+
&step1_id,
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
assert!(!child1_ctx.is_root());
|
|
721
|
+
assert_eq!(child1_ctx.trace.trace_id, root_ctx.trace.trace_id);
|
|
722
|
+
|
|
723
|
+
// Second-level child (sub-sub-agent)
|
|
724
|
+
let step2_id = StepId::from_string("step_2");
|
|
725
|
+
let child2_ctx = child1_ctx.child_context(
|
|
726
|
+
ExecutionId::from_string("exec_child2"),
|
|
727
|
+
&step2_id,
|
|
728
|
+
);
|
|
729
|
+
|
|
730
|
+
assert!(!child2_ctx.is_root());
|
|
731
|
+
// All share the same trace ID
|
|
732
|
+
assert_eq!(child2_ctx.trace.trace_id, root_ctx.trace.trace_id);
|
|
733
|
+
// But all have unique span IDs
|
|
734
|
+
assert_ne!(child2_ctx.trace.span_id, child1_ctx.trace.span_id);
|
|
735
|
+
assert_ne!(child1_ctx.trace.span_id, root_ctx.trace.span_id);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
#[test]
|
|
739
|
+
fn test_step_execution_creates_correct_spans() {
|
|
740
|
+
let exec_id = ExecutionId::from_string("exec_spans");
|
|
741
|
+
let tenant = create_test_tenant();
|
|
742
|
+
let root_ctx = RuntimeContext::new(exec_id, ParentLink::system(), tenant);
|
|
743
|
+
|
|
744
|
+
let step1 = StepId::from_string("step_a");
|
|
745
|
+
let step2 = StepId::from_string("step_b");
|
|
746
|
+
|
|
747
|
+
let ctx_step1 = root_ctx.enter_step(step1.clone());
|
|
748
|
+
let ctx_step2 = root_ctx.enter_step(step2.clone());
|
|
749
|
+
|
|
750
|
+
// Both steps should share the same trace ID
|
|
751
|
+
assert_eq!(ctx_step1.trace.trace_id, ctx_step2.trace.trace_id);
|
|
752
|
+
// But have different span IDs
|
|
753
|
+
assert_ne!(ctx_step1.trace.span_id, ctx_step2.trace.span_id);
|
|
754
|
+
// And different step IDs
|
|
755
|
+
assert_ne!(ctx_step1.step_id.unwrap().as_str(), ctx_step2.step_id.unwrap().as_str());
|
|
756
|
+
}
|
|
757
|
+
}
|