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,104 @@
|
|
|
1
|
+
//! GraphCallable - Wraps CompiledGraph to implement Callable trait
|
|
2
|
+
//!
|
|
3
|
+
//! This allows graphs to be registered in the CallableRegistry and executed
|
|
4
|
+
//! through the unified agent/stream endpoint alongside other callable types.
|
|
5
|
+
|
|
6
|
+
use super::Callable;
|
|
7
|
+
use crate::graph::CompiledGraph;
|
|
8
|
+
use async_trait::async_trait;
|
|
9
|
+
use std::sync::Arc;
|
|
10
|
+
|
|
11
|
+
/// A callable backed by a compiled graph
|
|
12
|
+
///
|
|
13
|
+
/// This wrapper allows `CompiledGraph` to be used as a `Callable`, enabling
|
|
14
|
+
/// graphs to be registered in the `CallableRegistry` and executed through
|
|
15
|
+
/// the unified agent/stream endpoint.
|
|
16
|
+
pub struct GraphCallable {
|
|
17
|
+
name: String,
|
|
18
|
+
graph: Arc<CompiledGraph>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl GraphCallable {
|
|
22
|
+
/// Create a new GraphCallable
|
|
23
|
+
///
|
|
24
|
+
/// # Arguments
|
|
25
|
+
/// * `name` - The name of this callable
|
|
26
|
+
/// * `graph` - The compiled graph to wrap
|
|
27
|
+
pub fn new(name: impl Into<String>, graph: Arc<CompiledGraph>) -> Self {
|
|
28
|
+
Self {
|
|
29
|
+
name: name.into(),
|
|
30
|
+
graph,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Get a reference to the underlying graph
|
|
35
|
+
pub fn graph(&self) -> &CompiledGraph {
|
|
36
|
+
&self.graph
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#[async_trait]
|
|
41
|
+
impl Callable for GraphCallable {
|
|
42
|
+
fn name(&self) -> &str {
|
|
43
|
+
&self.name
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fn description(&self) -> Option<&str> {
|
|
47
|
+
None // Could be extended to store description
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async fn run(&self, input: &str) -> anyhow::Result<String> {
|
|
51
|
+
// Run the graph with the input
|
|
52
|
+
let state = self.graph.run(input).await?;
|
|
53
|
+
|
|
54
|
+
// Convert NodeState to String
|
|
55
|
+
// NodeState contains a serde_json::Value, so we serialize it
|
|
56
|
+
if let Some(s) = state.as_str() {
|
|
57
|
+
Ok(s.to_string())
|
|
58
|
+
} else {
|
|
59
|
+
// If not a string, serialize the JSON value
|
|
60
|
+
Ok(serde_json::to_string(&state.data)?)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[cfg(test)]
|
|
66
|
+
mod tests {
|
|
67
|
+
use super::*;
|
|
68
|
+
use crate::graph::CompiledGraph;
|
|
69
|
+
use std::collections::HashMap;
|
|
70
|
+
|
|
71
|
+
#[tokio::test]
|
|
72
|
+
async fn test_graph_callable_name() {
|
|
73
|
+
// Create a minimal graph for testing
|
|
74
|
+
let graph = Arc::new(CompiledGraph {
|
|
75
|
+
nodes: HashMap::new(),
|
|
76
|
+
edges: vec![],
|
|
77
|
+
conditional_edges: vec![],
|
|
78
|
+
entry_point: "start".to_string(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
let callable = GraphCallable::new("test-graph", graph);
|
|
82
|
+
assert_eq!(callable.name(), "test-graph");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[tokio::test]
|
|
86
|
+
async fn test_graph_callable_run() {
|
|
87
|
+
// Create a minimal graph that just returns the input
|
|
88
|
+
// Note: This is a simplified test - a real graph would have nodes
|
|
89
|
+
let graph = Arc::new(CompiledGraph {
|
|
90
|
+
nodes: HashMap::new(),
|
|
91
|
+
edges: vec![],
|
|
92
|
+
conditional_edges: vec![],
|
|
93
|
+
entry_point: "start".to_string(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
let callable = GraphCallable::new("test-graph", graph);
|
|
97
|
+
|
|
98
|
+
// The graph will fail because it has no nodes, but we can test the structure
|
|
99
|
+
let result = callable.run("test input").await;
|
|
100
|
+
// This will fail because the graph has no nodes, but that's expected
|
|
101
|
+
assert!(result.is_err());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
//! LLM Callable - LLM-powered execution with tool loop
|
|
2
|
+
//!
|
|
3
|
+
//! This is an "agentic" callable - it runs an LLM with tools in a loop
|
|
4
|
+
//! until the LLM produces a final response.
|
|
5
|
+
|
|
6
|
+
use super::Callable;
|
|
7
|
+
use crate::providers::{ChatMessage, ChatRequest, ModelProvider};
|
|
8
|
+
use crate::tool::{DynTool, Tool};
|
|
9
|
+
use async_trait::async_trait;
|
|
10
|
+
use serde::{Deserialize, Serialize};
|
|
11
|
+
use serde_json::Value;
|
|
12
|
+
use std::sync::Arc;
|
|
13
|
+
|
|
14
|
+
/// Tool call from the LLM
|
|
15
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
16
|
+
pub struct ToolCall {
|
|
17
|
+
pub id: String,
|
|
18
|
+
pub name: String,
|
|
19
|
+
pub arguments: Value,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// Tool schema for LLM
|
|
23
|
+
#[derive(Debug, Clone, Serialize)]
|
|
24
|
+
pub struct ToolSchema {
|
|
25
|
+
#[serde(rename = "type")]
|
|
26
|
+
pub tool_type: String,
|
|
27
|
+
pub function: FunctionSchema,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[derive(Debug, Clone, Serialize)]
|
|
31
|
+
pub struct FunctionSchema {
|
|
32
|
+
pub name: String,
|
|
33
|
+
pub description: String,
|
|
34
|
+
pub parameters: Value,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
impl ToolSchema {
|
|
38
|
+
pub fn from_tool(tool: &dyn Tool) -> Self {
|
|
39
|
+
Self {
|
|
40
|
+
tool_type: "function".to_string(),
|
|
41
|
+
function: FunctionSchema {
|
|
42
|
+
name: tool.name().to_string(),
|
|
43
|
+
description: tool.description().to_string(),
|
|
44
|
+
parameters: tool.parameters_schema(),
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// LLM-powered callable with tool execution
|
|
51
|
+
///
|
|
52
|
+
/// This is the "agentic" callable - it runs the LLM in a loop,
|
|
53
|
+
/// executing tools as requested until a final response is produced.
|
|
54
|
+
///
|
|
55
|
+
/// Note: The loop is controlled by `max_iterations` to prevent runaway.
|
|
56
|
+
pub struct LlmCallable {
|
|
57
|
+
name: String,
|
|
58
|
+
description: Option<String>,
|
|
59
|
+
system_prompt: String,
|
|
60
|
+
provider: Arc<dyn ModelProvider>,
|
|
61
|
+
tools: Vec<DynTool>,
|
|
62
|
+
max_iterations: usize,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
impl LlmCallable {
|
|
67
|
+
/// Create with a custom provider
|
|
68
|
+
pub fn with_provider(
|
|
69
|
+
name: impl Into<String>,
|
|
70
|
+
system_prompt: impl Into<String>,
|
|
71
|
+
provider: Arc<dyn ModelProvider>,
|
|
72
|
+
) -> Self {
|
|
73
|
+
Self {
|
|
74
|
+
name: name.into(),
|
|
75
|
+
description: None,
|
|
76
|
+
system_prompt: system_prompt.into(),
|
|
77
|
+
provider,
|
|
78
|
+
tools: Vec::new(),
|
|
79
|
+
max_iterations: 10,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
pub fn with_description(mut self, description: impl Into<String>) -> Self {
|
|
84
|
+
self.description = Some(description.into());
|
|
85
|
+
self
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Add a tool to the callable
|
|
89
|
+
pub fn add_tool(mut self, tool: impl Tool + 'static) -> Self {
|
|
90
|
+
self.tools.push(Arc::new(tool));
|
|
91
|
+
self
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Add multiple tools
|
|
95
|
+
pub fn add_tools(mut self, tools: Vec<DynTool>) -> Self {
|
|
96
|
+
self.tools.extend(tools);
|
|
97
|
+
self
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Set max iterations for tool loop
|
|
101
|
+
pub fn max_iterations(mut self, max: usize) -> Self {
|
|
102
|
+
self.max_iterations = max;
|
|
103
|
+
self
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Execute a tool by name
|
|
107
|
+
async fn execute_tool(&self, name: &str, args: Value) -> anyhow::Result<Value> {
|
|
108
|
+
let tool = self
|
|
109
|
+
.tools
|
|
110
|
+
.iter()
|
|
111
|
+
.find(|t| t.name() == name)
|
|
112
|
+
.ok_or_else(|| anyhow::anyhow!("Tool '{}' not found", name))?;
|
|
113
|
+
|
|
114
|
+
tool.execute(args).await
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Get tool schemas for LLM
|
|
118
|
+
#[allow(dead_code)]
|
|
119
|
+
fn get_tool_schemas(&self) -> Vec<ToolSchema> {
|
|
120
|
+
self.tools
|
|
121
|
+
.iter()
|
|
122
|
+
.map(|t| ToolSchema::from_tool(t.as_ref()))
|
|
123
|
+
.collect()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// Check if response contains tool calls (simple heuristic)
|
|
127
|
+
fn extract_tool_calls(&self, content: &str) -> Option<Vec<ToolCall>> {
|
|
128
|
+
// Look for JSON tool call format in response
|
|
129
|
+
// Format: {"tool_call": {"name": "...", "arguments": {...}}}
|
|
130
|
+
if let Ok(parsed) = serde_json::from_str::<Value>(content) {
|
|
131
|
+
if let Some(tool_call) = parsed.get("tool_call") {
|
|
132
|
+
let name = tool_call.get("name")?.as_str()?.to_string();
|
|
133
|
+
let arguments = tool_call.get("arguments").cloned().unwrap_or(Value::Null);
|
|
134
|
+
return Some(vec![ToolCall {
|
|
135
|
+
id: format!("call_{}", uuid::Uuid::new_v4()),
|
|
136
|
+
name,
|
|
137
|
+
arguments,
|
|
138
|
+
}]);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
None
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#[async_trait]
|
|
146
|
+
impl Callable for LlmCallable {
|
|
147
|
+
fn name(&self) -> &str {
|
|
148
|
+
&self.name
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fn description(&self) -> Option<&str> {
|
|
152
|
+
self.description.as_deref()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async fn run(&self, input: &str) -> anyhow::Result<String> {
|
|
156
|
+
let mut messages = vec![
|
|
157
|
+
ChatMessage::system(&self.system_prompt),
|
|
158
|
+
ChatMessage::user(input),
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
// If we have tools, add instructions
|
|
162
|
+
if !self.tools.is_empty() {
|
|
163
|
+
let tool_names: Vec<&str> = self.tools.iter().map(|t| t.name()).collect();
|
|
164
|
+
let tool_instruction = format!(
|
|
165
|
+
"\n\nYou have access to these tools: {:?}. To use a tool, respond with ONLY a JSON object: {{\"tool_call\": {{\"name\": \"tool_name\", \"arguments\": {{...}}}}}}",
|
|
166
|
+
tool_names
|
|
167
|
+
);
|
|
168
|
+
messages[0] =
|
|
169
|
+
ChatMessage::system(format!("{}{}", self.system_prompt, tool_instruction));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Agentic loop
|
|
173
|
+
for iteration in 0..self.max_iterations {
|
|
174
|
+
tracing::debug!(iteration, "Callable iteration");
|
|
175
|
+
|
|
176
|
+
let request = ChatRequest {
|
|
177
|
+
messages: messages.clone(),
|
|
178
|
+
max_tokens: Some(4096),
|
|
179
|
+
temperature: Some(0.7),
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
let response = self.provider.chat(request).await?;
|
|
183
|
+
let content = response
|
|
184
|
+
.choices
|
|
185
|
+
.first()
|
|
186
|
+
.map(|c| c.message.content.clone())
|
|
187
|
+
.unwrap_or_default();
|
|
188
|
+
|
|
189
|
+
// Check for tool calls
|
|
190
|
+
if let Some(tool_calls) = self.extract_tool_calls(&content) {
|
|
191
|
+
for call in tool_calls {
|
|
192
|
+
tracing::debug!(tool = %call.name, "Executing tool");
|
|
193
|
+
|
|
194
|
+
let result = self.execute_tool(&call.name, call.arguments.clone()).await?;
|
|
195
|
+
|
|
196
|
+
// Add assistant message (tool call) and tool result to history
|
|
197
|
+
messages.push(ChatMessage::assistant(&content));
|
|
198
|
+
messages.push(ChatMessage {
|
|
199
|
+
role: "user".to_string(),
|
|
200
|
+
content: format!("Tool result: {}", serde_json::to_string(&result)?),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
// No tool calls - this is the final response
|
|
205
|
+
return Ok(content);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
anyhow::bail!("Max iterations ({}) reached", self.max_iterations)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//! Callable - The execution unit abstraction
|
|
2
|
+
//!
|
|
3
|
+
//! A Callable is anything that can be invoked with an input and produces an output.
|
|
4
|
+
//! This is the fundamental building block of execution.
|
|
5
|
+
//!
|
|
6
|
+
//! ## Key Distinction
|
|
7
|
+
//!
|
|
8
|
+
//! - **Callable**: The interface (trait) - defines HOW to invoke
|
|
9
|
+
//! - **Agent**: A marketing/user-facing term - we keep it as a type alias
|
|
10
|
+
//! - **LlmCallable**: A Callable backed by an LLM with tool loop
|
|
11
|
+
//! - **GraphCallable**: A Callable backed by a compiled graph
|
|
12
|
+
//!
|
|
13
|
+
//! ## Naming Convention
|
|
14
|
+
//!
|
|
15
|
+
//! Internally we use "Callable" to be precise about what this abstraction is.
|
|
16
|
+
//! Externally we re-export "Agent" as a type alias for user familiarity.
|
|
17
|
+
//!
|
|
18
|
+
//! ```text
|
|
19
|
+
//! ┌─────────────────────────────────────────────┐
|
|
20
|
+
//! │ trait Callable │
|
|
21
|
+
//! │ ┌─────────────────────────────────────┐ │
|
|
22
|
+
//! │ │ fn name() -> &str │ │
|
|
23
|
+
//! │ │ fn description() -> Option<&str> │ │
|
|
24
|
+
//! │ │ async fn run(&str) -> Result<String>│ │
|
|
25
|
+
//! │ └─────────────────────────────────────┘ │
|
|
26
|
+
//! └─────────────────────────────────────────────┘
|
|
27
|
+
//! ▲ ▲ ▲
|
|
28
|
+
//! │ │ │
|
|
29
|
+
//! ┌──────┴───┐ ┌──────┴───┐ ┌──────┴───┐
|
|
30
|
+
//! │LlmCallable│ │GraphCallable│ │FnCallable│
|
|
31
|
+
//! └──────────┘ └──────────┘ └──────────┘
|
|
32
|
+
//! ```
|
|
33
|
+
|
|
34
|
+
mod callable;
|
|
35
|
+
mod composite;
|
|
36
|
+
mod graph;
|
|
37
|
+
mod llm;
|
|
38
|
+
mod registry;
|
|
39
|
+
|
|
40
|
+
pub use callable::{Callable, DynCallable};
|
|
41
|
+
pub use composite::{
|
|
42
|
+
// Descriptor
|
|
43
|
+
CallableDescriptor,
|
|
44
|
+
CostTier,
|
|
45
|
+
// Invocation
|
|
46
|
+
CallableInvocation,
|
|
47
|
+
CallableInvocationResult,
|
|
48
|
+
// Resource allocation
|
|
49
|
+
ResourceAllocation,
|
|
50
|
+
ResourceAllocationStrategy,
|
|
51
|
+
ResourceBudget,
|
|
52
|
+
// Discovery
|
|
53
|
+
CallableInvoker,
|
|
54
|
+
DiscoveryQuery,
|
|
55
|
+
DiscoveryResult,
|
|
56
|
+
};
|
|
57
|
+
pub use graph::GraphCallable;
|
|
58
|
+
pub use llm::{LlmCallable, ToolCall, ToolSchema};
|
|
59
|
+
pub use registry::CallableRegistry;
|
|
60
|
+
|
|
61
|
+
// Re-export Agent as a user-friendly alias
|
|
62
|
+
// "Agent" is what users expect, "Callable" is what it really is
|
|
63
|
+
pub type Agent = dyn Callable;
|
|
64
|
+
pub type DynAgent = DynCallable;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
//! Callable Registry - Central registry for all callable types
|
|
2
|
+
//!
|
|
3
|
+
//! The registry allows registering and looking up any callable type (graphs, agents, workflows, LLM functions, etc.)
|
|
4
|
+
//! by name. This enables the unified agent/stream endpoint to execute any callable type through a single interface.
|
|
5
|
+
|
|
6
|
+
use super::DynCallable;
|
|
7
|
+
use std::collections::HashMap;
|
|
8
|
+
use std::sync::{Arc, RwLock};
|
|
9
|
+
|
|
10
|
+
/// Thread-safe registry for callables
|
|
11
|
+
///
|
|
12
|
+
/// Allows registering any callable type (LlmCallable, GraphCallable, FnCallable, etc.)
|
|
13
|
+
/// and looking them up by name. Used by the unified agent/stream endpoint.
|
|
14
|
+
pub struct CallableRegistry {
|
|
15
|
+
callables: Arc<RwLock<HashMap<String, DynCallable>>>,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl CallableRegistry {
|
|
19
|
+
/// Create a new empty registry
|
|
20
|
+
pub fn new() -> Self {
|
|
21
|
+
Self {
|
|
22
|
+
callables: Arc::new(RwLock::new(HashMap::new())),
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Register a callable with a given name
|
|
27
|
+
///
|
|
28
|
+
/// # Arguments
|
|
29
|
+
/// * `name` - The name to register the callable under
|
|
30
|
+
/// * `callable` - The callable to register
|
|
31
|
+
///
|
|
32
|
+
/// # Panics
|
|
33
|
+
/// This will overwrite any existing callable with the same name.
|
|
34
|
+
pub fn register(&self, name: String, callable: DynCallable) {
|
|
35
|
+
let mut callables = self.callables.write().unwrap();
|
|
36
|
+
callables.insert(name, callable);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Get a callable by name
|
|
40
|
+
///
|
|
41
|
+
/// # Arguments
|
|
42
|
+
/// * `name` - The name of the callable to retrieve
|
|
43
|
+
///
|
|
44
|
+
/// # Returns
|
|
45
|
+
/// * `Some(DynCallable)` if found
|
|
46
|
+
/// * `None` if not found
|
|
47
|
+
pub fn get(&self, name: &str) -> Option<DynCallable> {
|
|
48
|
+
let callables = self.callables.read().unwrap();
|
|
49
|
+
callables.get(name).cloned()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// List all registered callable names
|
|
53
|
+
///
|
|
54
|
+
/// # Returns
|
|
55
|
+
/// A vector of all registered callable names, sorted alphabetically
|
|
56
|
+
pub fn list(&self) -> Vec<String> {
|
|
57
|
+
let callables = self.callables.read().unwrap();
|
|
58
|
+
let mut names: Vec<String> = callables.keys().cloned().collect();
|
|
59
|
+
names.sort();
|
|
60
|
+
names
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Check if a callable is registered
|
|
64
|
+
///
|
|
65
|
+
/// # Arguments
|
|
66
|
+
/// * `name` - The name to check
|
|
67
|
+
///
|
|
68
|
+
/// # Returns
|
|
69
|
+
/// `true` if registered, `false` otherwise
|
|
70
|
+
pub fn contains(&self, name: &str) -> bool {
|
|
71
|
+
let callables = self.callables.read().unwrap();
|
|
72
|
+
callables.contains_key(name)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Remove a callable from the registry
|
|
76
|
+
///
|
|
77
|
+
/// # Arguments
|
|
78
|
+
/// * `name` - The name of the callable to remove
|
|
79
|
+
///
|
|
80
|
+
/// # Returns
|
|
81
|
+
/// `true` if the callable was removed, `false` if it wasn't found
|
|
82
|
+
pub fn remove(&self, name: &str) -> bool {
|
|
83
|
+
let mut callables = self.callables.write().unwrap();
|
|
84
|
+
callables.remove(name).is_some()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Get the number of registered callables
|
|
88
|
+
pub fn len(&self) -> usize {
|
|
89
|
+
let callables = self.callables.read().unwrap();
|
|
90
|
+
callables.len()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Check if the registry is empty
|
|
94
|
+
pub fn is_empty(&self) -> bool {
|
|
95
|
+
let callables = self.callables.read().unwrap();
|
|
96
|
+
callables.is_empty()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
impl Default for CallableRegistry {
|
|
101
|
+
fn default() -> Self {
|
|
102
|
+
Self::new()
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
impl Clone for CallableRegistry {
|
|
107
|
+
fn clone(&self) -> Self {
|
|
108
|
+
Self {
|
|
109
|
+
callables: Arc::clone(&self.callables),
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#[cfg(test)]
|
|
115
|
+
mod tests {
|
|
116
|
+
use super::*;
|
|
117
|
+
use crate::callable::Callable;
|
|
118
|
+
use async_trait::async_trait;
|
|
119
|
+
use std::sync::Arc;
|
|
120
|
+
|
|
121
|
+
struct MockCallable {
|
|
122
|
+
name: String,
|
|
123
|
+
output: String,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[async_trait]
|
|
127
|
+
impl Callable for MockCallable {
|
|
128
|
+
fn name(&self) -> &str {
|
|
129
|
+
&self.name
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async fn run(&self, _input: &str) -> anyhow::Result<String> {
|
|
133
|
+
Ok(self.output.clone())
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#[tokio::test]
|
|
138
|
+
async fn test_register_and_get() {
|
|
139
|
+
let registry = CallableRegistry::new();
|
|
140
|
+
let callable = Arc::new(MockCallable {
|
|
141
|
+
name: "test".to_string(),
|
|
142
|
+
output: "test output".to_string(),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
registry.register("test".to_string(), callable.clone());
|
|
146
|
+
let retrieved = registry.get("test").unwrap();
|
|
147
|
+
assert_eq!(retrieved.name(), "test");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
#[tokio::test]
|
|
151
|
+
async fn test_get_nonexistent() {
|
|
152
|
+
let registry = CallableRegistry::new();
|
|
153
|
+
assert!(registry.get("nonexistent").is_none());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#[tokio::test]
|
|
157
|
+
async fn test_list() {
|
|
158
|
+
let registry = CallableRegistry::new();
|
|
159
|
+
let callable1 = Arc::new(MockCallable {
|
|
160
|
+
name: "callable1".to_string(),
|
|
161
|
+
output: "output1".to_string(),
|
|
162
|
+
});
|
|
163
|
+
let callable2 = Arc::new(MockCallable {
|
|
164
|
+
name: "callable2".to_string(),
|
|
165
|
+
output: "output2".to_string(),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
registry.register("callable1".to_string(), callable1);
|
|
169
|
+
registry.register("callable2".to_string(), callable2);
|
|
170
|
+
|
|
171
|
+
let names = registry.list();
|
|
172
|
+
assert_eq!(names.len(), 2);
|
|
173
|
+
assert!(names.contains(&"callable1".to_string()));
|
|
174
|
+
assert!(names.contains(&"callable2".to_string()));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
#[tokio::test]
|
|
178
|
+
async fn test_contains() {
|
|
179
|
+
let registry = CallableRegistry::new();
|
|
180
|
+
let callable = Arc::new(MockCallable {
|
|
181
|
+
name: "test".to_string(),
|
|
182
|
+
output: "output".to_string(),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
registry.register("test".to_string(), callable);
|
|
186
|
+
assert!(registry.contains("test"));
|
|
187
|
+
assert!(!registry.contains("nonexistent"));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#[tokio::test]
|
|
191
|
+
async fn test_remove() {
|
|
192
|
+
let registry = CallableRegistry::new();
|
|
193
|
+
let callable = Arc::new(MockCallable {
|
|
194
|
+
name: "test".to_string(),
|
|
195
|
+
output: "output".to_string(),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
registry.register("test".to_string(), callable);
|
|
199
|
+
assert!(registry.contains("test"));
|
|
200
|
+
|
|
201
|
+
assert!(registry.remove("test"));
|
|
202
|
+
assert!(!registry.contains("test"));
|
|
203
|
+
assert!(!registry.remove("test"));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|