Browse Source

fix: scope API headers to active provider, temperature falsy bug, template prefix collision

- ControlPanel: only send the active provider's API key header instead of all three
- LLMControls: use nullish coalescing (??) for temperature so 0 is not treated as falsy
- PromptConstructorNode: single-pass regex for @variable resolution to prevent prefix collisions (@foo matching inside @foobar)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
95ae814ea2
  1. 18
      src/components/nodes/ControlPanel.tsx
  2. 15
      src/components/nodes/PromptConstructorNode.tsx

18
src/components/nodes/ControlPanel.tsx

@ -236,9 +236,17 @@ function GenerateImageControls({ node }: { node: Node }) {
try {
const capabilities = IMAGE_CAPABILITIES.join(",");
const headers: HeadersInit = {};
if (replicateApiKey) headers["X-Replicate-Key"] = replicateApiKey;
if (falApiKey) headers["X-Fal-Key"] = falApiKey;
if (kieApiKey) headers["X-Kie-Key"] = kieApiKey;
switch (currentProvider) {
case "replicate":
if (replicateApiKey) headers["X-Replicate-Key"] = replicateApiKey;
break;
case "fal":
if (falApiKey) headers["X-Fal-Key"] = falApiKey;
break;
case "kie":
if (kieApiKey) headers["X-Kie-Key"] = kieApiKey;
break;
}
const response = await deduplicatedFetch(`/api/models?provider=${currentProvider}&capabilities=${capabilities}`, { headers });
if (response.ok) {
@ -832,14 +840,14 @@ function LLMControls({ node }: { node: Node }) {
<div>
<label className="block text-xs font-medium text-neutral-300 mb-1">
Temperature: {nodeData.temperature?.toFixed(2) || "0.70"}
Temperature: {(nodeData.temperature ?? 0.7).toFixed(2)}
</label>
<input
type="range"
min="0"
max={provider === "anthropic" ? "1" : "2"}
step="0.01"
value={nodeData.temperature || 0.7}
value={nodeData.temperature ?? 0.7}
onChange={handleTemperatureChange}
className="nodrag nopan w-full h-1 bg-neutral-700 rounded-lg appearance-none cursor-pointer accent-blue-500"
/>

15
src/components/nodes/PromptConstructorNode.tsx

@ -119,21 +119,16 @@ export function PromptConstructorNode({ id, data, selected }: NodeProps<PromptCo
return unresolved;
}, [localTemplate, availableVariables]);
// Compute resolved text client-side for preview
// Compute resolved text client-side for preview (single-pass to avoid prefix collisions)
const resolvedPreview = useMemo(() => {
let resolved = localTemplate;
availableVariables.forEach((v) => {
resolved = resolved.replace(new RegExp(`@${v.name}`, 'g'), v.value);
});
return resolved;
const valueMap = new Map(availableVariables.map(v => [v.name, v.value]));
return localTemplate.replace(/@(\w+)/g, (match, name) => valueMap.get(name) ?? match);
}, [localTemplate, availableVariables]);
// Sync resolved text to outputText so downstream nodes can read it before execution
useEffect(() => {
let resolved = nodeData.template;
availableVariables.forEach((v) => {
resolved = resolved.replace(new RegExp(`@${v.name}`, 'g'), v.value);
});
const valueMap = new Map(availableVariables.map(v => [v.name, v.value]));
const resolved = nodeData.template.replace(/@(\w+)/g, (match, name) => valueMap.get(name) ?? match);
const outputValue = resolved || null;
if (outputValue !== nodeData.outputText) {
updateNodeData(id, { outputText: outputValue });

Loading…
Cancel
Save