nikcli 0.0.6
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/.turbo/turbo-typecheck.log +1 -0
- package/AGENTS.md +27 -0
- package/Dockerfile +18 -0
- package/README.md +15 -0
- package/bin/nikcli +84 -0
- package/config.json +13 -0
- package/docs/tailscale-mobile/01-tailscale-setup.md +94 -0
- package/docs/tailscale-mobile/02-host-setup.md +115 -0
- package/docs/tailscale-mobile/03-phone-and-serve.md +134 -0
- package/docs/tailscale-mobile/README.md +59 -0
- package/examples/README.md +54 -0
- package/package.json +147 -0
- package/parsers-config.ts +253 -0
- package/script/build.ts +179 -0
- package/script/postinstall.mjs +125 -0
- package/script/publish-registries.ts +187 -0
- package/script/publish.ts +100 -0
- package/script/schema.ts +47 -0
- package/script/seed-e2e.ts +50 -0
- package/sequential-prancing-forest.md +373 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +1303 -0
- package/src/acp/session.ts +105 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +528 -0
- package/src/agent/generate.txt +32 -0
- package/src/agent/prompt/compaction.txt +14 -0
- package/src/agent/prompt/explore.txt +18 -0
- package/src/agent/prompt/summary.txt +11 -0
- package/src/agent/prompt/title.txt +44 -0
- package/src/auth/index.ts +73 -0
- package/src/bun/index.ts +119 -0
- package/src/bun/registry.ts +54 -0
- package/src/bus/bus-event.ts +43 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +105 -0
- package/src/chatbot/handlers.ts +150 -0
- package/src/chatbot/index.ts +132 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +69 -0
- package/src/cli/cmd/ads.ts +377 -0
- package/src/cli/cmd/agent.ts +259 -0
- package/src/cli/cmd/auth.ts +400 -0
- package/src/cli/cmd/chatbot.ts +420 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/companion.ts +81 -0
- package/src/cli/cmd/connectors.ts +593 -0
- package/src/cli/cmd/debug/agent.ts +166 -0
- package/src/cli/cmd/debug/config.ts +16 -0
- package/src/cli/cmd/debug/file.ts +97 -0
- package/src/cli/cmd/debug/index.ts +48 -0
- package/src/cli/cmd/debug/lsp.ts +52 -0
- package/src/cli/cmd/debug/ripgrep.ts +87 -0
- package/src/cli/cmd/debug/scrap.ts +16 -0
- package/src/cli/cmd/debug/skill.ts +16 -0
- package/src/cli/cmd/debug/snapshot.ts +52 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +412 -0
- package/src/cli/cmd/image-model.ts +128 -0
- package/src/cli/cmd/import.ts +201 -0
- package/src/cli/cmd/lovable.ts +128 -0
- package/src/cli/cmd/mcp.ts +738 -0
- package/src/cli/cmd/mobile.ts +223 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/plug.ts +231 -0
- package/src/cli/cmd/pr.ts +104 -0
- package/src/cli/cmd/rag-model.ts +167 -0
- package/src/cli/cmd/remote.ts +416 -0
- package/src/cli/cmd/run.ts +589 -0
- package/src/cli/cmd/serve.ts +51 -0
- package/src/cli/cmd/session.ts +133 -0
- package/src/cli/cmd/speak-model.ts +204 -0
- package/src/cli/cmd/stats.ts +402 -0
- package/src/cli/cmd/tui/app.tsx +841 -0
- package/src/cli/cmd/tui/attach.ts +31 -0
- package/src/cli/cmd/tui/component/border.tsx +75 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +172 -0
- package/src/cli/cmd/tui/component/dialog-config.tsx +291 -0
- package/src/cli/cmd/tui/component/dialog-connectors.tsx +440 -0
- package/src/cli/cmd/tui/component/dialog-image-model.tsx +97 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +234 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +260 -0
- package/src/cli/cmd/tui/component/dialog-rag-model.tsx +217 -0
- package/src/cli/cmd/tui/component/dialog-remote.tsx +489 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +170 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-settings/index.tsx +59 -0
- package/src/cli/cmd/tui/component/dialog-settings/prompt.tsx +40 -0
- package/src/cli/cmd/tui/component/dialog-settings/sidebar.tsx +39 -0
- package/src/cli/cmd/tui/component/dialog-settings/spinner.tsx +62 -0
- package/src/cli/cmd/tui/component/dialog-settings/ui.tsx +58 -0
- package/src/cli/cmd/tui/component/dialog-skills.tsx +117 -0
- package/src/cli/cmd/tui/component/dialog-speak-model.tsx +304 -0
- package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +165 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-create.tsx +717 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +52 -0
- package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +350 -0
- package/src/cli/cmd/tui/component/error-component.tsx +91 -0
- package/src/cli/cmd/tui/component/logo.tsx +103 -0
- package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +669 -0
- package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +2165 -0
- package/src/cli/cmd/tui/component/prompt/stash.tsx +63 -0
- package/src/cli/cmd/tui/component/spinner.tsx +24 -0
- package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
- package/src/cli/cmd/tui/component/table/markdown-table.tsx +267 -0
- package/src/cli/cmd/tui/component/table-db/db/connections.ts +75 -0
- package/src/cli/cmd/tui/component/table-db/db/db-connection.ts +223 -0
- package/src/cli/cmd/tui/component/table-db/db/db-preview.ts +202 -0
- package/src/cli/cmd/tui/component/table-db/db/factory.ts +77 -0
- package/src/cli/cmd/tui/component/table-db/db/index.ts +9 -0
- package/src/cli/cmd/tui/component/table-db/db/mysql-connection.ts +330 -0
- package/src/cli/cmd/tui/component/table-db/db/postgres-connection.ts +338 -0
- package/src/cli/cmd/tui/component/table-db/db/sqlite-connection.ts +302 -0
- package/src/cli/cmd/tui/component/table-db/db/types.ts +108 -0
- package/src/cli/cmd/tui/component/table-db/table/dbedit-hooks.ts +74 -0
- package/src/cli/cmd/tui/component/table-db/table/index.ts +15 -0
- package/src/cli/cmd/tui/component/table-db/table/table-events.ts +54 -0
- package/src/cli/cmd/tui/component/table-db/table/table-formatters.ts +191 -0
- package/src/cli/cmd/tui/component/table-db/table/table-hooks.ts +105 -0
- package/src/cli/cmd/tui/component/table-db/table/table-keyboard-handler.ts +255 -0
- package/src/cli/cmd/tui/component/table-db/table/table-layout-engine.ts +208 -0
- package/src/cli/cmd/tui/component/table-db/table/table-renderable.ts +486 -0
- package/src/cli/cmd/tui/component/table-db/table/table-selection-manager.ts +136 -0
- package/src/cli/cmd/tui/component/table-db/table/table-state.ts +198 -0
- package/src/cli/cmd/tui/component/table-db/table/types.ts +69 -0
- package/src/cli/cmd/tui/component/table-db/ui/db-visualizer.tsx +71 -0
- package/src/cli/cmd/tui/component/table-db/ui/index.ts +2 -0
- package/src/cli/cmd/tui/component/table-db/ui/table-renderer.ts +607 -0
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
- package/src/cli/cmd/tui/component/tips.tsx +195 -0
- package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
- package/src/cli/cmd/tui/context/args.tsx +14 -0
- package/src/cli/cmd/tui/context/directory.ts +13 -0
- package/src/cli/cmd/tui/context/exit.tsx +24 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +102 -0
- package/src/cli/cmd/tui/context/kv.tsx +52 -0
- package/src/cli/cmd/tui/context/local.tsx +458 -0
- package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +54 -0
- package/src/cli/cmd/tui/context/sdk.tsx +128 -0
- package/src/cli/cmd/tui/context/server.tsx +8 -0
- package/src/cli/cmd/tui/context/sync.tsx +510 -0
- package/src/cli/cmd/tui/context/theme/abyss.json +233 -0
- package/src/cli/cmd/tui/context/theme/apple.json +235 -0
- package/src/cli/cmd/tui/context/theme/arctic.json +232 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/ayuai.json +229 -0
- package/src/cli/cmd/tui/context/theme/blood.json +229 -0
- package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
- package/src/cli/cmd/tui/context/theme/catmoe.json +235 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-latte.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +259 -0
- package/src/cli/cmd/tui/context/theme/charcoal.json +230 -0
- package/src/cli/cmd/tui/context/theme/chromatic.json +235 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/cosmic.json +234 -0
- package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
- package/src/cli/cmd/tui/context/theme/cyber.json +235 -0
- package/src/cli/cmd/tui/context/theme/dawnfox.json +229 -0
- package/src/cli/cmd/tui/context/theme/dimension.json +235 -0
- package/src/cli/cmd/tui/context/theme/dracula-official.json +222 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/dream.json +235 -0
- package/src/cli/cmd/tui/context/theme/duo.json +235 -0
- package/src/cli/cmd/tui/context/theme/dusk.json +235 -0
- package/src/cli/cmd/tui/context/theme/ebony.json +232 -0
- package/src/cli/cmd/tui/context/theme/equilibrium.json +232 -0
- package/src/cli/cmd/tui/context/theme/ethereal.json +235 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/fusion.json +235 -0
- package/src/cli/cmd/tui/context/theme/ghost.json +235 -0
- package/src/cli/cmd/tui/context/theme/github-dark.json +229 -0
- package/src/cli/cmd/tui/context/theme/github-dimmed.json +231 -0
- package/src/cli/cmd/tui/context/theme/github-light.json +229 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/glass.json +235 -0
- package/src/cli/cmd/tui/context/theme/gold.json +235 -0
- package/src/cli/cmd/tui/context/theme/gone.json +234 -0
- package/src/cli/cmd/tui/context/theme/greyscale.json +229 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
- package/src/cli/cmd/tui/context/theme/hacker.json +229 -0
- package/src/cli/cmd/tui/context/theme/holo.json +235 -0
- package/src/cli/cmd/tui/context/theme/ink.json +235 -0
- package/src/cli/cmd/tui/context/theme/jet.json +233 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +227 -0
- package/src/cli/cmd/tui/context/theme/lavender.json +236 -0
- package/src/cli/cmd/tui/context/theme/lightph.json +235 -0
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
- package/src/cli/cmd/tui/context/theme/material-ocean.json +230 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +227 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +245 -0
- package/src/cli/cmd/tui/context/theme/midnight.json +235 -0
- package/src/cli/cmd/tui/context/theme/modern.json +235 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/muted.json +229 -0
- package/src/cli/cmd/tui/context/theme/neon.json +229 -0
- package/src/cli/cmd/tui/context/theme/neonfusion.json +235 -0
- package/src/cli/cmd/tui/context/theme/neutral.json +235 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nikcli.json +245 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/nordic.json +235 -0
- package/src/cli/cmd/tui/context/theme/nova.json +235 -0
- package/src/cli/cmd/tui/context/theme/obsidian.json +234 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +231 -0
- package/src/cli/cmd/tui/context/theme/one-pro.json +229 -0
- package/src/cli/cmd/tui/context/theme/onyx.json +233 -0
- package/src/cli/cmd/tui/context/theme/orng.json +249 -0
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +240 -0
- package/src/cli/cmd/tui/context/theme/oxocarbon.json +229 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/poimandres.json +230 -0
- package/src/cli/cmd/tui/context/theme/prism.json +235 -0
- package/src/cli/cmd/tui/context/theme/radiant.json +235 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/shadow.json +235 -0
- package/src/cli/cmd/tui/context/theme/silicon.json +235 -0
- package/src/cli/cmd/tui/context/theme/slate.json +233 -0
- package/src/cli/cmd/tui/context/theme/soft.json +235 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/spectrum.json +235 -0
- package/src/cli/cmd/tui/context/theme/starlight.json +233 -0
- package/src/cli/cmd/tui/context/theme/sunrise.json +235 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tech.json +235 -0
- package/src/cli/cmd/tui/context/theme/tokyonight-storm.json +245 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vapor.json +235 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/vivid.json +232 -0
- package/src/cli/cmd/tui/context/theme/void.json +235 -0
- package/src/cli/cmd/tui/context/theme/vscode.json +235 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme/zinc.json +236 -0
- package/src/cli/cmd/tui/context/theme.tsx +1303 -0
- package/src/cli/cmd/tui/event.ts +48 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +152 -0
- package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +50 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +63 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +96 -0
- package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +48 -0
- package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +288 -0
- package/src/cli/cmd/tui/plugin/api.tsx +407 -0
- package/src/cli/cmd/tui/plugin/index.ts +3 -0
- package/src/cli/cmd/tui/plugin/internal.ts +25 -0
- package/src/cli/cmd/tui/plugin/runtime.ts +1048 -0
- package/src/cli/cmd/tui/plugin/slots.tsx +61 -0
- package/src/cli/cmd/tui/routes/home.tsx +153 -0
- package/src/cli/cmd/tui/routes/session/dbedit.tsx +474 -0
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +65 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +110 -0
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +105 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +75 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +177 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +2280 -0
- package/src/cli/cmd/tui/routes/session/permission.tsx +540 -0
- package/src/cli/cmd/tui/routes/session/question.tsx +435 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
- package/src/cli/cmd/tui/thread.ts +174 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +204 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +102 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +389 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +180 -0
- package/src/cli/cmd/tui/ui/link.tsx +34 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +138 -0
- package/src/cli/cmd/tui/util/clipboard.ts +154 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/signal.ts +7 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/util/transcript.ts +98 -0
- package/src/cli/cmd/tui/win32.ts +110 -0
- package/src/cli/cmd/tui/worker.ts +156 -0
- package/src/cli/cmd/uninstall.ts +357 -0
- package/src/cli/cmd/upgrade.ts +72 -0
- package/src/cli/cmd/web.ts +87 -0
- package/src/cli/cmd/workspace-serve.ts +16 -0
- package/src/cli/error.ts +57 -0
- package/src/cli/network.ts +55 -0
- package/src/cli/remote/index.ts +36 -0
- package/src/cli/remote/notifications.ts +104 -0
- package/src/cli/remote/qr-renderer.ts +86 -0
- package/src/cli/remote/remote-service.ts +757 -0
- package/src/cli/remote/session-manager.ts +284 -0
- package/src/cli/remote/subagent-hooks.ts +151 -0
- package/src/cli/remote/types.ts +121 -0
- package/src/cli/ui.ts +96 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +174 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +99 -0
- package/src/config/config.ts +1760 -0
- package/src/config/markdown.ts +88 -0
- package/src/config/migrate-tui-config.ts +155 -0
- package/src/config/paths.ts +174 -0
- package/src/config/tui-schema.ts +36 -0
- package/src/config/tui.ts +209 -0
- package/src/connectors/api/base.ts +75 -0
- package/src/connectors/api/figma.ts +103 -0
- package/src/connectors/api/github.ts +247 -0
- package/src/connectors/api/lovable.ts +126 -0
- package/src/connectors/api/slack.ts +137 -0
- package/src/connectors/auth.ts +68 -0
- package/src/connectors/cache.ts +119 -0
- package/src/connectors/credentials.ts +81 -0
- package/src/connectors/index.ts +202 -0
- package/src/connectors/registry.ts +358 -0
- package/src/docs/context.ts +120 -0
- package/src/docs/library.ts +189 -0
- package/src/env/index.ts +26 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +411 -0
- package/src/file/ripgrep.ts +402 -0
- package/src/file/time.ts +65 -0
- package/src/file/watcher.ts +127 -0
- package/src/flag/flag.ts +128 -0
- package/src/format/formatter.ts +356 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +57 -0
- package/src/id/id.ts +83 -0
- package/src/ide/index.ts +76 -0
- package/src/index.ts +184 -0
- package/src/installation/index.ts +246 -0
- package/src/lsp/client.ts +250 -0
- package/src/lsp/index.ts +483 -0
- package/src/lsp/language.ts +119 -0
- package/src/lsp/server.ts +2046 -0
- package/src/mcp/auth.ts +121 -0
- package/src/mcp/index.ts +860 -0
- package/src/mcp/oauth-callback.ts +198 -0
- package/src/mcp/oauth-provider.ts +148 -0
- package/src/mobile/auth.ts +97 -0
- package/src/mobile/github-repo.ts +185 -0
- package/src/patch/index.ts +631 -0
- package/src/permission/arity.ts +150 -0
- package/src/permission/dbedit.ts +236 -0
- package/src/permission/index.ts +210 -0
- package/src/permission/next.ts +287 -0
- package/src/plugin/codex.ts +493 -0
- package/src/plugin/copilot.ts +261 -0
- package/src/plugin/index.ts +714 -0
- package/src/plugin/install.ts +379 -0
- package/src/plugin/meta.ts +165 -0
- package/src/plugin/shared.ts +188 -0
- package/src/project/bootstrap.ts +35 -0
- package/src/project/instance.ts +84 -0
- package/src/project/project.ts +373 -0
- package/src/project/state.ts +66 -0
- package/src/project/vcs.ts +76 -0
- package/src/prompt/stash-store.ts +93 -0
- package/src/provider/auth.ts +147 -0
- package/src/provider/models-macro.ts +22 -0
- package/src/provider/models.ts +216 -0
- package/src/provider/provider.ts +1483 -0
- package/src/provider/sdk/openai-compatible/src/README.md +5 -0
- package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
- package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
- package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1732 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +828 -0
- package/src/pty/index.ts +241 -0
- package/src/question/index.ts +171 -0
- package/src/rag/chunk.ts +43 -0
- package/src/rag/embed.ts +179 -0
- package/src/rag/index.ts +376 -0
- package/src/rag/storage.ts +76 -0
- package/src/scheduler/index.ts +61 -0
- package/src/server/error.ts +36 -0
- package/src/server/event.ts +7 -0
- package/src/server/mdns.ts +59 -0
- package/src/server/routes/chatbot.ts +205 -0
- package/src/server/routes/companion.ts +729 -0
- package/src/server/routes/config.ts +92 -0
- package/src/server/routes/connectors.ts +121 -0
- package/src/server/routes/dbedit.ts +76 -0
- package/src/server/routes/experimental.ts +210 -0
- package/src/server/routes/file.ts +197 -0
- package/src/server/routes/global.ts +135 -0
- package/src/server/routes/mcp.ts +225 -0
- package/src/server/routes/mobile.ts +2044 -0
- package/src/server/routes/permission.ts +68 -0
- package/src/server/routes/project.ts +82 -0
- package/src/server/routes/provider.ts +235 -0
- package/src/server/routes/pty.ts +169 -0
- package/src/server/routes/question.ts +98 -0
- package/src/server/routes/session.ts +968 -0
- package/src/server/routes/tui.ts +379 -0
- package/src/server/routes/workspace.ts +104 -0
- package/src/server/server.ts +761 -0
- package/src/server/ssh.ts +207 -0
- package/src/session/auth.ts +402 -0
- package/src/session/compaction.ts +253 -0
- package/src/session/generate.ts +38 -0
- package/src/session/index.ts +598 -0
- package/src/session/llm.ts +273 -0
- package/src/session/message-v2.ts +836 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +408 -0
- package/src/session/prompt/anthropic-20250930.txt +165 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex_header.txt +79 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/session/prompt/plan.txt +25 -0
- package/src/session/prompt/qwen.txt +108 -0
- package/src/session/prompt.ts +1942 -0
- package/src/session/retry.ts +90 -0
- package/src/session/revert.ts +120 -0
- package/src/session/stats.ts +404 -0
- package/src/session/status.ts +84 -0
- package/src/session/summary.ts +184 -0
- package/src/session/system.ts +195 -0
- package/src/session/toast.tsx +105 -0
- package/src/session/todo.ts +258 -0
- package/src/session/uninstall.ts +357 -0
- package/src/share/share-next.ts +421 -0
- package/src/share/share.ts +92 -0
- package/src/shell/shell.ts +65 -0
- package/src/skill/index.ts +1 -0
- package/src/skill/skill.ts +232 -0
- package/src/snapshot/index.ts +297 -0
- package/src/storage/storage.ts +227 -0
- package/src/tool/apply_patch.ts +288 -0
- package/src/tool/apply_patch.txt +33 -0
- package/src/tool/bash.ts +252 -0
- package/src/tool/bash.txt +115 -0
- package/src/tool/batch.ts +175 -0
- package/src/tool/batch.txt +24 -0
- package/src/tool/codesearch.ts +132 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/context_collect.ts +152 -0
- package/src/tool/context_collect.txt +9 -0
- package/src/tool/context_diagnostics.ts +81 -0
- package/src/tool/context_diagnostics.txt +5 -0
- package/src/tool/context_related.ts +117 -0
- package/src/tool/context_related.txt +5 -0
- package/src/tool/context_search.ts +108 -0
- package/src/tool/context_search.txt +8 -0
- package/src/tool/db-diff.ts +434 -0
- package/src/tool/db-table.txt +15 -0
- package/src/tool/docs_add.ts +50 -0
- package/src/tool/docs_add.txt +5 -0
- package/src/tool/docs_context.ts +56 -0
- package/src/tool/docs_context.txt +4 -0
- package/src/tool/docs_gap_report.ts +79 -0
- package/src/tool/docs_gap_report.txt +7 -0
- package/src/tool/docs_load.ts +41 -0
- package/src/tool/docs_load.txt +4 -0
- package/src/tool/docs_request.ts +129 -0
- package/src/tool/docs_request.txt +7 -0
- package/src/tool/docs_search.ts +51 -0
- package/src/tool/docs_search.txt +6 -0
- package/src/tool/docs_unload.ts +38 -0
- package/src/tool/docs_unload.txt +5 -0
- package/src/tool/edit.ts +614 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/external-directory.ts +32 -0
- package/src/tool/generate_image.ts +174 -0
- package/src/tool/generate_image.txt +12 -0
- package/src/tool/glob.ts +79 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +153 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +116 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp.ts +96 -0
- package/src/tool/lsp.txt +19 -0
- package/src/tool/memory_search.ts +141 -0
- package/src/tool/memory_search.txt +8 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/plan-enter.txt +14 -0
- package/src/tool/plan-exit.txt +13 -0
- package/src/tool/plan.ts +130 -0
- package/src/tool/question.ts +33 -0
- package/src/tool/question.txt +10 -0
- package/src/tool/rag_index.ts +77 -0
- package/src/tool/rag_index.txt +10 -0
- package/src/tool/rag_reset.ts +26 -0
- package/src/tool/rag_reset.txt +4 -0
- package/src/tool/rag_search.ts +62 -0
- package/src/tool/rag_search.txt +6 -0
- package/src/tool/rag_status.ts +45 -0
- package/src/tool/rag_status.txt +4 -0
- package/src/tool/read.ts +203 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +214 -0
- package/src/tool/skill.ts +169 -0
- package/src/tool/skill.txt +3 -0
- package/src/tool/smart_docs.ts +74 -0
- package/src/tool/smart_docs.txt +7 -0
- package/src/tool/speak/elevenlabs.ts +201 -0
- package/src/tool/speak/openrouter.ts +240 -0
- package/src/tool/speak/provider.ts +83 -0
- package/src/tool/speak.ts +440 -0
- package/src/tool/task.ts +194 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +53 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +87 -0
- package/src/tool/tree.ts +218 -0
- package/src/tool/tree.txt +8 -0
- package/src/tool/truncation.ts +106 -0
- package/src/tool/use-connector.ts +47 -0
- package/src/tool/voice.ts +188 -0
- package/src/tool/webfetch.ts +205 -0
- package/src/tool/webfetch.txt +13 -0
- package/src/tool/websearch.ts +150 -0
- package/src/tool/websearch.txt +14 -0
- package/src/tool/write.ts +80 -0
- package/src/tool/write.txt +8 -0
- package/src/util/archive.ts +16 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/error.ts +77 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +125 -0
- package/src/util/flock.ts +329 -0
- package/src/util/fn.ts +11 -0
- package/src/util/format.ts +20 -0
- package/src/util/hash.ts +7 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +103 -0
- package/src/util/lazy.ts +18 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +180 -0
- package/src/util/network.ts +9 -0
- package/src/util/process.ts +15 -0
- package/src/util/queue.ts +32 -0
- package/src/util/record.ts +3 -0
- package/src/util/rpc.ts +66 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +56 -0
- package/src/workspace/adaptors/index.ts +271 -0
- package/src/workspace/adaptors/types.ts +14 -0
- package/src/workspace/adaptors/worktree.ts +31 -0
- package/src/workspace/config.ts +19 -0
- package/src/workspace/index.ts +223 -0
- package/src/workspace/session-proxy-middleware.ts +97 -0
- package/src/workspace/sse.ts +66 -0
- package/src/workspace/workspace-context.ts +23 -0
- package/src/workspace/workspace-server/routes.ts +33 -0
- package/src/workspace/workspace-server/server.ts +47 -0
- package/src/worktree/index.ts +487 -0
- package/sst-env.d.ts +10 -0
- package/test/benchmark.test.ts +121 -0
- package/test/build-optimizations.test.ts +124 -0
- package/test/id-benchmark.test.ts +132 -0
- package/test/optimizations.test.ts +302 -0
- package/test/preload.ts +1 -0
- package/test/solidjs-benchmark.test.ts +262 -0
- package/test/solidjs-optimizations.test.ts +259 -0
- package/test/tui-benchmark.test.ts +230 -0
- package/test/wildcard-benchmark.test.ts +180 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import z from "zod"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import os from "os"
|
|
4
|
+
import { spawn } from "child_process"
|
|
5
|
+
import { unlinkSync } from "fs"
|
|
6
|
+
|
|
7
|
+
import { Tool } from "./tool"
|
|
8
|
+
import { Log } from "@/util/log"
|
|
9
|
+
import { Config } from "@/config/config"
|
|
10
|
+
import { ttsRegistry, type TTSProvider } from "./speak/provider"
|
|
11
|
+
import { ELEVENLABS_VOICES_LIST, elevenLabsProvider } from "./speak/elevenlabs"
|
|
12
|
+
import { OPENROUTER_VOICES_LIST, openRouterProvider } from "./speak/openrouter"
|
|
13
|
+
|
|
14
|
+
const log = Log.create({ service: "tool.speak" })
|
|
15
|
+
|
|
16
|
+
const DEFAULT_VOICE_ID = "YOq2y2Up4RgXP2HyXjE5"
|
|
17
|
+
const DEFAULT_MODEL_ID = "eleven_v3"
|
|
18
|
+
const DEFAULT_OUTPUT_FORMAT = "mp3_44100_128"
|
|
19
|
+
const OPENROUTER_DEFAULT_VOICE_ID = "alloy"
|
|
20
|
+
const OPENROUTER_DEFAULT_MODEL_ID = "openai/gpt-audio-mini"
|
|
21
|
+
const OPENROUTER_DEFAULT_OUTPUT_FORMAT = "mp3"
|
|
22
|
+
const DEFAULT_PROVIDER = "openrouter"
|
|
23
|
+
|
|
24
|
+
// Register built-in providers
|
|
25
|
+
ttsRegistry.register(elevenLabsProvider)
|
|
26
|
+
ttsRegistry.register(openRouterProvider)
|
|
27
|
+
|
|
28
|
+
function defaultVoiceIdForProvider(providerId: string): string {
|
|
29
|
+
if (providerId === "openrouter") return OPENROUTER_DEFAULT_VOICE_ID
|
|
30
|
+
return DEFAULT_VOICE_ID
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function defaultModelIdForProvider(providerId: string): string {
|
|
34
|
+
if (providerId === "openrouter") return OPENROUTER_DEFAULT_MODEL_ID
|
|
35
|
+
return DEFAULT_MODEL_ID
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function defaultOutputFormatForProvider(providerId: string): string {
|
|
39
|
+
if (providerId === "openrouter") return OPENROUTER_DEFAULT_OUTPUT_FORMAT
|
|
40
|
+
return DEFAULT_OUTPUT_FORMAT
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function envVoiceIdForProvider(providerId: string): string | undefined {
|
|
44
|
+
if (providerId === "openrouter") {
|
|
45
|
+
return process.env.NIKCLI_OPENROUTER_VOICE_ID
|
|
46
|
+
}
|
|
47
|
+
return process.env.NIKCLI_ELEVENLABS_VOICE_ID
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function envModelIdForProvider(providerId: string): string | undefined {
|
|
51
|
+
if (providerId === "openrouter") {
|
|
52
|
+
return process.env.NIKCLI_OPENROUTER_MODEL_ID
|
|
53
|
+
}
|
|
54
|
+
return process.env.NIKCLI_ELEVENLABS_MODEL_ID
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function envOutputFormatForProvider(providerId: string): string | undefined {
|
|
58
|
+
if (providerId === "openrouter") {
|
|
59
|
+
return process.env.NIKCLI_OPENROUTER_OUTPUT_FORMAT
|
|
60
|
+
}
|
|
61
|
+
return process.env.NIKCLI_ELEVENLABS_OUTPUT_FORMAT
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Helper to resolve providers list to try, starting with the primary choice
|
|
65
|
+
async function resolveProvidersToTry(
|
|
66
|
+
providerParam?: string,
|
|
67
|
+
configProvider?: string,
|
|
68
|
+
): Promise<{ provider: TTSProvider; id: string }[]> {
|
|
69
|
+
const primaryId = providerParam ?? configProvider ?? process.env.NIKCLI_SPEAK_PROVIDER ?? DEFAULT_PROVIDER
|
|
70
|
+
|
|
71
|
+
const primary = ttsRegistry.get(primaryId)
|
|
72
|
+
if (!primary) {
|
|
73
|
+
const available = ttsRegistry
|
|
74
|
+
.list()
|
|
75
|
+
.map((p) => p.id)
|
|
76
|
+
.join(", ")
|
|
77
|
+
throw new Error(`Unknown TTS provider: ${primaryId}. Available providers: ${available}`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Determine fallback order: primary first, then others
|
|
81
|
+
const others = ttsRegistry.list().filter((p) => p.id !== primaryId)
|
|
82
|
+
|
|
83
|
+
return [{ provider: primary, id: primaryId }, ...others.map((p) => ({ provider: p, id: p.id }))]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Voice validation - currently only validates ElevenLabs voices
|
|
87
|
+
const KNOWN_ELEVENLABS_VOICES = ELEVENLABS_VOICES_LIST.map((voice) => voice.id)
|
|
88
|
+
const KNOWN_OPENROUTER_VOICES = new Set(OPENROUTER_VOICES_LIST.map((voice) => voice.id.toLowerCase()))
|
|
89
|
+
|
|
90
|
+
// ElevenLabs voice IDs are typically 21-character alphanumeric strings
|
|
91
|
+
const VOICE_ID_PATTERN = /^[a-zA-Z0-9_-]{21}$/
|
|
92
|
+
|
|
93
|
+
function validateVoiceId(voiceId: string, providerId: string): { valid: boolean; isKnown: boolean } {
|
|
94
|
+
if (providerId === "openrouter") {
|
|
95
|
+
const normalized = voiceId.toLowerCase()
|
|
96
|
+
const isKnown = KNOWN_OPENROUTER_VOICES.has(normalized)
|
|
97
|
+
return { valid: isKnown, isKnown }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// For now, only strictly validate ElevenLabs voices by pattern
|
|
101
|
+
if (providerId !== "elevenlabs") {
|
|
102
|
+
return { valid: true, isKnown: false }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const matchesPattern = VOICE_ID_PATTERN.test(voiceId)
|
|
106
|
+
const isKnown = KNOWN_ELEVENLABS_VOICES.includes(voiceId)
|
|
107
|
+
return { valid: matchesPattern, isKnown }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function resolveVoiceId(
|
|
111
|
+
inputVoiceId: string | undefined,
|
|
112
|
+
configVoiceId: string | undefined,
|
|
113
|
+
envVoiceId: string | undefined,
|
|
114
|
+
providerId: string,
|
|
115
|
+
): string {
|
|
116
|
+
const providedVoiceId = inputVoiceId ?? configVoiceId ?? envVoiceId
|
|
117
|
+
|
|
118
|
+
if (!providedVoiceId) {
|
|
119
|
+
return defaultVoiceIdForProvider(providerId)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const validation = validateVoiceId(providedVoiceId, providerId)
|
|
123
|
+
|
|
124
|
+
if (!validation.valid) {
|
|
125
|
+
log.warn("invalid voiceId format - using default", {
|
|
126
|
+
provided: providedVoiceId,
|
|
127
|
+
expected: `pattern: ${VOICE_ID_PATTERN.source}`,
|
|
128
|
+
})
|
|
129
|
+
return defaultVoiceIdForProvider(providerId)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!validation.isKnown) {
|
|
133
|
+
log.warn("voiceId not in known voices list - allowing anyway", {
|
|
134
|
+
voiceId: providedVoiceId,
|
|
135
|
+
providerId,
|
|
136
|
+
hint: "voice may work but is not in the known voices list",
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return providedVoiceId
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const DEFAULT_TIMEOUT_MS = 30_000
|
|
144
|
+
const MAX_TIMEOUT_MS = 120_000
|
|
145
|
+
const MAX_TEXT_LENGTH = 800
|
|
146
|
+
|
|
147
|
+
type AudioPlayer = {
|
|
148
|
+
name: "afplay" | "ffplay" | "mpg123"
|
|
149
|
+
command: string
|
|
150
|
+
args: (input: { filePath: string; volume: number }) => string[]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function clampNumber(value: number, min: number, max: number): number {
|
|
154
|
+
if (value < min) return min
|
|
155
|
+
if (value > max) return max
|
|
156
|
+
return value
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function detectPlayer(): AudioPlayer | undefined {
|
|
160
|
+
const afplay = Bun.which("afplay")
|
|
161
|
+
if (process.platform === "darwin" && afplay) {
|
|
162
|
+
return {
|
|
163
|
+
name: "afplay",
|
|
164
|
+
command: afplay,
|
|
165
|
+
args: ({ filePath, volume }) => ["-v", String(clampNumber(volume, 0, 2)), filePath],
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const ffplay = Bun.which("ffplay")
|
|
170
|
+
if (ffplay) {
|
|
171
|
+
// ffplay expects volume in 0-100.
|
|
172
|
+
return {
|
|
173
|
+
name: "ffplay",
|
|
174
|
+
command: ffplay,
|
|
175
|
+
args: ({ filePath, volume }) => {
|
|
176
|
+
const vol = Math.round(clampNumber(volume, 0, 1) * 100)
|
|
177
|
+
return ["-nodisp", "-autoexit", "-loglevel", "error", "-volume", String(vol), filePath]
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const mpg123 = Bun.which("mpg123")
|
|
183
|
+
if (mpg123) {
|
|
184
|
+
return {
|
|
185
|
+
name: "mpg123",
|
|
186
|
+
command: mpg123,
|
|
187
|
+
args: ({ filePath }) => ["-q", filePath],
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return undefined
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function normalizeText(input: string): { text: string; truncated: boolean } {
|
|
195
|
+
const text = input.trim()
|
|
196
|
+
if (!text) throw new Error("Text is required")
|
|
197
|
+
if (text.length <= MAX_TEXT_LENGTH) return { text, truncated: false }
|
|
198
|
+
return { text: text.slice(0, MAX_TEXT_LENGTH - 3) + "...", truncated: true }
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function extensionFromContentType(contentType: string) {
|
|
202
|
+
const lower = contentType.toLowerCase()
|
|
203
|
+
if (lower.includes("wav")) return "wav"
|
|
204
|
+
if (lower.includes("mp3")) return "mp3"
|
|
205
|
+
return "bin"
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function playAudioNonBlocking(player: AudioPlayer, filePath: string, volume: number) {
|
|
209
|
+
const cleanup = () => {
|
|
210
|
+
try {
|
|
211
|
+
unlinkSync(filePath)
|
|
212
|
+
} catch {
|
|
213
|
+
// Ignore cleanup failures.
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const child = spawn(player.command, player.args({ filePath, volume }), {
|
|
218
|
+
detached: process.platform !== "win32",
|
|
219
|
+
stdio: "ignore",
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
child.unref()
|
|
223
|
+
child.once("exit", cleanup)
|
|
224
|
+
child.once("error", (error) => {
|
|
225
|
+
log.error("audio playback failed", { error: error.message, player: player.name })
|
|
226
|
+
cleanup()
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const DESCRIPTION = `Convert text to speech and play it on the machine speakers (non-blocking).
|
|
231
|
+
|
|
232
|
+
This tool supports multiple TTS providers (ElevenLabs and OpenRouter).
|
|
233
|
+
|
|
234
|
+
Audio tag examples (ElevenLabs):
|
|
235
|
+
[laughs] [sighs] [excited] [sad] [angry]
|
|
236
|
+
[whispers] [shouts] [dramatically] [calmly]
|
|
237
|
+
[British accent] [strong French accent]
|
|
238
|
+
|
|
239
|
+
Usage guidance:
|
|
240
|
+
- Use in short bursts to notify about important state changes
|
|
241
|
+
- Good for: task completion, errors requiring attention, questions needing user input
|
|
242
|
+
- Keep messages concise (1-2 sentences)
|
|
243
|
+
|
|
244
|
+
Note: audio plays on the device running nikcli.`
|
|
245
|
+
|
|
246
|
+
export const SpeakTool = Tool.define("speak", {
|
|
247
|
+
description: DESCRIPTION,
|
|
248
|
+
parameters: z.object({
|
|
249
|
+
text: z.string().describe("Text to speak. Can include audio tags like [laughs], [whispers], [excited], etc."),
|
|
250
|
+
provider: z.string().optional().describe("TTS provider (e.g., elevenlabs, openrouter)"),
|
|
251
|
+
stability: z
|
|
252
|
+
.number()
|
|
253
|
+
.min(0)
|
|
254
|
+
.max(1)
|
|
255
|
+
.optional()
|
|
256
|
+
.describe("Voice stability (0-1). Lower = more expressive. Default: 0.5"),
|
|
257
|
+
similarityBoost: z.number().min(0).max(1).optional().describe("Voice similarity boost (0-1). Default: 0.75"),
|
|
258
|
+
speed: z.number().min(0.5).max(2).optional().describe("Speech speed multiplier (0.5-2). Default: 1.0"),
|
|
259
|
+
volume: z.number().min(0).max(2).optional().describe("Playback volume (0-2). Default: 1.0"),
|
|
260
|
+
voiceId: z.string().optional().describe("TTS voice ID (provider-dependent default)"),
|
|
261
|
+
modelId: z.string().optional().describe("TTS model ID (provider-dependent default)"),
|
|
262
|
+
outputFormat: z.string().optional().describe("TTS output format (provider-dependent default)"),
|
|
263
|
+
timeoutMs: z
|
|
264
|
+
.number()
|
|
265
|
+
.int()
|
|
266
|
+
.positive()
|
|
267
|
+
.optional()
|
|
268
|
+
.describe(`Request timeout in milliseconds (default: ${DEFAULT_TIMEOUT_MS})`),
|
|
269
|
+
}),
|
|
270
|
+
async execute(params, ctx) {
|
|
271
|
+
const config = await Config.get()
|
|
272
|
+
const speakConfig = config.speak ?? {}
|
|
273
|
+
|
|
274
|
+
const player = detectPlayer()
|
|
275
|
+
if (!player) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
[
|
|
278
|
+
"No supported audio player found.",
|
|
279
|
+
"",
|
|
280
|
+
"Supported players:",
|
|
281
|
+
"- macOS: afplay",
|
|
282
|
+
"- ffmpeg: ffplay",
|
|
283
|
+
"- mpg123: mpg123",
|
|
284
|
+
].join("\n"),
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Resolve providers list
|
|
289
|
+
const providersToTry = await resolveProvidersToTry(params.provider, speakConfig.provider)
|
|
290
|
+
const failureLogs: string[] = []
|
|
291
|
+
|
|
292
|
+
for (const { provider: ttsProvider, id: providerId } of providersToTry) {
|
|
293
|
+
const voiceId = resolveVoiceId(params.voiceId, speakConfig.model, envVoiceIdForProvider(providerId), providerId)
|
|
294
|
+
const modelId =
|
|
295
|
+
params.modelId ??
|
|
296
|
+
speakConfig.modelId ??
|
|
297
|
+
envModelIdForProvider(providerId) ??
|
|
298
|
+
defaultModelIdForProvider(providerId)
|
|
299
|
+
const outputFormat =
|
|
300
|
+
params.outputFormat ??
|
|
301
|
+
speakConfig.outputFormat ??
|
|
302
|
+
envOutputFormatForProvider(providerId) ??
|
|
303
|
+
defaultOutputFormatForProvider(providerId)
|
|
304
|
+
|
|
305
|
+
const stability = params.stability ?? 0.5
|
|
306
|
+
const similarityBoost = params.similarityBoost ?? 0.75
|
|
307
|
+
const speed = params.speed ?? 1.0
|
|
308
|
+
const volume = params.volume ?? 1.0
|
|
309
|
+
const timeoutMs = clampNumber(params.timeoutMs ?? DEFAULT_TIMEOUT_MS, 1000, MAX_TIMEOUT_MS)
|
|
310
|
+
|
|
311
|
+
const normalized = normalizeText(params.text)
|
|
312
|
+
|
|
313
|
+
// Optionally check if provider is valid (auth keys present)
|
|
314
|
+
// This helps quickly skip providers that are unconfigured
|
|
315
|
+
const validation = await ttsProvider.validate().catch((e) => ({ valid: false, error: e.message }))
|
|
316
|
+
if (!validation.valid) {
|
|
317
|
+
log.warn(`Provider ${providerId} validation failed, skipping`, { error: validation.error })
|
|
318
|
+
failureLogs.push(`[${providerId}] Skipped: Configuration invalid or missing API key (${validation.error})`)
|
|
319
|
+
continue
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
await ctx.ask({
|
|
324
|
+
permission: "speak",
|
|
325
|
+
patterns: [`${providerId}:${voiceId}`],
|
|
326
|
+
always: [`${providerId}*`],
|
|
327
|
+
metadata: {
|
|
328
|
+
provider: providerId,
|
|
329
|
+
voiceId,
|
|
330
|
+
modelId,
|
|
331
|
+
outputFormat,
|
|
332
|
+
player: player.name,
|
|
333
|
+
timeoutMs,
|
|
334
|
+
},
|
|
335
|
+
})
|
|
336
|
+
} catch (askError: any) {
|
|
337
|
+
// If the user rejects the permission, we must throw immediately
|
|
338
|
+
throw askError
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const controller = new AbortController()
|
|
342
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const ttsResponse = await ttsProvider
|
|
346
|
+
.speak(
|
|
347
|
+
{
|
|
348
|
+
text: normalized.text,
|
|
349
|
+
voiceId,
|
|
350
|
+
modelId,
|
|
351
|
+
outputFormat,
|
|
352
|
+
stability,
|
|
353
|
+
similarityBoost,
|
|
354
|
+
speed,
|
|
355
|
+
},
|
|
356
|
+
{ signal: AbortSignal.any([controller.signal, ctx.abort]) },
|
|
357
|
+
)
|
|
358
|
+
.finally(() => clearTimeout(timeoutId))
|
|
359
|
+
|
|
360
|
+
const ext = extensionFromContentType(ttsResponse.contentType)
|
|
361
|
+
const tempFile = path.join(
|
|
362
|
+
os.tmpdir(),
|
|
363
|
+
`nikcli-speak-${Date.now()}-${Math.random().toString(16).slice(2)}.${ext}`,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
await Bun.write(tempFile, ttsResponse.audio)
|
|
367
|
+
playAudioNonBlocking(player, tempFile, volume)
|
|
368
|
+
|
|
369
|
+
const preview = normalized.text.length > 80 ? normalized.text.slice(0, 80) + "..." : normalized.text
|
|
370
|
+
const truncated = normalized.truncated ? " (text truncated)" : ""
|
|
371
|
+
|
|
372
|
+
const outputText = [
|
|
373
|
+
`Playing speech (non-blocking): "${preview}"${truncated}`,
|
|
374
|
+
`Provider: ${ttsProvider.name} (${modelId})`,
|
|
375
|
+
`Voice: ${voiceId}`,
|
|
376
|
+
`Player: ${player.name}`,
|
|
377
|
+
]
|
|
378
|
+
|
|
379
|
+
if (failureLogs.length > 0) {
|
|
380
|
+
outputText.push(`\nFallback sequence:`)
|
|
381
|
+
outputText.push(...failureLogs)
|
|
382
|
+
outputText.push(`[${providerId}] Success!`)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
title: "Speak",
|
|
387
|
+
output: outputText.join("\n"),
|
|
388
|
+
metadata: {
|
|
389
|
+
provider: providerId,
|
|
390
|
+
voiceId,
|
|
391
|
+
modelId,
|
|
392
|
+
outputFormat,
|
|
393
|
+
player: player.name,
|
|
394
|
+
textTruncated: normalized.truncated,
|
|
395
|
+
fallbacks: failureLogs.length,
|
|
396
|
+
},
|
|
397
|
+
}
|
|
398
|
+
} catch (fetchError: any) {
|
|
399
|
+
const errorMessage = fetchError.cause?.message ?? fetchError.message
|
|
400
|
+
|
|
401
|
+
if (fetchError.name === "AbortError") {
|
|
402
|
+
if (ctx.abort.aborted) {
|
|
403
|
+
log.warn("request cancelled by user", { timeoutMs })
|
|
404
|
+
throw new Error("Speech request was cancelled")
|
|
405
|
+
}
|
|
406
|
+
log.error("request timed out", { timeoutMs, voiceId, modelId, provider: providerId })
|
|
407
|
+
failureLogs.push(`[${providerId}] Failed: Request timed out after ${timeoutMs}ms`)
|
|
408
|
+
continue
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
log.error(`network error calling ${ttsProvider.name} API`, {
|
|
412
|
+
error: errorMessage,
|
|
413
|
+
voiceId,
|
|
414
|
+
modelId,
|
|
415
|
+
provider: providerId,
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
if (errorMessage.includes("ENOTFOUND") || errorMessage.includes("dns")) {
|
|
419
|
+
failureLogs.push(`[${providerId}] Failed: DNS/Network error. Check internet connection.`)
|
|
420
|
+
} else if (errorMessage.includes("ECONNREFUSED")) {
|
|
421
|
+
failureLogs.push(`[${providerId}] Failed: Connection refused. Service may be unavailable.`)
|
|
422
|
+
} else {
|
|
423
|
+
failureLogs.push(`[${providerId}] Failed: ${errorMessage}`)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Loop continues to next provider
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// If we reach here, all providers failed
|
|
431
|
+
if (failureLogs.length > 0) {
|
|
432
|
+
throw new Error(`All TTS providers failed to speak:\n${failureLogs.join("\n")}`)
|
|
433
|
+
} else {
|
|
434
|
+
throw new Error("No available TTS providers could be used.")
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
// Export the provider registry for external use (e.g., CLI commands)
|
|
440
|
+
export { ttsRegistry }
|
package/src/tool/task.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { Tool } from "./tool"
|
|
2
|
+
import DESCRIPTION from "./task.txt"
|
|
3
|
+
import z from "zod"
|
|
4
|
+
import { Session } from "../session"
|
|
5
|
+
import { Bus } from "../bus"
|
|
6
|
+
import { MessageV2 } from "../session/message-v2"
|
|
7
|
+
import { Identifier } from "../id/id"
|
|
8
|
+
import { Agent } from "../agent/agent"
|
|
9
|
+
import { SessionPrompt } from "../session/prompt"
|
|
10
|
+
import { iife } from "@/util/iife"
|
|
11
|
+
import { defer } from "@/util/defer"
|
|
12
|
+
import { Config } from "../config/config"
|
|
13
|
+
import { PermissionNext } from "@/permission/next"
|
|
14
|
+
|
|
15
|
+
const parameters = z.object({
|
|
16
|
+
description: z.string().describe("A short (3-5 words) description of the task"),
|
|
17
|
+
prompt: z.string().describe("The task for the agent to perform"),
|
|
18
|
+
subagent_type: z.string().describe("The type of specialized agent to use for this task"),
|
|
19
|
+
session_id: z.string().describe("Existing Task session to continue").optional(),
|
|
20
|
+
command: z.string().describe("The command that triggered this task").optional(),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
export type TaskParams = z.infer<typeof parameters>
|
|
24
|
+
|
|
25
|
+
export async function runSubtask(params: TaskParams, ctx: Tool.Context) {
|
|
26
|
+
const config = await Config.get()
|
|
27
|
+
const bypass = Boolean(ctx.extra?.bypassAgentCheck)
|
|
28
|
+
|
|
29
|
+
if (!bypass) {
|
|
30
|
+
await ctx.ask({
|
|
31
|
+
permission: "task",
|
|
32
|
+
patterns: [params.subagent_type],
|
|
33
|
+
always: ["*"],
|
|
34
|
+
metadata: {
|
|
35
|
+
description: params.description,
|
|
36
|
+
subagent_type: params.subagent_type,
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const agent = await Agent.get(params.subagent_type)
|
|
42
|
+
if (!agent) throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`)
|
|
43
|
+
|
|
44
|
+
const hasTaskPermission = agent.permission.some((rule) => rule.permission === "task")
|
|
45
|
+
|
|
46
|
+
const session = await iife(async () => {
|
|
47
|
+
if (params.session_id) {
|
|
48
|
+
const found = await Session.get(params.session_id).catch(() => {})
|
|
49
|
+
if (found) return found
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return await Session.create({
|
|
53
|
+
parentID: ctx.sessionID,
|
|
54
|
+
title: params.description + ` (@${agent.name} subagent)`,
|
|
55
|
+
permission: [
|
|
56
|
+
{
|
|
57
|
+
permission: "todowrite",
|
|
58
|
+
pattern: "*",
|
|
59
|
+
action: "deny",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
permission: "todoread",
|
|
63
|
+
pattern: "*",
|
|
64
|
+
action: "deny",
|
|
65
|
+
},
|
|
66
|
+
...(hasTaskPermission
|
|
67
|
+
? []
|
|
68
|
+
: [
|
|
69
|
+
{
|
|
70
|
+
permission: "task" as const,
|
|
71
|
+
pattern: "*" as const,
|
|
72
|
+
action: "deny" as const,
|
|
73
|
+
},
|
|
74
|
+
]),
|
|
75
|
+
...(config.experimental?.primary_tools?.map((t) => ({
|
|
76
|
+
pattern: "*",
|
|
77
|
+
action: "allow" as const,
|
|
78
|
+
permission: t,
|
|
79
|
+
})) ?? []),
|
|
80
|
+
],
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
const msg = await MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID })
|
|
85
|
+
if (msg.info.role !== "assistant") throw new Error("Not an assistant message")
|
|
86
|
+
|
|
87
|
+
ctx.metadata({
|
|
88
|
+
title: params.description,
|
|
89
|
+
metadata: {
|
|
90
|
+
sessionId: session.id,
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const messageID = Identifier.ascending("message")
|
|
95
|
+
const parts: Record<string, { id: string; tool: string; state: { status: string; title?: string } }> = {}
|
|
96
|
+
const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
|
97
|
+
if (evt.properties.part.sessionID !== session.id) return
|
|
98
|
+
if (evt.properties.part.messageID === messageID) return
|
|
99
|
+
if (evt.properties.part.type !== "tool") return
|
|
100
|
+
const part = evt.properties.part
|
|
101
|
+
parts[part.id] = {
|
|
102
|
+
id: part.id,
|
|
103
|
+
tool: part.tool,
|
|
104
|
+
state: {
|
|
105
|
+
status: part.state.status,
|
|
106
|
+
title: part.state.status === "completed" ? part.state.title : undefined,
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
ctx.metadata({
|
|
110
|
+
title: params.description,
|
|
111
|
+
metadata: {
|
|
112
|
+
summary: Object.values(parts).sort((a, b) => a.id.localeCompare(b.id)),
|
|
113
|
+
sessionId: session.id,
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const model = agent.model ?? {
|
|
119
|
+
modelID: msg.info.modelID,
|
|
120
|
+
providerID: msg.info.providerID,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function cancel() {
|
|
124
|
+
SessionPrompt.cancel(session.id)
|
|
125
|
+
}
|
|
126
|
+
ctx.abort.addEventListener("abort", cancel)
|
|
127
|
+
using _ = defer(() => ctx.abort.removeEventListener("abort", cancel))
|
|
128
|
+
const promptParts = await SessionPrompt.resolvePromptParts(params.prompt)
|
|
129
|
+
|
|
130
|
+
const result = await SessionPrompt.prompt({
|
|
131
|
+
messageID,
|
|
132
|
+
sessionID: session.id,
|
|
133
|
+
model: {
|
|
134
|
+
modelID: model.modelID,
|
|
135
|
+
providerID: model.providerID,
|
|
136
|
+
},
|
|
137
|
+
agent: agent.name,
|
|
138
|
+
tools: {
|
|
139
|
+
todowrite: false,
|
|
140
|
+
todoread: false,
|
|
141
|
+
...(hasTaskPermission ? {} : { task: false }),
|
|
142
|
+
...Object.fromEntries((config.experimental?.primary_tools ?? []).map((t) => [t, false])),
|
|
143
|
+
},
|
|
144
|
+
parts: promptParts,
|
|
145
|
+
})
|
|
146
|
+
unsub()
|
|
147
|
+
const messages = await Session.messages({ sessionID: session.id })
|
|
148
|
+
const summary = messages
|
|
149
|
+
.filter((x) => x.info.role === "assistant")
|
|
150
|
+
.flatMap((msg) => msg.parts.filter((x: any) => x.type === "tool") as MessageV2.ToolPart[])
|
|
151
|
+
.map((part) => ({
|
|
152
|
+
id: part.id,
|
|
153
|
+
tool: part.tool,
|
|
154
|
+
state: {
|
|
155
|
+
status: part.state.status,
|
|
156
|
+
title: part.state.status === "completed" ? part.state.title : undefined,
|
|
157
|
+
},
|
|
158
|
+
}))
|
|
159
|
+
const text = result.parts.findLast((x) => x.type === "text")?.text ?? ""
|
|
160
|
+
|
|
161
|
+
const output = text + "\n\n" + ["<task_metadata>", `session_id: ${session.id}`, "</task_metadata>"].join("\n")
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
title: params.description,
|
|
165
|
+
metadata: {
|
|
166
|
+
summary,
|
|
167
|
+
sessionId: session.id,
|
|
168
|
+
},
|
|
169
|
+
output,
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export const TaskTool = Tool.define("task", async (ctx) => {
|
|
174
|
+
const agents = await Agent.list().then((x) => x.filter((a) => a.mode !== "primary"))
|
|
175
|
+
|
|
176
|
+
const caller = ctx?.agent
|
|
177
|
+
const accessibleAgents = caller
|
|
178
|
+
? agents.filter((a) => PermissionNext.evaluate("task", a.name, caller.permission).action !== "deny")
|
|
179
|
+
: agents
|
|
180
|
+
|
|
181
|
+
const description = DESCRIPTION.replace(
|
|
182
|
+
"{agents}",
|
|
183
|
+
accessibleAgents
|
|
184
|
+
.map((a) => `- ${a.name}: ${a.description ?? "This subagent should only be called manually by the user."}`)
|
|
185
|
+
.join("\n"),
|
|
186
|
+
)
|
|
187
|
+
return {
|
|
188
|
+
description,
|
|
189
|
+
parameters,
|
|
190
|
+
async execute(params: z.infer<typeof parameters>, ctx) {
|
|
191
|
+
return runSubtask(params, ctx)
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Launch a new agent to handle complex, multistep tasks autonomously.
|
|
2
|
+
|
|
3
|
+
Available agent types and the tools they have access to:
|
|
4
|
+
{agents}
|
|
5
|
+
|
|
6
|
+
When using the Task tool, you must specify a subagent_type parameter to select which agent type to use.
|
|
7
|
+
|
|
8
|
+
When to use the Task tool:
|
|
9
|
+
- When you are instructed to execute custom slash commands. Use the Task tool with the slash command invocation as the entire prompt. The slash command can take arguments. For example: Task(description="Check the file", prompt="/check-file path/to/file.py")
|
|
10
|
+
|
|
11
|
+
When NOT to use the Task tool:
|
|
12
|
+
- If you want to read a specific file path, use the Read or Glob tool instead of the Task tool, to find the match more quickly
|
|
13
|
+
- If you are searching for a specific class definition like "class Foo", use the Glob tool instead, to find the match more quickly
|
|
14
|
+
- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Task tool, to find the match more quickly
|
|
15
|
+
- Other tasks that are not related to the agent descriptions above
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Usage notes:
|
|
19
|
+
1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
20
|
+
2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
|
|
21
|
+
3. Each agent invocation is stateless unless you provide a session_id. Your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.
|
|
22
|
+
4. The agent's outputs should generally be trusted
|
|
23
|
+
5. Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent
|
|
24
|
+
6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
|
|
25
|
+
|
|
26
|
+
Example usage (NOTE: The agents below are fictional examples for illustration only - use the actual agents listed above):
|
|
27
|
+
|
|
28
|
+
<example_agent_descriptions>
|
|
29
|
+
"code-reviewer": use this agent after you are done writing a significant piece of code
|
|
30
|
+
"greeting-responder": use this agent when to respond to user greetings with a friendly joke
|
|
31
|
+
</example_agent_description>
|
|
32
|
+
|
|
33
|
+
<example>
|
|
34
|
+
user: "Please write a function that checks if a number is prime"
|
|
35
|
+
assistant: Sure let me write a function that checks if a number is prime
|
|
36
|
+
assistant: First let me use the Write tool to write a function that checks if a number is prime
|
|
37
|
+
assistant: I'm going to use the Write tool to write the following code:
|
|
38
|
+
<code>
|
|
39
|
+
function isPrime(n) {
|
|
40
|
+
if (n <= 1) return false
|
|
41
|
+
for (let i = 2; i * i <= n; i++) {
|
|
42
|
+
if (n % i === 0) return false
|
|
43
|
+
}
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
</code>
|
|
47
|
+
<commentary>
|
|
48
|
+
Since a significant piece of code was written and the task was completed, now use the code-reviewer agent to review the code
|
|
49
|
+
</commentary>
|
|
50
|
+
assistant: Now let me use the code-reviewer agent to review the code
|
|
51
|
+
assistant: Uses the Task tool to launch the code-reviewer agent
|
|
52
|
+
</example>
|
|
53
|
+
|
|
54
|
+
<example>
|
|
55
|
+
user: "Hello"
|
|
56
|
+
<commentary>
|
|
57
|
+
Since the user is greeting, use the greeting-responder agent to respond with a friendly joke
|
|
58
|
+
</commentary>
|
|
59
|
+
assistant: "I'm going to use the Task tool to launch the with the greeting-responder agent"
|
|
60
|
+
</example>
|