@xyit/wellspring 0.0.0-stage → 1.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/LICENSE +21 -0
- package/README.md +853 -2
- package/dist/agent/pending-asks.d.ts +20 -0
- package/dist/agent/pending-asks.js +70 -0
- package/dist/agent/pending-asks.js.map +1 -0
- package/dist/agent/task-registry.d.ts +14 -0
- package/dist/agent/task-registry.js +80 -0
- package/dist/agent/task-registry.js.map +1 -0
- package/dist/agent/tool-context.d.ts +30 -0
- package/dist/agent/tool-context.js +10 -0
- package/dist/agent/tool-context.js.map +1 -0
- package/dist/agent/usage.d.ts +40 -0
- package/dist/agent/usage.js +122 -0
- package/dist/agent/usage.js.map +1 -0
- package/dist/api/host/agent.d.ts +165 -0
- package/dist/api/host/agent.js +5 -0
- package/dist/api/host/agent.js.map +1 -0
- package/dist/api/host/events.d.ts +2 -0
- package/dist/api/host/events.js +6 -0
- package/dist/api/host/events.js.map +1 -0
- package/dist/api/host/exec.d.ts +36 -0
- package/dist/api/host/exec.js +10 -0
- package/dist/api/host/exec.js.map +1 -0
- package/dist/api/host/fs.d.ts +24 -0
- package/dist/api/host/fs.js +7 -0
- package/dist/api/host/fs.js.map +1 -0
- package/dist/api/host/hooks.d.ts +210 -0
- package/dist/api/host/hooks.js +401 -0
- package/dist/api/host/hooks.js.map +1 -0
- package/dist/api/host/host.d.ts +36 -0
- package/dist/api/host/host.js +53 -0
- package/dist/api/host/host.js.map +1 -0
- package/dist/api/host/http.d.ts +58 -0
- package/dist/api/host/http.js +6 -0
- package/dist/api/host/http.js.map +1 -0
- package/dist/api/host/index.d.ts +15 -0
- package/dist/api/host/index.js +20 -0
- package/dist/api/host/index.js.map +1 -0
- package/dist/api/host/models.d.ts +65 -0
- package/dist/api/host/models.js +8 -0
- package/dist/api/host/models.js.map +1 -0
- package/dist/api/host/network.d.ts +22 -0
- package/dist/api/host/network.js +7 -0
- package/dist/api/host/network.js.map +1 -0
- package/dist/api/host/plugin.d.ts +138 -0
- package/dist/api/host/plugin.js +6 -0
- package/dist/api/host/plugin.js.map +1 -0
- package/dist/api/host/plugins.d.ts +49 -0
- package/dist/api/host/plugins.js +6 -0
- package/dist/api/host/plugins.js.map +1 -0
- package/dist/api/host/pty.d.ts +55 -0
- package/dist/api/host/pty.js +21 -0
- package/dist/api/host/pty.js.map +1 -0
- package/dist/api/host/session.d.ts +5 -0
- package/dist/api/host/session.js +52 -0
- package/dist/api/host/session.js.map +1 -0
- package/dist/api/host/version.d.ts +2 -0
- package/dist/api/host/version.js +3 -0
- package/dist/api/host/version.js.map +1 -0
- package/dist/api/host/workspace.d.ts +38 -0
- package/dist/api/host/workspace.js +9 -0
- package/dist/api/host/workspace.js.map +1 -0
- package/dist/api/plugin/http-client.d.ts +42 -0
- package/dist/api/plugin/http-client.js +364 -0
- package/dist/api/plugin/http-client.js.map +1 -0
- package/dist/api/plugin/http-protocol.d.ts +152 -0
- package/dist/api/plugin/http-protocol.js +49 -0
- package/dist/api/plugin/http-protocol.js.map +1 -0
- package/dist/api/result/result.d.ts +16 -0
- package/dist/api/result/result.js +43 -0
- package/dist/api/result/result.js.map +1 -0
- package/dist/commands/agent-turn.d.ts +63 -0
- package/dist/commands/agent-turn.js +687 -0
- package/dist/commands/agent-turn.js.map +1 -0
- package/dist/commands/ask-prompt.d.ts +6 -0
- package/dist/commands/ask-prompt.js +49 -0
- package/dist/commands/ask-prompt.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +283 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/conversation.d.ts +51 -0
- package/dist/commands/conversation.js +630 -0
- package/dist/commands/conversation.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +77 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/exec-approval.d.ts +3 -0
- package/dist/commands/exec-approval.js +80 -0
- package/dist/commands/exec-approval.js.map +1 -0
- package/dist/commands/help.d.ts +2 -0
- package/dist/commands/help.js +35 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/key.d.ts +2 -0
- package/dist/commands/key.js +226 -0
- package/dist/commands/key.js.map +1 -0
- package/dist/commands/plugin.d.ts +2 -0
- package/dist/commands/plugin.js +190 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +167 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/shared.d.ts +35 -0
- package/dist/commands/shared.js +66 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +75 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/stop.d.ts +2 -0
- package/dist/commands/stop.js +24 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/version.d.ts +2 -0
- package/dist/commands/version.js +33 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/config/codes.d.ts +13 -0
- package/dist/config/codes.js +15 -0
- package/dist/config/codes.js.map +1 -0
- package/dist/config/credentials.d.ts +67 -0
- package/dist/config/credentials.js +214 -0
- package/dist/config/credentials.js.map +1 -0
- package/dist/config/defaults.d.ts +5 -0
- package/dist/config/defaults.js +31 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +10 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.js +68 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/providers.d.ts +30 -0
- package/dist/config/providers.js +97 -0
- package/dist/config/providers.js.map +1 -0
- package/dist/config/types.d.ts +75 -0
- package/dist/config/types.js +4 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validate.d.ts +4 -0
- package/dist/config/validate.js +391 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/display/markdown.d.ts +7 -0
- package/dist/display/markdown.js +116 -0
- package/dist/display/markdown.js.map +1 -0
- package/dist/display/tool-label.d.ts +6 -0
- package/dist/display/tool-label.js +81 -0
- package/dist/display/tool-label.js.map +1 -0
- package/dist/event/event.d.ts +27 -0
- package/dist/event/event.js +152 -0
- package/dist/event/event.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/dist/input/codes.d.ts +15 -0
- package/dist/input/codes.js +20 -0
- package/dist/input/codes.js.map +1 -0
- package/dist/input/commands.d.ts +10 -0
- package/dist/input/commands.js +65 -0
- package/dist/input/commands.js.map +1 -0
- package/dist/input/help.d.ts +8 -0
- package/dist/input/help.js +51 -0
- package/dist/input/help.js.map +1 -0
- package/dist/input/index.d.ts +6 -0
- package/dist/input/index.js +10 -0
- package/dist/input/index.js.map +1 -0
- package/dist/input/parse-options.d.ts +11 -0
- package/dist/input/parse-options.js +51 -0
- package/dist/input/parse-options.js.map +1 -0
- package/dist/input/parse.d.ts +3 -0
- package/dist/input/parse.js +119 -0
- package/dist/input/parse.js.map +1 -0
- package/dist/input/types.d.ts +17 -0
- package/dist/input/types.js +2 -0
- package/dist/input/types.js.map +1 -0
- package/dist/logger/elog4js.d.ts +65 -0
- package/dist/logger/elog4js.js +305 -0
- package/dist/logger/elog4js.js.map +1 -0
- package/dist/logger/logger.d.ts +37 -0
- package/dist/logger/logger.js +196 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/network/index.d.ts +2 -0
- package/dist/network/index.js +6 -0
- package/dist/network/index.js.map +1 -0
- package/dist/network/openai.d.ts +117 -0
- package/dist/network/openai.js +443 -0
- package/dist/network/openai.js.map +1 -0
- package/dist/network/proxy.d.ts +9 -0
- package/dist/network/proxy.js +72 -0
- package/dist/network/proxy.js.map +1 -0
- package/dist/network/web.d.ts +34 -0
- package/dist/network/web.js +152 -0
- package/dist/network/web.js.map +1 -0
- package/dist/platform/clipboard.d.ts +15 -0
- package/dist/platform/clipboard.js +82 -0
- package/dist/platform/clipboard.js.map +1 -0
- package/dist/platform/exec.d.ts +28 -0
- package/dist/platform/exec.js +95 -0
- package/dist/platform/exec.js.map +1 -0
- package/dist/platform/file.d.ts +38 -0
- package/dist/platform/file.js +197 -0
- package/dist/platform/file.js.map +1 -0
- package/dist/platform/index.d.ts +7 -0
- package/dist/platform/index.js +12 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/notification.d.ts +14 -0
- package/dist/platform/notification.js +82 -0
- package/dist/platform/notification.js.map +1 -0
- package/dist/platform/open-external.d.ts +10 -0
- package/dist/platform/open-external.js +105 -0
- package/dist/platform/open-external.js.map +1 -0
- package/dist/platform/os.d.ts +20 -0
- package/dist/platform/os.js +86 -0
- package/dist/platform/os.js.map +1 -0
- package/dist/platform/path.d.ts +32 -0
- package/dist/platform/path.js +154 -0
- package/dist/platform/path.js.map +1 -0
- package/dist/plugin/access-guard.d.ts +1 -0
- package/dist/plugin/access-guard.js +40 -0
- package/dist/plugin/access-guard.js.map +1 -0
- package/dist/plugin/agent-service.d.ts +25 -0
- package/dist/plugin/agent-service.js +809 -0
- package/dist/plugin/agent-service.js.map +1 -0
- package/dist/plugin/agent-tools.d.ts +12 -0
- package/dist/plugin/agent-tools.js +31 -0
- package/dist/plugin/agent-tools.js.map +1 -0
- package/dist/plugin/capabilities.d.ts +26 -0
- package/dist/plugin/capabilities.js +192 -0
- package/dist/plugin/capabilities.js.map +1 -0
- package/dist/plugin/console-guard.d.ts +2 -0
- package/dist/plugin/console-guard.js +52 -0
- package/dist/plugin/console-guard.js.map +1 -0
- package/dist/plugin/data-access.d.ts +15 -0
- package/dist/plugin/data-access.js +57 -0
- package/dist/plugin/data-access.js.map +1 -0
- package/dist/plugin/fs.d.ts +3 -0
- package/dist/plugin/fs.js +93 -0
- package/dist/plugin/fs.js.map +1 -0
- package/dist/plugin/host-alias.d.ts +2 -0
- package/dist/plugin/host-alias.js +57 -0
- package/dist/plugin/host-alias.js.map +1 -0
- package/dist/plugin/index.d.ts +7 -0
- package/dist/plugin/index.js +11 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/install.d.ts +17 -0
- package/dist/plugin/install.js +163 -0
- package/dist/plugin/install.js.map +1 -0
- package/dist/plugin/loader.d.ts +45 -0
- package/dist/plugin/loader.js +739 -0
- package/dist/plugin/loader.js.map +1 -0
- package/dist/plugin/manage.d.ts +31 -0
- package/dist/plugin/manage.js +271 -0
- package/dist/plugin/manage.js.map +1 -0
- package/dist/plugin/models-service.d.ts +15 -0
- package/dist/plugin/models-service.js +317 -0
- package/dist/plugin/models-service.js.map +1 -0
- package/dist/plugin/network-service.d.ts +10 -0
- package/dist/plugin/network-service.js +87 -0
- package/dist/plugin/network-service.js.map +1 -0
- package/dist/plugin/package-manager.d.ts +46 -0
- package/dist/plugin/package-manager.js +148 -0
- package/dist/plugin/package-manager.js.map +1 -0
- package/dist/plugin/paths.d.ts +6 -0
- package/dist/plugin/paths.js +15 -0
- package/dist/plugin/paths.js.map +1 -0
- package/dist/plugin/registry.d.ts +17 -0
- package/dist/plugin/registry.js +82 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/runtime.d.ts +9 -0
- package/dist/plugin/runtime.js +43 -0
- package/dist/plugin/runtime.js.map +1 -0
- package/dist/plugin/scaffold.d.ts +13 -0
- package/dist/plugin/scaffold.js +132 -0
- package/dist/plugin/scaffold.js.map +1 -0
- package/dist/plugin/state.d.ts +6 -0
- package/dist/plugin/state.js +38 -0
- package/dist/plugin/state.js.map +1 -0
- package/dist/plugin/zip.d.ts +7 -0
- package/dist/plugin/zip.js +138 -0
- package/dist/plugin/zip.js.map +1 -0
- package/dist/sandbox/audit.d.ts +12 -0
- package/dist/sandbox/audit.js +20 -0
- package/dist/sandbox/audit.js.map +1 -0
- package/dist/sandbox/backends/bwrap.d.ts +28 -0
- package/dist/sandbox/backends/bwrap.js +197 -0
- package/dist/sandbox/backends/bwrap.js.map +1 -0
- package/dist/sandbox/backends/direct.d.ts +7 -0
- package/dist/sandbox/backends/direct.js +32 -0
- package/dist/sandbox/backends/direct.js.map +1 -0
- package/dist/sandbox/bridge-state.d.ts +13 -0
- package/dist/sandbox/bridge-state.js +12 -0
- package/dist/sandbox/bridge-state.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +6 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +8 -0
- package/dist/sandbox/manager.js +325 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/memory-limit.d.ts +44 -0
- package/dist/sandbox/memory-limit.js +193 -0
- package/dist/sandbox/memory-limit.js.map +1 -0
- package/dist/sandbox/plugin-client.d.ts +80 -0
- package/dist/sandbox/plugin-client.js +1601 -0
- package/dist/sandbox/plugin-client.js.map +1 -0
- package/dist/sandbox/plugin-host.d.ts +1 -0
- package/dist/sandbox/plugin-host.js +1001 -0
- package/dist/sandbox/plugin-host.js.map +1 -0
- package/dist/sandbox/protocol.d.ts +43 -0
- package/dist/sandbox/protocol.js +96 -0
- package/dist/sandbox/protocol.js.map +1 -0
- package/dist/sandbox/rpc-timeouts.d.ts +28 -0
- package/dist/sandbox/rpc-timeouts.js +15 -0
- package/dist/sandbox/rpc-timeouts.js.map +1 -0
- package/dist/sandbox/supervisor.d.ts +31 -0
- package/dist/sandbox/supervisor.js +114 -0
- package/dist/sandbox/supervisor.js.map +1 -0
- package/dist/sandbox/types.d.ts +124 -0
- package/dist/sandbox/types.js +17 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/service/control.d.ts +32 -0
- package/dist/service/control.js +117 -0
- package/dist/service/control.js.map +1 -0
- package/dist/session/compress.d.ts +3 -0
- package/dist/session/compress.js +42 -0
- package/dist/session/compress.js.map +1 -0
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/registry.d.ts +4 -0
- package/dist/session/registry.js +12 -0
- package/dist/session/registry.js.map +1 -0
- package/dist/session/replay.d.ts +10 -0
- package/dist/session/replay.js +109 -0
- package/dist/session/replay.js.map +1 -0
- package/dist/session/session.d.ts +40 -0
- package/dist/session/session.js +108 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/store.d.ts +58 -0
- package/dist/session/store.js +382 -0
- package/dist/session/store.js.map +1 -0
- package/dist/session/types.d.ts +56 -0
- package/dist/session/types.js +3 -0
- package/dist/session/types.js.map +1 -0
- package/dist/workspace/index.d.ts +7 -0
- package/dist/workspace/index.js +17 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/registry.d.ts +25 -0
- package/dist/workspace/registry.js +293 -0
- package/dist/workspace/registry.js.map +1 -0
- package/package.json +73 -5
- package/scripts/build-node-pty.mjs +55 -0
- package/scripts/rewrite-dts.mjs +36 -0
- package/scripts/run-tests.mjs +41 -0
- package/scripts/verify-sandbox.ts +98 -0
- package/src/agent/pending-asks.ts +88 -0
- package/src/agent/task-registry.ts +108 -0
- package/src/agent/tool-context.ts +47 -0
- package/src/agent/usage.ts +170 -0
- package/src/api/host/agent.ts +162 -0
- package/src/api/host/events.ts +7 -0
- package/src/api/host/exec.ts +47 -0
- package/src/api/host/fs.ts +33 -0
- package/src/api/host/hooks.ts +635 -0
- package/src/api/host/host.ts +99 -0
- package/src/api/host/http.ts +79 -0
- package/src/api/host/index.ts +20 -0
- package/src/api/host/models.ts +81 -0
- package/src/api/host/network.ts +32 -0
- package/src/api/host/plugin.ts +158 -0
- package/src/api/host/plugins.ts +59 -0
- package/src/api/host/pty.ts +73 -0
- package/src/api/host/session.ts +61 -0
- package/src/api/host/version.ts +2 -0
- package/src/api/host/workspace.ts +51 -0
- package/src/api/plugin/http-client.ts +492 -0
- package/src/api/plugin/http-protocol.ts +231 -0
- package/src/api/result/result.ts +52 -0
- package/src/commands/agent-turn.ts +817 -0
- package/src/commands/ask-prompt.ts +52 -0
- package/src/commands/config.ts +306 -0
- package/src/commands/conversation.ts +777 -0
- package/src/commands/doctor.ts +92 -0
- package/src/commands/exec-approval.ts +91 -0
- package/src/commands/help.ts +41 -0
- package/src/commands/key.ts +281 -0
- package/src/commands/plugin.ts +222 -0
- package/src/commands/session.ts +179 -0
- package/src/commands/shared.ts +103 -0
- package/src/commands/start.ts +88 -0
- package/src/commands/stop.ts +24 -0
- package/src/commands/version.ts +40 -0
- package/src/config/codes.ts +17 -0
- package/src/config/credentials.ts +302 -0
- package/src/config/defaults.ts +32 -0
- package/src/config/index.ts +10 -0
- package/src/config/loader.ts +80 -0
- package/src/config/providers.ts +133 -0
- package/src/config/types.ts +88 -0
- package/src/config/validate.ts +458 -0
- package/src/display/markdown.ts +137 -0
- package/src/display/tool-label.ts +87 -0
- package/src/event/event.ts +171 -0
- package/src/index.ts +344 -0
- package/src/input/codes.ts +21 -0
- package/src/input/commands.ts +76 -0
- package/src/input/help.ts +60 -0
- package/src/input/index.ts +10 -0
- package/src/input/parse-options.ts +66 -0
- package/src/input/parse.ts +138 -0
- package/src/input/types.ts +19 -0
- package/src/logger/elog4js.ts +366 -0
- package/src/logger/logger.ts +251 -0
- package/src/network/index.ts +6 -0
- package/src/network/openai.ts +571 -0
- package/src/network/proxy.ts +80 -0
- package/src/network/web.ts +206 -0
- package/src/platform/clipboard.ts +107 -0
- package/src/platform/exec.ts +128 -0
- package/src/platform/file.ts +235 -0
- package/src/platform/index.ts +12 -0
- package/src/platform/notification.ts +108 -0
- package/src/platform/open-external.ts +132 -0
- package/src/platform/os.ts +101 -0
- package/src/platform/path.ts +214 -0
- package/src/plugin/access-guard.ts +46 -0
- package/src/plugin/agent-service.ts +969 -0
- package/src/plugin/agent-tools.ts +43 -0
- package/src/plugin/capabilities.ts +240 -0
- package/src/plugin/console-guard.ts +66 -0
- package/src/plugin/data-access.ts +70 -0
- package/src/plugin/fs.ts +109 -0
- package/src/plugin/host-alias.ts +61 -0
- package/src/plugin/index.ts +11 -0
- package/src/plugin/install.ts +213 -0
- package/src/plugin/loader.ts +952 -0
- package/src/plugin/manage.ts +338 -0
- package/src/plugin/models-service.ts +383 -0
- package/src/plugin/network-service.ts +102 -0
- package/src/plugin/package-manager.ts +214 -0
- package/src/plugin/paths.ts +19 -0
- package/src/plugin/registry.ts +103 -0
- package/src/plugin/runtime.ts +57 -0
- package/src/plugin/scaffold.ts +158 -0
- package/src/plugin/state.ts +52 -0
- package/src/plugin/zip.ts +156 -0
- package/src/sandbox/audit.ts +38 -0
- package/src/sandbox/backends/bwrap.ts +251 -0
- package/src/sandbox/backends/direct.ts +43 -0
- package/src/sandbox/bridge-state.ts +29 -0
- package/src/sandbox/index.ts +5 -0
- package/src/sandbox/manager.ts +406 -0
- package/src/sandbox/memory-limit.ts +245 -0
- package/src/sandbox/plugin-client.ts +1881 -0
- package/src/sandbox/plugin-host.ts +1282 -0
- package/src/sandbox/protocol.ts +142 -0
- package/src/sandbox/pty-bridge.py +154 -0
- package/src/sandbox/rpc-timeouts.ts +43 -0
- package/src/sandbox/supervisor.ts +172 -0
- package/src/sandbox/types.ts +149 -0
- package/src/service/control.ts +155 -0
- package/src/session/compress.ts +47 -0
- package/src/session/index.ts +8 -0
- package/src/session/registry.ts +17 -0
- package/src/session/replay.ts +132 -0
- package/src/session/session.ts +134 -0
- package/src/session/store.ts +468 -0
- package/src/session/types.ts +61 -0
- package/src/workspace/index.ts +21 -0
- package/src/workspace/registry.ts +356 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import type { LevelWithSilent } from "pino"
|
|
2
|
+
|
|
3
|
+
import { Result } from "../api/result/result.ts"
|
|
4
|
+
import { CONFIG_CODES, invalidCode } from "./codes.ts"
|
|
5
|
+
import { DEFAULT_MODELS, DEFAULT_SETTINGS } from "./defaults.ts"
|
|
6
|
+
import {
|
|
7
|
+
REASONING_LEVELS,
|
|
8
|
+
SETTING_VERSION,
|
|
9
|
+
type AppSetting,
|
|
10
|
+
type ModelProviderSetting,
|
|
11
|
+
type ModelsSetting,
|
|
12
|
+
type NetworkSetting,
|
|
13
|
+
type OpenAISetting,
|
|
14
|
+
type ProxySetting,
|
|
15
|
+
type SandboxAccess,
|
|
16
|
+
type SandboxBackend,
|
|
17
|
+
type SandboxMode,
|
|
18
|
+
type SandboxSetting,
|
|
19
|
+
} from "./types.ts"
|
|
20
|
+
|
|
21
|
+
const LEVELS: ReadonlySet<string> = new Set<LevelWithSilent>([
|
|
22
|
+
"fatal",
|
|
23
|
+
"error",
|
|
24
|
+
"warn",
|
|
25
|
+
"info",
|
|
26
|
+
"debug",
|
|
27
|
+
"trace",
|
|
28
|
+
"silent",
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
32
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isLevel(value: unknown): value is LevelWithSilent {
|
|
36
|
+
return typeof value === "string" && LEVELS.has(value)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isBaseUrl(value: unknown): value is string {
|
|
40
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const url = new URL(value)
|
|
45
|
+
return url.protocol === "http:" || url.protocol === "https:"
|
|
46
|
+
} catch {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isPositiveInteger(value: unknown): value is number {
|
|
52
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isNonNegativeInteger(value: unknown): value is number {
|
|
56
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function validateOpenAI(input: Record<string, unknown>): Result<OpenAISetting> {
|
|
60
|
+
let baseUrl = DEFAULT_SETTINGS.openai.baseUrl
|
|
61
|
+
const rawBaseUrl = input["baseUrl"]
|
|
62
|
+
if (rawBaseUrl !== undefined && rawBaseUrl !== null) {
|
|
63
|
+
if (!isBaseUrl(rawBaseUrl)) {
|
|
64
|
+
return Result.error<OpenAISetting>(invalidCode("openai.baseUrl"))
|
|
65
|
+
}
|
|
66
|
+
baseUrl = rawBaseUrl
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let model = DEFAULT_SETTINGS.openai.model
|
|
70
|
+
const rawModel = input["model"]
|
|
71
|
+
if (rawModel !== undefined) {
|
|
72
|
+
if (typeof rawModel !== "string" || rawModel.trim() === "") {
|
|
73
|
+
return Result.error<OpenAISetting>(invalidCode("openai.model"))
|
|
74
|
+
}
|
|
75
|
+
model = rawModel.trim()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let timeoutMs = DEFAULT_SETTINGS.openai.timeoutMs
|
|
79
|
+
const rawTimeout = input["timeoutMs"]
|
|
80
|
+
if (rawTimeout !== undefined) {
|
|
81
|
+
if (!isPositiveInteger(rawTimeout)) {
|
|
82
|
+
return Result.error<OpenAISetting>(invalidCode("openai.timeoutMs"))
|
|
83
|
+
}
|
|
84
|
+
timeoutMs = rawTimeout
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let maxRetries = DEFAULT_SETTINGS.openai.maxRetries
|
|
88
|
+
const rawRetries = input["maxRetries"]
|
|
89
|
+
if (rawRetries !== undefined) {
|
|
90
|
+
if (!isNonNegativeInteger(rawRetries)) {
|
|
91
|
+
return Result.error<OpenAISetting>(invalidCode("openai.maxRetries"))
|
|
92
|
+
}
|
|
93
|
+
maxRetries = rawRetries
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Result.successWithData<OpenAISetting>({ baseUrl, model, timeoutMs, maxRetries })
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const PROVIDER_ID = /^[a-z0-9][a-z0-9._-]{0,31}$/
|
|
100
|
+
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/
|
|
101
|
+
const BUILTIN_PROVIDER_ID = "openai"
|
|
102
|
+
const MAX_PROVIDERS = 20
|
|
103
|
+
const MAX_MODELS_PER_PROVIDER = 200
|
|
104
|
+
|
|
105
|
+
function validateProvider(
|
|
106
|
+
input: Record<string, unknown>,
|
|
107
|
+
seen: ReadonlySet<string>,
|
|
108
|
+
): Result<ModelProviderSetting> {
|
|
109
|
+
const rawId = input["id"]
|
|
110
|
+
const id = typeof rawId === "string" && PROVIDER_ID.test(rawId.trim()) ? rawId.trim() : null
|
|
111
|
+
if (id === null || id === BUILTIN_PROVIDER_ID) {
|
|
112
|
+
return Result.error<ModelProviderSetting>(invalidCode("models.providers.id"))
|
|
113
|
+
}
|
|
114
|
+
if (seen.has(id)) {
|
|
115
|
+
return Result.error<ModelProviderSetting>(invalidCode(`models.providers.${id}`))
|
|
116
|
+
}
|
|
117
|
+
const rawName = input["name"]
|
|
118
|
+
const name =
|
|
119
|
+
typeof rawName === "string" && rawName.trim() !== "" && rawName.trim().length <= 60
|
|
120
|
+
? rawName.trim()
|
|
121
|
+
: null
|
|
122
|
+
if (name === null) {
|
|
123
|
+
return Result.error<ModelProviderSetting>(invalidCode(`models.providers.${id}.name`))
|
|
124
|
+
}
|
|
125
|
+
let baseUrl: string | null = null
|
|
126
|
+
const rawBaseUrl = input["baseUrl"]
|
|
127
|
+
if (rawBaseUrl !== undefined && rawBaseUrl !== null) {
|
|
128
|
+
if (!isBaseUrl(rawBaseUrl)) {
|
|
129
|
+
return Result.error<ModelProviderSetting>(invalidCode(`models.providers.${id}.baseUrl`))
|
|
130
|
+
}
|
|
131
|
+
baseUrl = rawBaseUrl.trim()
|
|
132
|
+
}
|
|
133
|
+
const models: string[] = []
|
|
134
|
+
const rawModels = input["models"]
|
|
135
|
+
if (rawModels !== undefined) {
|
|
136
|
+
if (!Array.isArray(rawModels) || rawModels.length > MAX_MODELS_PER_PROVIDER) {
|
|
137
|
+
return Result.error<ModelProviderSetting>(invalidCode(`models.providers.${id}.models`))
|
|
138
|
+
}
|
|
139
|
+
for (const item of rawModels) {
|
|
140
|
+
if (typeof item !== "string" || item.trim() === "" || item.trim().length > 120) {
|
|
141
|
+
return Result.error<ModelProviderSetting>(
|
|
142
|
+
invalidCode(`models.providers.${id}.models`),
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
const model = item.trim()
|
|
146
|
+
if (!models.includes(model)) {
|
|
147
|
+
models.push(model)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
let defaultModel: string | null = null
|
|
152
|
+
const rawDefault = input["defaultModel"]
|
|
153
|
+
if (rawDefault !== undefined && rawDefault !== null) {
|
|
154
|
+
if (typeof rawDefault !== "string" || rawDefault.trim() === "") {
|
|
155
|
+
return Result.error<ModelProviderSetting>(
|
|
156
|
+
invalidCode(`models.providers.${id}.defaultModel`),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
defaultModel = rawDefault.trim()
|
|
160
|
+
}
|
|
161
|
+
let apiKeyEnv: string | null = null
|
|
162
|
+
const rawEnv = input["apiKeyEnv"]
|
|
163
|
+
if (rawEnv !== undefined && rawEnv !== null) {
|
|
164
|
+
if (typeof rawEnv !== "string" || !ENV_NAME.test(rawEnv.trim())) {
|
|
165
|
+
return Result.error<ModelProviderSetting>(
|
|
166
|
+
invalidCode(`models.providers.${id}.apiKeyEnv`),
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
apiKeyEnv = rawEnv.trim()
|
|
170
|
+
}
|
|
171
|
+
return Result.successWithData<ModelProviderSetting>({
|
|
172
|
+
id,
|
|
173
|
+
name,
|
|
174
|
+
baseUrl,
|
|
175
|
+
models,
|
|
176
|
+
defaultModel,
|
|
177
|
+
apiKeyEnv,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function validateModels(input: Record<string, unknown>): Result<ModelsSetting> {
|
|
182
|
+
const providers: ModelProviderSetting[] = []
|
|
183
|
+
const rawProviders = input["providers"]
|
|
184
|
+
if (rawProviders !== undefined && rawProviders !== null) {
|
|
185
|
+
if (!Array.isArray(rawProviders) || rawProviders.length > MAX_PROVIDERS) {
|
|
186
|
+
return Result.error<ModelsSetting>(invalidCode("models.providers"))
|
|
187
|
+
}
|
|
188
|
+
const seen = new Set<string>()
|
|
189
|
+
for (const item of rawProviders) {
|
|
190
|
+
if (!isPlainObject(item)) {
|
|
191
|
+
return Result.error<ModelsSetting>(invalidCode("models.providers"))
|
|
192
|
+
}
|
|
193
|
+
const validated = validateProvider(item, seen)
|
|
194
|
+
if (!validated.isSuccess()) {
|
|
195
|
+
return Result.error<ModelsSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
196
|
+
}
|
|
197
|
+
const provider = validated.getData()
|
|
198
|
+
if (provider === null) {
|
|
199
|
+
return Result.error<ModelsSetting>(invalidCode("models.providers"))
|
|
200
|
+
}
|
|
201
|
+
seen.add(provider.id)
|
|
202
|
+
providers.push(provider)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let activeProvider = DEFAULT_MODELS.activeProvider
|
|
207
|
+
const rawActiveProvider = input["activeProvider"]
|
|
208
|
+
if (rawActiveProvider !== undefined && rawActiveProvider !== null) {
|
|
209
|
+
if (typeof rawActiveProvider !== "string" || rawActiveProvider.trim() === "") {
|
|
210
|
+
return Result.error<ModelsSetting>(invalidCode("models.activeProvider"))
|
|
211
|
+
}
|
|
212
|
+
activeProvider = rawActiveProvider.trim()
|
|
213
|
+
}
|
|
214
|
+
const known =
|
|
215
|
+
activeProvider === BUILTIN_PROVIDER_ID || providers.some((p) => p.id === activeProvider)
|
|
216
|
+
if (!known) {
|
|
217
|
+
return Result.error<ModelsSetting>(invalidCode("models.activeProvider"))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
let activeModel: string | null = DEFAULT_MODELS.activeModel
|
|
221
|
+
const rawActiveModel = input["activeModel"]
|
|
222
|
+
if (rawActiveModel !== undefined && rawActiveModel !== null) {
|
|
223
|
+
if (typeof rawActiveModel !== "string" || rawActiveModel.trim() === "") {
|
|
224
|
+
return Result.error<ModelsSetting>(invalidCode("models.activeModel"))
|
|
225
|
+
}
|
|
226
|
+
activeModel = rawActiveModel.trim()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let activeReasoning = DEFAULT_MODELS.activeReasoning
|
|
230
|
+
const rawActiveReasoning = input["activeReasoning"]
|
|
231
|
+
if (rawActiveReasoning !== undefined && rawActiveReasoning !== null) {
|
|
232
|
+
if (
|
|
233
|
+
typeof rawActiveReasoning !== "string" ||
|
|
234
|
+
!(REASONING_LEVELS as readonly string[]).includes(rawActiveReasoning)
|
|
235
|
+
) {
|
|
236
|
+
return Result.error<ModelsSetting>(invalidCode("models.activeReasoning"))
|
|
237
|
+
}
|
|
238
|
+
activeReasoning = rawActiveReasoning as ModelsSetting["activeReasoning"]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return Result.successWithData<ModelsSetting>({
|
|
242
|
+
providers,
|
|
243
|
+
activeProvider,
|
|
244
|
+
activeModel,
|
|
245
|
+
activeReasoning,
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function validateProxy(input: Record<string, unknown>): Result<ProxySetting> {
|
|
250
|
+
const rawType = input["type"]
|
|
251
|
+
if (rawType !== undefined && rawType !== "http") {
|
|
252
|
+
return Result.error<ProxySetting>(invalidCode("network.proxy.type"))
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const rawUrl = input["url"]
|
|
256
|
+
if (!isBaseUrl(rawUrl)) {
|
|
257
|
+
return Result.error<ProxySetting>(invalidCode("network.proxy.url"))
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const noProxy: string[] = []
|
|
261
|
+
const rawNoProxy = input["noProxy"]
|
|
262
|
+
if (rawNoProxy !== undefined) {
|
|
263
|
+
if (!Array.isArray(rawNoProxy)) {
|
|
264
|
+
return Result.error<ProxySetting>(invalidCode("network.proxy.noProxy"))
|
|
265
|
+
}
|
|
266
|
+
for (const item of rawNoProxy) {
|
|
267
|
+
if (typeof item !== "string" || item.trim() === "") {
|
|
268
|
+
return Result.error<ProxySetting>(invalidCode("network.proxy.noProxy"))
|
|
269
|
+
}
|
|
270
|
+
noProxy.push(item.trim())
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return Result.successWithData<ProxySetting>({ type: "http", url: rawUrl, noProxy })
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function validateNetwork(input: Record<string, unknown>): Result<NetworkSetting> {
|
|
278
|
+
const rawProxy = input["proxy"]
|
|
279
|
+
if (rawProxy === undefined || rawProxy === null) {
|
|
280
|
+
return Result.successWithData<NetworkSetting>({ proxy: null })
|
|
281
|
+
}
|
|
282
|
+
if (!isPlainObject(rawProxy)) {
|
|
283
|
+
return Result.error<NetworkSetting>(invalidCode("network.proxy"))
|
|
284
|
+
}
|
|
285
|
+
const validated = validateProxy(rawProxy)
|
|
286
|
+
if (!validated.isSuccess()) {
|
|
287
|
+
return Result.error<NetworkSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
288
|
+
}
|
|
289
|
+
return Result.successWithData<NetworkSetting>({
|
|
290
|
+
proxy: validated.getData() ?? null,
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const SANDBOX_MODES: ReadonlySet<string> = new Set<SandboxMode>(["off", "strict", "best-effort"])
|
|
295
|
+
const SANDBOX_BACKENDS: ReadonlySet<string> = new Set<SandboxBackend>(["auto", "bwrap", "nsjail"])
|
|
296
|
+
const SANDBOX_ACCESS: ReadonlySet<string> = new Set<SandboxAccess>([
|
|
297
|
+
"read-only",
|
|
298
|
+
"workspace-write",
|
|
299
|
+
"danger-full-access",
|
|
300
|
+
])
|
|
301
|
+
|
|
302
|
+
function validateSandbox(input: Record<string, unknown>): Result<SandboxSetting> {
|
|
303
|
+
let mode = DEFAULT_SETTINGS.sandbox.mode
|
|
304
|
+
const rawMode = input["mode"]
|
|
305
|
+
if (rawMode !== undefined) {
|
|
306
|
+
if (typeof rawMode !== "string" || !SANDBOX_MODES.has(rawMode)) {
|
|
307
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.mode"))
|
|
308
|
+
}
|
|
309
|
+
mode = rawMode as SandboxMode
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
let backend = DEFAULT_SETTINGS.sandbox.backend
|
|
313
|
+
const rawBackend = input["backend"]
|
|
314
|
+
if (rawBackend !== undefined) {
|
|
315
|
+
if (typeof rawBackend !== "string" || !SANDBOX_BACKENDS.has(rawBackend)) {
|
|
316
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.backend"))
|
|
317
|
+
}
|
|
318
|
+
backend = rawBackend as SandboxBackend
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
let access = DEFAULT_SETTINGS.sandbox.access
|
|
322
|
+
const rawAccess = input["access"]
|
|
323
|
+
if (rawAccess !== undefined) {
|
|
324
|
+
if (typeof rawAccess !== "string" || !SANDBOX_ACCESS.has(rawAccess)) {
|
|
325
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.access"))
|
|
326
|
+
}
|
|
327
|
+
access = rawAccess as SandboxAccess
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
let maxConcurrent = DEFAULT_SETTINGS.sandbox.maxConcurrent
|
|
331
|
+
const rawMaxConcurrent = input["maxConcurrent"]
|
|
332
|
+
if (rawMaxConcurrent !== undefined) {
|
|
333
|
+
if (!isPositiveInteger(rawMaxConcurrent) || rawMaxConcurrent > 32) {
|
|
334
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.maxConcurrent"))
|
|
335
|
+
}
|
|
336
|
+
maxConcurrent = rawMaxConcurrent
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
let defaultTimeoutMs = DEFAULT_SETTINGS.sandbox.defaultTimeoutMs
|
|
340
|
+
const rawTimeout = input["defaultTimeoutMs"]
|
|
341
|
+
if (rawTimeout !== undefined) {
|
|
342
|
+
if (!isPositiveInteger(rawTimeout) || rawTimeout > 600_000) {
|
|
343
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.defaultTimeoutMs"))
|
|
344
|
+
}
|
|
345
|
+
defaultTimeoutMs = rawTimeout
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
let defaultMemoryMB = DEFAULT_SETTINGS.sandbox.defaultMemoryMB
|
|
349
|
+
const rawMemory = input["defaultMemoryMB"]
|
|
350
|
+
if (rawMemory !== undefined) {
|
|
351
|
+
if (!isPositiveInteger(rawMemory) || rawMemory > 8192) {
|
|
352
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.defaultMemoryMB"))
|
|
353
|
+
}
|
|
354
|
+
defaultMemoryMB = rawMemory
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let outputLimitBytes = DEFAULT_SETTINGS.sandbox.outputLimitBytes
|
|
358
|
+
const rawOutput = input["outputLimitBytes"]
|
|
359
|
+
if (rawOutput !== undefined) {
|
|
360
|
+
if (!isPositiveInteger(rawOutput) || rawOutput < 1024 || rawOutput > 64 * 1024 * 1024) {
|
|
361
|
+
return Result.error<SandboxSetting>(invalidCode("sandbox.outputLimitBytes"))
|
|
362
|
+
}
|
|
363
|
+
outputLimitBytes = rawOutput
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return Result.successWithData<SandboxSetting>({
|
|
367
|
+
mode,
|
|
368
|
+
backend,
|
|
369
|
+
access,
|
|
370
|
+
maxConcurrent,
|
|
371
|
+
defaultTimeoutMs,
|
|
372
|
+
defaultMemoryMB,
|
|
373
|
+
outputLimitBytes,
|
|
374
|
+
})
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** 校验并补齐默认值;未声明字段忽略,不做保留 */
|
|
378
|
+
export function validateSettings(input: unknown): Result<AppSetting> {
|
|
379
|
+
if (!isPlainObject(input)) {
|
|
380
|
+
return Result.error<AppSetting>(invalidCode("root"))
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const version = input["version"]
|
|
384
|
+
if (version !== undefined && version !== SETTING_VERSION) {
|
|
385
|
+
return Result.error<AppSetting>(`${CONFIG_CODES.versionUnsupported}:${String(version)}`)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const logger = input["logger"]
|
|
389
|
+
if (logger !== undefined && !isPlainObject(logger)) {
|
|
390
|
+
return Result.error<AppSetting>(invalidCode("logger"))
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const rawLevel = logger === undefined ? undefined : logger["level"]
|
|
394
|
+
if (rawLevel !== undefined && !isLevel(rawLevel)) {
|
|
395
|
+
return Result.error<AppSetting>(invalidCode("logger.level"))
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const openai = input["openai"]
|
|
399
|
+
if (openai !== undefined && !isPlainObject(openai)) {
|
|
400
|
+
return Result.error<AppSetting>(invalidCode("openai"))
|
|
401
|
+
}
|
|
402
|
+
let openaiSetting = DEFAULT_SETTINGS.openai
|
|
403
|
+
if (openai !== undefined) {
|
|
404
|
+
const validated = validateOpenAI(openai)
|
|
405
|
+
if (!validated.isSuccess()) {
|
|
406
|
+
return Result.error<AppSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
407
|
+
}
|
|
408
|
+
openaiSetting = validated.getData() ?? DEFAULT_SETTINGS.openai
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const models = input["models"]
|
|
412
|
+
if (models !== undefined && models !== null && !isPlainObject(models)) {
|
|
413
|
+
return Result.error<AppSetting>(invalidCode("models"))
|
|
414
|
+
}
|
|
415
|
+
let modelsSetting = DEFAULT_MODELS
|
|
416
|
+
if (models !== undefined && models !== null) {
|
|
417
|
+
const validated = validateModels(models)
|
|
418
|
+
if (!validated.isSuccess()) {
|
|
419
|
+
return Result.error<AppSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
420
|
+
}
|
|
421
|
+
modelsSetting = validated.getData() ?? DEFAULT_MODELS
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const network = input["network"]
|
|
425
|
+
if (network !== undefined && !isPlainObject(network)) {
|
|
426
|
+
return Result.error<AppSetting>(invalidCode("network"))
|
|
427
|
+
}
|
|
428
|
+
let networkSetting = DEFAULT_SETTINGS.network
|
|
429
|
+
if (network !== undefined) {
|
|
430
|
+
const validated = validateNetwork(network)
|
|
431
|
+
if (!validated.isSuccess()) {
|
|
432
|
+
return Result.error<AppSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
433
|
+
}
|
|
434
|
+
networkSetting = validated.getData() ?? DEFAULT_SETTINGS.network
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const sandbox = input["sandbox"]
|
|
438
|
+
if (sandbox !== undefined && !isPlainObject(sandbox)) {
|
|
439
|
+
return Result.error<AppSetting>(invalidCode("sandbox"))
|
|
440
|
+
}
|
|
441
|
+
let sandboxSetting = DEFAULT_SETTINGS.sandbox
|
|
442
|
+
if (sandbox !== undefined) {
|
|
443
|
+
const validated = validateSandbox(sandbox)
|
|
444
|
+
if (!validated.isSuccess()) {
|
|
445
|
+
return Result.error<AppSetting>(validated.getCode() ?? CONFIG_CODES.invalid)
|
|
446
|
+
}
|
|
447
|
+
sandboxSetting = validated.getData() ?? DEFAULT_SETTINGS.sandbox
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return Result.successWithData<AppSetting>({
|
|
451
|
+
version: SETTING_VERSION,
|
|
452
|
+
logger: { level: rawLevel ?? DEFAULT_SETTINGS.logger.level },
|
|
453
|
+
openai: openaiSetting,
|
|
454
|
+
models: modelsSetting,
|
|
455
|
+
network: networkSetting,
|
|
456
|
+
sandbox: sandboxSetting,
|
|
457
|
+
})
|
|
458
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// TTY Markdown 渲染
|
|
2
|
+
|
|
3
|
+
import { highlight, supportsLanguage } from "cli-highlight"
|
|
4
|
+
import { createMarkdownStreamer, render } from "markdansi"
|
|
5
|
+
|
|
6
|
+
export interface MarkdownStream {
|
|
7
|
+
push(text: string): string
|
|
8
|
+
finish(): string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 终端宽度
|
|
12
|
+
function terminalWidth(): number {
|
|
13
|
+
return Math.max(40, (process.stdout.columns ?? 80) - 2)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 语言别名
|
|
17
|
+
const LANGUAGE_ALIASES: Readonly<Record<string, string>> = {
|
|
18
|
+
"c++": "cpp",
|
|
19
|
+
asm: "x86asm",
|
|
20
|
+
proto: "protobuf",
|
|
21
|
+
shell: "bash",
|
|
22
|
+
sh: "bash",
|
|
23
|
+
vimscript: "vim",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 代码块高亮
|
|
27
|
+
function highlightCode(code: string, language?: string): string {
|
|
28
|
+
if (!markdownColor() || language === undefined) {
|
|
29
|
+
return code
|
|
30
|
+
}
|
|
31
|
+
const resolved = LANGUAGE_ALIASES[language.toLowerCase()] ?? language
|
|
32
|
+
if (!supportsLanguage(resolved)) {
|
|
33
|
+
return code
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return highlight(code, { language: resolved, ignoreIllegals: true })
|
|
37
|
+
} catch {
|
|
38
|
+
return code
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 单行代码块补一行,markdansi 才会画框
|
|
43
|
+
function ensureCodeBox(block: string): string {
|
|
44
|
+
const match = /^(`{3,}|~{3,})([^\n]*)\n([\s\S]*?)\n\1$/.exec(block)
|
|
45
|
+
if (match === null) {
|
|
46
|
+
return block
|
|
47
|
+
}
|
|
48
|
+
const [, fence, info, content] = match
|
|
49
|
+
if (content === undefined || content.includes("\n")) {
|
|
50
|
+
return block
|
|
51
|
+
}
|
|
52
|
+
return `${fence}${info ?? ""}\n${content}\n\u200B\n${fence}`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 去掉单行代码框的占位行
|
|
56
|
+
function stripCodePad(output: string): string {
|
|
57
|
+
return output.replace(/^.*\u200B.*\n/m, "")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 代码块外的 Markdown 预处理
|
|
61
|
+
function prepareMarkdown(markdown: string): string {
|
|
62
|
+
const parts = markdown.split(/(```[\s\S]*?```|~~~[\s\S]*?~~~)/g)
|
|
63
|
+
return parts
|
|
64
|
+
.map((part, index) => {
|
|
65
|
+
if (index % 2 === 1) {
|
|
66
|
+
return ensureCodeBox(part)
|
|
67
|
+
}
|
|
68
|
+
return part
|
|
69
|
+
.replace(
|
|
70
|
+
/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g,
|
|
71
|
+
(_match, alt: string, url: string) =>
|
|
72
|
+
alt === "" ? `图片(${url})` : `图片:${alt}(${url})`,
|
|
73
|
+
)
|
|
74
|
+
.replace(/<summary>([\s\S]*?)<\/summary>/gi, "▶ $1")
|
|
75
|
+
.replace(/<\/?details[^>]*>/gi, "")
|
|
76
|
+
.replace(/^(\s*[-*+]\s+)\[x\]\s*/gim, "$1☑ ")
|
|
77
|
+
.replace(/^(\s*[-*+]\s+)\[ \]\s*/gim, "$1☐ ")
|
|
78
|
+
})
|
|
79
|
+
.join("")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 是否启用颜色
|
|
83
|
+
export function markdownColor(): boolean {
|
|
84
|
+
return (
|
|
85
|
+
process.stdout.isTTY === true &&
|
|
86
|
+
process.env["NO_COLOR"] === undefined &&
|
|
87
|
+
process.env["TERM"] !== "dumb"
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 渲染完整 Markdown
|
|
92
|
+
export function renderMarkdown(markdown: string): string {
|
|
93
|
+
try {
|
|
94
|
+
return stripCodePad(
|
|
95
|
+
render(prepareMarkdown(markdown), {
|
|
96
|
+
width: terminalWidth(),
|
|
97
|
+
color: markdownColor(),
|
|
98
|
+
hyperlinks: markdownColor(),
|
|
99
|
+
highlighter: highlightCode,
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
} catch {
|
|
103
|
+
return markdown
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 流式渲染 Markdown
|
|
108
|
+
export function createMarkdownStream(): MarkdownStream {
|
|
109
|
+
const streamer = createMarkdownStreamer({
|
|
110
|
+
render: (markdown) =>
|
|
111
|
+
stripCodePad(
|
|
112
|
+
render(prepareMarkdown(markdown), {
|
|
113
|
+
width: terminalWidth(),
|
|
114
|
+
color: markdownColor(),
|
|
115
|
+
hyperlinks: markdownColor(),
|
|
116
|
+
highlighter: highlightCode,
|
|
117
|
+
}),
|
|
118
|
+
),
|
|
119
|
+
spacing: "single",
|
|
120
|
+
})
|
|
121
|
+
return {
|
|
122
|
+
push(text) {
|
|
123
|
+
try {
|
|
124
|
+
return streamer.push(text)
|
|
125
|
+
} catch {
|
|
126
|
+
return text
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
finish() {
|
|
130
|
+
try {
|
|
131
|
+
return streamer.finish()
|
|
132
|
+
} catch {
|
|
133
|
+
return ""
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 工具调用的终端展示:中文动作名 + 一行参数摘要。
|
|
3
|
+
* 与网页里的工具行保持一致(执行命令 / 读取文件 / 搜索网页 …)。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const TOOL_LABELS: Readonly<Record<string, string>> = {
|
|
7
|
+
execute_code: "执行命令",
|
|
8
|
+
read: "读取文件",
|
|
9
|
+
delete_file: "移入回收站",
|
|
10
|
+
web_search: "搜索网页",
|
|
11
|
+
web_fetch: "抓取网页",
|
|
12
|
+
query_task: "查询任务",
|
|
13
|
+
stop_task: "停止任务",
|
|
14
|
+
ask: "询问用户",
|
|
15
|
+
skill_list: "列出技能",
|
|
16
|
+
skill_read: "读取技能",
|
|
17
|
+
skill_install: "安装技能",
|
|
18
|
+
skill_modify: "修改技能",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const SUMMARY_LIMIT = 160
|
|
22
|
+
|
|
23
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
24
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function text(value: unknown): string {
|
|
28
|
+
return typeof value === "string" ? value.trim() : ""
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function truncate(value: string): string {
|
|
32
|
+
const line = value.split(/\r?\n/)[0]?.trim() ?? ""
|
|
33
|
+
return line.length > SUMMARY_LIMIT ? `${line.slice(0, SUMMARY_LIMIT)}…` : line
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 工具名 → 中文动作名;未知工具直接显示原名 */
|
|
37
|
+
export function toolLabel(name: string): string {
|
|
38
|
+
return TOOL_LABELS[name] ?? name
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 工具参数 → 一行摘要(命令、路径、搜索词等) */
|
|
42
|
+
export function toolSummary(name: string, args: Record<string, unknown>): string {
|
|
43
|
+
if (name === "execute_code") {
|
|
44
|
+
const command = text(args["command"])
|
|
45
|
+
const rawArgv = args["argv"]
|
|
46
|
+
const argv = Array.isArray(rawArgv)
|
|
47
|
+
? rawArgv.filter((item): item is string => typeof item === "string")
|
|
48
|
+
: []
|
|
49
|
+
return truncate([command, ...argv].filter((item) => item !== "").join(" "))
|
|
50
|
+
}
|
|
51
|
+
if (name === "delete_file") {
|
|
52
|
+
return text(args["path"])
|
|
53
|
+
}
|
|
54
|
+
if (name === "read") {
|
|
55
|
+
return truncate(text(args["file_path"]))
|
|
56
|
+
}
|
|
57
|
+
if (name === "web_search") {
|
|
58
|
+
return truncate(text(args["query"]))
|
|
59
|
+
}
|
|
60
|
+
if (name === "web_fetch") {
|
|
61
|
+
return truncate(text(args["url"]))
|
|
62
|
+
}
|
|
63
|
+
if (name === "query_task") {
|
|
64
|
+
return truncate(text(args["task_id"]))
|
|
65
|
+
}
|
|
66
|
+
if (name === "stop_task") {
|
|
67
|
+
return truncate([text(args["task_id"]), text(args["type"])].filter(Boolean).join(" "))
|
|
68
|
+
}
|
|
69
|
+
if (name === "ask") {
|
|
70
|
+
return truncate(text(args["question"]))
|
|
71
|
+
}
|
|
72
|
+
if (name === "skill_read" || name === "skill_install" || name === "skill_modify") {
|
|
73
|
+
return truncate(text(args["name"]) || text(args["path"]))
|
|
74
|
+
}
|
|
75
|
+
const first = Object.values(args).find((value): value is string => typeof value === "string")
|
|
76
|
+
return truncate(first ?? "")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 参数是 JSON 字符串时先解析,失败按空对象处理 */
|
|
80
|
+
export function toolArgs(raw: string): Record<string, unknown> {
|
|
81
|
+
try {
|
|
82
|
+
const value: unknown = JSON.parse(raw)
|
|
83
|
+
return isRecord(value) ? value : {}
|
|
84
|
+
} catch {
|
|
85
|
+
return {}
|
|
86
|
+
}
|
|
87
|
+
}
|