@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.21
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 +292 -0
- package/README.md +8 -11
- package/docs/prefix-cache-architecture.md +14 -0
- package/package.json +22 -24
- package/packages/ask-user/README.md +55 -107
- package/packages/ask-user/ask-ui.ts +306 -732
- package/packages/ask-user/clipboard.ts +50 -0
- package/packages/ask-user/config.ts +74 -78
- package/packages/ask-user/package.json +2 -2
- package/packages/ask-user/questions.ts +151 -0
- package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
- package/packages/ask-user/tools.ts +198 -432
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +38 -43
- package/packages/autocomplete/src/sorting.ts +8 -0
- package/packages/background-tasks/package.json +2 -2
- package/packages/background-tasks/src/config.ts +0 -73
- package/packages/background-tasks/src/index.ts +20 -16
- package/packages/background-tasks/src/registry.ts +1 -171
- package/packages/background-tasks/src/types.ts +0 -32
- package/packages/btw/README.md +13 -56
- package/packages/btw/extensions/btw.ts +403 -1796
- package/packages/btw/package.json +5 -2
- package/packages/btw/skills/btw/SKILL.md +7 -143
- package/packages/compactor/README.md +56 -287
- package/packages/compactor/package.json +5 -9
- package/packages/compactor/skills/compactor/SKILL.md +13 -20
- package/packages/compactor/src/card.ts +90 -0
- package/packages/compactor/src/commands/index.ts +73 -130
- package/packages/compactor/src/compaction/compact-args.ts +5 -3
- package/packages/compactor/src/compaction/filter-noise.ts +1 -1
- package/packages/compactor/src/compaction/hooks.ts +487 -311
- package/packages/compactor/src/compaction/source.ts +178 -0
- package/packages/compactor/src/compaction/summarize.ts +586 -52
- package/packages/compactor/src/config/manager.ts +130 -127
- package/packages/compactor/src/config/schema.ts +32 -48
- package/packages/compactor/src/index.ts +40 -431
- package/packages/compactor/src/info-screen.ts +44 -190
- package/packages/compactor/src/session/recall-blocks.ts +1 -1
- package/packages/compactor/src/stats.ts +76 -0
- package/packages/compactor/src/tools/context-budget.ts +17 -34
- package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
- package/packages/compactor/src/tools/register.ts +29 -269
- package/packages/compactor/src/types.ts +47 -186
- package/packages/core/README.md +25 -0
- package/packages/core/child-agent.ts +1 -0
- package/packages/core/command-echo.ts +63 -0
- package/packages/core/compaction-context.ts +41 -0
- package/packages/core/constants.ts +8 -38
- package/packages/core/events.ts +0 -53
- package/packages/core/fusion-status.ts +4 -0
- package/packages/core/global.d.ts +10 -0
- package/packages/core/harness-messages.ts +392 -0
- package/packages/core/index.ts +14 -0
- package/packages/core/kanboard-status.ts +49 -0
- package/packages/core/long-horizon-owner-status.ts +46 -0
- package/packages/core/model-cache.ts +81 -7
- package/packages/core/package.json +6 -3
- package/packages/core/src/attach/detect.ts +163 -0
- package/packages/core/src/child-agent/child-args.ts +31 -0
- package/packages/core/src/child-agent/delivery.ts +41 -0
- package/packages/core/src/child-agent/index.ts +5 -0
- package/packages/core/src/child-agent/readers.ts +203 -0
- package/packages/core/src/child-agent/runtime.ts +584 -0
- package/packages/core/src/evidence.ts +78 -0
- package/packages/core/src/hints/browser.ts +278 -0
- package/packages/core/src/hints/crab-data.ts +19 -0
- package/packages/core/src/hints/index.ts +865 -0
- package/packages/core/src/hints/lines.ts +607 -0
- package/packages/core/src/hints/store.ts +120 -0
- package/packages/core/src/jev/chatter.ts +24 -0
- package/packages/core/src/jev/settings.ts +177 -14
- package/packages/core/src/package-colors.ts +2 -0
- package/packages/core/src/settings/catalog.ts +39 -15
- package/packages/core/src/settings/engine.ts +48 -2
- package/packages/core/src/settings/hub.ts +83 -20
- package/packages/core/src/settings/open.ts +49 -0
- package/packages/core/src/settings/schema.ts +27 -7
- package/packages/core/src/tui/hub-kit.ts +18 -5
- package/packages/core/src/tui/kit.ts +198 -0
- package/packages/core/src/tui/progress.ts +73 -0
- package/packages/core/src/turn/arbiter.ts +290 -0
- package/packages/footer/README.md +4 -6
- package/packages/footer/package.json +3 -3
- package/packages/footer/src/glance-editor.ts +19 -11
- package/packages/footer/src/help.ts +1 -1
- package/packages/footer/src/index.ts +36 -3
- package/packages/footer/src/presets.ts +3 -4
- package/packages/footer/src/rendering/icons.ts +0 -20
- package/packages/footer/src/segments/compactor.ts +52 -142
- package/packages/footer/src/segments/status-ext.ts +0 -1
- package/packages/fusion/README.md +14 -4
- package/packages/fusion/package.json +4 -3
- package/packages/fusion/src/child-args.ts +1 -0
- package/packages/fusion/src/index.ts +161 -8
- package/packages/fusion/src/pi-settings.ts +57 -0
- package/packages/fusion/src/picker.ts +186 -51
- package/packages/fusion/src/preset.ts +56 -2
- package/packages/fusion/src/prompts.ts +1 -1
- package/packages/fusion/src/sidekick-runtime.ts +1 -420
- package/packages/fusion/src/tools.ts +107 -128
- package/packages/fusion/src/transcript.ts +27 -85
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/README.md +18 -30
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/input-shortcuts/src/burst.ts +88 -0
- package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
- package/packages/input-shortcuts/src/cleared-input.ts +97 -0
- package/packages/input-shortcuts/src/index.ts +99 -193
- package/packages/input-shortcuts/src/last-response.ts +40 -0
- package/packages/input-shortcuts/src/registers.ts +8 -23
- package/packages/input-shortcuts/src/types.ts +4 -16
- package/packages/input-shortcuts/src/undo-redo.ts +59 -47
- package/packages/kanboard/README.md +51 -47
- package/packages/kanboard/index.ts +293 -55
- package/packages/kanboard/package.json +8 -8
- package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
- package/packages/kanboard/src/badges.ts +93 -0
- package/packages/kanboard/src/bin.ts +4 -2
- package/packages/kanboard/src/commands.ts +218 -84
- package/packages/kanboard/src/debug.ts +20 -0
- package/packages/kanboard/src/guard.ts +267 -109
- package/packages/kanboard/src/monitor.ts +330 -0
- package/packages/kanboard/src/notice-buffer.ts +74 -0
- package/packages/kanboard/src/progress.ts +27 -0
- package/packages/kanboard/src/reminders.ts +234 -0
- package/packages/kanboard/src/settings.ts +69 -15
- package/packages/kanboard/src/shapes.ts +5 -0
- package/packages/long-horizon/index.ts +190 -13
- package/packages/long-horizon/package.json +3 -3
- package/packages/long-horizon/src/commands.ts +103 -7
- package/packages/long-horizon/src/compaction-brief.ts +35 -0
- package/packages/long-horizon/src/engine/continuation.ts +84 -15
- package/packages/long-horizon/src/engine/goal-state.ts +64 -13
- package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
- package/packages/long-horizon/src/engine/ralph.ts +3 -2
- package/packages/long-horizon/src/engine/runaway.ts +68 -11
- package/packages/long-horizon/src/engine/verifier.ts +19 -0
- package/packages/long-horizon/src/gate.ts +37 -12
- package/packages/long-horizon/src/judge/resolve.ts +1 -0
- package/packages/long-horizon/src/owner.ts +35 -2
- package/packages/long-horizon/src/progress.ts +87 -0
- package/packages/long-horizon/src/prompts/goal.ts +1 -1
- package/packages/long-horizon/src/runtime.ts +172 -18
- package/packages/long-horizon/src/settings.ts +54 -39
- package/packages/long-horizon/src/tools/goal.ts +6 -0
- package/packages/long-horizon/src/tools/graph.ts +1 -1
- package/packages/long-horizon/src/tools/swarm.ts +3 -3
- package/packages/mcp/package.json +2 -2
- package/packages/memory/commands.ts +7 -2
- package/packages/memory/index.ts +210 -32
- package/packages/memory/package.json +3 -3
- package/packages/memory/save-session.ts +264 -0
- package/packages/memory/settings.ts +17 -0
- package/packages/memory/tools.ts +253 -203
- package/packages/notify/package.json +2 -2
- package/packages/skill-registry/README.md +53 -16
- package/packages/skill-registry/index.ts +230 -0
- package/packages/skill-registry/package.json +19 -8
- package/packages/skill-registry/src/editor.ts +206 -0
- package/packages/skill-registry/src/judge.ts +289 -0
- package/packages/skill-registry/src/registry.ts +87 -0
- package/packages/skill-registry/src/settings.ts +259 -0
- package/packages/skill-registry/src/vault.ts +80 -0
- package/packages/subagents/README.md +39 -119
- package/packages/subagents/package.json +6 -13
- package/packages/subagents/skills/subagents/SKILL.md +18 -42
- package/packages/subagents/src/agents.ts +213 -0
- package/packages/subagents/src/cards.ts +182 -0
- package/packages/subagents/src/index.ts +609 -1084
- package/packages/subagents/src/manager.ts +429 -0
- package/packages/subagents/src/profiles.ts +130 -0
- package/packages/subagents/src/transcript.ts +154 -0
- package/packages/subagents/src/ui.ts +389 -0
- package/packages/unipi/bundled.js +39756 -45569
- package/packages/unipi/index.ts +55 -10
- package/packages/updater/package.json +2 -2
- package/packages/utility/README.md +76 -69
- package/packages/utility/package.json +2 -2
- package/packages/utility/skills/image/SKILL.md +37 -0
- package/packages/utility/skills/utility/SKILL.md +17 -60
- package/packages/utility/src/answer/extract.ts +128 -0
- package/packages/utility/src/answer/index.ts +213 -0
- package/packages/utility/src/answer/reply.ts +133 -0
- package/packages/utility/src/answer/web.ts +167 -0
- package/packages/utility/src/attach/index.ts +205 -0
- package/packages/utility/src/commands.ts +38 -142
- package/packages/utility/src/diagnostics/engine.ts +50 -5
- package/packages/utility/src/image/index.ts +33 -0
- package/packages/utility/src/image/models.ts +221 -0
- package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
- package/packages/utility/src/image/settings.ts +178 -0
- package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
- package/packages/utility/src/image/tools.ts +168 -0
- package/packages/utility/src/image/transports.ts +186 -0
- package/packages/utility/src/index.ts +68 -389
- package/packages/utility/src/lifecycle/cleanup.ts +116 -311
- package/packages/utility/src/rename/gate.ts +102 -0
- package/packages/utility/src/rename/index.ts +191 -0
- package/packages/utility/src/rename/session.ts +170 -0
- package/packages/utility/src/render/delegated.ts +285 -0
- package/packages/utility/src/render/harness.ts +683 -0
- package/packages/utility/src/render/parse.ts +156 -0
- package/packages/utility/src/render/pi-settings.ts +38 -0
- package/packages/utility/src/render/reply-bg.ts +307 -0
- package/packages/utility/src/render/simple.ts +724 -0
- package/packages/utility/src/render/spacing.ts +235 -0
- package/packages/utility/src/render/styled.ts +251 -0
- package/packages/utility/src/render/tools.ts +353 -0
- package/packages/utility/src/settings.ts +166 -233
- package/packages/utility/src/types.ts +1 -222
- package/packages/watchdog/index.ts +17 -6
- package/packages/watchdog/package.json +3 -3
- package/packages/watchdog/src/config.ts +3 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/README.md +3 -0
- package/packages/workflow/index.ts +0 -2
- package/packages/workflow/package.json +2 -2
- package/packages/workflow/src/permission/decide.ts +6 -4
- package/packages/workflow/src/permission/index.ts +17 -7
- package/packages/workflow/src/permission/settings.ts +39 -4
- package/packages/workflow/src/plan/index.ts +19 -4
- package/packages/background-tasks/extensions/delegate-child.ts +0 -1
- package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
- package/packages/background-tasks/src/context-token-budget.ts +0 -903
- package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
- package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
- package/packages/background-tasks/src/delegate/budget.ts +0 -415
- package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
- package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
- package/packages/background-tasks/src/delegate/launch.ts +0 -484
- package/packages/background-tasks/src/delegate/result-package.ts +0 -459
- package/packages/background-tasks/src/delegate/runner.ts +0 -430
- package/packages/background-tasks/src/delegate/seed.ts +0 -423
- package/packages/background-tasks/src/delegate/types.ts +0 -323
- package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
- package/packages/background-tasks/src/delegate-extension.ts +0 -654
- package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
- package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
- package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
- package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
- package/packages/compactor/src/compaction/build-sections.ts +0 -76
- package/packages/compactor/src/compaction/extract/goals.ts +0 -36
- package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
- package/packages/compactor/src/compaction/format.ts +0 -53
- package/packages/compactor/src/compaction/merge.ts +0 -143
- package/packages/compactor/src/config/presets.ts +0 -160
- package/packages/compactor/src/executor/executor.ts +0 -233
- package/packages/compactor/src/executor/runtime.ts +0 -115
- package/packages/compactor/src/security/evaluator.ts +0 -89
- package/packages/compactor/src/security/policy.ts +0 -96
- package/packages/compactor/src/security/scanner.ts +0 -65
- package/packages/compactor/src/session/auto-inject.ts +0 -60
- package/packages/compactor/src/session/db.ts +0 -325
- package/packages/compactor/src/session/extract.ts +0 -144
- package/packages/compactor/src/session/resume-inject.ts +0 -64
- package/packages/compactor/src/session/snapshot.ts +0 -327
- package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
- package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
- package/packages/compactor/src/tools/ctx-execute.ts +0 -23
- package/packages/compactor/src/tools/ctx-stats.ts +0 -96
- package/packages/image/README.md +0 -99
- package/packages/image/package.json +0 -61
- package/packages/image/skills/image/SKILL.md +0 -76
- package/packages/image/src/generate.ts +0 -256
- package/packages/image/src/index.ts +0 -135
- package/packages/image/src/models.ts +0 -519
- package/packages/image/src/openai-images-api.ts +0 -282
- package/packages/image/src/register-providers.ts +0 -209
- package/packages/image/src/settings.ts +0 -173
- package/packages/image/src/tools.ts +0 -326
- package/packages/input-shortcuts/src/clipboard.ts +0 -119
- package/packages/kanboard/src/runner.ts +0 -817
- package/packages/skill-registry/skills/auto/SKILL.md +0 -465
- package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
- package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
- package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
- package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
- package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
- package/packages/skill-registry/skills/debug/SKILL.md +0 -228
- package/packages/skill-registry/skills/document/SKILL.md +0 -120
- package/packages/skill-registry/skills/fix/SKILL.md +0 -212
- package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
- package/packages/skill-registry/skills/plan/SKILL.md +0 -231
- package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
- package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
- package/packages/skill-registry/skills/research/SKILL.md +0 -251
- package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
- package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
- package/packages/skill-registry/skills/work/SKILL.md +0 -218
- package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
- package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
- package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
- package/packages/subagents/agents/delegate.md +0 -14
- package/packages/subagents/agents/oracle.md +0 -78
- package/packages/subagents/agents/researcher.md +0 -52
- package/packages/subagents/agents/reviewer.md +0 -80
- package/packages/subagents/agents/scout.md +0 -50
- package/packages/subagents/agents/worker.md +0 -59
- package/packages/subagents/prompts/council.md +0 -48
- package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
- package/packages/subagents/prompts/parallel-cleanup.md +0 -59
- package/packages/subagents/prompts/parallel-research.md +0 -50
- package/packages/subagents/prompts/parallel-review.md +0 -54
- package/packages/subagents/prompts/review-loop.md +0 -43
- package/packages/subagents/skills/council-mode/SKILL.md +0 -230
- package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
- package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
- package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
- package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
- package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
- package/packages/subagents/src/acceptance.ts +0 -331
- package/packages/subagents/src/agent-manager.ts +0 -405
- package/packages/subagents/src/agent-memory.ts +0 -300
- package/packages/subagents/src/agent-overrides.ts +0 -183
- package/packages/subagents/src/agent-runner.ts +0 -271
- package/packages/subagents/src/async-runner.ts +0 -422
- package/packages/subagents/src/authority-policy.ts +0 -47
- package/packages/subagents/src/budgets.ts +0 -285
- package/packages/subagents/src/child-safety.ts +0 -140
- package/packages/subagents/src/config.ts +0 -249
- package/packages/subagents/src/conversation-viewer.ts +0 -281
- package/packages/subagents/src/core-compat.ts +0 -94
- package/packages/subagents/src/custom-agents.ts +0 -343
- package/packages/subagents/src/file-system-retry.ts +0 -50
- package/packages/subagents/src/fleet-data.ts +0 -105
- package/packages/subagents/src/fleet-view.ts +0 -322
- package/packages/subagents/src/foreground-detach.ts +0 -59
- package/packages/subagents/src/fork-context.ts +0 -285
- package/packages/subagents/src/global.d.ts +0 -7
- package/packages/subagents/src/guide.ts +0 -129
- package/packages/subagents/src/mission-state.ts +0 -133
- package/packages/subagents/src/mission-store.ts +0 -436
- package/packages/subagents/src/output-limits.ts +0 -142
- package/packages/subagents/src/parity-types.ts +0 -315
- package/packages/subagents/src/pi-args.ts +0 -167
- package/packages/subagents/src/result-files.ts +0 -232
- package/packages/subagents/src/result-watcher.ts +0 -221
- package/packages/subagents/src/retained-children.ts +0 -176
- package/packages/subagents/src/run-fanout-budget.ts +0 -356
- package/packages/subagents/src/scheduled-runs.ts +0 -349
- package/packages/subagents/src/schemas.ts +0 -263
- package/packages/subagents/src/slash-commands.ts +0 -80
- package/packages/subagents/src/supervisor-channel.ts +0 -249
- package/packages/subagents/src/tool-handler.ts +0 -1144
- package/packages/subagents/src/types.ts +0 -238
- package/packages/subagents/src/widget.ts +0 -457
- package/packages/subagents/src/workflow-script.ts +0 -737
- package/packages/subagents/src/workflow-worker.ts +0 -384
- package/packages/subagents/src/worktree.ts +0 -614
- package/packages/utility/src/analytics/collector.ts +0 -293
- package/packages/utility/src/info-screen.ts +0 -80
- package/packages/utility/src/lifecycle/process.ts +0 -162
- package/packages/utility/src/prefix-cache.ts +0 -263
- package/packages/utility/src/skill-discovery.ts +0 -542
- package/packages/utility/src/tools/env.ts +0 -113
- package/packages/utility/src/tui/name-badge-state.ts +0 -315
- package/packages/utility/src/tui/name-badge.ts +0 -109
- /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: image
|
|
3
|
-
description: Generate images from text prompts and analyze images with vision models
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Image Tools
|
|
7
|
-
|
|
8
|
-
Two agent tools: `image_generate` creates images from a text prompt, and
|
|
9
|
-
`image_recognize` analyzes an existing image.
|
|
10
|
-
|
|
11
|
-
## image_generate
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
image_generate(prompt: "A cutaway diagram of a submarine, technical illustration, muted blues")
|
|
15
|
-
image_generate(prompt: "...", model: "flux.2-pro")
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
- `prompt` (required) — describe subject, style, composition and lighting.
|
|
19
|
-
Detail materially improves the result.
|
|
20
|
-
- `model` (optional) — fuzzy-matched against the image catalog
|
|
21
|
-
(`flux`, `gemini-3-pro-image`, `recraft-v4`, …). Omit to use the model
|
|
22
|
-
configured in `/unipi:settings`.
|
|
23
|
-
|
|
24
|
-
The image is returned inline and, when `saveToDisk` is on (the default),
|
|
25
|
-
written to the output directory (default `~/.unipi/images`). The saved path is
|
|
26
|
-
reported in the result.
|
|
27
|
-
|
|
28
|
-
**Image generation costs money per call.** Never regenerate an image
|
|
29
|
-
speculatively — only when the user asks for a change.
|
|
30
|
-
|
|
31
|
-
Models are served through OpenRouter, so an OpenRouter key is required:
|
|
32
|
-
https://openrouter.ai/keys
|
|
33
|
-
|
|
34
|
-
## image_recognize
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
image_recognize(image: "./screenshot.png")
|
|
38
|
-
image_recognize(image: "./error.png", prompt: "What does the stack trace say?")
|
|
39
|
-
image_recognize(image: "...", model: "claude-sonnet", systemPrompt: "Reply only with the visible text.")
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
- `image` (required) — a local file path, a `data:` URL, or raw base64.
|
|
43
|
-
**Prefer a file path**: inlining base64 into the conversation is far more
|
|
44
|
-
expensive. Remote URLs are not fetched — download first.
|
|
45
|
-
- `prompt` (optional) — the question to ask. Defaults to a general
|
|
46
|
-
description. A specific question gives a far more useful answer.
|
|
47
|
-
- `model` (optional) — must accept image input. Omit to use the configured
|
|
48
|
-
model, falling back to the session's current model.
|
|
49
|
-
- `systemPrompt` (optional) — override the configured system prompt for one
|
|
50
|
-
call.
|
|
51
|
-
|
|
52
|
-
Supported types: PNG, JPEG, GIF, WebP. The type is detected from the file's
|
|
53
|
-
magic numbers, so a misnamed extension still works.
|
|
54
|
-
|
|
55
|
-
### When to use it
|
|
56
|
-
|
|
57
|
-
- Reading a screenshot of an error, a stack trace, or failing UI
|
|
58
|
-
- Understanding a design mockup or wireframe before implementing it
|
|
59
|
-
- Extracting content from an architecture diagram or flowchart
|
|
60
|
-
- Checking what a rendered page or chart actually looks like
|
|
61
|
-
|
|
62
|
-
## Configuration
|
|
63
|
-
|
|
64
|
-
`/unipi:settings` configures both tools:
|
|
65
|
-
|
|
66
|
-
- Generation model (picker over the built-in catalog plus image models from
|
|
67
|
-
any provider registered by another extension)
|
|
68
|
-
- Recognition model (picker over vision-capable models only)
|
|
69
|
-
- Either picker accepts a **custom** `provider/model-id` — press `c` — for a
|
|
70
|
-
model the catalog does not list
|
|
71
|
-
- Enable/disable either tool
|
|
72
|
-
- Output directory and whether to save to disk
|
|
73
|
-
- The recognition system prompt
|
|
74
|
-
|
|
75
|
-
Config lives at `~/.unipi/config/image/config.json`. Toggling a tool on or off
|
|
76
|
-
takes effect on the next session, since tools are registered at startup.
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pi-unipi/image — Image generation
|
|
3
|
-
*
|
|
4
|
-
* Wraps pi-ai's image API. `generateImages` never rejects — failures come back
|
|
5
|
-
* as `stopReason: "error"` — so every call site must inspect the result rather
|
|
6
|
-
* than relying on try/catch.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import * as fs from "node:fs";
|
|
10
|
-
import * as path from "node:path";
|
|
11
|
-
|
|
12
|
-
import { getImagesModels, type ImageGenModel, type ImagesModelsLike } from "./models.js";
|
|
13
|
-
|
|
14
|
-
export interface GeneratedImage {
|
|
15
|
-
/** Base64 image data. */
|
|
16
|
-
data: string;
|
|
17
|
-
mimeType: string;
|
|
18
|
-
/** Absolute path, when saved to disk. */
|
|
19
|
-
path?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface GenerateResult {
|
|
23
|
-
images: GeneratedImage[];
|
|
24
|
-
/** Any accompanying commentary from the model. */
|
|
25
|
-
text: string;
|
|
26
|
-
model: string;
|
|
27
|
-
provider: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Structural view of pi-ai's AssistantImages. */
|
|
31
|
-
interface AssistantImagesLike {
|
|
32
|
-
output?: Array<{ type?: string; text?: string; data?: string; mimeType?: string }>;
|
|
33
|
-
stopReason?: string;
|
|
34
|
-
errorMessage?: string;
|
|
35
|
-
usage?: unknown;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Injectable generation function, for tests. */
|
|
39
|
-
export type GenerateImagesFn = (
|
|
40
|
-
model: unknown,
|
|
41
|
-
context: { input: Array<{ type: string; text?: string }> },
|
|
42
|
-
options: { apiKey?: string; signal?: AbortSignal },
|
|
43
|
-
) => Promise<AssistantImagesLike>;
|
|
44
|
-
|
|
45
|
-
/** Extension for a media type, for naming saved files. */
|
|
46
|
-
function extensionFor(mimeType: string): string {
|
|
47
|
-
switch (mimeType) {
|
|
48
|
-
case "image/png":
|
|
49
|
-
return ".png";
|
|
50
|
-
case "image/jpeg":
|
|
51
|
-
return ".jpg";
|
|
52
|
-
case "image/webp":
|
|
53
|
-
return ".webp";
|
|
54
|
-
case "image/gif":
|
|
55
|
-
return ".gif";
|
|
56
|
-
case "image/svg+xml":
|
|
57
|
-
return ".svg";
|
|
58
|
-
default:
|
|
59
|
-
return ".img";
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Filesystem-safe slug from a prompt, for a recognizable filename. */
|
|
64
|
-
export function slugify(prompt: string, maxLength = 40): string {
|
|
65
|
-
const slug = prompt
|
|
66
|
-
.toLowerCase()
|
|
67
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
68
|
-
.replace(/^-+|-+$/g, "")
|
|
69
|
-
.slice(0, maxLength)
|
|
70
|
-
.replace(/-+$/g, "");
|
|
71
|
-
return slug || "image";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Build a collision-free filename. */
|
|
75
|
-
export function buildFileName(
|
|
76
|
-
prompt: string,
|
|
77
|
-
mimeType: string,
|
|
78
|
-
index: number,
|
|
79
|
-
now: Date = new Date(),
|
|
80
|
-
): string {
|
|
81
|
-
const stamp = now.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
82
|
-
const suffix = index > 0 ? `-${index + 1}` : "";
|
|
83
|
-
return `${stamp}-${slugify(prompt)}${suffix}${extensionFor(mimeType)}`;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Write an image to disk.
|
|
88
|
-
* @returns the absolute path, or undefined if the write failed (never throws —
|
|
89
|
-
* a failed save must not discard a successfully generated image).
|
|
90
|
-
*/
|
|
91
|
-
export function saveImage(
|
|
92
|
-
outputDir: string,
|
|
93
|
-
fileName: string,
|
|
94
|
-
base64: string,
|
|
95
|
-
): string | undefined {
|
|
96
|
-
try {
|
|
97
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
98
|
-
const target = path.join(outputDir, fileName);
|
|
99
|
-
fs.writeFileSync(target, Buffer.from(base64, "base64"));
|
|
100
|
-
return target;
|
|
101
|
-
} catch {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Providers pi-ai's images collection can actually generate with. */
|
|
107
|
-
function supportedProviders(imagesApi: ImagesModelsLike): string[] {
|
|
108
|
-
try {
|
|
109
|
-
return [...new Set(imagesApi.getModels().map((m) => m.provider))];
|
|
110
|
-
} catch {
|
|
111
|
-
return [];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Whether generation can route to a provider. Unknown/empty catalogs are
|
|
117
|
-
* treated as capable so a stubbed or future pi-ai is never blocked by this
|
|
118
|
-
* check — the real call still reports its own error.
|
|
119
|
-
*/
|
|
120
|
-
function providerCanGenerate(imagesApi: ImagesModelsLike, provider: string): boolean {
|
|
121
|
-
const providers = supportedProviders(imagesApi);
|
|
122
|
-
if (providers.length === 0) return true;
|
|
123
|
-
return providers.includes(provider);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface GenerateOptions {
|
|
127
|
-
prompt: string;
|
|
128
|
-
model: ImageGenModel;
|
|
129
|
-
/** Fallback key, used only when pi-ai's own auth resolution comes up empty. */
|
|
130
|
-
apiKey?: string;
|
|
131
|
-
signal?: AbortSignal;
|
|
132
|
-
/** Absolute directory for saved images; omit to skip saving. */
|
|
133
|
-
outputDir?: string;
|
|
134
|
-
/** Source image; when set the request is an edit rather than a generation. */
|
|
135
|
-
inputImage?: { data: string; mimeType: string };
|
|
136
|
-
now?: Date;
|
|
137
|
-
/** Injected images collection, for tests. */
|
|
138
|
-
images?: ImagesModelsLike;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Generate images and optionally save them.
|
|
143
|
-
* @throws {Error} with an actionable message when generation fails.
|
|
144
|
-
*/
|
|
145
|
-
export async function generateImage(options: GenerateOptions): Promise<GenerateResult> {
|
|
146
|
-
const { prompt, model, signal, outputDir, now, inputImage } = options;
|
|
147
|
-
|
|
148
|
-
if (!prompt.trim()) {
|
|
149
|
-
throw new Error("A non-empty prompt is required.");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const imagesApi = options.images ?? (await getImagesModels());
|
|
153
|
-
if (!imagesApi) {
|
|
154
|
-
throw new Error(
|
|
155
|
-
"Image generation is unavailable — this version of pi-ai does not expose an image API.",
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// pi-ai's images collection has its own provider set, separate from pi's
|
|
160
|
-
// chat registry. `registerRegistryImageProviders()` bridges pi's providers
|
|
161
|
-
// in, but a model may still name a provider with no image route at all —
|
|
162
|
-
// pi-ai would answer with a bare "Unknown provider: x", so say something
|
|
163
|
-
// useful instead.
|
|
164
|
-
if (!providerCanGenerate(imagesApi, model.provider)) {
|
|
165
|
-
const supported = supportedProviders(imagesApi);
|
|
166
|
-
throw new Error(
|
|
167
|
-
`Provider "${model.provider}" has no image-generation route.\n` +
|
|
168
|
-
`→ Available: ${supported.join(", ") || "openrouter"}.\n` +
|
|
169
|
-
"→ Providers are bridged from pi automatically; one without a baseUrl " +
|
|
170
|
-
"or an API key cannot be used.\n" +
|
|
171
|
-
"→ Pick another with /unipi:settings.",
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Prefer pi-ai's own credential store, then the caller-supplied fallback so
|
|
176
|
-
// a bare OPENROUTER_API_KEY still works.
|
|
177
|
-
let apiKey: string | undefined;
|
|
178
|
-
try {
|
|
179
|
-
// pi-ai resolves to an `AuthResult`, i.e. `{ auth: { apiKey } }`. Older
|
|
180
|
-
// shapes put the key at the top level, so accept both — reading only one
|
|
181
|
-
// fails silently and looks like a missing credential.
|
|
182
|
-
const resolvedAuth = (await imagesApi.getAuth(model)) as
|
|
183
|
-
| { apiKey?: string; auth?: { apiKey?: string } }
|
|
184
|
-
| undefined;
|
|
185
|
-
apiKey = resolvedAuth?.auth?.apiKey ?? resolvedAuth?.apiKey;
|
|
186
|
-
} catch {
|
|
187
|
-
// Reported as a missing key below.
|
|
188
|
-
}
|
|
189
|
-
apiKey ||= options.apiKey;
|
|
190
|
-
|
|
191
|
-
if (!apiKey) {
|
|
192
|
-
throw new Error(
|
|
193
|
-
`No API key for provider "${model.provider}".\n` +
|
|
194
|
-
"→ Sign in with /login, or set the provider's API key environment variable.\n" +
|
|
195
|
-
`→ Expected environment variable: ` +
|
|
196
|
-
`${model.provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`,
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const input: Array<{ type: string; text?: string; data?: string; mimeType?: string }> =
|
|
201
|
-
[{ type: "text", text: prompt }];
|
|
202
|
-
if (inputImage) {
|
|
203
|
-
input.push({
|
|
204
|
-
type: "image",
|
|
205
|
-
data: inputImage.data,
|
|
206
|
-
mimeType: inputImage.mimeType,
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const result = (await imagesApi.generateImages(
|
|
211
|
-
model,
|
|
212
|
-
{ input } as { input: Array<{ type: string; text?: string }> },
|
|
213
|
-
{ apiKey, ...(signal ? { signal } : {}) },
|
|
214
|
-
)) as AssistantImagesLike;
|
|
215
|
-
|
|
216
|
-
// pi-ai reports failures in-band rather than rejecting.
|
|
217
|
-
if (result.stopReason === "error") {
|
|
218
|
-
throw new Error(result.errorMessage || "Image generation failed.");
|
|
219
|
-
}
|
|
220
|
-
if (result.stopReason === "aborted") {
|
|
221
|
-
throw new Error("Image generation was cancelled.");
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const images: GeneratedImage[] = [];
|
|
225
|
-
const textParts: string[] = [];
|
|
226
|
-
|
|
227
|
-
for (const part of result.output ?? []) {
|
|
228
|
-
if (part?.type === "image" && typeof part.data === "string" && part.data.length > 0) {
|
|
229
|
-
images.push({ data: part.data, mimeType: part.mimeType || "image/png" });
|
|
230
|
-
} else if (part?.type === "text" && typeof part.text === "string" && part.text.trim()) {
|
|
231
|
-
textParts.push(part.text.trim());
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (images.length === 0) {
|
|
236
|
-
throw new Error(
|
|
237
|
-
textParts.length > 0
|
|
238
|
-
? `The model returned no image. It said: ${textParts.join(" ")}`
|
|
239
|
-
: "The model returned no image.",
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (outputDir) {
|
|
244
|
-
images.forEach((image, index) => {
|
|
245
|
-
const fileName = buildFileName(prompt, image.mimeType, index, now);
|
|
246
|
-
image.path = saveImage(outputDir, fileName, image.data);
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return {
|
|
251
|
-
images,
|
|
252
|
-
text: textParts.join("\n"),
|
|
253
|
-
model: model.id,
|
|
254
|
-
provider: model.provider,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pi-unipi/image — Extension entry
|
|
3
|
-
*
|
|
4
|
-
* Provides the `image_generate` and `image_recognize` agent tools plus the
|
|
5
|
-
* Settings are managed in the unified /unipi:settings hub.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { dirname } from "node:path";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import {
|
|
12
|
-
IMAGE_TOOLS,
|
|
13
|
-
MODULES,
|
|
14
|
-
UNIPI_EVENTS,
|
|
15
|
-
emitEvent,
|
|
16
|
-
getPackageVersion,
|
|
17
|
-
} from "@pi-unipi/core";
|
|
18
|
-
|
|
19
|
-
import { registerImageTools } from "./tools.js";
|
|
20
|
-
import {
|
|
21
|
-
applyRecognizeGating,
|
|
22
|
-
isVisionModel,
|
|
23
|
-
listImageGenModels,
|
|
24
|
-
listVisionModels,
|
|
25
|
-
type ChatModelRegistry,
|
|
26
|
-
} from "./models.js";
|
|
27
|
-
import { registerRegistryImageProviders } from "./register-providers.js";
|
|
28
|
-
import { loadConfig } from "./settings.js";
|
|
29
|
-
|
|
30
|
-
const VERSION = getPackageVersion(dirname(fileURLToPath(import.meta.url)));
|
|
31
|
-
|
|
32
|
-
/** Info-screen registry, read off the global to avoid load-order coupling. */
|
|
33
|
-
function getInfoRegistry() {
|
|
34
|
-
return (
|
|
35
|
-
globalThis as {
|
|
36
|
-
__unipi_info_registry?: {
|
|
37
|
-
registerGroup(group: unknown): void;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
).__unipi_info_registry;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Hide image_recognize when the session model can natively see images, and
|
|
45
|
-
* restore it when a text-only model takes over. Returns whether the tool is
|
|
46
|
-
* provided after gating.
|
|
47
|
-
*/
|
|
48
|
-
function applyVisionGating(pi: ExtensionAPI, model: unknown): boolean {
|
|
49
|
-
const active = pi.getActiveTools();
|
|
50
|
-
const next = applyRecognizeGating(active, model, IMAGE_TOOLS.RECOGNIZE);
|
|
51
|
-
if (next !== active) pi.setActiveTools(next);
|
|
52
|
-
return next.includes(IMAGE_TOOLS.RECOGNIZE);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default function (pi: ExtensionAPI) {
|
|
56
|
-
registerImageTools(pi);
|
|
57
|
-
|
|
58
|
-
pi.on("model_select", (event) => {
|
|
59
|
-
if (!loadConfig().recognize.enabled) return;
|
|
60
|
-
applyVisionGating(pi, event.model);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
64
|
-
const config = loadConfig();
|
|
65
|
-
|
|
66
|
-
// Bridge pi's configured providers into pi-ai's images collection up front,
|
|
67
|
-
// so the settings picker and the info screen see them without a prior
|
|
68
|
-
// image_generate call. Best-effort: never block session start.
|
|
69
|
-
void registerRegistryImageProviders(
|
|
70
|
-
(ctx as unknown as { modelRegistry?: ChatModelRegistry }).modelRegistry,
|
|
71
|
-
).catch(() => undefined);
|
|
72
|
-
|
|
73
|
-
// A vision-capable session model reads images itself, so image_recognize
|
|
74
|
-
// would only duplicate that ability. Drop it from the active tool set;
|
|
75
|
-
// the model_select handler above restores it when a text-only model is
|
|
76
|
-
// chosen later in the same session.
|
|
77
|
-
const recognizeProvided =
|
|
78
|
-
config.recognize.enabled && applyVisionGating(pi, ctx.model);
|
|
79
|
-
|
|
80
|
-
const tools: string[] = [];
|
|
81
|
-
if (config.generate.enabled) tools.push(IMAGE_TOOLS.GENERATE);
|
|
82
|
-
if (recognizeProvided) tools.push(IMAGE_TOOLS.RECOGNIZE);
|
|
83
|
-
|
|
84
|
-
emitEvent(pi, UNIPI_EVENTS.MODULE_READY, {
|
|
85
|
-
name: MODULES.IMAGE,
|
|
86
|
-
version: VERSION,
|
|
87
|
-
commands: [],
|
|
88
|
-
tools,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const registry = getInfoRegistry();
|
|
92
|
-
if (!registry) return;
|
|
93
|
-
|
|
94
|
-
registry.registerGroup({
|
|
95
|
-
id: "image",
|
|
96
|
-
name: "Image",
|
|
97
|
-
icon: "🎨",
|
|
98
|
-
priority: 55,
|
|
99
|
-
config: {
|
|
100
|
-
showByDefault: true,
|
|
101
|
-
stats: [
|
|
102
|
-
{ id: "generate", label: "Generate", show: true },
|
|
103
|
-
{ id: "recognize", label: "Recognize", show: true },
|
|
104
|
-
{ id: "visionModels", label: "Vision Models", show: true },
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
dataProvider: async () => {
|
|
108
|
-
const current = loadConfig();
|
|
109
|
-
|
|
110
|
-
const genModels = await listImageGenModels();
|
|
111
|
-
const generate = current.generate.enabled
|
|
112
|
-
? genModels.length > 0
|
|
113
|
-
? current.generate.model
|
|
114
|
-
: "No image models available"
|
|
115
|
-
: "Disabled";
|
|
116
|
-
|
|
117
|
-
const chatRegistry = (ctx as unknown as { modelRegistry?: ChatModelRegistry })
|
|
118
|
-
.modelRegistry;
|
|
119
|
-
const vision = chatRegistry ? listVisionModels(chatRegistry) : [];
|
|
120
|
-
|
|
121
|
-
const recognize = !current.recognize.enabled
|
|
122
|
-
? "Disabled"
|
|
123
|
-
: isVisionModel(ctx.model)
|
|
124
|
-
? "Hidden (model has vision)"
|
|
125
|
-
: current.recognize.model || "Session model";
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
generate: { value: generate },
|
|
129
|
-
recognize: { value: recognize },
|
|
130
|
-
visionModels: { value: String(vision.length) },
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
}
|