mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-13 08:15:21 +02:00
feat: support {{variable}} in HTTP tool URL and add variable extraction timing option
- Apply render_template() to the endpoint URL at runtime so
{{initial_context.*}} and {{gathered_context.*}} work in URL
paths (same logic as node prompts and preset parameters).
- Update URL validation to allow template variables in the path
but reject them in the domain.
- Add variable_extraction_timing setting (before/after/both) to
HTTP tools, controlling when conversation variable extraction
runs relative to the tool call.
- Add Variable Extraction Timing radio group to the tool Settings
tab with Before/After/Both options.
This commit is contained in:
parent
49fcb770a4
commit
66bc5d3e60
4 changed files with 95 additions and 0 deletions
|
|
@ -378,6 +378,14 @@ class CustomToolManager:
|
|||
)
|
||||
)
|
||||
|
||||
# Determine when to run variable extraction relative to the tool call
|
||||
extraction_timing = config.get("variable_extraction_timing", "before")
|
||||
|
||||
if extraction_timing in ("before", "both"):
|
||||
await self._engine._perform_variable_extraction_if_needed(
|
||||
self._engine._current_node, run_in_background=False
|
||||
)
|
||||
|
||||
result = await execute_http_tool(
|
||||
tool=tool,
|
||||
arguments=function_call_params.arguments,
|
||||
|
|
@ -386,6 +394,11 @@ class CustomToolManager:
|
|||
organization_id=await self.get_organization_id(),
|
||||
)
|
||||
|
||||
if extraction_timing in ("after", "both"):
|
||||
await self._engine._perform_variable_extraction_if_needed(
|
||||
self._engine._current_node, run_in_background=False
|
||||
)
|
||||
|
||||
await function_call_params.result_callback(result)
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { AlertCircle, Variable } from "lucide-react";
|
||||
|
||||
import type { RecordingResponseSchema } from "@/client/types.gen";
|
||||
import { StaticTextWarning, TextOrAudioInput } from "@/components/flow/TextOrAudioInput";
|
||||
import {
|
||||
|
|
@ -17,6 +19,7 @@ import {
|
|||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
|
||||
|
|
@ -45,6 +48,8 @@ export interface HttpApiToolConfigProps {
|
|||
onCustomMessageTypeChange: (type: 'text' | 'audio') => void;
|
||||
customMessageRecordingId: string;
|
||||
onCustomMessageRecordingIdChange: (id: string) => void;
|
||||
variableExtractionTiming: 'before' | 'after' | 'both';
|
||||
onVariableExtractionTimingChange: (timing: 'before' | 'after' | 'both') => void;
|
||||
recordings?: RecordingResponseSchema[];
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +78,8 @@ export function HttpApiToolConfig({
|
|||
onCustomMessageTypeChange,
|
||||
customMessageRecordingId,
|
||||
onCustomMessageRecordingIdChange,
|
||||
variableExtractionTiming,
|
||||
onVariableExtractionTimingChange,
|
||||
recordings = [],
|
||||
}: HttpApiToolConfigProps) {
|
||||
return (
|
||||
|
|
@ -152,6 +159,63 @@ export function HttpApiToolConfig({
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 pt-4 border-t">
|
||||
<div className="flex items-center gap-2">
|
||||
<Variable className="h-4 w-4" />
|
||||
<Label>Variable Extraction Timing</Label>
|
||||
</div>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Control when conversation variables are extracted for use in tool parameters
|
||||
</Label>
|
||||
<RadioGroup
|
||||
value={variableExtractionTiming}
|
||||
onValueChange={(v) => onVariableExtractionTimingChange(v as 'before' | 'after' | 'both')}
|
||||
>
|
||||
<label
|
||||
htmlFor="extract-before"
|
||||
className={`flex items-start gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
|
||||
variableExtractionTiming === 'before' ? 'border-primary bg-primary/5' : 'hover:bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
<RadioGroupItem value="before" id="extract-before" className="mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium text-sm">Before tool call</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Extract variables from the conversation before the HTTP request. Use when URL or preset parameters depend on gathered context.
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
htmlFor="extract-after"
|
||||
className={`flex items-start gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
|
||||
variableExtractionTiming === 'after' ? 'border-primary bg-primary/5' : 'hover:bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
<RadioGroupItem value="after" id="extract-after" className="mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium text-sm">After tool call</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Extract variables after the HTTP response returns. Use when downstream nodes need data derived from the response.
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
<label
|
||||
htmlFor="extract-both"
|
||||
className={`flex items-start gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
|
||||
variableExtractionTiming === 'both' ? 'border-primary bg-primary/5' : 'hover:bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
<RadioGroupItem value="both" id="extract-both" className="mt-0.5" />
|
||||
<div>
|
||||
<p className="font-medium text-sm">Both</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Extract before and after the tool call. Ensures parameters use the latest context and the response is captured for downstream use.
|
||||
</p>
|
||||
</div>
|
||||
</label>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2 pt-4 border-t">
|
||||
<Label>Custom Message</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
|
|
@ -166,6 +230,11 @@ export function HttpApiToolConfig({
|
|||
>
|
||||
<>
|
||||
<StaticTextWarning />
|
||||
<div className="flex items-start gap-2 rounded-md bg-amber-50 p-2 text-xs text-amber-700 border border-amber-200">
|
||||
<AlertCircle className="h-3.5 w-3.5 mt-0.5 shrink-0" />
|
||||
<span>This text is spoken as-is. For multilingual workflows, choose your phrasing carefully.</span>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
value={customMessage}
|
||||
onChange={(e) => onCustomMessageChange(e.target.value)}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ export default function ToolDetailPage() {
|
|||
// HTTP API form state - custom message type
|
||||
const [customMessageType, setCustomMessageType] = useState<'text' | 'audio'>('text');
|
||||
const [customMessageRecordingId, setCustomMessageRecordingId] = useState("");
|
||||
const [variableExtractionTiming, setVariableExtractionTiming] = useState<'before' | 'after' | 'both'>('before');
|
||||
|
||||
// MCP form state
|
||||
const [mcpUrl, setMcpUrl] = useState("");
|
||||
|
|
@ -225,6 +226,9 @@ export default function ToolDetailPage() {
|
|||
setCustomMessage(config.customMessage || "");
|
||||
setCustomMessageType(config.customMessageType || "text");
|
||||
setCustomMessageRecordingId(config.customMessageRecordingId || "");
|
||||
setVariableExtractionTiming(
|
||||
(config.variable_extraction_timing as 'before' | 'after' | 'both') || 'before'
|
||||
);
|
||||
|
||||
// Convert headers object to array
|
||||
if (config.headers) {
|
||||
|
|
@ -437,6 +441,7 @@ export default function ToolDetailPage() {
|
|||
customMessage: customMessageType === 'text' ? (customMessage || undefined) : undefined,
|
||||
customMessageType,
|
||||
customMessageRecordingId: customMessageType === 'audio' ? (customMessageRecordingId || undefined) : undefined,
|
||||
variable_extraction_timing: variableExtractionTiming,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -762,6 +767,8 @@ const data = await response.json();`;
|
|||
onCustomMessageTypeChange={setCustomMessageType}
|
||||
customMessageRecordingId={customMessageRecordingId}
|
||||
onCustomMessageRecordingIdChange={setCustomMessageRecordingId}
|
||||
variableExtractionTiming={variableExtractionTiming}
|
||||
onVariableExtractionTimingChange={setVariableExtractionTiming}
|
||||
recordings={recordings}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1894,6 +1894,12 @@ export type HttpApiConfig = {
|
|||
* Recording ID for an audio custom message.
|
||||
*/
|
||||
customMessageRecordingId?: string | null;
|
||||
/**
|
||||
* VariableExtractionTiming
|
||||
*
|
||||
* When to run variable extraction relative to the tool call (before, after, or both)
|
||||
*/
|
||||
variable_extraction_timing?: 'before' | 'after' | 'both' | null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue