@neurocode-ai/core 1.18.8
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/bin/neurocode +199 -0
- package/bunfig.toml +2 -0
- package/drizzle.config.ts +10 -0
- package/package.json +131 -0
- package/schema.json +2071 -0
- package/script/fix-node-pty.ts +28 -0
- package/script/migration.ts +196 -0
- package/src/account/sql.ts +39 -0
- package/src/account.ts +101 -0
- package/src/agent.ts +111 -0
- package/src/aisdk.ts +235 -0
- package/src/background-job.ts +365 -0
- package/src/catalog.ts +301 -0
- package/src/command.ts +64 -0
- package/src/config/agent.ts +25 -0
- package/src/config/attachments.ts +15 -0
- package/src/config/command.ts +12 -0
- package/src/config/compaction.ts +15 -0
- package/src/config/experimental.ts +18 -0
- package/src/config/formatter.ts +12 -0
- package/src/config/lsp.ts +18 -0
- package/src/config/markdown.ts +36 -0
- package/src/config/mcp.ts +48 -0
- package/src/config/plugin/agent.ts +179 -0
- package/src/config/plugin/command.ts +83 -0
- package/src/config/plugin/external.ts +91 -0
- package/src/config/plugin/provider.ts +113 -0
- package/src/config/plugin/reference.ts +70 -0
- package/src/config/plugin/skill.ts +50 -0
- package/src/config/plugin.ts +13 -0
- package/src/config/provider.ts +71 -0
- package/src/config/reference.ts +22 -0
- package/src/config/tool-output.ts +9 -0
- package/src/config/watcher.ts +7 -0
- package/src/config.ts +227 -0
- package/src/control-plane/move-session.ts +148 -0
- package/src/control-plane/workspace.sql.ts +20 -0
- package/src/credential/sql.ts +14 -0
- package/src/credential.ts +138 -0
- package/src/cross-spawn-spawner.ts +507 -0
- package/src/data-migration.sql.ts +6 -0
- package/src/database/database.ts +57 -0
- package/src/database/migration/20260127222353_familiar_lady_ursula.ts +107 -0
- package/src/database/migration/20260211171708_add_project_commands.ts +11 -0
- package/src/database/migration/20260213144116_wakeful_the_professor.ts +23 -0
- package/src/database/migration/20260225215848_workspace.ts +19 -0
- package/src/database/migration/20260227213759_add_session_workspace_id.ts +12 -0
- package/src/database/migration/20260228203230_blue_harpoon.ts +30 -0
- package/src/database/migration/20260303231226_add_workspace_fields.ts +15 -0
- package/src/database/migration/20260309230000_move_org_to_state.ts +15 -0
- package/src/database/migration/20260312043431_session_message_cursor.ts +16 -0
- package/src/database/migration/20260323234822_events.ts +26 -0
- package/src/database/migration/20260410174513_workspace-name.ts +29 -0
- package/src/database/migration/20260413175956_chief_energizer.ts +24 -0
- package/src/database/migration/20260423070820_add_icon_url_override.ts +14 -0
- package/src/database/migration/20260427172553_slow_nightmare.ts +30 -0
- package/src/database/migration/20260428004200_add_session_path.ts +11 -0
- package/src/database/migration/20260501142318_next_venus.ts +12 -0
- package/src/database/migration/20260504145000_add_sync_owner.ts +11 -0
- package/src/database/migration/20260507164347_add_workspace_time.ts +11 -0
- package/src/database/migration/20260510033149_session_usage.ts +56 -0
- package/src/database/migration/20260511000411_data_migration_state.ts +16 -0
- package/src/database/migration/20260511173437_session-metadata.ts +16 -0
- package/src/database/migration/20260601010001_normalize_storage_paths.ts +22 -0
- package/src/database/migration/20260601202201_amazing_prowler.ts +11 -0
- package/src/database/migration/20260602002951_lowly_union_jack.ts +24 -0
- package/src/database/migration/20260602182828_add_project_directories.ts +20 -0
- package/src/database/migration/20260603001617_session_message_projection_indexes.ts +19 -0
- package/src/database/migration/20260603040000_session_message_projection_order.ts +19 -0
- package/src/database/migration/20260603141458_session_input_inbox.ts +25 -0
- package/src/database/migration/20260603160727_jittery_ezekiel_stane.ts +20 -0
- package/src/database/migration/20260604172448_event_sourced_session_input.ts +47 -0
- package/src/database/migration/20260605003541_add_session_context_snapshot.ts +21 -0
- package/src/database/migration/20260605042240_add_context_epoch_agent.ts +11 -0
- package/src/database/migration/20260611035744_credential.ts +25 -0
- package/src/database/migration/20260611192811_lush_chimera.ts +25 -0
- package/src/database/migration/20260612174303_project_dir_strategy.ts +29 -0
- package/src/database/migration/20260622142730_simplify_session_context_epoch.ts +13 -0
- package/src/database/migration/20260622170816_reset_v2_session_state.ts +17 -0
- package/src/database/migration/20260622202450_simplify_session_input.ts +17 -0
- package/src/database/migration.gen.ts +44 -0
- package/src/database/migration.ts +81 -0
- package/src/database/path.ts +91 -0
- package/src/database/schema.gen.ts +274 -0
- package/src/database/schema.sql.ts +10 -0
- package/src/database/sqlite.bun.ts +183 -0
- package/src/database/sqlite.node.ts +178 -0
- package/src/database/sqlite.ts +8 -0
- package/src/effect/app-node-builder.ts +23 -0
- package/src/effect/app-node-platform.ts +18 -0
- package/src/effect/app-node.ts +14 -0
- package/src/effect/dfdf +1 -0
- package/src/effect/keyed-mutex.ts +45 -0
- package/src/effect/layer-node.ts +333 -0
- package/src/effect/memo-map.ts +3 -0
- package/src/effect/runtime.ts +21 -0
- package/src/effect/service-use.ts +43 -0
- package/src/event/sql.ts +25 -0
- package/src/event.ts +638 -0
- package/src/file-mutation.ts +207 -0
- package/src/file.ts +6 -0
- package/src/filesystem/fff.bun.ts +140 -0
- package/src/filesystem/fff.node.ts +138 -0
- package/src/filesystem/ignore.ts +67 -0
- package/src/filesystem/protected.ts +53 -0
- package/src/filesystem/search.ts +239 -0
- package/src/filesystem/watcher.ts +140 -0
- package/src/filesystem.ts +118 -0
- package/src/flag/flag.ts +78 -0
- package/src/fs-util.ts +274 -0
- package/src/git.ts +987 -0
- package/src/github-copilot/README.md +5 -0
- package/src/github-copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
- package/src/github-copilot/chat/get-response-metadata.ts +15 -0
- package/src/github-copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
- package/src/github-copilot/chat/openai-compatible-api-types.ts +64 -0
- package/src/github-copilot/chat/openai-compatible-chat-language-model.ts +815 -0
- package/src/github-copilot/chat/openai-compatible-chat-options.ts +28 -0
- package/src/github-copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
- package/src/github-copilot/chat/openai-compatible-prepare-tools.ts +83 -0
- package/src/github-copilot/copilot-provider.ts +100 -0
- package/src/github-copilot/openai-compatible-error.ts +27 -0
- package/src/github-copilot/responses/convert-to-openai-responses-input.ts +335 -0
- package/src/github-copilot/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/github-copilot/responses/openai-config.ts +18 -0
- package/src/github-copilot/responses/openai-error.ts +22 -0
- package/src/github-copilot/responses/openai-responses-api-types.ts +214 -0
- package/src/github-copilot/responses/openai-responses-language-model.ts +1770 -0
- package/src/github-copilot/responses/openai-responses-prepare-tools.ts +173 -0
- package/src/github-copilot/responses/openai-responses-settings.ts +1 -0
- package/src/github-copilot/responses/tool/code-interpreter.ts +87 -0
- package/src/github-copilot/responses/tool/file-search.ts +127 -0
- package/src/github-copilot/responses/tool/image-generation.ts +114 -0
- package/src/github-copilot/responses/tool/local-shell.ts +64 -0
- package/src/github-copilot/responses/tool/web-search-preview.ts +103 -0
- package/src/github-copilot/responses/tool/web-search.ts +102 -0
- package/src/global.ts +87 -0
- package/src/id/id.ts +47 -0
- package/src/image/photon.ts +94 -0
- package/src/image.ts +81 -0
- package/src/installation/version.ts +8 -0
- package/src/instruction-context.ts +101 -0
- package/src/integration/connection.ts +12 -0
- package/src/integration.ts +520 -0
- package/src/location-mutation.ts +162 -0
- package/src/location-service-map.ts +18 -0
- package/src/location-services.ts +115 -0
- package/src/location.ts +39 -0
- package/src/markdown.d.ts +4 -0
- package/src/model.ts +41 -0
- package/src/models-dev.ts +260 -0
- package/src/npm-config.ts +40 -0
- package/src/npm.ts +269 -0
- package/src/oauth/page.ts +276 -0
- package/src/observability/logging.ts +71 -0
- package/src/observability/otlp.ts +79 -0
- package/src/observability/shared.ts +1 -0
- package/src/observability.ts +24 -0
- package/src/patch.ts +197 -0
- package/src/permission/saved.ts +79 -0
- package/src/permission/sql.ts +20 -0
- package/src/permission.ts +310 -0
- package/src/plugin/agent.ts +206 -0
- package/src/plugin/command/initialize.txt +65 -0
- package/src/plugin/command/review.txt +100 -0
- package/src/plugin/command.ts +25 -0
- package/src/plugin/host.ts +219 -0
- package/src/plugin/internal.ts +153 -0
- package/src/plugin/layer-map.example.ts +94 -0
- package/src/plugin/models-dev.ts +183 -0
- package/src/plugin/promise.ts +93 -0
- package/src/plugin/provider/alibaba.ts +15 -0
- package/src/plugin/provider/amazon-bedrock.ts +126 -0
- package/src/plugin/provider/anthropic.ts +27 -0
- package/src/plugin/provider/azure.ts +82 -0
- package/src/plugin/provider/cerebras.ts +26 -0
- package/src/plugin/provider/cloudflare-ai-gateway.ts +81 -0
- package/src/plugin/provider/cloudflare-workers-ai.ts +81 -0
- package/src/plugin/provider/cohere.ts +15 -0
- package/src/plugin/provider/deepinfra.ts +15 -0
- package/src/plugin/provider/dynamic.ts +31 -0
- package/src/plugin/provider/gateway.ts +15 -0
- package/src/plugin/provider/github-copilot.ts +52 -0
- package/src/plugin/provider/gitlab.ts +65 -0
- package/src/plugin/provider/google-vertex.ts +173 -0
- package/src/plugin/provider/google.ts +15 -0
- package/src/plugin/provider/groq.ts +15 -0
- package/src/plugin/provider/kilo.ts +21 -0
- package/src/plugin/provider/llmgateway.ts +26 -0
- package/src/plugin/provider/mistral.ts +15 -0
- package/src/plugin/provider/nvidia.ts +22 -0
- package/src/plugin/provider/openai-compatible.ts +17 -0
- package/src/plugin/provider/openai.ts +292 -0
- package/src/plugin/provider/opencode.ts +311 -0
- package/src/plugin/provider/openrouter.ts +36 -0
- package/src/plugin/provider/perplexity.ts +15 -0
- package/src/plugin/provider/sap-ai-core.ts +46 -0
- package/src/plugin/provider/snowflake-cortex.ts +89 -0
- package/src/plugin/provider/togetherai.ts +15 -0
- package/src/plugin/provider/venice.ts +15 -0
- package/src/plugin/provider/vercel.ts +27 -0
- package/src/plugin/provider/xai.ts +22 -0
- package/src/plugin/provider/zenmux.ts +21 -0
- package/src/plugin/provider.ts +71 -0
- package/src/plugin/skill/customize-neurocode.md +452 -0
- package/src/plugin/skill.ts +31 -0
- package/src/plugin/variant.ts +39 -0
- package/src/plugin.ts +167 -0
- package/src/policy.ts +49 -0
- package/src/process.ts +261 -0
- package/src/project/copy-strategies.ts +35 -0
- package/src/project/copy.ts +292 -0
- package/src/project/directories.ts +158 -0
- package/src/project/schema.ts +16 -0
- package/src/project/sql.ts +35 -0
- package/src/project.ts +136 -0
- package/src/provider.ts +25 -0
- package/src/pty/protocol.ts +37 -0
- package/src/pty/pty.bun.ts +26 -0
- package/src/pty/pty.node.ts +29 -0
- package/src/pty/pty.ts +25 -0
- package/src/pty/schema.ts +1 -0
- package/src/pty/ticket.ts +56 -0
- package/src/pty.ts +318 -0
- package/src/public-event-manifest.ts +7 -0
- package/src/question.ts +153 -0
- package/src/reference/guidance.ts +69 -0
- package/src/reference.ts +125 -0
- package/src/repository-cache.ts +259 -0
- package/src/repository.ts +214 -0
- package/src/ripgrep/binary.ts +132 -0
- package/src/ripgrep.ts +281 -0
- package/src/schema.ts +79 -0
- package/src/session/compaction.ts +241 -0
- package/src/session/context-epoch.ts +174 -0
- package/src/session/error.ts +24 -0
- package/src/session/event.ts +2 -0
- package/src/session/execution/local.ts +46 -0
- package/src/session/execution.ts +34 -0
- package/src/session/history.ts +101 -0
- package/src/session/info.ts +50 -0
- package/src/session/input.ts +288 -0
- package/src/session/message-updater.ts +397 -0
- package/src/session/message.ts +2 -0
- package/src/session/projector.ts +458 -0
- package/src/session/prompt.ts +1 -0
- package/src/session/revert.ts +121 -0
- package/src/session/run-coordinator.ts +104 -0
- package/src/session/runner/index.ts +28 -0
- package/src/session/runner/llm.ts +432 -0
- package/src/session/runner/max-steps.ts +16 -0
- package/src/session/runner/model.ts +218 -0
- package/src/session/runner/publish-llm-event.ts +423 -0
- package/src/session/runner/to-llm-message.ts +171 -0
- package/src/session/schema.ts +9 -0
- package/src/session/sql.ts +176 -0
- package/src/session/store.ts +63 -0
- package/src/session/todo.ts +78 -0
- package/src/session.ts +486 -0
- package/src/share/sql.ts +13 -0
- package/src/shell.ts +226 -0
- package/src/skill/discovery.ts +213 -0
- package/src/skill/guidance.ts +76 -0
- package/src/skill.ts +132 -0
- package/src/snapshot.ts +266 -0
- package/src/state.ts +128 -0
- package/src/system-context/builtins.ts +50 -0
- package/src/system-context/index.ts +320 -0
- package/src/system-context/registry.ts +49 -0
- package/src/tool/AGENTS.md +59 -0
- package/src/tool/application-tools.ts +57 -0
- package/src/tool/apply-patch.ts +219 -0
- package/src/tool/bash.ts +207 -0
- package/src/tool/builtins.ts +48 -0
- package/src/tool/edit.ts +223 -0
- package/src/tool/glob.ts +105 -0
- package/src/tool/grep.ts +137 -0
- package/src/tool/http-body.ts +30 -0
- package/src/tool/question.ts +94 -0
- package/src/tool/read-filesystem.ts +366 -0
- package/src/tool/read.ts +117 -0
- package/src/tool/registry.ts +147 -0
- package/src/tool/skill.ts +109 -0
- package/src/tool/todowrite.ts +62 -0
- package/src/tool/tool.ts +162 -0
- package/src/tool/tools.ts +13 -0
- package/src/tool/webfetch.ts +218 -0
- package/src/tool/websearch.ts +260 -0
- package/src/tool/write.ts +101 -0
- package/src/tool-output-store.ts +211 -0
- package/src/util/array.ts +10 -0
- package/src/util/binary.ts +41 -0
- package/src/util/effect-flock.ts +284 -0
- package/src/util/encode.ts +51 -0
- package/src/util/error.ts +70 -0
- package/src/util/flock.ts +358 -0
- package/src/util/glob.ts +34 -0
- package/src/util/hash.ts +11 -0
- package/src/util/identifier.ts +1 -0
- package/src/util/iife.ts +3 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/module.ts +10 -0
- package/src/util/path.ts +37 -0
- package/src/util/retry.ts +42 -0
- package/src/util/slug.ts +74 -0
- package/src/util/token.ts +5 -0
- package/src/util/which.ts +14 -0
- package/src/util/wildcard.ts +14 -0
- package/src/v1/config/agent.ts +89 -0
- package/src/v1/config/attachment.ts +25 -0
- package/src/v1/config/command.ts +13 -0
- package/src/v1/config/config.ts +192 -0
- package/src/v1/config/console-state.ts +16 -0
- package/src/v1/config/error.ts +39 -0
- package/src/v1/config/formatter.ts +13 -0
- package/src/v1/config/layout.ts +6 -0
- package/src/v1/config/lsp.ts +80 -0
- package/src/v1/config/mcp.ts +63 -0
- package/src/v1/config/migrate.ts +254 -0
- package/src/v1/config/permission.ts +50 -0
- package/src/v1/config/plugin.ts +9 -0
- package/src/v1/config/provider-options.ts +227 -0
- package/src/v1/config/provider.ts +121 -0
- package/src/v1/config/server.ts +19 -0
- package/src/v1/config/skills.ts +13 -0
- package/src/v1/permission.ts +33 -0
- package/src/v1/session.ts +68 -0
- package/src/v2-schema.ts +3 -0
- package/src/workspace.ts +6 -0
- package/sst-env.d.ts +10 -0
- package/test/agent.test.ts +131 -0
- package/test/application-tools.test.ts +287 -0
- package/test/background-job.test.ts +106 -0
- package/test/catalog.test.ts +353 -0
- package/test/command.test.ts +56 -0
- package/test/config/agent.test.ts +349 -0
- package/test/config/command.test.ts +83 -0
- package/test/config/config.test.ts +798 -0
- package/test/config/fixtures/plugin/directory-plugin.ts +13 -0
- package/test/config/plugin.test.ts +248 -0
- package/test/config/provider-options.test.ts +224 -0
- package/test/config/provider.test.ts +269 -0
- package/test/config/skill.test.ts +80 -0
- package/test/credential.test.ts +36 -0
- package/test/database-migration.test.ts +644 -0
- package/test/effect/cross-spawn-spawner.test.ts +426 -0
- package/test/effect/keyed-mutex.test.ts +73 -0
- package/test/effect/layer-node/layer-node-types.test.ts +143 -0
- package/test/effect/layer-node/layer-node.test.ts +261 -0
- package/test/effect/layer-node/node-build.test.ts +125 -0
- package/test/effect/observability.test.ts +109 -0
- package/test/event.test.ts +1124 -0
- package/test/file-mutation.test.ts +368 -0
- package/test/filesystem/filesystem.test.ts +387 -0
- package/test/filesystem/ignore.test.ts +10 -0
- package/test/filesystem/search.test.ts +44 -0
- package/test/filesystem/watcher.test.ts +266 -0
- package/test/fixture/effect-flock-worker.ts +60 -0
- package/test/fixture/flock-worker.ts +72 -0
- package/test/fixture/git.ts +49 -0
- package/test/fixture/location.ts +26 -0
- package/test/fixture/tmpdir.ts +25 -0
- package/test/fixtures/recordings/session-runner/openai-chat-streams-text.json +27 -0
- package/test/git.test.ts +164 -0
- package/test/github-copilot/convert-to-copilot-messages.test.ts +523 -0
- package/test/github-copilot/copilot-chat-model.test.ts +592 -0
- package/test/github-copilot/openai-responses-language-model.test.ts +206 -0
- package/test/global.test.ts +16 -0
- package/test/instruction-context.test.ts +323 -0
- package/test/integration.test.ts +349 -0
- package/test/legacy-event-schema.test.ts +16 -0
- package/test/lib/effect.ts +53 -0
- package/test/lib/tool.ts +20 -0
- package/test/location-filesystem.test.ts +69 -0
- package/test/location-layer.test.ts +226 -0
- package/test/location-mutation.test.ts +178 -0
- package/test/location.test.ts +42 -0
- package/test/model.test.ts +23 -0
- package/test/models.test.ts +290 -0
- package/test/move-session.test.ts +235 -0
- package/test/npm-config.test.ts +51 -0
- package/test/npm.test.ts +84 -0
- package/test/oauth-page.test.ts +15 -0
- package/test/patch.test.ts +68 -0
- package/test/permission.test.ts +315 -0
- package/test/plugin/command.test.ts +47 -0
- package/test/plugin/fixture.ts +52 -0
- package/test/plugin/fixtures/config-effect-plugin.ts +15 -0
- package/test/plugin/fixtures/config-promise-plugin.ts +13 -0
- package/test/plugin/fixtures/invalid-plugin.ts +1 -0
- package/test/plugin/fixtures/models-dev.json +14 -0
- package/test/plugin/fixtures/provider-factory.ts +9 -0
- package/test/plugin/host.ts +303 -0
- package/test/plugin/models-dev.test.ts +170 -0
- package/test/plugin/promise.test.ts +67 -0
- package/test/plugin/provider-alibaba.test.ts +92 -0
- package/test/plugin/provider-amazon-bedrock.test.ts +622 -0
- package/test/plugin/provider-anthropic.test.ts +94 -0
- package/test/plugin/provider-azure-cognitive-services.test.ts +199 -0
- package/test/plugin/provider-azure.test.ts +293 -0
- package/test/plugin/provider-cerebras.test.ts +136 -0
- package/test/plugin/provider-cloudflare-ai-gateway.test.ts +426 -0
- package/test/plugin/provider-cloudflare-workers-ai.test.ts +279 -0
- package/test/plugin/provider-cohere.test.ts +123 -0
- package/test/plugin/provider-deepinfra.test.ts +159 -0
- package/test/plugin/provider-dynamic.test.ts +184 -0
- package/test/plugin/provider-gateway.test.ts +115 -0
- package/test/plugin/provider-github-copilot.test.ts +278 -0
- package/test/plugin/provider-gitlab.test.ts +308 -0
- package/test/plugin/provider-google-vertex-anthropic.test.ts +264 -0
- package/test/plugin/provider-google-vertex.test.ts +387 -0
- package/test/plugin/provider-google.test.ts +80 -0
- package/test/plugin/provider-groq.test.ts +121 -0
- package/test/plugin/provider-kilo.test.ts +99 -0
- package/test/plugin/provider-llmgateway.test.ts +80 -0
- package/test/plugin/provider-mistral.test.ts +129 -0
- package/test/plugin/provider-nvidia.test.ts +97 -0
- package/test/plugin/provider-openai-compatible.test.ts +107 -0
- package/test/plugin/provider-openai.test.ts +176 -0
- package/test/plugin/provider-opencode.test.ts +423 -0
- package/test/plugin/provider-openrouter.test.ts +113 -0
- package/test/plugin/provider-perplexity.test.ts +122 -0
- package/test/plugin/provider-sap-ai-core.test.ts +159 -0
- package/test/plugin/provider-snowflake-cortex.test.ts +261 -0
- package/test/plugin/provider-togetherai.test.ts +129 -0
- package/test/plugin/provider-venice.test.ts +115 -0
- package/test/plugin/provider-vercel.test.ts +83 -0
- package/test/plugin/provider-xai.test.ts +125 -0
- package/test/plugin/provider-zenmux.test.ts +110 -0
- package/test/plugin/skill.test.ts +25 -0
- package/test/plugin/variant.test.ts +67 -0
- package/test/plugin.test.ts +71 -0
- package/test/policy.test.ts +85 -0
- package/test/preload.ts +5 -0
- package/test/process/process.test.ts +368 -0
- package/test/project-copy.test.ts +400 -0
- package/test/project-directories.test.ts +61 -0
- package/test/project.test.ts +221 -0
- package/test/provider-mistral.test.ts +282 -0
- package/test/provider-xai-responses.test.ts +32 -0
- package/test/pty/info-schema.test.ts +32 -0
- package/test/pty/protocol.test.ts +27 -0
- package/test/pty/pty-session.test.ts +240 -0
- package/test/pty/ticket.test.ts +62 -0
- package/test/question.test.ts +114 -0
- package/test/reference-guidance.test.ts +76 -0
- package/test/reference.test.ts +78 -0
- package/test/repository-cache.test.ts +153 -0
- package/test/repository.test.ts +71 -0
- package/test/ripgrep.test.ts +65 -0
- package/test/session-compaction.test.ts +27 -0
- package/test/session-create.test.ts +425 -0
- package/test/session-history.test.ts +165 -0
- package/test/session-projector.test.ts +533 -0
- package/test/session-prompt.test.ts +584 -0
- package/test/session-run-coordinator.test.ts +418 -0
- package/test/session-runner-message.test.ts +501 -0
- package/test/session-runner-model.test.ts +347 -0
- package/test/session-runner-recorded.test.ts +193 -0
- package/test/session-runner-tool-events.test.ts +136 -0
- package/test/session-runner-tool-registry.test.ts +452 -0
- package/test/session-runner.test.ts +3365 -0
- package/test/session-todo.test.ts +94 -0
- package/test/session-tool-progress.test.ts +158 -0
- package/test/shared-schema.test.ts +206 -0
- package/test/shell.test.ts +108 -0
- package/test/skill/guidance.test.ts +144 -0
- package/test/skill-discovery.test.ts +165 -0
- package/test/skill.test.ts +125 -0
- package/test/snapshot.test.ts +178 -0
- package/test/state.test.ts +115 -0
- package/test/system-context/builtins.test.ts +129 -0
- package/test/system-context/index.test.ts +307 -0
- package/test/system-context/registry.test.ts +114 -0
- package/test/tool-apply-patch.test.ts +436 -0
- package/test/tool-bash.test.ts +437 -0
- package/test/tool-edit.test.ts +434 -0
- package/test/tool-output-store.test.ts +247 -0
- package/test/tool-question.test.ts +162 -0
- package/test/tool-read-filesystem.test.ts +118 -0
- package/test/tool-read.test.ts +674 -0
- package/test/tool-skill.test.ts +149 -0
- package/test/tool-todowrite.test.ts +125 -0
- package/test/tool-webfetch.test.ts +281 -0
- package/test/tool-websearch.test.ts +316 -0
- package/test/tool-write.test.ts +305 -0
- package/test/util/effect-flock.test.ts +392 -0
- package/test/util/flock.test.ts +428 -0
- package/test/util/which.test.ts +100 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
export * as SystemContext from "./index"
|
|
2
|
+
|
|
3
|
+
import { Effect, Option, Schema } from "effect"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Models privileged system context as independently refreshable typed sources.
|
|
7
|
+
*
|
|
8
|
+
* `Source<A>` describes how to observe, compare, and render one value. `make`
|
|
9
|
+
* closes over `A`, producing an opaque `SystemContext` that composes uniformly
|
|
10
|
+
* with contexts built from other value types. Interpreters observe the composed
|
|
11
|
+
* context once, then produce a durable structured
|
|
12
|
+
* `Snapshot` alongside the exact model-visible baseline or update text.
|
|
13
|
+
*
|
|
14
|
+
* Returning `unavailable` means observation failed temporarily. It differs from
|
|
15
|
+
* removing a source from the context: refresh preserves the admitted snapshot,
|
|
16
|
+
* and replacement waits rather than silently constructing an incomplete baseline.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Stable namespaced identity for one independently refreshable context source. */
|
|
22
|
+
export const Key = Schema.String.check(Schema.isPattern(/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._/-]*$/)).pipe(
|
|
23
|
+
Schema.brand("SystemContext.Key"),
|
|
24
|
+
)
|
|
25
|
+
export type Key = typeof Key.Type
|
|
26
|
+
|
|
27
|
+
/** Indicates that a source could not be observed without treating it as removed. */
|
|
28
|
+
export const unavailable = Symbol.for("@neurocode/SystemContext.Unavailable")
|
|
29
|
+
export type Unavailable = typeof unavailable
|
|
30
|
+
|
|
31
|
+
/** Defines one typed source before its value type is hidden by `make`. */
|
|
32
|
+
export interface Source<A> {
|
|
33
|
+
readonly key: Key
|
|
34
|
+
readonly codec: Schema.Codec<A, Schema.Json, never, never>
|
|
35
|
+
readonly load: Effect.Effect<A | Unavailable>
|
|
36
|
+
readonly baseline: (current: A) => string
|
|
37
|
+
readonly update: (previous: A, current: A) => string
|
|
38
|
+
readonly removed?: (previous: A) => string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ContextTypeId: unique symbol = Symbol.for("@neurocode/SystemContext")
|
|
42
|
+
|
|
43
|
+
/** Opaque carrier for composable system context sources. */
|
|
44
|
+
export interface SystemContext {
|
|
45
|
+
readonly [ContextTypeId]: ReadonlyArray<PackedSource>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Durable comparison state for one admitted source. */
|
|
49
|
+
export const SourceSnapshot = Schema.Struct({
|
|
50
|
+
value: Schema.Json,
|
|
51
|
+
removed: Schema.optional(Schema.NonEmptyString),
|
|
52
|
+
})
|
|
53
|
+
export type SourceSnapshot = typeof SourceSnapshot.Type
|
|
54
|
+
|
|
55
|
+
/** Durable structured comparison state for one active context generation. */
|
|
56
|
+
export const Snapshot = Schema.Record(Key, SourceSnapshot)
|
|
57
|
+
export type Snapshot = Readonly<Record<string, SourceSnapshot>>
|
|
58
|
+
|
|
59
|
+
export interface Generation {
|
|
60
|
+
readonly baseline: string
|
|
61
|
+
readonly snapshot: Snapshot
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface Updated {
|
|
65
|
+
readonly _tag: "Updated"
|
|
66
|
+
readonly text: string
|
|
67
|
+
readonly snapshot: Snapshot
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ReplacementReady {
|
|
71
|
+
readonly _tag: "ReplacementReady"
|
|
72
|
+
readonly generation: Generation
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ReplacementBlocked {
|
|
76
|
+
readonly _tag: "ReplacementBlocked"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type ReplacementResult = ReplacementReady | ReplacementBlocked
|
|
80
|
+
export type ReconcileResult = { readonly _tag: "Unchanged" } | Updated | ReplacementResult
|
|
81
|
+
|
|
82
|
+
export class InitializationBlocked extends Schema.TaggedErrorClass<InitializationBlocked>()(
|
|
83
|
+
"SystemContext.InitializationBlocked",
|
|
84
|
+
{ keys: Schema.Array(Key) },
|
|
85
|
+
) {
|
|
86
|
+
override get message() {
|
|
87
|
+
return `System context initialization blocked by unavailable sources: ${this.keys.join(", ")}`
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class DuplicateKeyError extends Schema.TaggedErrorClass<DuplicateKeyError>()("SystemContext.DuplicateKeyError", {
|
|
92
|
+
key: Key,
|
|
93
|
+
}) {
|
|
94
|
+
override get message() {
|
|
95
|
+
return `Duplicate system context key: ${this.key}`
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface PackedSource {
|
|
100
|
+
readonly key: Key
|
|
101
|
+
readonly load: Effect.Effect<Loaded | Unavailable>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface Loaded {
|
|
105
|
+
readonly baseline: () => Rendered
|
|
106
|
+
readonly compare: (previous: Schema.Json) => Compared
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface Rendered {
|
|
110
|
+
readonly text: string
|
|
111
|
+
readonly snapshot: SourceSnapshot
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type Compared =
|
|
115
|
+
| { readonly _tag: "Incompatible" }
|
|
116
|
+
| { readonly _tag: "Unchanged" }
|
|
117
|
+
| { readonly _tag: "Updated"; readonly render: () => Rendered }
|
|
118
|
+
|
|
119
|
+
interface AvailableEntry extends Loaded {
|
|
120
|
+
readonly _tag: "Available"
|
|
121
|
+
readonly key: Key
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface UnavailableEntry {
|
|
125
|
+
readonly _tag: "Unavailable"
|
|
126
|
+
readonly key: Key
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
type Entry = AvailableEntry | UnavailableEntry
|
|
130
|
+
|
|
131
|
+
/** The identity context. */
|
|
132
|
+
export const empty = context([])
|
|
133
|
+
|
|
134
|
+
/** Closes a typed source into a context that composes with differently typed sources. */
|
|
135
|
+
export function make<A>(source: Source<A>): SystemContext {
|
|
136
|
+
const decode = Schema.decodeUnknownOption(source.codec)
|
|
137
|
+
const encode = Schema.encodeSync(source.codec)
|
|
138
|
+
const equivalent = Schema.toEquivalence(source.codec)
|
|
139
|
+
return context([
|
|
140
|
+
{
|
|
141
|
+
key: source.key,
|
|
142
|
+
load: source.load.pipe(
|
|
143
|
+
Effect.map((value) => {
|
|
144
|
+
if (isUnavailable(value)) return value
|
|
145
|
+
const snapshot = (): SourceSnapshot => ({
|
|
146
|
+
value: encode(value),
|
|
147
|
+
...(source.removed ? { removed: requireText(source.key, "removal", source.removed(value)) } : {}),
|
|
148
|
+
})
|
|
149
|
+
return {
|
|
150
|
+
baseline: (): Rendered => ({
|
|
151
|
+
text: requireText(source.key, "baseline", source.baseline(value)),
|
|
152
|
+
snapshot: snapshot(),
|
|
153
|
+
}),
|
|
154
|
+
compare: (previous): Compared =>
|
|
155
|
+
Option.match(decode(previous), {
|
|
156
|
+
onNone: (): Compared => ({ _tag: "Incompatible" }),
|
|
157
|
+
onSome: (decoded): Compared =>
|
|
158
|
+
equivalent(decoded, value)
|
|
159
|
+
? { _tag: "Unchanged" }
|
|
160
|
+
: {
|
|
161
|
+
_tag: "Updated",
|
|
162
|
+
render: () => ({
|
|
163
|
+
text: requireText(source.key, "update", source.update(decoded, value)),
|
|
164
|
+
snapshot: snapshot(),
|
|
165
|
+
}),
|
|
166
|
+
},
|
|
167
|
+
}),
|
|
168
|
+
}
|
|
169
|
+
}),
|
|
170
|
+
),
|
|
171
|
+
},
|
|
172
|
+
])
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Combines contexts in order and rejects duplicate source keys immediately. */
|
|
176
|
+
export function combine(values: ReadonlyArray<SystemContext>): SystemContext {
|
|
177
|
+
const sources = values.flatMap((value) => value[ContextTypeId])
|
|
178
|
+
assertUniqueKeys(sources)
|
|
179
|
+
return context(sources)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const observe = (value: SystemContext) =>
|
|
183
|
+
Effect.forEach(
|
|
184
|
+
value[ContextTypeId],
|
|
185
|
+
(source) =>
|
|
186
|
+
source.load.pipe(
|
|
187
|
+
Effect.map(
|
|
188
|
+
(result): Entry =>
|
|
189
|
+
result === unavailable
|
|
190
|
+
? { _tag: "Unavailable", key: source.key }
|
|
191
|
+
: { _tag: "Available", key: source.key, ...result },
|
|
192
|
+
),
|
|
193
|
+
),
|
|
194
|
+
{ concurrency: "unbounded" },
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
/** Creates the immutable baseline and durable snapshot for a new generation. */
|
|
198
|
+
export function initialize(value: SystemContext): Effect.Effect<Generation, InitializationBlocked> {
|
|
199
|
+
return observe(value).pipe(
|
|
200
|
+
Effect.flatMap((entries) => {
|
|
201
|
+
const unavailable = entries.flatMap((entry) => (entry._tag === "Unavailable" ? [entry.key] : []))
|
|
202
|
+
if (unavailable.length > 0) return new InitializationBlocked({ keys: unavailable })
|
|
203
|
+
return Effect.succeed(initializeObservation(entries))
|
|
204
|
+
}),
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function initializeObservation(entries: ReadonlyArray<Entry>): Generation {
|
|
209
|
+
const available = entries.filter((entry): entry is AvailableEntry => entry._tag === "Available")
|
|
210
|
+
const rendered = available.map((entry) => [entry.key, entry.baseline()] as const)
|
|
211
|
+
return {
|
|
212
|
+
baseline: render(rendered.map(([, result]) => result.text)),
|
|
213
|
+
snapshot: Object.fromEntries(rendered.map(([key, result]) => [key, result.snapshot])),
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Reconciles current source values with one active generation. */
|
|
218
|
+
export function reconcile(value: SystemContext, previous: Snapshot): Effect.Effect<ReconcileResult> {
|
|
219
|
+
return observe(value).pipe(
|
|
220
|
+
Effect.map((entries): ReconcileResult => {
|
|
221
|
+
const result = reconcileObservation(entries, previous)
|
|
222
|
+
if (result._tag === "Unchanged" || result._tag === "Updated") return result
|
|
223
|
+
return replaceObservation(entries, previous)
|
|
224
|
+
}),
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function reconcileObservation(
|
|
229
|
+
entries: ReadonlyArray<Entry>,
|
|
230
|
+
previous: Snapshot,
|
|
231
|
+
): { readonly _tag: "Unchanged" } | Updated | { readonly _tag: "Replace" } {
|
|
232
|
+
const keys = new Set(entries.map((entry) => entry.key))
|
|
233
|
+
const comparisons = new Map<Key, Compared>()
|
|
234
|
+
for (const entry of entries) {
|
|
235
|
+
if (entry._tag === "Unavailable") continue
|
|
236
|
+
const stored = getSnapshot(previous, entry.key)
|
|
237
|
+
if (!stored) continue
|
|
238
|
+
const compared = entry.compare(stored.value)
|
|
239
|
+
if (compared._tag === "Incompatible") return { _tag: "Replace" }
|
|
240
|
+
comparisons.set(entry.key, compared)
|
|
241
|
+
}
|
|
242
|
+
for (const key of Object.keys(previous).sort()) {
|
|
243
|
+
if (keys.has(Key.make(key))) continue
|
|
244
|
+
if (previous[key].removed === undefined) return { _tag: "Replace" }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const snapshot: Record<string, SourceSnapshot> = {}
|
|
248
|
+
const updates: string[] = []
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
const stored = getSnapshot(previous, entry.key)
|
|
251
|
+
if (entry._tag === "Unavailable") {
|
|
252
|
+
if (stored) snapshot[entry.key] = stored
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
255
|
+
if (!stored) {
|
|
256
|
+
const rendered = entry.baseline()
|
|
257
|
+
updates.push(rendered.text)
|
|
258
|
+
snapshot[entry.key] = rendered.snapshot
|
|
259
|
+
continue
|
|
260
|
+
}
|
|
261
|
+
const compared = comparisons.get(entry.key)
|
|
262
|
+
if (!compared || compared._tag === "Incompatible")
|
|
263
|
+
throw new Error(`Missing comparison for system context source ${entry.key}`)
|
|
264
|
+
if (compared._tag === "Unchanged") {
|
|
265
|
+
snapshot[entry.key] = stored
|
|
266
|
+
continue
|
|
267
|
+
}
|
|
268
|
+
const rendered = compared.render()
|
|
269
|
+
updates.push(rendered.text)
|
|
270
|
+
snapshot[entry.key] = rendered.snapshot
|
|
271
|
+
}
|
|
272
|
+
for (const key of Object.keys(previous).sort()) {
|
|
273
|
+
if (keys.has(Key.make(key))) continue
|
|
274
|
+
const removed = previous[key].removed
|
|
275
|
+
if (removed === undefined) throw new Error(`Missing removal rendering for system context source ${key}`)
|
|
276
|
+
updates.push(removed)
|
|
277
|
+
}
|
|
278
|
+
if (updates.length === 0) return { _tag: "Unchanged" }
|
|
279
|
+
return { _tag: "Updated", text: render(updates), snapshot }
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Creates a complete replacement generation or blocks while admitted context is unavailable. */
|
|
283
|
+
export function replace(value: SystemContext, previous: Snapshot): Effect.Effect<ReplacementResult> {
|
|
284
|
+
return observe(value).pipe(Effect.map((entries) => replaceObservation(entries, previous)))
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function replaceObservation(entries: ReadonlyArray<Entry>, previous: Snapshot): ReplacementResult {
|
|
288
|
+
if (entries.some((entry) => entry._tag === "Unavailable" && getSnapshot(previous, entry.key) !== undefined))
|
|
289
|
+
return { _tag: "ReplacementBlocked" }
|
|
290
|
+
return { _tag: "ReplacementReady", generation: initializeObservation(entries) }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function context(sources: ReadonlyArray<PackedSource>): SystemContext {
|
|
294
|
+
return { [ContextTypeId]: sources }
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function render(parts: ReadonlyArray<string>) {
|
|
298
|
+
return parts.join("\n\n")
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getSnapshot(snapshot: Snapshot, key: Key) {
|
|
302
|
+
return Object.hasOwn(snapshot, key) ? snapshot[key] : undefined
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isUnavailable(value: unknown): value is Unavailable {
|
|
306
|
+
return value === unavailable
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function requireText(key: Key, kind: string, text: string) {
|
|
310
|
+
if (text.length === 0) throw new Error(`System context source ${key} rendered an empty ${kind}`)
|
|
311
|
+
return text
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function assertUniqueKeys(sources: ReadonlyArray<PackedSource>) {
|
|
315
|
+
const keys = new Set<Key>()
|
|
316
|
+
for (const source of sources) {
|
|
317
|
+
if (keys.has(source.key)) throw new DuplicateKeyError({ key: source.key })
|
|
318
|
+
keys.add(source.key)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export * as SystemContextRegistry from "./registry"
|
|
2
|
+
|
|
3
|
+
import { Context, Effect, Layer, Ref, Scope } from "effect"
|
|
4
|
+
import { SystemContext } from "./index"
|
|
5
|
+
import { makeLocationNode } from "../effect/app-node"
|
|
6
|
+
|
|
7
|
+
export interface Entry {
|
|
8
|
+
readonly key: SystemContext.Key
|
|
9
|
+
readonly load: Effect.Effect<SystemContext.SystemContext>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Interface {
|
|
13
|
+
readonly register: (entry: Entry) => Effect.Effect<void, never, Scope.Scope>
|
|
14
|
+
readonly load: () => Effect.Effect<SystemContext.SystemContext>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class Service extends Context.Service<Service, Interface>()("@neurocode/v2/SystemContextRegistry") {}
|
|
18
|
+
|
|
19
|
+
const layer = Layer.effect(
|
|
20
|
+
Service,
|
|
21
|
+
Effect.gen(function* () {
|
|
22
|
+
const entries = yield* Ref.make<ReadonlyArray<Entry>>([])
|
|
23
|
+
|
|
24
|
+
return Service.of({
|
|
25
|
+
register: Effect.fn("SystemContextRegistry.register")(function* (entry) {
|
|
26
|
+
yield* Effect.acquireRelease(
|
|
27
|
+
Ref.modify(entries, (current) => {
|
|
28
|
+
if (current.some((item) => item.key === entry.key)) return [false, current]
|
|
29
|
+
return [true, [...current, entry]]
|
|
30
|
+
}).pipe(
|
|
31
|
+
Effect.flatMap((added) =>
|
|
32
|
+
added ? Effect.void : Effect.die(`Duplicate system context entry key: ${entry.key}`),
|
|
33
|
+
),
|
|
34
|
+
Effect.as(entry),
|
|
35
|
+
),
|
|
36
|
+
(entry) => Ref.update(entries, (current) => current.filter((item) => item !== entry)),
|
|
37
|
+
)
|
|
38
|
+
}),
|
|
39
|
+
load: Effect.fn("SystemContextRegistry.load")(function* () {
|
|
40
|
+
const current = (yield* Ref.get(entries)).toSorted((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0))
|
|
41
|
+
return SystemContext.combine(
|
|
42
|
+
yield* Effect.forEach(current, (entry) => entry.load, { concurrency: "unbounded" }),
|
|
43
|
+
)
|
|
44
|
+
}),
|
|
45
|
+
})
|
|
46
|
+
}),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export const node = makeLocationNode({ service: Service, layer, deps: [] })
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Core Tool Architecture
|
|
2
|
+
|
|
3
|
+
This folder owns Core's one local tool representation, process and Location registration, effective lookup, and settlement.
|
|
4
|
+
|
|
5
|
+
## Representations
|
|
6
|
+
|
|
7
|
+
- `tool.ts` defines the opaque canonical `Tool.make({ description, input, output, execute, toModelOutput })` value. Application tools and shipped built-ins use the same type.
|
|
8
|
+
- `application-tools.ts` stores process-scoped application registrations.
|
|
9
|
+
- `tools.ts` exposes the registration-only `Tools.Service` view used by Location producers.
|
|
10
|
+
- `registry.ts` stores only canonical tools, overlays Location registrations over application registrations, derives definitions, invokes tools, and applies generic output bounding.
|
|
11
|
+
|
|
12
|
+
Do not add a second executable entry type, registry-owned executor, authorization callback, output-path callback, or legacy normalization path.
|
|
13
|
+
|
|
14
|
+
## Construction
|
|
15
|
+
|
|
16
|
+
Tool schemas and projection use `input` and `output` terminology. A tool value is opaque: its codecs, executor, definition derivation, and catalog permission declaration are private runtime details.
|
|
17
|
+
|
|
18
|
+
Location-scoped built-in layers acquire `PermissionV2.Service` and every other required Location service while the layer is constructed. The executor captures those services. Permission sources are always constructed from the canonical invocation context:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const source = {
|
|
22
|
+
type: "tool" as const,
|
|
23
|
+
messageID: context.assistantMessageID,
|
|
24
|
+
callID: context.toolCallID,
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Leaves own resolution, permission, and side-effect ordering. Translate only expected typed errors into `ToolFailure`; do not use `catchCause`, because interruption and defects must survive.
|
|
29
|
+
|
|
30
|
+
## Registration
|
|
31
|
+
|
|
32
|
+
Built-ins register through `Tools.Service.register({ [name]: tool })`. Application tools register through `ApplicationTools.Service.register(...)`, exposed publicly as `neurocode.tools.register(...)`.
|
|
33
|
+
|
|
34
|
+
Both are scoped:
|
|
35
|
+
|
|
36
|
+
- The latest active same-placement registration wins.
|
|
37
|
+
- Closing any registration removes only that registration and reveals the next active one.
|
|
38
|
+
- Location registrations take precedence over application registrations.
|
|
39
|
+
- An invocation captures the effective tool once settlement starts.
|
|
40
|
+
|
|
41
|
+
`ApplicationTools.Service` is process-scoped and shared by all Locations. `ToolRegistry.Service` is Location-scoped. Do not make the registry process-global or construct a separate application-tool service for each Location.
|
|
42
|
+
|
|
43
|
+
## Permissions
|
|
44
|
+
|
|
45
|
+
The registry has no `PermissionV2.Service` dependency and performs no execution authorization. An internal built-in-only operation attaches a permission action solely to preserve whole-tool definition filtering; it is not part of public `Tool.make`. Most tools default to their registered name; `edit`, `write`, and `apply_patch` declare the shared `edit` action.
|
|
46
|
+
|
|
47
|
+
Definition filtering is catalog visibility, not execution authorization. A call still executes the captured leaf policy if it reaches settlement.
|
|
48
|
+
|
|
49
|
+
## Output
|
|
50
|
+
|
|
51
|
+
Built-ins return complete validated domain output. `ToolRegistry.Materialization.settle` is the only execution and generic model-output bounding boundary and owns managed retention paths.
|
|
52
|
+
|
|
53
|
+
Producer capture limits are separate. For example, Bash keeps `AppProcess.maxOutputBytes` and accurately reports stdout/stderr capture loss, but it does not run model-output truncation or return a managed `outputPath`.
|
|
54
|
+
|
|
55
|
+
## Current Gaps
|
|
56
|
+
|
|
57
|
+
- Plugin boot has not been redesigned to register canonical tools through `Tools.Service`; do not redesign it as part of leaf migrations.
|
|
58
|
+
- MCP and future Session-scoped registrations still need an explicit canonical registration design.
|
|
59
|
+
- The public Session result shape currently exposes managed `outputPaths`; full storage encapsulation requires a future opaque managed-output reference design.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export * as ApplicationTools from "./application-tools"
|
|
2
|
+
|
|
3
|
+
import { Context, Effect, Layer, Scope } from "effect"
|
|
4
|
+
import { State } from "../state"
|
|
5
|
+
import { Tool } from "./tool"
|
|
6
|
+
import { makeGlobalNode } from "../effect/app-node"
|
|
7
|
+
|
|
8
|
+
type Data = {
|
|
9
|
+
readonly entries: Map<string, Entry>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Draft = {
|
|
13
|
+
readonly set: (name: string, entry: Entry) => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Entry {
|
|
17
|
+
readonly identity: object
|
|
18
|
+
readonly tool: Tool.AnyTool
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Interface {
|
|
22
|
+
readonly register: (
|
|
23
|
+
tools: Readonly<Record<string, Tool.AnyTool>>,
|
|
24
|
+
) => Effect.Effect<void, Tool.RegistrationError, Scope.Scope>
|
|
25
|
+
readonly entries: () => ReadonlyMap<string, Entry>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class Service extends Context.Service<Service, Interface>()("@neurocode/ApplicationTools") {}
|
|
29
|
+
|
|
30
|
+
const layer = Layer.effect(
|
|
31
|
+
Service,
|
|
32
|
+
Effect.gen(function* () {
|
|
33
|
+
const state = State.create<Data, Draft>({
|
|
34
|
+
initial: () => ({ entries: new Map() }),
|
|
35
|
+
draft: (draft) => ({
|
|
36
|
+
set: (name, tool) => {
|
|
37
|
+
draft.entries.set(name, tool)
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return Service.of({
|
|
43
|
+
register: Effect.fn("ApplicationTools.register")(function* (tools) {
|
|
44
|
+
const entries = Object.entries(tools)
|
|
45
|
+
if (entries.length === 0) return
|
|
46
|
+
yield* Effect.forEach(entries, ([name]) => Tool.validateName(name), { discard: true })
|
|
47
|
+
const registrations = entries.map(([name, tool]) => [name, { identity: {}, tool }] as const)
|
|
48
|
+
yield* state.transform((draft) => {
|
|
49
|
+
for (const [name, entry] of registrations) draft.set(name, entry)
|
|
50
|
+
})
|
|
51
|
+
}),
|
|
52
|
+
entries: () => state.get().entries,
|
|
53
|
+
})
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
export const node = makeGlobalNode({ service: Service, layer, deps: [] })
|