Browse Source
Phase 14 complete - Milestone v1.1 finished Tasks completed: - Normalize dynamic handle IDs to standard values - Update connection validation for normalized handles - Map normalized handles to schema names in execution - Add placeholder handles for unused input types SUMMARY: .planning/phases/14-fix-drag-connect-bugs/14-01-SUMMARY.md Co-Authored-By: Claude <noreply@anthropic.com>handoff-20260429-1057
4 changed files with 334 additions and 17 deletions
@ -0,0 +1,204 @@ |
|||||
|
--- |
||||
|
phase: 14-fix-drag-connect-bugs |
||||
|
plan: 01 |
||||
|
type: execute |
||||
|
--- |
||||
|
|
||||
|
<objective> |
||||
|
Fix two bugs with nodes created via drag-connect: |
||||
|
1. Connection vanishes after selecting model from browser |
||||
|
2. Node defaults to Gemini with correct Browse button but connection to default handles breaks when model schema loads |
||||
|
|
||||
|
**Root Cause Analysis:** |
||||
|
|
||||
|
Bug 1 (Connection Vanishes): |
||||
|
- Node created via drag-connect gets default Gemini model (no `inputSchema`) |
||||
|
- Connection made to default handle IDs: `"image"` and `"text"` |
||||
|
- User clicks Browse → selects external model (Replicate/fal.ai) |
||||
|
- `handleBrowseModelSelect` updates `selectedModel` |
||||
|
- `ModelParameters` component loads schema → calls `handleInputsLoaded` → sets `inputSchema` |
||||
|
- Node re-renders with dynamic handles that have **different IDs** from schema (e.g., `"image_url"` instead of `"image"`) |
||||
|
- React Flow invalidates edges connected to non-existent handles → **connection vanishes** |
||||
|
|
||||
|
Bug 2 is a symptom of Bug 1 - the node works fine with Gemini defaults, but switching to an external provider with dynamic schema causes the connection loss. |
||||
|
|
||||
|
**Solution:** |
||||
|
When a user selects an external model on a node created via drag-connect, we need to either: |
||||
|
A) Remap existing connections to the new dynamic handle IDs, OR |
||||
|
B) Keep standard `"image"` and `"text"` handles for external models too (normalize schema handle IDs) |
||||
|
|
||||
|
Option B is simpler and more robust - normalize all dynamic schema handles to use standard IDs. The schema already provides semantic type info ("image" vs "text"), so we don't need the provider-specific names as handle IDs. |
||||
|
|
||||
|
Output: Connections persist when switching from default Gemini to external provider on drag-connect-created nodes. |
||||
|
</objective> |
||||
|
|
||||
|
<execution_context> |
||||
|
@~/.claude/get-shit-done/workflows/execute-phase.md |
||||
|
@~/.claude/get-shit-done/templates/summary.md |
||||
|
</execution_context> |
||||
|
|
||||
|
<context> |
||||
|
@.planning/PROJECT.md |
||||
|
@.planning/ROADMAP.md |
||||
|
@.planning/STATE.md |
||||
|
|
||||
|
**Key source files:** |
||||
|
@src/components/nodes/GenerateImageNode.tsx - Dynamic handle rendering (lines 464-550) |
||||
|
@src/components/WorkflowCanvas.tsx - Connection handling, handleMenuSelect (lines 529-646) |
||||
|
@src/components/nodes/ModelParameters.tsx - Schema fetching and input loading |
||||
|
|
||||
|
**Current behavior:** |
||||
|
1. `handleMenuSelect` creates node with `addNode(nodeType, flowPosition)` - no initial data |
||||
|
2. Node gets default Gemini with handles `id="image"` and `id="text"` |
||||
|
3. Connection made to default handle IDs |
||||
|
4. User selects external model → `handleInputsLoaded` sets `inputSchema` |
||||
|
5. Node renders dynamic handles with schema-specific IDs (e.g., `"image_url"`, `"prompt"`) |
||||
|
6. Connection to `"image"` or `"text"` becomes invalid → edge removed |
||||
|
|
||||
|
**Target behavior:** |
||||
|
- Dynamic handles use standard IDs (`"image"`, `"text"`) regardless of schema |
||||
|
- Schema still provides semantic info but doesn't change handle IDs |
||||
|
- Connections persist through model changes |
||||
|
</context> |
||||
|
|
||||
|
<tasks> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 1: Normalize dynamic handle IDs to standard values</name> |
||||
|
<files>src/components/nodes/GenerateImageNode.tsx</files> |
||||
|
<action> |
||||
|
Modify the dynamic handle rendering logic (lines 464-510) to use standard handle IDs instead of schema-specific names: |
||||
|
|
||||
|
1. In the dynamic handle rendering section, change `id={input.name}` to use standard IDs: |
||||
|
- For image inputs: use `"image"` (or `"image-{index}"` if multiple) |
||||
|
- For text inputs: use `"text"` (or `"text-{index}"` if multiple) |
||||
|
|
||||
|
2. Update the handle key to use a combination of type and index for uniqueness |
||||
|
|
||||
|
3. The schema `input.name` is still used for: |
||||
|
- `title` attribute (tooltip) |
||||
|
- Label display |
||||
|
- Parameter mapping during execution (stored in nodeData, not handle ID) |
||||
|
|
||||
|
This ensures connections made to `"image"` or `"text"` remain valid when schema loads. |
||||
|
|
||||
|
Example change: |
||||
|
```typescript |
||||
|
// Before: |
||||
|
<Handle |
||||
|
type="target" |
||||
|
position={Position.Left} |
||||
|
id={input.name} // e.g., "image_url" |
||||
|
... |
||||
|
/> |
||||
|
|
||||
|
// After: |
||||
|
<Handle |
||||
|
type="target" |
||||
|
position={Position.Left} |
||||
|
id={imageInputs.length > 1 ? `image-${imageIndex}` : "image"} // Standard ID |
||||
|
... |
||||
|
/> |
||||
|
``` |
||||
|
</action> |
||||
|
<verify> |
||||
|
1. Create node via drag-connect from image output |
||||
|
2. Connection appears with default Gemini handles |
||||
|
3. Click Browse → select Replicate model |
||||
|
4. Connection persists after schema loads |
||||
|
</verify> |
||||
|
<done> |
||||
|
- Dynamic handles use standard IDs: "image", "text" (or indexed if multiple) |
||||
|
- Schema input names preserved for labels and tooltips |
||||
|
- Connections persist through model changes |
||||
|
</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 2: Update connection validation for normalized handles</name> |
||||
|
<files>src/components/WorkflowCanvas.tsx</files> |
||||
|
<action> |
||||
|
Verify and update `getHandleType` and `findCompatibleHandle` functions to work with normalized handle IDs: |
||||
|
|
||||
|
1. `getHandleType` (lines 63-73): May need updates if we use indexed handles like `"image-0"` |
||||
|
- Add pattern matching for indexed handles: `if (handleId.startsWith("image")) return "image"` |
||||
|
|
||||
|
2. `findCompatibleHandle` (lines 327-341): Update to return standard handle IDs |
||||
|
- When finding compatible input handle, return `"image"` or `"text"` instead of schema name |
||||
|
|
||||
|
3. `handleMenuSelect` (lines 544-646): Already uses `"image"` and `"text"` for targetHandleId, so should work as-is |
||||
|
|
||||
|
The key insight: by normalizing handle IDs in the node, all existing connection logic that expects `"image"` and `"text"` will continue to work. |
||||
|
</action> |
||||
|
<verify> |
||||
|
1. Drag connection from prompt node's text output |
||||
|
2. Drop on empty space → select "Generate Image" |
||||
|
3. Connection creates to text handle |
||||
|
4. Browse → select fal.ai model with text input |
||||
|
5. Connection persists (text handle still valid) |
||||
|
</verify> |
||||
|
<done> |
||||
|
- getHandleType handles indexed handle IDs |
||||
|
- findCompatibleHandle returns normalized IDs |
||||
|
- Multi-input models (multiple images) work correctly |
||||
|
</done> |
||||
|
</task> |
||||
|
|
||||
|
<task type="auto"> |
||||
|
<name>Task 3: Update execution to map normalized handles to schema names</name> |
||||
|
<files>src/store/workflowStore.ts, src/app/api/generate/route.ts</files> |
||||
|
<action> |
||||
|
Ensure the execution pipeline correctly maps normalized handle IDs back to schema parameter names: |
||||
|
|
||||
|
1. In `getConnectedInputs` (workflowStore.ts): Check if it needs to map handle IDs to schema names |
||||
|
- Currently uses handle IDs directly for dynamicInputs |
||||
|
- May need to look up schema to get the actual parameter name |
||||
|
|
||||
|
2. In `/api/generate/route.ts`: Verify parameter mapping |
||||
|
- Check how dynamicInputs are passed to provider APIs |
||||
|
- Ensure the provider receives the correct parameter names (e.g., "image_url" not "image") |
||||
|
|
||||
|
3. Store the schema input name mapping in nodeData for execution: |
||||
|
- `inputSchema` already has `{ name, type, label }` |
||||
|
- Execution can look up: "image" handle → first image input from schema → use schema name for API |
||||
|
|
||||
|
If execution already uses nodeData.inputSchema for parameter names (not handle IDs), this task may be minimal. |
||||
|
</action> |
||||
|
<verify> |
||||
|
1. Create node via drag-connect |
||||
|
2. Connect image and text inputs |
||||
|
3. Select external model (Replicate/fal.ai) |
||||
|
4. Run workflow |
||||
|
5. Verify API call uses correct parameter names from schema |
||||
|
</verify> |
||||
|
<done> |
||||
|
- Execution maps normalized handle IDs to schema parameter names |
||||
|
- Provider APIs receive correct parameter names |
||||
|
- No regression in existing workflows |
||||
|
</done> |
||||
|
</task> |
||||
|
|
||||
|
</tasks> |
||||
|
|
||||
|
<verification> |
||||
|
Before declaring phase complete: |
||||
|
- [ ] `npm run build` succeeds without errors |
||||
|
- [ ] Drag-connect from image output → Generate Image → connection persists |
||||
|
- [ ] Browse → select external model → connection still persists |
||||
|
- [ ] Drag-connect from text output → Generate Image → connection persists after model change |
||||
|
- [ ] Execute workflow with drag-connect-created node → works correctly |
||||
|
- [ ] Existing workflows (created via action bar) still work |
||||
|
- [ ] Multiple input models (if any) handle correctly |
||||
|
</verification> |
||||
|
|
||||
|
<success_criteria> |
||||
|
- All tasks completed |
||||
|
- All verification checks pass |
||||
|
- Connections persist when switching models on drag-connect nodes |
||||
|
- No regression in existing functionality |
||||
|
- External providers work correctly with normalized handles |
||||
|
</success_criteria> |
||||
|
|
||||
|
<output> |
||||
|
After completion, create `.planning/phases/14-fix-drag-connect-bugs/14-01-SUMMARY.md` |
||||
|
</output> |
||||
@ -0,0 +1,109 @@ |
|||||
|
--- |
||||
|
phase: 14-fix-drag-connect-bugs |
||||
|
plan: 01 |
||||
|
subsystem: ui |
||||
|
tags: [react-flow, handles, connections, node-editor] |
||||
|
|
||||
|
requires: |
||||
|
- phase: 03-generate-node-refactor |
||||
|
provides: Dynamic handle rendering from model schema |
||||
|
- phase: 04-model-search-dialog |
||||
|
provides: Model selection and schema loading |
||||
|
provides: |
||||
|
- Stable drag-connect node creation that persists through model selection |
||||
|
- Normalized handle ID system for multi-provider compatibility |
||||
|
- Handle-to-schema mapping for API parameter passing |
||||
|
affects: [future-node-types, connection-system-improvements] |
||||
|
|
||||
|
tech-stack: |
||||
|
added: [] |
||||
|
patterns: |
||||
|
- "Normalized handle IDs (image, text, image-0, text-0) for connection stability" |
||||
|
- "data-schema-name attribute for preserving API parameter names" |
||||
|
- "handleToSchemaName mapping in execution for API compatibility" |
||||
|
|
||||
|
key-files: |
||||
|
created: [] |
||||
|
modified: |
||||
|
- src/components/nodes/GenerateImageNode.tsx |
||||
|
- src/components/nodes/GenerateVideoNode.tsx |
||||
|
- src/components/WorkflowCanvas.tsx |
||||
|
- src/store/workflowStore.ts |
||||
|
|
||||
|
key-decisions: |
||||
|
- "Use normalized handle IDs instead of schema names for React Flow handles" |
||||
|
- "Store schema name in data-schema-name attribute for reference" |
||||
|
- "Build handleToSchemaName mapping at execution time from inputSchema" |
||||
|
|
||||
|
patterns-established: |
||||
|
- "Handle normalization: single input uses type name (image), multiple use indexed (image-0)" |
||||
|
- "Schema mapping: inputSchema drives normalized ID to schema name conversion" |
||||
|
|
||||
|
issues-created: [] |
||||
|
|
||||
|
duration: 7min |
||||
|
completed: 2026-01-12 |
||||
|
--- |
||||
|
|
||||
|
# Phase 14 Plan 01: Fix Drag-Connect Node Creation Bugs Summary |
||||
|
|
||||
|
**Placeholder handles ensure connections persist when selecting models that don't use all input types** |
||||
|
|
||||
|
## Performance |
||||
|
|
||||
|
- **Duration:** 12 min |
||||
|
- **Started:** 2026-01-12T10:11:43Z |
||||
|
- **Completed:** 2026-01-12T10:23:00Z |
||||
|
- **Tasks:** 3 |
||||
|
- **Files modified:** 4 |
||||
|
|
||||
|
## Accomplishments |
||||
|
- Always render "image" and "text" handles even when model schema doesn't include them |
||||
|
- Placeholder handles (dimmed at 30% opacity) preserve connections for models that don't use that input type |
||||
|
- Normalized dynamic handle IDs to use standard values ("image", "text") instead of schema-specific names |
||||
|
- Updated connection validation to return normalized handle IDs when finding compatible targets |
||||
|
- Added handle-to-schema mapping in execution to preserve API parameter compatibility |
||||
|
|
||||
|
## Task Commits |
||||
|
|
||||
|
Each task was committed atomically: |
||||
|
|
||||
|
1. **Task 1: Normalize handle IDs + placeholder handles** - `7548e5a` (fix) |
||||
|
2. **Task 2: Update connection validation** - `714b60b` (fix) |
||||
|
3. **Task 3: Map handles to schema names in execution** - `5643cb8` (feat) |
||||
|
|
||||
|
## Files Created/Modified |
||||
|
- `src/components/nodes/GenerateImageNode.tsx` - Placeholder handles for missing inputs, normalized IDs |
||||
|
- `src/components/nodes/GenerateVideoNode.tsx` - Same fix for video nodes |
||||
|
- `src/components/WorkflowCanvas.tsx` - findCompatibleHandle returns normalized IDs |
||||
|
- `src/store/workflowStore.ts` - getConnectedInputs builds handleToSchemaName mapping |
||||
|
|
||||
|
## Decisions Made |
||||
|
- **Placeholder handles**: Always render "image" and "text" handles, dimmed when model doesn't use them |
||||
|
- **Normalized handle naming**: Single input of type uses base name ("image"), multiple use indexed ("image-0", "image-1") |
||||
|
- **Schema name preservation**: Stored in data-schema-name attribute for debugging/reference |
||||
|
- **Execution mapping**: Build mapping at runtime from inputSchema rather than storing in edge data |
||||
|
|
||||
|
## Deviations from Plan |
||||
|
|
||||
|
### Auto-fixed Issues |
||||
|
|
||||
|
**1. [Rule 1 - Bug] Handle disappearance with text-to-image models** |
||||
|
- **Found during:** Testing after initial fix |
||||
|
- **Issue:** Text-to-image models (FLUX, etc.) have no image input in schema, causing image handle to disappear |
||||
|
- **Fix:** Always render placeholder handles for missing input types (dimmed at 30% opacity) |
||||
|
- **Files modified:** GenerateImageNode.tsx, GenerateVideoNode.tsx |
||||
|
- **Verification:** Build passes, handles persist through model selection |
||||
|
|
||||
|
## Issues Encountered |
||||
|
|
||||
|
None |
||||
|
|
||||
|
## Next Phase Readiness |
||||
|
- Phase 14 complete (single plan phase) |
||||
|
- Milestone v1.1 complete - all 8 phases finished |
||||
|
- Ready for `/gsd:complete-milestone` |
||||
|
|
||||
|
--- |
||||
|
*Phase: 14-fix-drag-connect-bugs* |
||||
|
*Completed: 2026-01-12* |
||||
Loading…
Reference in new issue