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,817 @@
|
|
|
1
|
+
//! Composite Callable - Callables that invoke other callables
|
|
2
|
+
//!
|
|
3
|
+
//! This module provides the infrastructure for:
|
|
4
|
+
//! - Callable-within-callable invocation
|
|
5
|
+
//! - Dynamic callable discovery
|
|
6
|
+
//! - Resource allocation strategies
|
|
7
|
+
//!
|
|
8
|
+
//! @see packages/enact-schemas/src/execution.schemas.ts
|
|
9
|
+
|
|
10
|
+
use serde::{Deserialize, Serialize};
|
|
11
|
+
use std::collections::HashMap;
|
|
12
|
+
use std::time::Instant;
|
|
13
|
+
|
|
14
|
+
use super::{Callable, CallableRegistry, DynCallable};
|
|
15
|
+
use crate::kernel::ids::{CallableType, ExecutionId, SpawnMode};
|
|
16
|
+
use crate::kernel::TokenUsage;
|
|
17
|
+
|
|
18
|
+
/// CostTier - Estimated cost tier for resource planning
|
|
19
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - callableDescriptorSchema.costTier
|
|
20
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
21
|
+
#[serde(rename_all = "snake_case")]
|
|
22
|
+
pub enum CostTier {
|
|
23
|
+
Free,
|
|
24
|
+
Low,
|
|
25
|
+
#[default]
|
|
26
|
+
Medium,
|
|
27
|
+
High,
|
|
28
|
+
Premium,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// CallableDescriptor - Describes a callable for discovery
|
|
32
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - callableDescriptorSchema
|
|
33
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
34
|
+
#[serde(rename_all = "camelCase")]
|
|
35
|
+
pub struct CallableDescriptor {
|
|
36
|
+
/// Callable name (unique identifier)
|
|
37
|
+
pub name: String,
|
|
38
|
+
|
|
39
|
+
/// Human-readable description
|
|
40
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
41
|
+
pub description: Option<String>,
|
|
42
|
+
|
|
43
|
+
/// Callable type
|
|
44
|
+
pub callable_type: CallableType,
|
|
45
|
+
|
|
46
|
+
/// Input schema (JSON Schema)
|
|
47
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
48
|
+
pub input_schema: Option<serde_json::Value>,
|
|
49
|
+
|
|
50
|
+
/// Output schema (JSON Schema)
|
|
51
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
52
|
+
pub output_schema: Option<serde_json::Value>,
|
|
53
|
+
|
|
54
|
+
/// Tags for categorization
|
|
55
|
+
#[serde(default)]
|
|
56
|
+
pub tags: Vec<String>,
|
|
57
|
+
|
|
58
|
+
/// Whether this callable can spawn children
|
|
59
|
+
#[serde(default)]
|
|
60
|
+
pub can_spawn_children: bool,
|
|
61
|
+
|
|
62
|
+
/// Estimated cost tier
|
|
63
|
+
#[serde(default)]
|
|
64
|
+
pub cost_tier: CostTier,
|
|
65
|
+
|
|
66
|
+
/// Average latency in milliseconds
|
|
67
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
68
|
+
pub avg_latency_ms: Option<u64>,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
impl CallableDescriptor {
|
|
72
|
+
/// Create a new descriptor from a callable
|
|
73
|
+
pub fn from_callable(callable: &dyn Callable, callable_type: CallableType) -> Self {
|
|
74
|
+
Self {
|
|
75
|
+
name: callable.name().to_string(),
|
|
76
|
+
description: callable.description().map(String::from),
|
|
77
|
+
callable_type,
|
|
78
|
+
input_schema: None,
|
|
79
|
+
output_schema: None,
|
|
80
|
+
tags: Vec::new(),
|
|
81
|
+
can_spawn_children: false,
|
|
82
|
+
cost_tier: CostTier::Medium,
|
|
83
|
+
avg_latency_ms: None,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Add tags
|
|
88
|
+
pub fn with_tags(mut self, tags: Vec<String>) -> Self {
|
|
89
|
+
self.tags = tags;
|
|
90
|
+
self
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Set cost tier
|
|
94
|
+
pub fn with_cost_tier(mut self, tier: CostTier) -> Self {
|
|
95
|
+
self.cost_tier = tier;
|
|
96
|
+
self
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Set can spawn children
|
|
100
|
+
pub fn with_spawn_capability(mut self, can_spawn: bool) -> Self {
|
|
101
|
+
self.can_spawn_children = can_spawn;
|
|
102
|
+
self
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// CallableInvocation - Request to invoke a callable from another callable
|
|
107
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - callableInvocationSchema
|
|
108
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
109
|
+
#[serde(rename_all = "camelCase")]
|
|
110
|
+
pub struct CallableInvocation {
|
|
111
|
+
/// Target callable name
|
|
112
|
+
pub callable_name: String,
|
|
113
|
+
|
|
114
|
+
/// Input to pass
|
|
115
|
+
pub input: String,
|
|
116
|
+
|
|
117
|
+
/// Context to pass
|
|
118
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
119
|
+
pub context: Option<HashMap<String, String>>,
|
|
120
|
+
|
|
121
|
+
/// Spawn mode for child execution
|
|
122
|
+
#[serde(default)]
|
|
123
|
+
pub spawn_mode: SpawnMode,
|
|
124
|
+
|
|
125
|
+
/// Priority (higher = more important)
|
|
126
|
+
#[serde(default = "default_priority")]
|
|
127
|
+
pub priority: u8,
|
|
128
|
+
|
|
129
|
+
/// Timeout in milliseconds
|
|
130
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
131
|
+
pub timeout_ms: Option<u64>,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
fn default_priority() -> u8 {
|
|
135
|
+
50
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// CallableInvocationResult - Result of a callable invocation
|
|
139
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - callableInvocationResultSchema
|
|
140
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
141
|
+
#[serde(rename_all = "camelCase")]
|
|
142
|
+
pub struct CallableInvocationResult {
|
|
143
|
+
/// Whether the invocation succeeded
|
|
144
|
+
pub success: bool,
|
|
145
|
+
|
|
146
|
+
/// Output (if successful)
|
|
147
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
148
|
+
pub output: Option<String>,
|
|
149
|
+
|
|
150
|
+
/// Error message (if failed)
|
|
151
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
152
|
+
pub error: Option<String>,
|
|
153
|
+
|
|
154
|
+
/// Child execution ID (for SpawnMode::Child)
|
|
155
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
156
|
+
pub child_execution_id: Option<ExecutionId>,
|
|
157
|
+
|
|
158
|
+
/// Duration in milliseconds
|
|
159
|
+
pub duration_ms: u64,
|
|
160
|
+
|
|
161
|
+
/// Token usage
|
|
162
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
163
|
+
pub token_usage: Option<TokenUsage>,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
impl CallableInvocationResult {
|
|
167
|
+
/// Create a success result
|
|
168
|
+
pub fn success(output: String, duration_ms: u64) -> Self {
|
|
169
|
+
Self {
|
|
170
|
+
success: true,
|
|
171
|
+
output: Some(output),
|
|
172
|
+
error: None,
|
|
173
|
+
child_execution_id: None,
|
|
174
|
+
duration_ms,
|
|
175
|
+
token_usage: None,
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/// Create a failure result
|
|
180
|
+
pub fn failure(error: impl Into<String>, duration_ms: u64) -> Self {
|
|
181
|
+
Self {
|
|
182
|
+
success: false,
|
|
183
|
+
output: None,
|
|
184
|
+
error: Some(error.into()),
|
|
185
|
+
child_execution_id: None,
|
|
186
|
+
duration_ms,
|
|
187
|
+
token_usage: None,
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// Create a child spawn result
|
|
192
|
+
pub fn child_spawned(execution_id: ExecutionId, duration_ms: u64) -> Self {
|
|
193
|
+
Self {
|
|
194
|
+
success: true,
|
|
195
|
+
output: None,
|
|
196
|
+
error: None,
|
|
197
|
+
child_execution_id: Some(execution_id),
|
|
198
|
+
duration_ms,
|
|
199
|
+
token_usage: None,
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/// ResourceAllocationStrategy - How to allocate resources among child callables
|
|
205
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - resourceAllocationStrategySchema
|
|
206
|
+
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
|
207
|
+
#[serde(rename_all = "snake_case")]
|
|
208
|
+
pub enum ResourceAllocationStrategy {
|
|
209
|
+
/// Divide resources equally among children
|
|
210
|
+
EqualSplit,
|
|
211
|
+
/// Shared pool with first-come-first-served
|
|
212
|
+
#[default]
|
|
213
|
+
SharedPool,
|
|
214
|
+
/// Higher priority gets more resources
|
|
215
|
+
Priority,
|
|
216
|
+
/// Allocate based on estimated cost
|
|
217
|
+
Proportional,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/// ResourceBudget - Budget for a callable execution
|
|
221
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - resourceBudgetSchema
|
|
222
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
223
|
+
#[serde(rename_all = "camelCase")]
|
|
224
|
+
pub struct ResourceBudget {
|
|
225
|
+
/// Maximum tokens
|
|
226
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
227
|
+
pub max_tokens: Option<u64>,
|
|
228
|
+
|
|
229
|
+
/// Maximum time in milliseconds
|
|
230
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
231
|
+
pub max_time_ms: Option<u64>,
|
|
232
|
+
|
|
233
|
+
/// Maximum cost in cents
|
|
234
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
235
|
+
pub max_cost_cents: Option<f64>,
|
|
236
|
+
|
|
237
|
+
/// Maximum child spawns
|
|
238
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
239
|
+
pub max_children: Option<u32>,
|
|
240
|
+
|
|
241
|
+
/// Maximum discovery depth
|
|
242
|
+
#[serde(default = "default_max_depth")]
|
|
243
|
+
pub max_discovery_depth: u32,
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fn default_max_depth() -> u32 {
|
|
247
|
+
3
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
impl Default for ResourceBudget {
|
|
251
|
+
fn default() -> Self {
|
|
252
|
+
Self {
|
|
253
|
+
max_tokens: None,
|
|
254
|
+
max_time_ms: None,
|
|
255
|
+
max_cost_cents: None,
|
|
256
|
+
max_children: None,
|
|
257
|
+
max_discovery_depth: default_max_depth(),
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/// ResourceAllocation - Allocated resources for an execution
|
|
263
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - resourceAllocationSchema
|
|
264
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
265
|
+
#[serde(rename_all = "camelCase")]
|
|
266
|
+
pub struct ResourceAllocation {
|
|
267
|
+
/// Allocation strategy used
|
|
268
|
+
pub strategy: ResourceAllocationStrategy,
|
|
269
|
+
|
|
270
|
+
/// Budget for this allocation
|
|
271
|
+
pub budget: ResourceBudget,
|
|
272
|
+
|
|
273
|
+
/// Currently used tokens
|
|
274
|
+
#[serde(default)]
|
|
275
|
+
pub used_tokens: u64,
|
|
276
|
+
|
|
277
|
+
/// Currently used time in milliseconds
|
|
278
|
+
#[serde(default)]
|
|
279
|
+
pub used_time_ms: u64,
|
|
280
|
+
|
|
281
|
+
/// Currently used cost in cents
|
|
282
|
+
#[serde(default)]
|
|
283
|
+
pub used_cost_cents: f64,
|
|
284
|
+
|
|
285
|
+
/// Number of children spawned
|
|
286
|
+
#[serde(default)]
|
|
287
|
+
pub children_spawned: u32,
|
|
288
|
+
|
|
289
|
+
/// Current discovery depth
|
|
290
|
+
#[serde(default)]
|
|
291
|
+
pub current_depth: u32,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
impl ResourceAllocation {
|
|
295
|
+
/// Create a new allocation with a budget
|
|
296
|
+
pub fn new(strategy: ResourceAllocationStrategy, budget: ResourceBudget) -> Self {
|
|
297
|
+
Self {
|
|
298
|
+
strategy,
|
|
299
|
+
budget,
|
|
300
|
+
used_tokens: 0,
|
|
301
|
+
used_time_ms: 0,
|
|
302
|
+
used_cost_cents: 0.0,
|
|
303
|
+
children_spawned: 0,
|
|
304
|
+
current_depth: 0,
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/// Check if we can spawn another child
|
|
309
|
+
pub fn can_spawn_child(&self) -> bool {
|
|
310
|
+
match self.budget.max_children {
|
|
311
|
+
Some(max) => self.children_spawned < max,
|
|
312
|
+
None => true,
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// Check if we can go deeper in discovery
|
|
317
|
+
pub fn can_discover_deeper(&self) -> bool {
|
|
318
|
+
self.current_depth < self.budget.max_discovery_depth
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/// Check if we have token budget remaining
|
|
322
|
+
pub fn has_token_budget(&self, tokens: u64) -> bool {
|
|
323
|
+
match self.budget.max_tokens {
|
|
324
|
+
Some(max) => self.used_tokens + tokens <= max,
|
|
325
|
+
None => true,
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/// Check if we have time budget remaining
|
|
330
|
+
pub fn has_time_budget(&self, time_ms: u64) -> bool {
|
|
331
|
+
match self.budget.max_time_ms {
|
|
332
|
+
Some(max) => self.used_time_ms + time_ms <= max,
|
|
333
|
+
None => true,
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/// Record token usage
|
|
338
|
+
pub fn record_tokens(&mut self, tokens: u64) {
|
|
339
|
+
self.used_tokens += tokens;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/// Record time usage
|
|
343
|
+
pub fn record_time(&mut self, time_ms: u64) {
|
|
344
|
+
self.used_time_ms += time_ms;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/// Record child spawn
|
|
348
|
+
pub fn record_child_spawn(&mut self) {
|
|
349
|
+
self.children_spawned += 1;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/// Increment depth
|
|
353
|
+
pub fn increment_depth(&mut self) {
|
|
354
|
+
self.current_depth += 1;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/// Create a child allocation (for nested invocations)
|
|
358
|
+
pub fn child_allocation(&self) -> Self {
|
|
359
|
+
let mut child = self.clone();
|
|
360
|
+
child.increment_depth();
|
|
361
|
+
|
|
362
|
+
// Adjust budget based on strategy
|
|
363
|
+
match self.strategy {
|
|
364
|
+
ResourceAllocationStrategy::EqualSplit => {
|
|
365
|
+
// Split remaining budget
|
|
366
|
+
if let Some(max) = child.budget.max_tokens {
|
|
367
|
+
let remaining = max.saturating_sub(self.used_tokens);
|
|
368
|
+
child.budget.max_tokens = Some(remaining / 2);
|
|
369
|
+
}
|
|
370
|
+
if let Some(max) = child.budget.max_time_ms {
|
|
371
|
+
let remaining = max.saturating_sub(self.used_time_ms);
|
|
372
|
+
child.budget.max_time_ms = Some(remaining / 2);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
ResourceAllocationStrategy::SharedPool => {
|
|
376
|
+
// Share the same budget (just track separately)
|
|
377
|
+
}
|
|
378
|
+
ResourceAllocationStrategy::Priority => {
|
|
379
|
+
// High priority children get more (80%)
|
|
380
|
+
if let Some(max) = child.budget.max_tokens {
|
|
381
|
+
let remaining = max.saturating_sub(self.used_tokens);
|
|
382
|
+
child.budget.max_tokens = Some((remaining * 80) / 100);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
ResourceAllocationStrategy::Proportional => {
|
|
386
|
+
// Based on cost tier - would need callable info
|
|
387
|
+
// For now, same as equal split
|
|
388
|
+
if let Some(max) = child.budget.max_tokens {
|
|
389
|
+
let remaining = max.saturating_sub(self.used_tokens);
|
|
390
|
+
child.budget.max_tokens = Some(remaining / 2);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
child
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/// DiscoveryQuery - Query for discovering callables
|
|
400
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - discoveryQuerySchema
|
|
401
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
402
|
+
#[serde(rename_all = "camelCase")]
|
|
403
|
+
pub struct DiscoveryQuery {
|
|
404
|
+
/// Filter by callable type
|
|
405
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
406
|
+
pub callable_type: Option<CallableType>,
|
|
407
|
+
|
|
408
|
+
/// Filter by tags (any match)
|
|
409
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
410
|
+
pub tags: Option<Vec<String>>,
|
|
411
|
+
|
|
412
|
+
/// Filter by name pattern (glob-like)
|
|
413
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
414
|
+
pub name_pattern: Option<String>,
|
|
415
|
+
|
|
416
|
+
/// Filter by maximum cost tier
|
|
417
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
418
|
+
pub max_cost_tier: Option<CostTier>,
|
|
419
|
+
|
|
420
|
+
/// Maximum results
|
|
421
|
+
#[serde(default = "default_limit")]
|
|
422
|
+
pub limit: usize,
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
fn default_limit() -> usize {
|
|
426
|
+
10
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
impl Default for DiscoveryQuery {
|
|
430
|
+
fn default() -> Self {
|
|
431
|
+
Self {
|
|
432
|
+
callable_type: None,
|
|
433
|
+
tags: None,
|
|
434
|
+
name_pattern: None,
|
|
435
|
+
max_cost_tier: None,
|
|
436
|
+
limit: default_limit(),
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/// DiscoveryResult - Result of a callable discovery query
|
|
442
|
+
/// @see packages/enact-schemas/src/execution.schemas.ts - discoveryResultSchema
|
|
443
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
444
|
+
#[serde(rename_all = "camelCase")]
|
|
445
|
+
pub struct DiscoveryResult {
|
|
446
|
+
/// Matching callables
|
|
447
|
+
pub callables: Vec<CallableDescriptor>,
|
|
448
|
+
|
|
449
|
+
/// Total count (before limit)
|
|
450
|
+
pub total_count: usize,
|
|
451
|
+
|
|
452
|
+
/// Query that was executed
|
|
453
|
+
pub query: DiscoveryQuery,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/// CallableInvoker - Invokes callables from a registry
|
|
457
|
+
///
|
|
458
|
+
/// This is the core mechanism for callable-within-callable invocation.
|
|
459
|
+
pub struct CallableInvoker {
|
|
460
|
+
registry: CallableRegistry,
|
|
461
|
+
descriptors: HashMap<String, CallableDescriptor>,
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
impl CallableInvoker {
|
|
465
|
+
/// Create a new invoker with a registry
|
|
466
|
+
pub fn new(registry: CallableRegistry) -> Self {
|
|
467
|
+
Self {
|
|
468
|
+
registry,
|
|
469
|
+
descriptors: HashMap::new(),
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/// Register a descriptor for a callable
|
|
474
|
+
pub fn register_descriptor(&mut self, descriptor: CallableDescriptor) {
|
|
475
|
+
self.descriptors.insert(descriptor.name.clone(), descriptor);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/// Get a callable from the registry
|
|
479
|
+
pub fn get(&self, name: &str) -> Option<DynCallable> {
|
|
480
|
+
self.registry.get(name)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/// Invoke a callable by name
|
|
484
|
+
pub async fn invoke(&self, invocation: CallableInvocation) -> CallableInvocationResult {
|
|
485
|
+
let start = Instant::now();
|
|
486
|
+
|
|
487
|
+
let callable = match self.registry.get(&invocation.callable_name) {
|
|
488
|
+
Some(c) => c,
|
|
489
|
+
None => {
|
|
490
|
+
return CallableInvocationResult::failure(
|
|
491
|
+
format!("Callable '{}' not found", invocation.callable_name),
|
|
492
|
+
start.elapsed().as_millis() as u64,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
match invocation.spawn_mode {
|
|
498
|
+
SpawnMode::Inline => {
|
|
499
|
+
// Inline execution - run directly
|
|
500
|
+
match callable.run(&invocation.input).await {
|
|
501
|
+
Ok(output) => {
|
|
502
|
+
CallableInvocationResult::success(output, start.elapsed().as_millis() as u64)
|
|
503
|
+
}
|
|
504
|
+
Err(e) => CallableInvocationResult::failure(
|
|
505
|
+
e.to_string(),
|
|
506
|
+
start.elapsed().as_millis() as u64,
|
|
507
|
+
),
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
SpawnMode::Child { background, .. } => {
|
|
511
|
+
if background {
|
|
512
|
+
// Background execution - spawn and return immediately
|
|
513
|
+
let execution_id = ExecutionId::new();
|
|
514
|
+
// In a real implementation, this would spawn a background task
|
|
515
|
+
CallableInvocationResult::child_spawned(
|
|
516
|
+
execution_id,
|
|
517
|
+
start.elapsed().as_millis() as u64,
|
|
518
|
+
)
|
|
519
|
+
} else {
|
|
520
|
+
// Child execution - run and wait
|
|
521
|
+
match callable.run(&invocation.input).await {
|
|
522
|
+
Ok(output) => CallableInvocationResult::success(
|
|
523
|
+
output,
|
|
524
|
+
start.elapsed().as_millis() as u64,
|
|
525
|
+
),
|
|
526
|
+
Err(e) => CallableInvocationResult::failure(
|
|
527
|
+
e.to_string(),
|
|
528
|
+
start.elapsed().as_millis() as u64,
|
|
529
|
+
),
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/// Discover callables matching a query
|
|
537
|
+
pub fn discover(&self, query: DiscoveryQuery) -> DiscoveryResult {
|
|
538
|
+
let mut matches: Vec<CallableDescriptor> = self
|
|
539
|
+
.descriptors
|
|
540
|
+
.values()
|
|
541
|
+
.filter(|desc| {
|
|
542
|
+
// Filter by type
|
|
543
|
+
if let Some(ref t) = query.callable_type {
|
|
544
|
+
if &desc.callable_type != t {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Filter by tags
|
|
550
|
+
if let Some(ref tags) = query.tags {
|
|
551
|
+
if !tags.iter().any(|t| desc.tags.contains(t)) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Filter by name pattern (simple glob)
|
|
557
|
+
if let Some(ref pattern) = query.name_pattern {
|
|
558
|
+
if !matches_glob(&desc.name, pattern) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Filter by cost tier
|
|
564
|
+
if let Some(ref max_tier) = query.max_cost_tier {
|
|
565
|
+
if !is_cost_tier_within(&desc.cost_tier, max_tier) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
true
|
|
571
|
+
})
|
|
572
|
+
.cloned()
|
|
573
|
+
.collect();
|
|
574
|
+
|
|
575
|
+
let total_count = matches.len();
|
|
576
|
+
matches.truncate(query.limit);
|
|
577
|
+
|
|
578
|
+
DiscoveryResult {
|
|
579
|
+
callables: matches,
|
|
580
|
+
total_count,
|
|
581
|
+
query,
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/// List all registered callable names
|
|
586
|
+
pub fn list(&self) -> Vec<String> {
|
|
587
|
+
self.registry.list()
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/// Simple glob matching (supports * and ?)
|
|
592
|
+
fn matches_glob(name: &str, pattern: &str) -> bool {
|
|
593
|
+
// Simple glob matching without regex
|
|
594
|
+
let mut name_chars = name.chars().peekable();
|
|
595
|
+
let mut pattern_chars = pattern.chars().peekable();
|
|
596
|
+
|
|
597
|
+
while let Some(p) = pattern_chars.next() {
|
|
598
|
+
match p {
|
|
599
|
+
'*' => {
|
|
600
|
+
// * matches zero or more characters
|
|
601
|
+
if pattern_chars.peek().is_none() {
|
|
602
|
+
return true; // Trailing * matches everything
|
|
603
|
+
}
|
|
604
|
+
// Try matching zero characters first, then more
|
|
605
|
+
let remaining_pattern: String = pattern_chars.collect();
|
|
606
|
+
let mut remaining_name = String::new();
|
|
607
|
+
loop {
|
|
608
|
+
if matches_glob(&remaining_name, &remaining_pattern) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
match name_chars.next() {
|
|
612
|
+
Some(c) => remaining_name.push(c),
|
|
613
|
+
None => return matches_glob("", &remaining_pattern),
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
'?' => {
|
|
618
|
+
// ? matches exactly one character
|
|
619
|
+
if name_chars.next().is_none() {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
c => {
|
|
624
|
+
// Literal character must match
|
|
625
|
+
match name_chars.next() {
|
|
626
|
+
Some(nc) if nc == c => continue,
|
|
627
|
+
_ => return false,
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Pattern exhausted - name should be too
|
|
634
|
+
name_chars.next().is_none()
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/// Check if cost tier is within limit
|
|
638
|
+
fn is_cost_tier_within(tier: &CostTier, max_tier: &CostTier) -> bool {
|
|
639
|
+
let tier_value = match tier {
|
|
640
|
+
CostTier::Free => 0,
|
|
641
|
+
CostTier::Low => 1,
|
|
642
|
+
CostTier::Medium => 2,
|
|
643
|
+
CostTier::High => 3,
|
|
644
|
+
CostTier::Premium => 4,
|
|
645
|
+
};
|
|
646
|
+
let max_value = match max_tier {
|
|
647
|
+
CostTier::Free => 0,
|
|
648
|
+
CostTier::Low => 1,
|
|
649
|
+
CostTier::Medium => 2,
|
|
650
|
+
CostTier::High => 3,
|
|
651
|
+
CostTier::Premium => 4,
|
|
652
|
+
};
|
|
653
|
+
tier_value <= max_value
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
#[cfg(test)]
|
|
657
|
+
mod tests {
|
|
658
|
+
use super::*;
|
|
659
|
+
use async_trait::async_trait;
|
|
660
|
+
use std::sync::Arc;
|
|
661
|
+
|
|
662
|
+
struct TestCallable {
|
|
663
|
+
name: String,
|
|
664
|
+
output: String,
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
#[async_trait]
|
|
668
|
+
impl Callable for TestCallable {
|
|
669
|
+
fn name(&self) -> &str {
|
|
670
|
+
&self.name
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
async fn run(&self, _input: &str) -> anyhow::Result<String> {
|
|
674
|
+
Ok(self.output.clone())
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
#[test]
|
|
679
|
+
fn test_callable_descriptor() {
|
|
680
|
+
let callable = TestCallable {
|
|
681
|
+
name: "test".to_string(),
|
|
682
|
+
output: "output".to_string(),
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
let desc = CallableDescriptor::from_callable(&callable, CallableType::Agent)
|
|
686
|
+
.with_tags(vec!["research".to_string(), "analysis".to_string()])
|
|
687
|
+
.with_cost_tier(CostTier::High)
|
|
688
|
+
.with_spawn_capability(true);
|
|
689
|
+
|
|
690
|
+
assert_eq!(desc.name, "test");
|
|
691
|
+
assert_eq!(desc.callable_type, CallableType::Agent);
|
|
692
|
+
assert_eq!(desc.tags.len(), 2);
|
|
693
|
+
assert_eq!(desc.cost_tier, CostTier::High);
|
|
694
|
+
assert!(desc.can_spawn_children);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
#[test]
|
|
698
|
+
fn test_resource_allocation() {
|
|
699
|
+
let budget = ResourceBudget {
|
|
700
|
+
max_tokens: Some(1000),
|
|
701
|
+
max_time_ms: Some(5000),
|
|
702
|
+
max_children: Some(3),
|
|
703
|
+
..Default::default()
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
let mut allocation = ResourceAllocation::new(ResourceAllocationStrategy::EqualSplit, budget);
|
|
707
|
+
|
|
708
|
+
assert!(allocation.can_spawn_child());
|
|
709
|
+
assert!(allocation.has_token_budget(500));
|
|
710
|
+
|
|
711
|
+
allocation.record_tokens(400);
|
|
712
|
+
allocation.record_child_spawn();
|
|
713
|
+
|
|
714
|
+
assert!(allocation.has_token_budget(500));
|
|
715
|
+
assert!(!allocation.has_token_budget(700));
|
|
716
|
+
assert!(allocation.can_spawn_child());
|
|
717
|
+
|
|
718
|
+
allocation.record_child_spawn();
|
|
719
|
+
allocation.record_child_spawn();
|
|
720
|
+
assert!(!allocation.can_spawn_child());
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
#[test]
|
|
724
|
+
fn test_child_allocation() {
|
|
725
|
+
let budget = ResourceBudget {
|
|
726
|
+
max_tokens: Some(1000),
|
|
727
|
+
..Default::default()
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
let allocation = ResourceAllocation::new(ResourceAllocationStrategy::EqualSplit, budget);
|
|
731
|
+
let child = allocation.child_allocation();
|
|
732
|
+
|
|
733
|
+
assert_eq!(child.current_depth, 1);
|
|
734
|
+
assert_eq!(child.budget.max_tokens, Some(500)); // Half of parent
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
#[tokio::test]
|
|
738
|
+
async fn test_callable_invoker() {
|
|
739
|
+
let registry = CallableRegistry::new();
|
|
740
|
+
let callable = Arc::new(TestCallable {
|
|
741
|
+
name: "test".to_string(),
|
|
742
|
+
output: "test output".to_string(),
|
|
743
|
+
});
|
|
744
|
+
registry.register("test".to_string(), callable);
|
|
745
|
+
|
|
746
|
+
let invoker = CallableInvoker::new(registry);
|
|
747
|
+
|
|
748
|
+
let invocation = CallableInvocation {
|
|
749
|
+
callable_name: "test".to_string(),
|
|
750
|
+
input: "input".to_string(),
|
|
751
|
+
context: None,
|
|
752
|
+
spawn_mode: SpawnMode::Inline,
|
|
753
|
+
priority: 50,
|
|
754
|
+
timeout_ms: None,
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
let result = invoker.invoke(invocation).await;
|
|
758
|
+
assert!(result.success);
|
|
759
|
+
assert_eq!(result.output, Some("test output".to_string()));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
#[test]
|
|
763
|
+
fn test_discovery() {
|
|
764
|
+
let registry = CallableRegistry::new();
|
|
765
|
+
let mut invoker = CallableInvoker::new(registry);
|
|
766
|
+
|
|
767
|
+
invoker.register_descriptor(
|
|
768
|
+
CallableDescriptor::from_callable(
|
|
769
|
+
&TestCallable {
|
|
770
|
+
name: "research-agent".to_string(),
|
|
771
|
+
output: "".to_string(),
|
|
772
|
+
},
|
|
773
|
+
CallableType::Agent,
|
|
774
|
+
)
|
|
775
|
+
.with_tags(vec!["research".to_string()])
|
|
776
|
+
.with_cost_tier(CostTier::Medium),
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
invoker.register_descriptor(
|
|
780
|
+
CallableDescriptor::from_callable(
|
|
781
|
+
&TestCallable {
|
|
782
|
+
name: "analysis-agent".to_string(),
|
|
783
|
+
output: "".to_string(),
|
|
784
|
+
},
|
|
785
|
+
CallableType::Agent,
|
|
786
|
+
)
|
|
787
|
+
.with_tags(vec!["analysis".to_string()])
|
|
788
|
+
.with_cost_tier(CostTier::High),
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
// Query by tag
|
|
792
|
+
let result = invoker.discover(DiscoveryQuery {
|
|
793
|
+
tags: Some(vec!["research".to_string()]),
|
|
794
|
+
..Default::default()
|
|
795
|
+
});
|
|
796
|
+
assert_eq!(result.callables.len(), 1);
|
|
797
|
+
assert_eq!(result.callables[0].name, "research-agent");
|
|
798
|
+
|
|
799
|
+
// Query by cost tier
|
|
800
|
+
let result = invoker.discover(DiscoveryQuery {
|
|
801
|
+
max_cost_tier: Some(CostTier::Medium),
|
|
802
|
+
..Default::default()
|
|
803
|
+
});
|
|
804
|
+
assert_eq!(result.callables.len(), 1);
|
|
805
|
+
|
|
806
|
+
// Query all
|
|
807
|
+
let result = invoker.discover(DiscoveryQuery::default());
|
|
808
|
+
assert_eq!(result.total_count, 2);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
#[test]
|
|
812
|
+
fn test_cost_tier_comparison() {
|
|
813
|
+
assert!(is_cost_tier_within(&CostTier::Free, &CostTier::High));
|
|
814
|
+
assert!(is_cost_tier_within(&CostTier::Medium, &CostTier::Medium));
|
|
815
|
+
assert!(!is_cost_tier_within(&CostTier::High, &CostTier::Low));
|
|
816
|
+
}
|
|
817
|
+
}
|