pi-multimodal-proxy 1.7.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,33 +1,45 @@
1
- {
2
- "name": "pi-multimodal-proxy",
3
- "version": "1.7.1",
4
- "description": "Automatic image, video and audio description for any model in Pi. Routes media to a multimodal model and injects descriptions into context.",
5
- "keywords": [
6
- "pi-package"
7
- ],
8
- "license": "MIT",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/pungggi/pi-vision-proxy.git"
12
- },
13
- "homepage": "https://github.com/pungggi/pi-vision-proxy#readme",
14
- "type": "module",
15
- "scripts": {
16
- "test": "node --experimental-strip-types --no-warnings --test extensions/__tests__/*.test.ts"
17
- },
18
- "pi": {
19
- "extensions": [
20
- "./extensions/vision-proxy.ts"
21
- ]
22
- },
23
- "dependencies": {
24
- "image-size": "^2.0.2",
25
- "imagescript": "^1.3.1",
26
- "imghash": "^1.1.4"
27
- },
28
- "peerDependencies": {
29
- "@earendil-works/pi-ai": ">=0.74.0",
30
- "@earendil-works/pi-coding-agent": ">=0.74.0",
31
- "typebox": "*"
32
- }
33
- }
1
+ {
2
+ "name": "pi-multimodal-proxy",
3
+ "version": "1.11.0",
4
+ "description": "Automatic image, video and audio description for any model in Pi. Routes media to a multimodal model and injects descriptions into context.",
5
+ "keywords": [
6
+ "pi-package"
7
+ ],
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/pungggi/pi-multimodal-proxy.git"
12
+ },
13
+ "homepage": "https://github.com/pungggi/pi-multimodal-proxy#readme",
14
+ "type": "module",
15
+ "scripts": {
16
+ "test": "node --experimental-strip-types --no-warnings --test extensions/__tests__/*.test.ts",
17
+ "prepublishOnly": "node -e \"if(!process.env.CI)throw new Error('publish via release.yml CI: push a v* tag. Manual npm publish is blocked.')\""
18
+ },
19
+ "pi": {
20
+ "extensions": [
21
+ "./extensions/vision-proxy.ts"
22
+ ]
23
+ },
24
+ "dependencies": {
25
+ "image-size": "^2.0.2",
26
+ "imagescript": "^1.3.1",
27
+ "imghash": "^1.1.4"
28
+ },
29
+ "peerDependencies": {
30
+ "@earendil-works/pi-ai": ">=0.74.0",
31
+ "@earendil-works/pi-coding-agent": ">=0.74.0",
32
+ "typebox": "*"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public",
36
+ "provenance": true
37
+ },
38
+ "files": [
39
+ "extensions",
40
+ "docs",
41
+ "README.md",
42
+ "CHANGELOG.md",
43
+ "SECURITY-REVIEW.md"
44
+ ]
45
+ }
@@ -1,170 +0,0 @@
1
- # PRD Implementation Status
2
-
3
- **PRD version:** 1.4.0 Final
4
- **Last updated:** 2026-05-03
5
-
6
- ---
7
-
8
- ## Legend
9
-
10
- | Status | Meaning |
11
- |---|---|
12
- | ⬜ Not started | No code written yet |
13
- | šŸ”µ In progress | Actively being implemented |
14
- | 🟔 Done, needs review | Code written, awaiting review/testing |
15
- | āœ… Complete | Reviewed and merged |
16
- | ā³ Blocked | Waiting on a dependency or decision |
17
- | āŒ Deferred | Moved to a later milestone |
18
-
19
- ---
20
-
21
- ## Open questions
22
-
23
- | # | Question | Status | Blocks |
24
- |---|---|---|---|
25
- | OQ-1 | Is `sharp` a hard or optional dependency? What is the degradation behavior when absent? | āœ… Resolved | Used `imagescript` + `imghash` instead — zero native deps, pure JS/WASM |
26
-
27
- ---
28
-
29
- ## Feature 1 — `analyze_image` tool
30
-
31
- | FR | Description | Status | Notes |
32
- |---|---|---|---|
33
- | FR-1.1 | Register `analyze_image` tool when proxy enabled | 🟔 Done | Registered conditionally on `tool=on && mode!=off` |
34
- | FR-1.2 | Tool schema (images, question, model, crop, reason) | 🟔 Done | TypeBox schema with all fields |
35
- | FR-1.2.1 | Crop semantics (region, normalized, pixels) | āœ… Complete | All three forms resolve to pixels; cropping applied via ImageScript |
36
- | FR-1.2.2 | `reason` field (analytics logging) | 🟔 Done | Logged in telemetry entry |
37
- | FR-1.2.3 | Tool description text for agent | 🟔 Done | Full description per PRD spec |
38
- | FR-1.3 | Path resolution and security | 🟔 Done | Delegates to existing readImageFileWithReason + path allowlist |
39
- | FR-1.4 | Model override parameter | 🟔 Done | Agent-initiated override honoured |
40
- | FR-1.5 | Per-provider consent for tool calls | 🟔 Done | Checks existing consent |
41
- | FR-1.6 | Result LRU cache | 🟔 Done | LRUCache with configurable size, keyed by (hashes, crop sig, question hash, model) |
42
- | FR-1.7 | Configuration (tool, max-images-per-call, cache-size) | 🟔 Done | Slash commands + env vars |
43
- | FR-1.8 | Result fencing with `<vision_proxy_analysis>` tag | 🟔 Done | buildAnalysisFence with all attributes |
44
- | FR-1.8 | `crop_origin` attribute on cropped results | 🟔 Done | Included in fence when crop applied |
45
- | FR-1.8 | `image` attribute suffixed with `#crop:x,y,w,h` | 🟔 Done | Included in fence when crop applied |
46
- | FR-1.9 | Telemetry (`vision_proxy.tool_call` entries) | 🟔 Done | Appended via pi.appendEntry |
47
- | FR-1.10 | Precedence rule (tool > generic, no correction entry) | 🟔 Done | Tool result returned directly; no correction entry |
48
-
49
- ## Feature 1 — Infrastructure
50
-
51
- | Item | Description | Status | Notes |
52
- |---|---|---|---|
53
- | INFRA-1 | `image-size` integration for dimension extraction | 🟔 Done | extractDimensions() + storeImageMeta() |
54
- | INFRA-2 | `imagescript` integration for cropping | āœ… Complete | cropImage() + piAiImageToBuffer/bufferToPiAiImage helpers |
55
- | INFRA-3 | `imghash` integration for pHash | āœ… Complete | computePHash() + hammingDistance() helpers; lazy-loaded |
56
- | INFRA-4 | In-memory `_imageMeta` map (hash → width/height/filename) | 🟔 Done | Map exported, populated on ingestion |
57
- | INFRA-5 | Update `readImageFileWithReason` to return basename | 🟔 Done | `filename` field added to ReadImageResult |
58
- | INFRA-6 | Update `fenceUntrusted` to handle all three fence tags | 🟔 Done | Regex covers description, analysis, joint_description |
59
- | INFRA-7 | Region → pixel rectangle resolution | 🟔 Done | resolveRegion() + normalizedToPixels() |
60
- | INFRA-8 | Normalized → pixel rectangle resolution | 🟔 Done | normalizedToPixels() with clamping |
61
- | INFRA-9 | Pixel clamp + zero-area validation | 🟔 Done | clampPixels() with null return on zero area |
62
-
63
- ## Feature 2 — Multi-image batched comparison
64
-
65
- | FR | Description | Status | Notes |
66
- |---|---|---|---|
67
- | FR-2.1 | Auto-proxy: joint description for N ≄ 2 images | āœ… Complete | Joint call after per-image analysis, cached in session | |
68
- | FR-2.2 | `analyze_image` with ≄2 images: batched vision call | 🟔 Done | Sends all images; uses adaptive prompt when available |
69
- | FR-2.3 | Joint calls obey consent + injection fence + include_context | āœ… Complete | Reuses same consent/fence flow | |
70
- | FR-2.4 | `maxBatch` config | 🟔 Done | Config field + slash command + env var |
71
- | FR-2.5 | Adaptive joint-call system prompt | āœ… Complete | buildAdaptiveJointPrompt with comparison structure | |
72
- | FR-2.5.1 | Filename hint patterns (Appendix D) | āœ… Complete | generateFilenameHints + extractVersion; before/after, old/new, versioned, numbered, date-ordered | |
73
- | FR-2.5.2 | pHash similarity hint | 🟔 Done | computePHash() + hammingDistance() available via imghash |
74
- | FR-2.5.3 | Hints are advisory | āœ… Complete | Hints only appended to prompt, not required | |
75
- | FR-2.5.4 | Hints suppressed for tool path | āœ… Complete | Hints not included in analyze_image tool calls | |
76
- | FR-2.6 | Joint description fencing with `<vision_proxy_joint_description>` | āœ… Complete | buildJointDescriptionFence with dimensions JSON | |
77
- | FR-2.7 | Joint description cost telemetry | āœ… Complete | CUSTOM_TYPE_JOINT entry with images and description | |
78
-
79
- ## Feature 3 — `/vision-proxy describe` slash command
80
-
81
- | FR | Description | Status | Notes |
82
- |---|---|---|---|
83
- | FR-3.1 | `describe` and `redescribe` subcommands with extended crop syntax | āœ… Complete | parseDescribeArgs + full slash handler | |
84
- | FR-3.2 | `describe` semantics (resolve, joint, --save) | āœ… Complete | Resolves images, supports --question/--crop/--model/--save | |
85
- | FR-3.3 | `redescribe` sugar for `describe --save` | āœ… Complete | parseDescribeArgs with isRedescribe flag | |
86
- | FR-3.4 | Inline consent prompts | āœ… Complete | Checks hasConsent before calling vision model | |
87
- | FR-3.5 | TUI output with `[Vision Proxy]` prefix | āœ… Complete | All output uses [Vision Proxy] prefix | |
88
- | FR-3.6 | `vision_proxy.command` logging | āœ… Complete | CUSTOM_TYPE_COMMAND entry with command, images, question, model, latency | |
89
-
90
- ## Feature 4 — Optional grounded-coordinate output
91
-
92
- | FR | Description | Status | Notes |
93
- |---|---|---|---|
94
- | FR-4.1 | `supportsGrounding` per-model flag | 🟔 Done | Via groundingModels config map |
95
- | FR-4.1.1 | Curated Tier 1 default list | 🟔 Done | Shipped in DEFAULT_CONFIG |
96
- | FR-4.1.2 | Grounding-models slash commands (add/remove/list/reset) | āœ… Complete | With excluded-model confirmation prompt, --format flag, default qwen_pixels | |
97
- | FR-4.2 | Native-format grounding system prompt injection | 🟔 Done | buildGroundingInstruction() for all formats |
98
- | FR-4.3 | No grounding instruction when `supportsGrounding: false` | 🟔 Done | Returns empty string |
99
- | FR-4.4 | Proxy does not parse/rewrite returned coordinates | 🟔 Done | Pass-through |
100
- | FR-4.5 | Additive — model ignoring instruction is harmless | 🟔 Done | Instruction appended, not required |
101
- | FR-4.6 | Crop + grounding: coordinates relative to crop, `crop_origin` for mapping | 🟔 Done | crop_origin in fence attributes |
102
- | FR-4.7 | Per-model `grounding_format` registry + default mappings | 🟔 Done | groundingModels map + getGroundingFormat() |
103
-
104
- ## Cross-cutting
105
-
106
- | Item | Description | Status | Notes |
107
- |---|---|---|---|
108
- | CC-1 | Update auto-proxy fence to `<vision_proxy_description>` with width/height/filename attributes | 🟔 Done | buildDescriptionFence() used in before_agent_start |
109
- | CC-2 | Update `context` handler to use new fence format | 🟔 Done | Uses buildDescriptionFence() in context handler |
110
- | CC-3 | Configuration: new fields in `vision-proxy.json` | 🟔 Done | All new fields with defaults |
111
- | CC-4 | Configuration: new slash subcommands (tool, max-images-per-call, max-batch, cache-size) | 🟔 Done | All four subcommands + interactive menu |
112
- | CC-5 | Configuration: new env var overrides | 🟔 Done | All env vars parsed in readEnvOverrides() |
113
- | CC-6 | Telemetry: new session entry types | 🟔 Done | CUSTOM_TYPE_TOOL_CALL constant |
114
- | CC-7 | Security: closing-tag neutralisation for all three fence tags | 🟔 Done | Updated fenceUntrusted regex |
115
- | CC-8 | Backwards compat: 1.3.0 config files load unchanged | 🟔 Done | sanitize() fills new fields with defaults |
116
- | CC-9 | Update README.md | āœ… Complete | Updated for 1.4.0 GA with all features documented | |
117
-
118
- ## Tests
119
-
120
- | Area | Status | Notes |
121
- |---|---|---|
122
- | Unit: crop resolution (region → pixels) | āœ… Complete | resolveRegion, resolveCropEntry |
123
- | Unit: crop resolution (normalized → pixels) | āœ… Complete | normalizedToPixels with clamping |
124
- | Unit: pixel clamp + zero-area validation | āœ… Complete | clampPixels |
125
- | Unit: region name validation | āœ… Complete | isValidNamedRegion |
126
- | Unit: `CropEntry` union discrimination | āœ… Complete | resolveCropEntry |
127
- | Unit: filename hint pattern matching | āœ… Complete | generateFilenameHints + extractVersion |
128
- | Unit: version extraction (non-contiguous, decimal) | āœ… Complete | extractVersion |
129
- | Unit: `fenceUntrusted` with all three tags | āœ… Complete | |
130
- | Unit: `_imageMeta` map population | āœ… Complete | storeImageMeta + extractDimensions |
131
- | Unit: LRU cache key stability across crop forms | āœ… Complete | cropSignature + buildToolCacheKey |
132
- | Unit: grounding format registry lookups | āœ… Complete | getGroundingFormat |
133
- | Unit: config backwards compatibility | āœ… Complete | sanitize defaults for new fields |
134
- | Unit: slash command argument parsing (--crop forms) | āœ… Complete | parseDescribeArgs: region, normalized, pixels, --question, --save, --model, redescribe restrictions | |
135
- | Unit: readEnvOverrides for 1.4.0 fields | āœ… Complete | |
136
- | Unit: buildDescriptionFence / buildAnalysisFence | āœ… Complete | |
137
- | Unit: cropImage (ImageScript cropping) | āœ… Complete | 10Ɨ10 PNG → 5Ɨ5 crop, JPEG encoding, OOB |
138
- | Unit: piAiImageToBuffer / bufferToPiAiImage | āœ… Complete | Round-trip base64, default MIME |
139
- | Unit: computePHash | āœ… Complete | Valid image → hex hash |
140
- | Unit: hammingDistance | āœ… Complete | Identical, differing, null, unequal length |
141
- | Integration: `analyze_image` tool end-to-end | āœ… Complete | Mock-based: validation, consent, path security |
142
- | Integration: auto-proxy + tool in same turn | āœ… Complete | Consent flow tests cover the per-provider consent wiring |
143
- | Integration: joint description for N ≄ 2 auto-proxy | āœ… Complete | Fence format + crop pipeline round-trip tests |
144
- | Integration: `/vision-proxy describe` slash command | āœ… Complete | parseDescribeArgs tested for all crop forms, redescribe restrictions |
145
-
146
- ---
147
-
148
- ## Milestones
149
-
150
- | Milestone | Target | Status |
151
- |---|---|---|
152
- | 1.4.0-beta.1 | Feature 1 (`tool=off` default), crop forms, dimensions in fence | 🟔 Done, needs review |
153
- | 1.4.0-beta.2 | Feature 3 (slash commands with crop syntax) | āœ… Complete |
154
- | 1.4.0-beta.3 | Feature 2 (`maxBatch=1` default), adaptive prompt, hints | āœ… Complete |
155
- | 1.4.0-beta.4 | Feature 4 (grounding registry, Tier 1 list) | āœ… Complete |
156
- | 1.4.0 | Flip `tool=on`, `maxBatch=4` | āœ… Complete |
157
-
158
- ---
159
-
160
- ## Changelog
161
-
162
- | Date | Change |
163
- |---|---|
164
- | 2026-05-03 | Added 33 mock-based integration tests covering fence output, neutralisation, consent flow, crop pipeline, ImageScript round-trip, pHash, describe parsing, filename hints, GA config defaults. 213 tests total, all passing. |: Flipped defaults (tool=on, maxBatch=4). Security review: fixed consent slash command (now records provider), sanitized question in describe handler, removed dead pHash stub. Updated README.md. 180 tests passing. |
165
- | 2026-05-03 | Milestone beta.4: Feature 4 grounding-models slash commands (add/remove/list/reset), excluded-model warnings, parseGroundingFormat validator. 180 tests passing. |
166
- | 2026-05-03 | Milestone beta.3: Feature 2 (multi-image batched comparison). Auto-proxy joint descriptions for N≄2 images, adaptive joint prompt with comparison structure, filename hint patterns (Appendix D), pHash infrastructure, buildJointDescriptionFence. 172 tests passing. |
167
- | 2026-05-03 | Milestone beta.2: Feature 3 (`/vision-proxy describe` + `redescribe`) fully implemented. parseDescribeArgs with all three crop forms, --question/--crop/--model/--save flags, consent checks, [Vision Proxy] TUI prefix, vision_proxy.command telemetry. 152 tests passing. |
168
- | 2026-05-03 | OQ-1 resolved: chose `imagescript` + `imghash` over `sharp`. INFRA-2 (cropping) and INFRA-3 (pHash) implemented. Crop now applied to image bytes in `analyze_image` tool. 134 tests passing. |
169
- | 2026-05-03 | Milestone beta.1 implementation: Feature 1 core + infrastructure + cross-cutting config/fence updates. 112 tests passing. |
170
- | 2026-05-03 | Initial status document created |