@oh-my-pi/pi-coding-agent 7.0.0 → 8.0.1
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/CHANGELOG.md +87 -0
- package/README.md +1 -1
- package/docs/hooks.md +2 -2
- package/docs/sdk.md +1 -1
- package/package.json +12 -11
- package/scripts/format-prompts.ts +143 -0
- package/scripts/generate-template.ts +1 -1
- package/src/cli/args.ts +3 -3
- package/src/cli/config-cli.ts +4 -4
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +2 -2
- package/src/cli/plugin-cli.ts +3 -3
- package/src/cli/session-picker.ts +2 -2
- package/src/cli/setup-cli.ts +2 -2
- package/src/cli/stats-cli.ts +1 -1
- package/src/cli/update-cli.ts +2 -2
- package/src/{core → config}/keybindings.ts +1 -1
- package/src/{core → config}/model-registry.ts +1 -1
- package/src/{core → config}/model-resolver.ts +3 -3
- package/src/{core → config}/prompt-templates.ts +2 -2
- package/src/{core → config}/settings-manager.ts +6 -6
- package/src/{core/cursor/exec-bridge.ts → cursor.ts} +4 -4
- package/src/discovery/agents-md.ts +4 -4
- package/src/discovery/builtin.ts +17 -17
- package/src/discovery/claude.ts +12 -12
- package/src/discovery/cline.ts +6 -6
- package/src/discovery/codex.ts +21 -21
- package/src/discovery/cursor.ts +9 -9
- package/src/discovery/gemini.ts +9 -9
- package/src/discovery/github.ts +6 -6
- package/src/discovery/helpers.ts +4 -4
- package/src/discovery/index.ts +16 -16
- package/src/discovery/mcp-json.ts +4 -4
- package/src/discovery/ssh.ts +4 -4
- package/src/discovery/vscode.ts +4 -4
- package/src/discovery/windsurf.ts +6 -6
- package/src/{core/tools/exa → exa}/company.ts +2 -3
- package/src/{core/tools/exa → exa}/index.ts +2 -2
- package/src/{core/tools/exa → exa}/linkedin.ts +2 -3
- package/src/{core/tools/exa → exa}/mcp-client.ts +2 -2
- package/src/{core/tools/exa → exa}/render.ts +3 -3
- package/src/{core/tools/exa → exa}/researcher.ts +1 -1
- package/src/{core/tools/exa → exa}/search.ts +2 -10
- package/src/{core/tools/exa → exa}/websets.ts +1 -1
- package/src/{core → exec}/bash-executor.ts +22 -6
- package/src/{core → export}/custom-share.ts +1 -1
- package/src/{core/export-html → export/html}/index.ts +3 -3
- package/src/{core → export}/ttsr.ts +2 -2
- package/src/{core → extensibility}/custom-commands/bundled/review/index.ts +4 -4
- package/src/{core → extensibility}/custom-commands/loader.ts +3 -3
- package/src/{core → extensibility}/custom-commands/types.ts +1 -1
- package/src/{core → extensibility}/custom-tools/loader.ts +9 -9
- package/src/{core → extensibility}/custom-tools/types.ts +6 -6
- package/src/{core → extensibility}/custom-tools/wrapper.ts +1 -1
- package/src/{core → extensibility}/extensions/loader.ts +8 -8
- package/src/{core → extensibility}/extensions/runner.ts +3 -3
- package/src/{core → extensibility}/extensions/types.ts +15 -15
- package/src/{core → extensibility}/extensions/wrapper.ts +1 -1
- package/src/{core → extensibility}/hooks/index.ts +1 -1
- package/src/{core → extensibility}/hooks/loader.ts +7 -7
- package/src/{core → extensibility}/hooks/runner.ts +4 -4
- package/src/{core → extensibility}/hooks/types.ts +9 -9
- package/src/{core → extensibility}/plugins/doctor.ts +1 -1
- package/src/{core → extensibility}/plugins/installer.ts +2 -3
- package/src/{core → extensibility}/plugins/paths.ts +1 -1
- package/src/{core → extensibility}/skills.ts +8 -48
- package/src/{core → extensibility}/slash-commands.ts +6 -6
- package/src/index.ts +127 -128
- package/src/internal-urls/agent-protocol.ts +126 -0
- package/src/internal-urls/artifact-protocol.ts +93 -0
- package/src/internal-urls/index.ts +28 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/router.ts +69 -0
- package/src/internal-urls/rule-protocol.ts +56 -0
- package/src/internal-urls/skill-protocol.ts +112 -0
- package/src/internal-urls/types.ts +48 -0
- package/src/{core/python-executor.ts → ipy/executor.ts} +51 -11
- package/src/{core/python-gateway-coordinator.ts → ipy/gateway-coordinator.ts} +41 -325
- package/src/{core/python-kernel.ts → ipy/kernel.ts} +38 -10
- package/src/ipy/prelude.ts +3 -0
- package/src/{core/tools/lsp → lsp}/client.ts +7 -6
- package/src/{core/tools/lsp → lsp}/clients/biome-client.ts +1 -1
- package/src/{core/tools/lsp → lsp}/clients/index.ts +1 -1
- package/src/{core/tools/lsp → lsp}/clients/lsp-linter-client.ts +4 -4
- package/src/{core/tools/lsp → lsp}/config.ts +1 -1
- package/src/{core/tools/lsp → lsp}/index.ts +16 -15
- package/src/{core/tools/lsp → lsp}/render.ts +2 -2
- package/src/{core/tools/lsp → lsp}/types.ts +14 -16
- package/src/{core/tools/lsp → lsp}/utils.ts +1 -1
- package/src/main.ts +12 -12
- package/src/{core/mcp → mcp}/config.ts +8 -8
- package/src/{core/mcp → mcp}/loader.ts +5 -6
- package/src/{core/mcp → mcp}/manager.ts +2 -2
- package/src/{core/mcp → mcp}/tool-bridge.ts +35 -6
- package/src/{core/mcp → mcp}/tool-cache.ts +1 -1
- package/src/{core/mcp → mcp}/transports/http.ts +7 -1
- package/src/{core/mcp → mcp}/transports/stdio.ts +1 -1
- package/src/{core/mcp → mcp}/types.ts +1 -1
- package/src/migrations.ts +2 -2
- package/src/modes/{interactive/components → components}/armin.ts +1 -1
- package/src/modes/{interactive/components → components}/assistant-message.ts +1 -1
- package/src/modes/{interactive/components → components}/bash-execution.ts +37 -29
- package/src/modes/{interactive/components → components}/bordered-loader.ts +1 -1
- package/src/modes/{interactive/components → components}/branch-summary-message.ts +2 -2
- package/src/modes/{interactive/components → components}/compaction-summary-message.ts +2 -2
- package/src/modes/{interactive/components → components}/custom-message.ts +3 -3
- package/src/modes/{interactive/components → components}/diff.ts +1 -1
- package/src/modes/{interactive/components → components}/dynamic-border.ts +1 -1
- package/src/modes/{interactive/components → components}/extensions/extension-dashboard.ts +3 -3
- package/src/modes/{interactive/components → components}/extensions/extension-list.ts +2 -2
- package/src/modes/{interactive/components → components}/extensions/inspector-panel.ts +1 -1
- package/src/modes/{interactive/components → components}/extensions/state-manager.ts +11 -17
- package/src/modes/{interactive/components → components}/extensions/types.ts +1 -1
- package/src/modes/{interactive/components → components}/footer.ts +3 -3
- package/src/modes/{interactive/components → components}/history-search.ts +2 -2
- package/src/modes/{interactive/components → components}/hook-editor.ts +1 -1
- package/src/modes/{interactive/components → components}/hook-input.ts +1 -1
- package/src/modes/{interactive/components → components}/hook-message.ts +3 -3
- package/src/modes/{interactive/components → components}/hook-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/keybinding-hints.ts +2 -2
- package/src/modes/{interactive/components → components}/login-dialog.ts +1 -1
- package/src/modes/{interactive/components → components}/model-selector.ts +5 -5
- package/src/modes/{interactive/components → components}/oauth-selector.ts +2 -2
- package/src/modes/{interactive/components → components}/plugin-settings.ts +3 -3
- package/src/modes/{interactive/components → components}/python-execution.ts +35 -24
- package/src/modes/{interactive/components → components}/queue-mode-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/read-tool-group.ts +2 -2
- package/src/modes/{interactive/components → components}/session-selector.ts +3 -3
- package/src/modes/{interactive/components → components}/settings-defs.ts +2 -2
- package/src/modes/{interactive/components → components}/settings-selector.ts +2 -2
- package/src/modes/{interactive/components → components}/show-images-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/status-line/segments.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line/separators.ts +1 -1
- package/src/modes/{interactive/components → components}/status-line/types.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line-segment-editor.ts +2 -2
- package/src/modes/{interactive/components → components}/status-line.ts +3 -3
- package/src/modes/{interactive/components → components}/theme-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/thinking-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/todo-display.ts +3 -4
- package/src/modes/{interactive/components → components}/todo-reminder.ts +2 -2
- package/src/modes/{interactive/components → components}/tool-execution.ts +8 -8
- package/src/modes/{interactive/components → components}/tree-selector.ts +3 -3
- package/src/modes/{interactive/components → components}/ttsr-notification.ts +2 -2
- package/src/modes/{interactive/components → components}/user-message-selector.ts +1 -1
- package/src/modes/{interactive/components → components}/user-message.ts +1 -1
- package/src/modes/{interactive/components → components}/welcome.ts +2 -2
- package/src/modes/{interactive/controllers → controllers}/command-controller.ts +32 -30
- package/src/modes/{interactive/controllers → controllers}/event-controller.ts +9 -9
- package/src/modes/{interactive/controllers → controllers}/extension-ui-controller.ts +8 -8
- package/src/modes/{interactive/controllers → controllers}/input-controller.ts +6 -6
- package/src/modes/{interactive/controllers → controllers}/selector-controller.ts +16 -16
- package/src/modes/index.ts +1 -1
- package/src/modes/{interactive/interactive-mode.ts → interactive-mode.ts} +14 -14
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +3 -3
- package/src/modes/rpc/rpc-mode.ts +3 -3
- package/src/modes/rpc/rpc-types.ts +3 -3
- package/src/modes/{interactive/theme → theme}/theme.ts +1 -1
- package/src/modes/{interactive/types.ts → types.ts} +8 -9
- package/src/modes/{interactive/utils → utils}/ui-helpers.ts +20 -27
- package/src/{core/tools/patch → patch}/applicator.ts +1 -1
- package/src/{core/tools/patch → patch}/diff.ts +1 -1
- package/src/{core/tools/patch → patch}/index.ts +31 -36
- package/src/{core/tools/patch → patch}/shared.ts +9 -6
- package/src/prompts/agents/explore.md +83 -46
- package/src/prompts/agents/init.md +9 -4
- package/src/prompts/agents/plan.md +8 -7
- package/src/prompts/agents/reviewer.md +36 -18
- package/src/prompts/agents/task.md +4 -4
- package/src/prompts/compaction/branch-summary-preamble.md +0 -1
- package/src/prompts/review-request.md +0 -1
- package/src/prompts/system/custom-system-prompt.md +2 -14
- package/src/prompts/system/file-operations.md +0 -2
- package/src/prompts/system/system-prompt.md +147 -138
- package/src/prompts/system/web-search.md +26 -0
- package/src/prompts/tools/ask.md +31 -24
- package/src/prompts/tools/bash.md +20 -17
- package/src/prompts/tools/calculator.md +9 -5
- package/src/prompts/tools/fetch.md +16 -0
- package/src/prompts/tools/find.md +15 -5
- package/src/prompts/tools/gemini-image.md +21 -6
- package/src/prompts/tools/grep.md +28 -12
- package/src/prompts/tools/lsp.md +35 -14
- package/src/prompts/tools/patch.md +39 -41
- package/src/prompts/tools/python.md +59 -76
- package/src/prompts/tools/read.md +23 -22
- package/src/prompts/tools/replace.md +19 -12
- package/src/prompts/tools/ssh.md +21 -28
- package/src/prompts/tools/task.md +54 -44
- package/src/prompts/tools/todo-write.md +52 -163
- package/src/prompts/tools/web-search.md +16 -9
- package/src/prompts/tools/write.md +13 -2
- package/src/{core/sdk.ts → sdk.ts} +65 -34
- package/src/{core → session}/agent-session.ts +45 -37
- package/src/{core → session}/agent-storage.ts +2 -2
- package/src/session/artifacts.ts +110 -0
- package/src/{core → session}/auth-storage.ts +1 -1
- package/src/{core → session}/compaction/branch-summarization.ts +5 -5
- package/src/{core → session}/compaction/compaction.ts +6 -6
- package/src/{core → session}/compaction/utils.ts +3 -3
- package/src/{core → session}/history-storage.ts +1 -1
- package/src/{core → session}/messages.ts +6 -8
- package/src/{core → session}/session-manager.ts +2 -2
- package/src/{core → session}/storage-migration.ts +2 -2
- package/src/session/streaming-output.ts +177 -0
- package/src/{core/ssh → ssh}/connection-manager.ts +1 -1
- package/src/{core/ssh → ssh}/ssh-executor.ts +19 -4
- package/src/{core/ssh → ssh}/sshfs-mount.ts +1 -1
- package/src/{core/system-prompt.ts → system-prompt.ts} +8 -37
- package/src/{core/tools/task → task}/agents.ts +8 -8
- package/src/{core/tools/task → task}/commands.ts +5 -6
- package/src/{core/tools/task → task}/discovery.ts +3 -3
- package/src/{core/tools/task → task}/executor.ts +34 -44
- package/src/{core/tools/task → task}/index.ts +206 -50
- package/src/{core/tools/task → task}/render.ts +80 -23
- package/src/{core/tools/task → task}/subprocess-tool-registry.ts +1 -1
- package/src/task/template.ts +47 -0
- package/src/{core/tools/task → task}/types.ts +19 -27
- package/src/{core/tools/task → task}/worker-protocol.ts +8 -4
- package/src/{core/tools/task → task}/worker.ts +34 -29
- package/src/task/worktree.ts +166 -0
- package/src/{core/tools → tools}/ask.ts +13 -21
- package/src/{core/tools → tools}/bash-interceptor.ts +1 -1
- package/src/{core/tools → tools}/bash.ts +61 -63
- package/src/{core/tools → tools}/calculator.ts +4 -4
- package/src/{core/tools → tools}/complete.ts +1 -1
- package/src/{core/tools → tools}/context.ts +2 -2
- package/src/{core/tools/web-fetch.ts → tools/fetch.ts} +97 -76
- package/src/{core/tools → tools}/find.ts +80 -104
- package/src/{core/tools → tools}/gemini-image.ts +420 -29
- package/src/{core/tools → tools}/grep.ts +155 -164
- package/src/{core/tools → tools}/index.ts +63 -56
- package/src/tools/list-limit.ts +40 -0
- package/src/{core/tools → tools}/ls.ts +44 -35
- package/src/{core/tools → tools}/notebook.ts +3 -3
- package/src/tools/output-meta.ts +443 -0
- package/src/tools/output-utils.ts +63 -0
- package/src/{core/tools → tools}/python.ts +105 -89
- package/src/tools/read.ts +882 -0
- package/src/{core/tools → tools}/render-utils.ts +1 -1
- package/src/{core/tools → tools}/renderers.ts +8 -10
- package/src/{core/tools → tools}/review.ts +2 -2
- package/src/{core/tools → tools}/ssh.ts +56 -59
- package/src/{core/tools → tools}/todo-write.ts +12 -23
- package/src/tools/tool-errors.ts +95 -0
- package/src/tools/tool-result.ts +92 -0
- package/src/{core/tools → tools}/truncate.ts +2 -2
- package/src/{core/tools → tools}/write.ts +15 -13
- package/src/utils/changelog.ts +1 -1
- package/src/{core → utils}/file-mentions.ts +4 -4
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/shell.ts +1 -1
- package/src/{core → utils}/title-generator.ts +4 -4
- package/src/utils/tools-manager.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/choosealicense.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/twitter.ts +3 -2
- package/src/{core/tools/web-scrapers → web/scrapers}/types.ts +4 -2
- package/src/{core/tools/web-scrapers → web/scrapers}/utils.ts +1 -1
- package/src/{core/tools/web-scrapers → web/scrapers}/youtube.ts +14 -13
- package/src/{core/tools/web-search → web/search}/auth.ts +4 -4
- package/src/{core/tools/web-search → web/search}/index.ts +22 -71
- package/src/{core/tools/web-search → web/search}/providers/anthropic.ts +7 -10
- package/src/{core/tools/web-search → web/search}/providers/exa.ts +2 -2
- package/src/{core/tools/web-search → web/search}/providers/perplexity.ts +4 -16
- package/src/{core/tools/web-search → web/search}/render.ts +3 -3
- package/tsconfig.json +25 -0
- package/scripts/migrate-sessions.sh +0 -93
- package/src/core/index.ts +0 -56
- package/src/core/python-prelude.ts +0 -3
- package/src/core/ssh-executor.ts +0 -5
- package/src/core/streaming-output.ts +0 -115
- package/src/core/tools/output.ts +0 -519
- package/src/core/tools/read.ts +0 -717
- package/src/core/tools/task/template.ts +0 -37
- package/src/prompts/tools/output.md +0 -47
- package/src/prompts/tools/web-fetch.md +0 -9
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
- /package/src/{core/tools/exa → exa}/types.ts +0 -0
- /package/src/{core → exec}/exec.ts +0 -0
- /package/src/{core/export-html → export/html}/template.css +0 -0
- /package/src/{core/export-html → export/html}/template.generated.ts +0 -0
- /package/src/{core/export-html → export/html}/template.html +0 -0
- /package/src/{core/export-html → export/html}/template.js +0 -0
- /package/src/{core/export-html → export/html}/template.macro.ts +0 -0
- /package/src/{core/export-html → export/html}/vendor/highlight.min.js +0 -0
- /package/src/{core/export-html → export/html}/vendor/marked.min.js +0 -0
- /package/src/{core → extensibility}/custom-commands/index.ts +0 -0
- /package/src/{core → extensibility}/custom-tools/index.ts +0 -0
- /package/src/{core → extensibility}/extensions/index.ts +0 -0
- /package/src/{core → extensibility}/hooks/tool-wrapper.ts +0 -0
- /package/src/{core → extensibility}/plugins/index.ts +0 -0
- /package/src/{core → extensibility}/plugins/loader.ts +0 -0
- /package/src/{core → extensibility}/plugins/manager.ts +0 -0
- /package/src/{core → extensibility}/plugins/parser.ts +0 -0
- /package/src/{core → extensibility}/plugins/types.ts +0 -0
- /package/src/{core/python-modules.ts → ipy/modules.ts} +0 -0
- /package/src/{core/python-prelude.py → ipy/prelude.py} +0 -0
- /package/src/{core/tools/lsp → lsp}/defaults.json +0 -0
- /package/src/{core/tools/lsp → lsp}/edits.ts +0 -0
- /package/src/{core/tools/lsp → lsp}/lspmux.ts +0 -0
- /package/src/{core/tools/lsp → lsp}/rust-analyzer.ts +0 -0
- /package/src/{core/mcp → mcp}/client.ts +0 -0
- /package/src/{core/mcp → mcp}/index.ts +0 -0
- /package/src/{core/mcp → mcp}/json-rpc.ts +0 -0
- /package/src/{core/mcp → mcp}/transports/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/countdown-timer.ts +0 -0
- /package/src/modes/{interactive/components → components}/custom-editor.ts +0 -0
- /package/src/modes/{interactive/components → components}/extensions/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/status-line/index.ts +0 -0
- /package/src/modes/{interactive/components → components}/status-line/presets.ts +0 -0
- /package/src/modes/{interactive/components → components}/visual-truncate.ts +0 -0
- /package/src/modes/{interactive/theme → theme}/dark.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/alabaster.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/amethyst.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/anthracite.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/basalt.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/birch.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-abyss.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-arctic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-aurora.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-catppuccin.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cavern.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-copper.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cosmos.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-cyberpunk.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-dracula.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-eclipse.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-ember.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-equinox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-forest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-github.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-gruvbox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-lavender.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-lunar.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-midnight.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-monochrome.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-monokai.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-nebula.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-nord.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-ocean.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-one.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-rainforest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-reef.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-retro.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-rose-pine.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-sakura.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-slate.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-solarized.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-solstice.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-starfall.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-sunset.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-swamp.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-synthwave.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-taiga.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-terminal.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-tokyo-night.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-tundra.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-twilight.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/dark-volcanic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/graphite.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/index.ts +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-arctic.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-aurora-day.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-canyon.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-catppuccin.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-cirrus.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-coral.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-cyberpunk.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-dawn.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-dunes.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-eucalyptus.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-forest.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-frost.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-github.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-glacier.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-gruvbox.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-haze.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-honeycomb.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-lagoon.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-lavender.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-meadow.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-mint.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-monochrome.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-ocean.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-one.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-opal.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-orchard.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-paper.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-prism.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-retro.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-sand.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-savanna.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-solarized.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-soleil.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-sunset.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-synthwave.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-tokyo-night.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-wetland.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/light-zenith.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/limestone.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/mahogany.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/marble.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/obsidian.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/onyx.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/pearl.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/porcelain.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/quartz.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/sandstone.json +0 -0
- /package/src/modes/{interactive/theme → theme}/defaults/titanium.json +0 -0
- /package/src/modes/{interactive/theme → theme}/light.json +0 -0
- /package/src/modes/{interactive/theme → theme}/theme-schema.json +0 -0
- /package/src/{core/tools/patch → patch}/fuzzy.ts +0 -0
- /package/src/{core/tools/patch → patch}/normalize.ts +0 -0
- /package/src/{core/tools/patch → patch}/normative.ts +0 -0
- /package/src/{core/tools/patch → patch}/parser.ts +0 -0
- /package/src/{core/tools/patch → patch}/types.ts +0 -0
- /package/src/{core → session}/compaction/index.ts +0 -0
- /package/src/{core → session}/session-storage.ts +0 -0
- /package/src/{core/tools/task → task}/name-generator.ts +0 -0
- /package/src/{core/tools/task → task}/omp-command.ts +0 -0
- /package/src/{core/tools/task → task}/parallel.ts +0 -0
- /package/src/{core/tools → tools}/jtd-to-json-schema.ts +0 -0
- /package/src/{core/tools → tools}/path-utils.ts +0 -0
- /package/src/{core → utils}/event-bus.ts +0 -0
- /package/src/{core → utils}/frontmatter.ts +0 -0
- /package/src/{core → utils}/terminal-notify.ts +0 -0
- /package/src/{core → utils}/timings.ts +0 -0
- /package/src/{core → utils}/utils.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/artifacthub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/arxiv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/aur.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/biorxiv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/bluesky.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/brew.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/cheatsh.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/chocolatey.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/cisa-kev.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/clojars.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/coingecko.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/crates-io.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/crossref.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/devto.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/discogs.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/discourse.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/dockerhub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/fdroid.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/firefox-addons.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/flathub.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/github-gist.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/github.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/gitlab.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/go-pkg.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hackage.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hackernews.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/hex.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/huggingface.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/iacr.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/index.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/jetbrains-marketplace.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/lemmy.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/lobsters.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/mastodon.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/maven.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/mdn.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/metacpan.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/musicbrainz.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/npm.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/nuget.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/nvd.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/ollama.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/open-vsx.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/opencorporates.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/openlibrary.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/orcid.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/osv.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/packagist.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pub-dev.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pubmed.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/pypi.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rawg.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/readthedocs.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/reddit.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/repology.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rfc.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/rubygems.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/searchcode.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/sec-edgar.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/semantic-scholar.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/snapcraft.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/sourcegraph.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/spdx.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/spotify.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/stackoverflow.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/terraform.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/tldr.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/vimeo.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/vscode-marketplace.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/w3c.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/wikidata.ts +0 -0
- /package/src/{core/tools/web-scrapers → web/scrapers}/wikipedia.ts +0 -0
- /package/src/{core/tools/web-search → web/search}/types.ts +0 -0
|
@@ -4,22 +4,38 @@ import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
|
4
4
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
6
6
|
import { nanoid } from "nanoid";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import type { CustomTool } from "
|
|
10
|
-
import
|
|
7
|
+
import type { ModelRegistry } from "$c/config/model-registry";
|
|
8
|
+
import { renderPromptTemplate } from "$c/config/prompt-templates";
|
|
9
|
+
import type { CustomTool } from "$c/extensibility/custom-tools/types";
|
|
10
|
+
import geminiImageDescription from "$c/prompts/tools/gemini-image.md" with { type: "text" };
|
|
11
|
+
import { detectSupportedImageMimeTypeFromFile } from "$c/utils/mime";
|
|
12
|
+
import { getEnv } from "$c/web/search/auth";
|
|
11
13
|
import { resolveReadPath } from "./path-utils";
|
|
12
|
-
import { getEnv } from "./web-search/auth";
|
|
13
14
|
|
|
14
15
|
const DEFAULT_MODEL = "gemini-3-pro-image-preview";
|
|
15
16
|
const DEFAULT_OPENROUTER_MODEL = "google/gemini-3-pro-image-preview";
|
|
17
|
+
const DEFAULT_ANTIGRAVITY_MODEL = "gemini-3-pro-image";
|
|
16
18
|
const DEFAULT_TIMEOUT_SECONDS = 120;
|
|
17
19
|
const MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
const ANTIGRAVITY_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
|
|
22
|
+
const ANTIGRAVITY_HEADERS = {
|
|
23
|
+
"User-Agent": "antigravity/1.11.5 darwin/arm64",
|
|
24
|
+
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
25
|
+
"Client-Metadata": JSON.stringify({
|
|
26
|
+
ideType: "IDE_UNSPECIFIED",
|
|
27
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
28
|
+
pluginType: "GEMINI",
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
const IMAGE_SYSTEM_INSTRUCTION =
|
|
32
|
+
"You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request.";
|
|
33
|
+
|
|
34
|
+
type ImageProvider = "antigravity" | "gemini" | "openrouter";
|
|
20
35
|
interface ImageApiKey {
|
|
21
36
|
provider: ImageProvider;
|
|
22
37
|
apiKey: string;
|
|
38
|
+
projectId?: string;
|
|
23
39
|
}
|
|
24
40
|
|
|
25
41
|
const responseModalitySchema = StringEnum(["Image", "Text"]);
|
|
@@ -39,12 +55,63 @@ const inputImageSchema = Type.Object(
|
|
|
39
55
|
{ additionalProperties: false },
|
|
40
56
|
);
|
|
41
57
|
|
|
42
|
-
|
|
58
|
+
const baseImageSchema = Type.Object(
|
|
43
59
|
{
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
subject: Type.String({
|
|
61
|
+
description:
|
|
62
|
+
"Main subject with key descriptors (e.g., 'A stoic robot barista with glowing blue optics', 'A weathered lighthouse on a rocky cliff').",
|
|
63
|
+
}),
|
|
64
|
+
action: Type.Optional(
|
|
65
|
+
Type.String({
|
|
66
|
+
description: "What the subject is doing (e.g., 'pouring latte art', 'standing against crashing waves').",
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
scene: Type.Optional(
|
|
70
|
+
Type.String({
|
|
71
|
+
description:
|
|
72
|
+
"Location or environment (e.g., 'in a futuristic café on Mars', 'during a violent thunderstorm at dusk').",
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
composition: Type.Optional(
|
|
76
|
+
Type.String({
|
|
77
|
+
description:
|
|
78
|
+
"Camera angle, framing, depth of field (e.g., 'low-angle close-up, shallow depth of field', 'wide establishing shot').",
|
|
79
|
+
}),
|
|
80
|
+
),
|
|
81
|
+
lighting: Type.Optional(
|
|
82
|
+
Type.String({
|
|
83
|
+
description:
|
|
84
|
+
"Lighting setup and mood (e.g., 'warm rim lighting', 'golden hour backlight', 'hard noon shadows').",
|
|
85
|
+
}),
|
|
86
|
+
),
|
|
87
|
+
style: Type.Optional(
|
|
88
|
+
Type.String({
|
|
89
|
+
description:
|
|
90
|
+
"Artistic style, mood, color grading (e.g., 'film noir mood, cinematic color grading', 'Studio Ghibli watercolor', 'photorealistic').",
|
|
91
|
+
}),
|
|
92
|
+
),
|
|
93
|
+
camera: Type.Optional(
|
|
94
|
+
Type.String({
|
|
95
|
+
description:
|
|
96
|
+
"Lens and camera specs (e.g., 'Shot on 35mm, f/1.8', 'macro lens, extreme close-up', '85mm portrait lens').",
|
|
97
|
+
}),
|
|
98
|
+
),
|
|
99
|
+
text: Type.Optional(
|
|
46
100
|
Type.String({
|
|
47
|
-
description:
|
|
101
|
+
description:
|
|
102
|
+
"Text to render in image with specs: exact wording in quotes, font style, color, placement (e.g., 'Headline \"URBAN EXPLORER\" in bold white sans-serif at top center').",
|
|
103
|
+
}),
|
|
104
|
+
),
|
|
105
|
+
changes: Type.Optional(
|
|
106
|
+
Type.Array(Type.String(), {
|
|
107
|
+
description:
|
|
108
|
+
"For edits: specific changes to make (e.g., ['Change the tie to green', 'Remove the car in background']). Use with input_images.",
|
|
109
|
+
}),
|
|
110
|
+
),
|
|
111
|
+
preserve: Type.Optional(
|
|
112
|
+
Type.String({
|
|
113
|
+
description:
|
|
114
|
+
"For edits: what to keep unchanged (e.g., 'identity, face, hairstyle, lighting'). Use with input_images and changes.",
|
|
48
115
|
}),
|
|
49
116
|
),
|
|
50
117
|
aspect_ratio: Type.Optional(aspectRatioSchema),
|
|
@@ -54,20 +121,54 @@ export const geminiImageSchema = Type.Object(
|
|
|
54
121
|
description: "Optional input images for edits or variations.",
|
|
55
122
|
}),
|
|
56
123
|
),
|
|
57
|
-
|
|
58
|
-
Type.Number({
|
|
59
|
-
description: `Request timeout in seconds (default: ${DEFAULT_TIMEOUT_SECONDS}).`,
|
|
60
|
-
minimum: 1,
|
|
61
|
-
maximum: 600,
|
|
62
|
-
}),
|
|
63
|
-
),
|
|
124
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 120)" })),
|
|
64
125
|
},
|
|
65
126
|
{ additionalProperties: false },
|
|
66
127
|
);
|
|
67
128
|
|
|
129
|
+
export const geminiImageSchema = baseImageSchema;
|
|
68
130
|
export type GeminiImageParams = Static<typeof geminiImageSchema>;
|
|
69
131
|
export type GeminiResponseModality = Static<typeof responseModalitySchema>;
|
|
70
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Assembles a structured prompt from the provided parameters.
|
|
135
|
+
* For generation: builds "subject, action, scene. composition. lighting. camera. style."
|
|
136
|
+
* For edits: appends change instructions and preserve directives.
|
|
137
|
+
*/
|
|
138
|
+
function assemblePrompt(params: GeminiImageParams): string {
|
|
139
|
+
const parts: string[] = [];
|
|
140
|
+
|
|
141
|
+
// Core subject line: subject + action + scene
|
|
142
|
+
const subjectParts = [params.subject];
|
|
143
|
+
if (params.action) subjectParts.push(params.action);
|
|
144
|
+
if (params.scene) subjectParts.push(params.scene);
|
|
145
|
+
parts.push(subjectParts.join(", "));
|
|
146
|
+
|
|
147
|
+
// Technical details as separate sentences
|
|
148
|
+
if (params.composition) parts.push(params.composition);
|
|
149
|
+
if (params.lighting) parts.push(params.lighting);
|
|
150
|
+
if (params.camera) parts.push(params.camera);
|
|
151
|
+
if (params.style) parts.push(params.style);
|
|
152
|
+
|
|
153
|
+
// Join with periods for sentence structure
|
|
154
|
+
let prompt = `${parts.map((p) => p.replace(/[.!,;:]+$/, "")).join(". ")}.`;
|
|
155
|
+
|
|
156
|
+
// Text rendering specs
|
|
157
|
+
if (params.text) {
|
|
158
|
+
prompt += `\n\nText: ${params.text}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Edit mode: changes and preserve directives
|
|
162
|
+
if (params.changes?.length) {
|
|
163
|
+
prompt += `\n\nChanges:\n${params.changes.map((c) => `- ${c}`).join("\n")}`;
|
|
164
|
+
if (params.preserve) {
|
|
165
|
+
prompt += `\n\nPreserve: ${params.preserve}`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return prompt;
|
|
170
|
+
}
|
|
171
|
+
|
|
71
172
|
interface GeminiInlineData {
|
|
72
173
|
data?: string;
|
|
73
174
|
mimeType?: string;
|
|
@@ -127,6 +228,39 @@ interface OpenRouterResponse {
|
|
|
127
228
|
choices?: OpenRouterChoice[];
|
|
128
229
|
}
|
|
129
230
|
|
|
231
|
+
interface AntigravityRequest {
|
|
232
|
+
project: string;
|
|
233
|
+
model: string;
|
|
234
|
+
request: {
|
|
235
|
+
contents: Array<{ role: "user"; parts: Array<{ text?: string; inlineData?: InlineImageData }> }>;
|
|
236
|
+
systemInstruction?: { parts: Array<{ text: string }> };
|
|
237
|
+
generationConfig?: {
|
|
238
|
+
responseModalities?: GeminiResponseModality[];
|
|
239
|
+
imageConfig?: { aspectRatio?: string; imageSize?: string };
|
|
240
|
+
candidateCount?: number;
|
|
241
|
+
};
|
|
242
|
+
safetySettings?: Array<{ category: string; threshold: string }>;
|
|
243
|
+
};
|
|
244
|
+
requestType?: string;
|
|
245
|
+
userAgent?: string;
|
|
246
|
+
requestId?: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
interface AntigravityResponseChunk {
|
|
250
|
+
response?: {
|
|
251
|
+
candidates?: Array<{
|
|
252
|
+
content?: {
|
|
253
|
+
role: string;
|
|
254
|
+
parts?: Array<{
|
|
255
|
+
text?: string;
|
|
256
|
+
inlineData?: { mimeType?: string; data?: string };
|
|
257
|
+
}>;
|
|
258
|
+
};
|
|
259
|
+
}>;
|
|
260
|
+
usageMetadata?: GeminiUsageMetadata;
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
130
264
|
interface GeminiImageToolDetails {
|
|
131
265
|
provider: ImageProvider;
|
|
132
266
|
model: string;
|
|
@@ -235,8 +369,44 @@ export function setPreferredImageProvider(provider: ImageProvider | "auto"): voi
|
|
|
235
369
|
preferredImageProvider = provider;
|
|
236
370
|
}
|
|
237
371
|
|
|
238
|
-
|
|
372
|
+
interface ParsedAntigravityCredentials {
|
|
373
|
+
accessToken: string;
|
|
374
|
+
projectId: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function parseAntigravityCredentials(raw: string): ParsedAntigravityCredentials | null {
|
|
378
|
+
try {
|
|
379
|
+
const parsed = JSON.parse(raw) as { token?: string; projectId?: string };
|
|
380
|
+
if (parsed.token && parsed.projectId) {
|
|
381
|
+
return { accessToken: parsed.token, projectId: parsed.projectId };
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
// Invalid JSON
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function findAntigravityCredentials(modelRegistry: ModelRegistry): Promise<ImageApiKey | null> {
|
|
390
|
+
const apiKey = await modelRegistry.getApiKeyForProvider("google-antigravity");
|
|
391
|
+
if (!apiKey) return null;
|
|
392
|
+
|
|
393
|
+
const parsed = parseAntigravityCredentials(apiKey);
|
|
394
|
+
if (!parsed) return null;
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
provider: "antigravity",
|
|
398
|
+
apiKey: parsed.accessToken,
|
|
399
|
+
projectId: parsed.projectId,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async function findImageApiKey(modelRegistry?: ModelRegistry): Promise<ImageApiKey | null> {
|
|
239
404
|
// If a specific provider is preferred, try it first
|
|
405
|
+
if (preferredImageProvider === "antigravity" && modelRegistry) {
|
|
406
|
+
const antigravity = await findAntigravityCredentials(modelRegistry);
|
|
407
|
+
if (antigravity) return antigravity;
|
|
408
|
+
// Fall through to auto-detect if preferred provider key not found
|
|
409
|
+
}
|
|
240
410
|
if (preferredImageProvider === "gemini") {
|
|
241
411
|
const geminiKey = await getEnv("GEMINI_API_KEY");
|
|
242
412
|
if (geminiKey) return { provider: "gemini", apiKey: geminiKey };
|
|
@@ -249,7 +419,12 @@ async function findImageApiKey(): Promise<ImageApiKey | null> {
|
|
|
249
419
|
// Fall through to auto-detect if preferred provider key not found
|
|
250
420
|
}
|
|
251
421
|
|
|
252
|
-
// Auto-detect:
|
|
422
|
+
// Auto-detect: Antigravity takes priority, then OpenRouter, then Gemini
|
|
423
|
+
if (modelRegistry) {
|
|
424
|
+
const antigravity = await findAntigravityCredentials(modelRegistry);
|
|
425
|
+
if (antigravity) return antigravity;
|
|
426
|
+
}
|
|
427
|
+
|
|
253
428
|
const openRouterKey = await getEnv("OPENROUTER_API_KEY");
|
|
254
429
|
if (openRouterKey) return { provider: "openrouter", apiKey: openRouterKey };
|
|
255
430
|
|
|
@@ -323,8 +498,13 @@ async function saveImagesToTemp(images: InlineImageData[]): Promise<string[]> {
|
|
|
323
498
|
return Promise.all(images.map(saveImageToTemp));
|
|
324
499
|
}
|
|
325
500
|
|
|
326
|
-
function buildResponseSummary(
|
|
327
|
-
|
|
501
|
+
function buildResponseSummary(
|
|
502
|
+
provider: ImageProvider,
|
|
503
|
+
model: string,
|
|
504
|
+
imagePaths: string[],
|
|
505
|
+
responseText: string | undefined,
|
|
506
|
+
): string {
|
|
507
|
+
const lines = [`Provider: ${provider}`, `Model: ${model}`, `Generated ${imagePaths.length} image(s):`];
|
|
328
508
|
for (const p of imagePaths) {
|
|
329
509
|
lines.push(` ${p}`);
|
|
330
510
|
}
|
|
@@ -365,6 +545,121 @@ function createRequestSignal(signal: AbortSignal | undefined, timeoutSeconds: nu
|
|
|
365
545
|
return signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
366
546
|
}
|
|
367
547
|
|
|
548
|
+
function buildAntigravityRequest(
|
|
549
|
+
prompt: string,
|
|
550
|
+
model: string,
|
|
551
|
+
projectId: string,
|
|
552
|
+
aspectRatio: string | undefined,
|
|
553
|
+
imageSize: string | undefined,
|
|
554
|
+
inputImages: InlineImageData[],
|
|
555
|
+
): AntigravityRequest {
|
|
556
|
+
const parts: Array<{ text?: string; inlineData?: InlineImageData }> = [];
|
|
557
|
+
for (const image of inputImages) {
|
|
558
|
+
parts.push({ inlineData: image });
|
|
559
|
+
}
|
|
560
|
+
parts.push({ text: prompt });
|
|
561
|
+
|
|
562
|
+
const imageConfig = aspectRatio || imageSize ? { aspectRatio: aspectRatio, imageSize: imageSize } : undefined;
|
|
563
|
+
|
|
564
|
+
return {
|
|
565
|
+
project: projectId,
|
|
566
|
+
model,
|
|
567
|
+
request: {
|
|
568
|
+
contents: [{ role: "user", parts }],
|
|
569
|
+
systemInstruction: { parts: [{ text: IMAGE_SYSTEM_INSTRUCTION }] },
|
|
570
|
+
generationConfig: {
|
|
571
|
+
responseModalities: ["Image"],
|
|
572
|
+
imageConfig,
|
|
573
|
+
candidateCount: 1,
|
|
574
|
+
},
|
|
575
|
+
safetySettings: [
|
|
576
|
+
{ category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_ONLY_HIGH" },
|
|
577
|
+
{ category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_ONLY_HIGH" },
|
|
578
|
+
{ category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_ONLY_HIGH" },
|
|
579
|
+
{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_ONLY_HIGH" },
|
|
580
|
+
{ category: "HARM_CATEGORY_CIVIC_INTEGRITY", threshold: "BLOCK_ONLY_HIGH" },
|
|
581
|
+
],
|
|
582
|
+
},
|
|
583
|
+
requestType: "agent",
|
|
584
|
+
requestId: `agent-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
|
|
585
|
+
userAgent: "antigravity",
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
interface AntigravitySseResult {
|
|
590
|
+
images: InlineImageData[];
|
|
591
|
+
text: string[];
|
|
592
|
+
usage?: GeminiUsageMetadata;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async function parseAntigravitySseForImage(response: Response, signal?: AbortSignal): Promise<AntigravitySseResult> {
|
|
596
|
+
if (!response.body) {
|
|
597
|
+
throw new Error("No response body");
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const reader = response.body.getReader();
|
|
601
|
+
const decoder = new TextDecoder();
|
|
602
|
+
let buffer = "";
|
|
603
|
+
const textParts: string[] = [];
|
|
604
|
+
const images: InlineImageData[] = [];
|
|
605
|
+
let usage: GeminiUsageMetadata | undefined;
|
|
606
|
+
|
|
607
|
+
try {
|
|
608
|
+
while (true) {
|
|
609
|
+
if (signal?.aborted) {
|
|
610
|
+
throw new Error("Request was aborted");
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const { done, value } = await reader.read();
|
|
614
|
+
if (done) break;
|
|
615
|
+
|
|
616
|
+
buffer += decoder.decode(value, { stream: true });
|
|
617
|
+
const lines = buffer.split("\n");
|
|
618
|
+
buffer = lines.pop() ?? "";
|
|
619
|
+
|
|
620
|
+
for (const line of lines) {
|
|
621
|
+
if (!line.startsWith("data:")) continue;
|
|
622
|
+
const jsonStr = line.slice(5).trim();
|
|
623
|
+
if (!jsonStr) continue;
|
|
624
|
+
|
|
625
|
+
let chunk: AntigravityResponseChunk;
|
|
626
|
+
try {
|
|
627
|
+
chunk = JSON.parse(jsonStr);
|
|
628
|
+
} catch {
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const responseData = chunk.response;
|
|
633
|
+
if (!responseData?.candidates) continue;
|
|
634
|
+
|
|
635
|
+
if (responseData.usageMetadata) {
|
|
636
|
+
usage = responseData.usageMetadata;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
for (const candidate of responseData.candidates) {
|
|
640
|
+
const parts = candidate.content?.parts;
|
|
641
|
+
if (!parts) continue;
|
|
642
|
+
for (const part of parts) {
|
|
643
|
+
if (part.text) {
|
|
644
|
+
textParts.push(part.text);
|
|
645
|
+
}
|
|
646
|
+
if (part.inlineData?.data && part.inlineData?.mimeType) {
|
|
647
|
+
images.push({
|
|
648
|
+
data: part.inlineData.data,
|
|
649
|
+
mimeType: part.inlineData.mimeType,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
} finally {
|
|
657
|
+
reader.releaseLock();
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
return { images, text: textParts, usage };
|
|
661
|
+
}
|
|
662
|
+
|
|
368
663
|
export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageToolDetails> = {
|
|
369
664
|
name: "generate_image",
|
|
370
665
|
label: "GenerateImage",
|
|
@@ -372,13 +667,20 @@ export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageTo
|
|
|
372
667
|
parameters: geminiImageSchema,
|
|
373
668
|
async execute(_toolCallId, params, _onUpdate, ctx, signal) {
|
|
374
669
|
return untilAborted(signal, async () => {
|
|
375
|
-
const apiKey = await findImageApiKey();
|
|
670
|
+
const apiKey = await findImageApiKey(ctx.modelRegistry);
|
|
376
671
|
if (!apiKey) {
|
|
377
|
-
throw new Error(
|
|
672
|
+
throw new Error(
|
|
673
|
+
"No image API credentials found. Login with google-antigravity, or set OPENROUTER_API_KEY, GEMINI_API_KEY, or GOOGLE_API_KEY.",
|
|
674
|
+
);
|
|
378
675
|
}
|
|
379
676
|
|
|
380
677
|
const provider = apiKey.provider;
|
|
381
|
-
const model =
|
|
678
|
+
const model =
|
|
679
|
+
provider === "antigravity"
|
|
680
|
+
? DEFAULT_ANTIGRAVITY_MODEL
|
|
681
|
+
: provider === "openrouter"
|
|
682
|
+
? DEFAULT_OPENROUTER_MODEL
|
|
683
|
+
: DEFAULT_MODEL;
|
|
382
684
|
const resolvedModel = provider === "openrouter" ? resolveOpenRouterModel(model) : model;
|
|
383
685
|
const cwd = ctx.sessionManager.getCwd();
|
|
384
686
|
|
|
@@ -389,11 +691,90 @@ export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageTo
|
|
|
389
691
|
}
|
|
390
692
|
}
|
|
391
693
|
|
|
392
|
-
const
|
|
694
|
+
const { timeout: rawTimeout = DEFAULT_TIMEOUT_SECONDS } = params;
|
|
695
|
+
// Auto-convert milliseconds to seconds if value > 1000 (16+ min is unreasonable)
|
|
696
|
+
let timeoutSeconds = rawTimeout > 1000 ? rawTimeout / 1000 : rawTimeout;
|
|
697
|
+
// Clamp to reasonable range: 1s - 600s (10 min)
|
|
698
|
+
timeoutSeconds = Math.max(1, Math.min(600, timeoutSeconds));
|
|
393
699
|
const requestSignal = createRequestSignal(signal, timeoutSeconds);
|
|
394
700
|
|
|
701
|
+
if (provider === "antigravity") {
|
|
702
|
+
if (!apiKey.projectId) {
|
|
703
|
+
throw new Error("Missing projectId in antigravity credentials");
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const prompt = assemblePrompt(params);
|
|
707
|
+
const requestBody = buildAntigravityRequest(
|
|
708
|
+
prompt,
|
|
709
|
+
model,
|
|
710
|
+
apiKey.projectId,
|
|
711
|
+
params.aspect_ratio,
|
|
712
|
+
params.image_size,
|
|
713
|
+
resolvedImages,
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
const response = await fetch(`${ANTIGRAVITY_ENDPOINT}/v1internal:streamGenerateContent?alt=sse`, {
|
|
717
|
+
method: "POST",
|
|
718
|
+
headers: {
|
|
719
|
+
Authorization: `Bearer ${apiKey.apiKey}`,
|
|
720
|
+
"Content-Type": "application/json",
|
|
721
|
+
Accept: "text/event-stream",
|
|
722
|
+
...ANTIGRAVITY_HEADERS,
|
|
723
|
+
},
|
|
724
|
+
body: JSON.stringify(requestBody),
|
|
725
|
+
signal: requestSignal,
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
if (!response.ok) {
|
|
729
|
+
const errorText = await response.text();
|
|
730
|
+
let message = errorText;
|
|
731
|
+
try {
|
|
732
|
+
const parsed = JSON.parse(errorText) as { error?: { message?: string } };
|
|
733
|
+
message = parsed.error?.message ?? message;
|
|
734
|
+
} catch {
|
|
735
|
+
// Keep raw text.
|
|
736
|
+
}
|
|
737
|
+
throw new Error(`Antigravity image request failed (${response.status}): ${message}`);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
const parsed = await parseAntigravitySseForImage(response, requestSignal);
|
|
741
|
+
const responseText = parsed.text.length > 0 ? parsed.text.join(" ") : undefined;
|
|
742
|
+
|
|
743
|
+
if (parsed.images.length === 0) {
|
|
744
|
+
const messageText = responseText ? `\n\n${responseText}` : "";
|
|
745
|
+
return {
|
|
746
|
+
content: [{ type: "text", text: `No image data returned.${messageText}` }],
|
|
747
|
+
details: {
|
|
748
|
+
provider,
|
|
749
|
+
model,
|
|
750
|
+
imageCount: 0,
|
|
751
|
+
imagePaths: [],
|
|
752
|
+
images: [],
|
|
753
|
+
responseText,
|
|
754
|
+
usage: parsed.usage,
|
|
755
|
+
},
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const imagePaths = await saveImagesToTemp(parsed.images);
|
|
760
|
+
|
|
761
|
+
return {
|
|
762
|
+
content: [{ type: "text", text: buildResponseSummary(provider, model, imagePaths, responseText) }],
|
|
763
|
+
details: {
|
|
764
|
+
provider,
|
|
765
|
+
model,
|
|
766
|
+
imageCount: parsed.images.length,
|
|
767
|
+
imagePaths,
|
|
768
|
+
images: parsed.images,
|
|
769
|
+
responseText,
|
|
770
|
+
usage: parsed.usage,
|
|
771
|
+
},
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
395
775
|
if (provider === "openrouter") {
|
|
396
|
-
const
|
|
776
|
+
const prompt = assemblePrompt(params);
|
|
777
|
+
const contentParts: OpenRouterContentPart[] = [{ type: "text", text: prompt }];
|
|
397
778
|
for (const image of resolvedImages) {
|
|
398
779
|
contentParts.push({ type: "image_url", image_url: { url: toDataUrl(image) } });
|
|
399
780
|
}
|
|
@@ -452,7 +833,9 @@ export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageTo
|
|
|
452
833
|
const imagePaths = await saveImagesToTemp(inlineImages);
|
|
453
834
|
|
|
454
835
|
return {
|
|
455
|
-
content: [
|
|
836
|
+
content: [
|
|
837
|
+
{ type: "text", text: buildResponseSummary(provider, resolvedModel, imagePaths, responseText) },
|
|
838
|
+
],
|
|
456
839
|
details: {
|
|
457
840
|
provider,
|
|
458
841
|
model: resolvedModel,
|
|
@@ -468,7 +851,7 @@ export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageTo
|
|
|
468
851
|
for (const image of resolvedImages) {
|
|
469
852
|
parts.push({ inlineData: image });
|
|
470
853
|
}
|
|
471
|
-
parts.push({ text: params
|
|
854
|
+
parts.push({ text: assemblePrompt(params) });
|
|
472
855
|
|
|
473
856
|
const generationConfig: {
|
|
474
857
|
responseModalities: GeminiResponseModality[];
|
|
@@ -541,7 +924,7 @@ export const geminiImageTool: CustomTool<typeof geminiImageSchema, GeminiImageTo
|
|
|
541
924
|
const imagePaths = await saveImagesToTemp(inlineImages);
|
|
542
925
|
|
|
543
926
|
return {
|
|
544
|
-
content: [{ type: "text", text: buildResponseSummary(model, imagePaths, responseText) }],
|
|
927
|
+
content: [{ type: "text", text: buildResponseSummary(provider, model, imagePaths, responseText) }],
|
|
545
928
|
details: {
|
|
546
929
|
provider,
|
|
547
930
|
model,
|
|
@@ -564,3 +947,11 @@ export async function getGeminiImageTools(): Promise<
|
|
|
564
947
|
if (!apiKey) return [];
|
|
565
948
|
return [geminiImageTool];
|
|
566
949
|
}
|
|
950
|
+
|
|
951
|
+
export async function getGeminiImageToolsWithRegistry(
|
|
952
|
+
modelRegistry: ModelRegistry,
|
|
953
|
+
): Promise<Array<CustomTool<typeof geminiImageSchema, GeminiImageToolDetails>>> {
|
|
954
|
+
const apiKey = await findImageApiKey(modelRegistry);
|
|
955
|
+
if (!apiKey) return [];
|
|
956
|
+
return [geminiImageTool];
|
|
957
|
+
}
|