mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
feat: add default initial context variables
This commit is contained in:
parent
f368fe5134
commit
96c90376c3
8 changed files with 112 additions and 19 deletions
|
|
@ -47,7 +47,6 @@ from api.services.workflow.pipecat_engine_variable_extractor import (
|
|||
from api.services.workflow.tools.knowledge_base import (
|
||||
retrieve_from_knowledge_base,
|
||||
)
|
||||
from api.services.workflow.tools.timezone import get_current_time
|
||||
from api.utils.template_renderer import render_template
|
||||
|
||||
|
||||
|
|
@ -149,15 +148,6 @@ class PipecatEngine:
|
|||
# Helper that encapsulates custom tool management
|
||||
self._custom_tool_manager = CustomToolManager(self)
|
||||
|
||||
# Add current time in EST (America/New_York) to gathered context
|
||||
try:
|
||||
est_time_result = get_current_time("America/New_York")
|
||||
# The get_current_time utility returns a dict with 'datetime' field
|
||||
# Store the ISO formatted datetime string under the key 'time'
|
||||
self._gathered_context["time"] = est_time_result.get("datetime")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch current EST time: {e}")
|
||||
|
||||
await self.set_node(self.workflow.start_node_id)
|
||||
|
||||
logger.debug(f"{self.__class__.__name__} initialized")
|
||||
|
|
|
|||
|
|
@ -2,10 +2,17 @@
|
|||
|
||||
import json
|
||||
import re
|
||||
from typing import Any, Dict, Union
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional, Union
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from api.services.workflow.workflow import TEMPLATE_VAR_PATTERN
|
||||
|
||||
_CURRENT_TIME_PREFIX = "current_time"
|
||||
_CURRENT_WEEKDAY_PREFIX = "current_weekday"
|
||||
|
||||
|
||||
def get_nested_value(obj: Any, path: str) -> Any:
|
||||
"""
|
||||
|
|
@ -85,6 +92,70 @@ def render_template(
|
|||
return _render_string(template, context)
|
||||
|
||||
|
||||
def _extract_timezone_from_template(template_str: str) -> Optional[str]:
|
||||
"""Extract the timezone from a ``current_time_<TZ>`` or ``current_weekday_<TZ>`` variable.
|
||||
|
||||
Returns the first IANA timezone found, or None.
|
||||
"""
|
||||
pattern = (
|
||||
r"\{\{\s*(?:"
|
||||
+ re.escape(_CURRENT_TIME_PREFIX)
|
||||
+ r"|"
|
||||
+ re.escape(_CURRENT_WEEKDAY_PREFIX)
|
||||
+ r")_([^|\s}]+)"
|
||||
)
|
||||
match = re.search(pattern, template_str)
|
||||
return match.group(1).strip() if match else None
|
||||
|
||||
|
||||
def _resolve_builtin_variable(
|
||||
variable_path: str, default_tz: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
"""Resolve built-in template variables that are available in all contexts.
|
||||
|
||||
Supported variables:
|
||||
- ``current_time`` – current time in UTC
|
||||
- ``current_time_<TIMEZONE>`` – current time in the given IANA timezone
|
||||
- ``current_weekday`` – current weekday name (uses *default_tz* if set, else UTC)
|
||||
- ``current_weekday_<TIMEZONE>`` – current weekday name in the given timezone
|
||||
|
||||
Args:
|
||||
variable_path: The template variable name to resolve.
|
||||
default_tz: Fallback timezone for ``current_weekday`` when no explicit
|
||||
timezone suffix is provided (typically inferred from a
|
||||
``current_time_<TZ>`` variable in the same template).
|
||||
|
||||
Returns:
|
||||
The resolved string value, or None if *variable_path* is not a
|
||||
recognised built-in.
|
||||
"""
|
||||
if variable_path == _CURRENT_TIME_PREFIX:
|
||||
tz = ZoneInfo(default_tz) if default_tz else ZoneInfo("UTC")
|
||||
return datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S %Z")
|
||||
|
||||
if variable_path.startswith(_CURRENT_TIME_PREFIX + "_"):
|
||||
timezone = variable_path[len(_CURRENT_TIME_PREFIX) + 1 :]
|
||||
try:
|
||||
return datetime.now(ZoneInfo(timezone)).strftime("%Y-%m-%d %H:%M:%S %Z")
|
||||
except Exception:
|
||||
logger.warning(f"Invalid timezone in template variable: {timezone}")
|
||||
return None
|
||||
|
||||
if variable_path == _CURRENT_WEEKDAY_PREFIX:
|
||||
tz = ZoneInfo(default_tz) if default_tz else ZoneInfo("UTC")
|
||||
return datetime.now(tz).strftime("%A")
|
||||
|
||||
if variable_path.startswith(_CURRENT_WEEKDAY_PREFIX + "_"):
|
||||
timezone = variable_path[len(_CURRENT_WEEKDAY_PREFIX) + 1 :]
|
||||
try:
|
||||
return datetime.now(ZoneInfo(timezone)).strftime("%A")
|
||||
except Exception:
|
||||
logger.warning(f"Invalid timezone in template variable: {timezone}")
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _render_string(template_str: str, context: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Render a string template with variable substitution.
|
||||
|
|
@ -99,11 +170,20 @@ def _render_string(template_str: str, context: Dict[str, Any]) -> str:
|
|||
if not template_str:
|
||||
return template_str
|
||||
|
||||
# Pre-scan for a current_time_<TZ> variable so that {{current_weekday}}
|
||||
# can inherit the same timezone instead of defaulting to UTC.
|
||||
default_tz = _extract_timezone_from_template(template_str)
|
||||
|
||||
def _replace(match: re.Match[str]) -> str: # type: ignore[type-arg]
|
||||
variable_path = match.group(1).strip()
|
||||
filter_name = match.group(2).strip() if match.group(2) else None
|
||||
filter_value = match.group(3).strip() if match.group(3) else None
|
||||
|
||||
# Check for built-in variables first (current_time, current_weekday)
|
||||
builtin_value = _resolve_builtin_variable(variable_path, default_tz)
|
||||
if builtin_value is not None:
|
||||
return builtin_value
|
||||
|
||||
# Get value using nested path lookup
|
||||
value = get_nested_value(context, variable_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,27 @@ whether they'd like to continue.
|
|||
|
||||
When the call starts, Dograh substitutes the values before sending the prompt to the LLM — so the agent speaks naturally as if it already knows the contact.
|
||||
|
||||
### Built-in template variables
|
||||
|
||||
Dograh provides built-in variables for current time and weekday that you can use in any prompt without setting up `initial_context`.
|
||||
|
||||
| Variable | Description | Example output |
|
||||
|---|---|---|
|
||||
| `{{current_time}}` | Current time in UTC (or inferred timezone) | `2026-04-02 14:30:45 UTC` |
|
||||
| `{{current_time_<TIMEZONE>}}` | Current time in the specified timezone | `2026-04-02 20:00:45 IST` |
|
||||
| `{{current_weekday}}` | Current weekday name in UTC (or inferred timezone) | `Thursday` |
|
||||
| `{{current_weekday_<TIMEZONE>}}` | Current weekday name in the specified timezone | `Thursday` |
|
||||
|
||||
Replace `<TIMEZONE>` with an [IANA timezone name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) such as `Asia/Kolkata`, `America/New_York`, or `Europe/London`.
|
||||
|
||||
```
|
||||
Today is {{current_weekday}} and the current time is {{current_time_America/New_York}}.
|
||||
```
|
||||
|
||||
<Note>
|
||||
When you use a timezone suffix on **either** `current_time` or `current_weekday`, the other variable without a suffix will automatically use the same timezone instead of UTC. For example, if your prompt contains both `{{current_time_Asia/Kolkata}}` and `{{current_weekday}}`, the weekday will also be resolved in `Asia/Kolkata`.
|
||||
</Note>
|
||||
|
||||
### gathered_context
|
||||
|
||||
Data the agent collects *during* the call. You configure what to extract in the agent node's extraction settings — each variable has a name, type, and a prompt that tells the LLM what to look for.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { Input } from "@/components/ui/input";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
import { CONTEXT_VARIABLES_DOC_URL, NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
|
||||
import { NodeContent } from "./common/NodeContent";
|
||||
import { NodeEditDialog } from "./common/NodeEditDialog";
|
||||
|
|
@ -313,7 +313,7 @@ const AgentNodeEditForm = ({
|
|||
<div className="pt-2 space-y-2">
|
||||
<Label>Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Prompt engineering's best practices apply.
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Supports <a href={CONTEXT_VARIABLES_DOC_URL} target="_blank" rel="noopener noreferrer" className="underline">template variables</a>
|
||||
</Label>
|
||||
<MentionTextarea
|
||||
value={prompt}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Input } from "@/components/ui/input";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
import { CONTEXT_VARIABLES_DOC_URL, NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
|
||||
import { NodeContent } from "./common/NodeContent";
|
||||
import { NodeEditDialog } from "./common/NodeEditDialog";
|
||||
|
|
@ -216,7 +216,7 @@ const EndCallEditForm = ({
|
|||
|
||||
<Label>Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Prompt engineering's best practices apply.
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Supports <a href={CONTEXT_VARIABLES_DOC_URL} target="_blank" rel="noopener noreferrer" className="underline">template variables</a>
|
||||
</Label>
|
||||
<MentionTextarea
|
||||
value={prompt}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { FlowNodeData } from "@/components/flow/types";
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
import { CONTEXT_VARIABLES_DOC_URL, NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
|
||||
import { NodeContent } from "./common/NodeContent";
|
||||
import { NodeEditDialog } from "./common/NodeEditDialog";
|
||||
|
|
@ -145,7 +145,7 @@ const GlobalNodeEditForm = ({
|
|||
|
||||
<Label>Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
This is the global prompt. This will be added to the system prompt of all the agents.
|
||||
This is the global prompt. This will be added to the system prompt of all the agents. Supports <a href={CONTEXT_VARIABLES_DOC_URL} target="_blank" rel="noopener noreferrer" className="underline">template variables</a>
|
||||
</Label>
|
||||
<MentionTextarea
|
||||
value={prompt}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { Input } from "@/components/ui/input";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
import { CONTEXT_VARIABLES_DOC_URL, NODE_DOCUMENTATION_URLS } from "@/constants/documentation";
|
||||
|
||||
import { NodeContent } from "./common/NodeContent";
|
||||
import { NodeEditDialog } from "./common/NodeEditDialog";
|
||||
|
|
@ -334,7 +334,7 @@ const StartCallEditForm = ({
|
|||
|
||||
<Label>Prompt</Label>
|
||||
<Label className="text-xs text-muted-foreground">
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Prompt engineering's best practices apply.
|
||||
Enter the prompt for the agent. This will be used to generate the agent's response. Supports <a href={CONTEXT_VARIABLES_DOC_URL} target="_blank" rel="noopener noreferrer" className="underline">template variables</a>
|
||||
</Label>
|
||||
<MentionTextarea
|
||||
value={prompt}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ export const NODE_DOCUMENTATION_URLS: Record<string, string> = {
|
|||
qaAnalysis: `${DOCS_BASE}/getting-started`,
|
||||
};
|
||||
|
||||
export const CONTEXT_VARIABLES_DOC_URL = `${DOCS_BASE}/core-concepts/context-and-variables`;
|
||||
|
||||
export const TOOL_DOCUMENTATION_URLS: Record<string, string> = {
|
||||
http_api: `${DOCS_BASE}/voice-agent/tools/http-api`,
|
||||
end_call: `${DOCS_BASE}/voice-agent/tools/end-call`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue