mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
feat: create tools using MCP
This commit is contained in:
parent
5c29b6ed94
commit
fcb7004c7a
17 changed files with 1989 additions and 572 deletions
|
|
@ -12,6 +12,7 @@ from __future__ import annotations
|
|||
from typing import Any
|
||||
|
||||
from dograh_sdk._generated_models import (
|
||||
CreateToolRequest,
|
||||
CreateWorkflowRequest,
|
||||
CredentialResponse,
|
||||
DocumentListResponseSchema,
|
||||
|
|
@ -29,6 +30,11 @@ from dograh_sdk._generated_models import (
|
|||
class _GeneratedClient:
|
||||
# `DograhClient.__init__` installs `self._request` (see client.py).
|
||||
|
||||
def create_tool(self, *, body: CreateToolRequest) -> ToolResponse:
|
||||
"""Create a reusable tool for the authenticated organization."""
|
||||
data = self._request("POST", "/tools/", json=body.model_dump(mode="json", exclude_none=True))
|
||||
return ToolResponse.model_validate(data)
|
||||
|
||||
def create_workflow(self, *, body: CreateWorkflowRequest) -> WorkflowResponse:
|
||||
"""Create a new workflow from a workflow definition."""
|
||||
data = self._request("POST", "/workflow/create/definition", json=body.model_dump(mode="json", exclude_none=True))
|
||||
|
|
|
|||
|
|
@ -1,13 +1,28 @@
|
|||
# generated by datamodel-codegen:
|
||||
# filename: dograh-openapi-aBVTJk.json
|
||||
# timestamp: 2026-05-27T10:06:12+00:00
|
||||
# filename: dograh-openapi-EZT8BU.json
|
||||
# timestamp: 2026-05-31T10:54:36+00:00
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Annotated, Any
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
|
||||
from pydantic import AwareDatetime, BaseModel, ConfigDict, Field, RootModel
|
||||
|
||||
|
||||
class CalculatorToolDefinition(BaseModel):
|
||||
"""
|
||||
Tool definition for Calculator tools.
|
||||
"""
|
||||
|
||||
schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
|
||||
"""
|
||||
Schema version.
|
||||
"""
|
||||
type: Annotated[Literal['calculator'], Field(title='Type')]
|
||||
"""
|
||||
Tool type.
|
||||
"""
|
||||
|
||||
|
||||
class CallDispositionCodes(BaseModel):
|
||||
|
|
@ -16,6 +31,34 @@ class CallDispositionCodes(BaseModel):
|
|||
)
|
||||
|
||||
|
||||
class Category(Enum):
|
||||
"""
|
||||
Tool category. Must match definition.type.
|
||||
"""
|
||||
|
||||
http_api = 'http_api'
|
||||
end_call = 'end_call'
|
||||
transfer_call = 'transfer_call'
|
||||
calculator = 'calculator'
|
||||
native = 'native'
|
||||
integration = 'integration'
|
||||
mcp = 'mcp'
|
||||
|
||||
|
||||
class Icon(RootModel[str]):
|
||||
root: Annotated[str, Field(max_length=50, title='Icon')] = 'globe'
|
||||
"""
|
||||
Lucide icon identifier.
|
||||
"""
|
||||
|
||||
|
||||
class IconColor(RootModel[str]):
|
||||
root: Annotated[str, Field(max_length=7, title='Icon Color')] = '#3B82F6'
|
||||
"""
|
||||
Hex color for the tool icon.
|
||||
"""
|
||||
|
||||
|
||||
class CreateWorkflowRequest(BaseModel):
|
||||
name: Annotated[str, Field(title='Name')]
|
||||
workflow_definition: Annotated[dict[str, Any], Field(title='Workflow Definition')]
|
||||
|
|
@ -90,6 +133,64 @@ class DocumentResponseSchema(BaseModel):
|
|||
is_active: Annotated[bool, Field(title='Is Active')]
|
||||
|
||||
|
||||
class MessageType(Enum):
|
||||
"""
|
||||
Type of goodbye message.
|
||||
"""
|
||||
|
||||
none = 'none'
|
||||
custom = 'custom'
|
||||
audio = 'audio'
|
||||
|
||||
|
||||
class EndCallConfig(BaseModel):
|
||||
"""
|
||||
Configuration for End Call tools.
|
||||
"""
|
||||
|
||||
messageType: Annotated[MessageType | None, Field(title='Messagetype')] = 'none'
|
||||
"""
|
||||
Type of goodbye message.
|
||||
"""
|
||||
customMessage: Annotated[str | None, Field(title='Custommessage')] = None
|
||||
"""
|
||||
Custom message to play before ending the call.
|
||||
"""
|
||||
audioRecordingId: Annotated[str | None, Field(title='Audiorecordingid')] = None
|
||||
"""
|
||||
Recording ID for audio goodbye message.
|
||||
"""
|
||||
endCallReason: Annotated[bool | None, Field(title='Endcallreason')] = False
|
||||
"""
|
||||
When enabled, the model must provide a reason for ending the call. The reason is set as call disposition and added to call tags.
|
||||
"""
|
||||
endCallReasonDescription: Annotated[
|
||||
str | None, Field(title='Endcallreasondescription')
|
||||
] = None
|
||||
"""
|
||||
Description shown to the model for the reason parameter. Used only when endCallReason is enabled.
|
||||
"""
|
||||
|
||||
|
||||
class EndCallToolDefinition(BaseModel):
|
||||
"""
|
||||
Tool definition for End Call tools.
|
||||
"""
|
||||
|
||||
schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
|
||||
"""
|
||||
Schema version.
|
||||
"""
|
||||
type: Annotated[Literal['end_call'], Field(title='Type')]
|
||||
"""
|
||||
Tool type.
|
||||
"""
|
||||
config: EndCallConfig
|
||||
"""
|
||||
End Call configuration.
|
||||
"""
|
||||
|
||||
|
||||
class GraphConstraints(BaseModel):
|
||||
"""
|
||||
Per-node-type graph rules. WorkflowGraph enforces these at validation.
|
||||
|
|
@ -104,6 +205,34 @@ class GraphConstraints(BaseModel):
|
|||
max_outgoing: Annotated[int | None, Field(title='Max Outgoing')] = None
|
||||
|
||||
|
||||
class Method(Enum):
|
||||
"""
|
||||
HTTP method to use for the request.
|
||||
"""
|
||||
|
||||
GET = 'GET'
|
||||
POST = 'POST'
|
||||
PUT = 'PUT'
|
||||
PATCH = 'PATCH'
|
||||
DELETE = 'DELETE'
|
||||
|
||||
|
||||
class TimeoutMs(RootModel[int]):
|
||||
root: Annotated[int, Field(ge=1, title='Timeout Ms')] = 5000
|
||||
"""
|
||||
Request timeout in milliseconds.
|
||||
"""
|
||||
|
||||
|
||||
class CustomMessageType(Enum):
|
||||
"""
|
||||
Type of custom message.
|
||||
"""
|
||||
|
||||
text = 'text'
|
||||
audio = 'audio'
|
||||
|
||||
|
||||
class InitiateCallRequest(BaseModel):
|
||||
workflow_id: Annotated[int, Field(title='Workflow Id')]
|
||||
workflow_run_id: Annotated[int | None, Field(title='Workflow Run Id')] = None
|
||||
|
|
@ -116,6 +245,66 @@ class InitiateCallRequest(BaseModel):
|
|||
)
|
||||
|
||||
|
||||
class McpToolConfig(BaseModel):
|
||||
"""
|
||||
Configuration for a customer MCP server tool definition.
|
||||
"""
|
||||
|
||||
transport: Annotated[Literal['streamable_http'], Field(title='Transport')] = (
|
||||
'streamable_http'
|
||||
)
|
||||
"""
|
||||
MCP transport protocol.
|
||||
"""
|
||||
url: Annotated[str, Field(title='Url')]
|
||||
"""
|
||||
MCP server URL. Must use http:// or https://.
|
||||
"""
|
||||
credential_uuid: Annotated[str | None, Field(title='Credential Uuid')] = None
|
||||
"""
|
||||
Reference to an external credential for MCP server auth.
|
||||
"""
|
||||
tools_filter: Annotated[list[str] | None, Field(title='Tools Filter')] = None
|
||||
"""
|
||||
Allowlist of MCP tool names to expose. Empty exposes all tools.
|
||||
"""
|
||||
timeout_secs: Annotated[int | None, Field(ge=0, title='Timeout Secs')] = 30
|
||||
"""
|
||||
Connection timeout in seconds.
|
||||
"""
|
||||
sse_read_timeout_secs: Annotated[
|
||||
int | None, Field(ge=0, title='Sse Read Timeout Secs')
|
||||
] = 300
|
||||
"""
|
||||
SSE read timeout in seconds.
|
||||
"""
|
||||
discovered_tools: Annotated[
|
||||
list[dict[str, Any]] | None, Field(title='Discovered Tools')
|
||||
] = None
|
||||
"""
|
||||
Server-managed cache of the MCP server's tool catalog [{name, description}]. Populated best-effort by the backend.
|
||||
"""
|
||||
|
||||
|
||||
class McpToolDefinition(BaseModel):
|
||||
"""
|
||||
Persisted MCP tool definition.
|
||||
"""
|
||||
|
||||
schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
|
||||
"""
|
||||
Schema version.
|
||||
"""
|
||||
type: Annotated[Literal['mcp'], Field(title='Type')]
|
||||
"""
|
||||
Tool type.
|
||||
"""
|
||||
config: McpToolConfig
|
||||
"""
|
||||
MCP server configuration.
|
||||
"""
|
||||
|
||||
|
||||
class NodeCategory(Enum):
|
||||
"""
|
||||
Drives grouping in the AddNodePanel UI.
|
||||
|
|
@ -140,6 +329,39 @@ class NodeExample(BaseModel):
|
|||
data: Annotated[dict[str, Any], Field(title='Data')]
|
||||
|
||||
|
||||
class Type(Enum):
|
||||
"""
|
||||
JSON type for the resolved value.
|
||||
"""
|
||||
|
||||
string = 'string'
|
||||
number = 'number'
|
||||
boolean = 'boolean'
|
||||
|
||||
|
||||
class PresetToolParameter(BaseModel):
|
||||
"""
|
||||
A parameter injected by Dograh at runtime.
|
||||
"""
|
||||
|
||||
name: Annotated[str, Field(title='Name')]
|
||||
"""
|
||||
Parameter name used as a key in the request body.
|
||||
"""
|
||||
type: Annotated[Type, Field(title='Type')]
|
||||
"""
|
||||
JSON type for the resolved value.
|
||||
"""
|
||||
value_template: Annotated[str, Field(title='Value Template')]
|
||||
"""
|
||||
Fixed value or template, e.g. {{initial_context.phone_number}}.
|
||||
"""
|
||||
required: Annotated[bool | None, Field(title='Required')] = True
|
||||
"""
|
||||
Whether the parameter must resolve to a non-empty value.
|
||||
"""
|
||||
|
||||
|
||||
class PropertyOption(BaseModel):
|
||||
"""
|
||||
An option in an `options` or `multi_options` dropdown.
|
||||
|
|
@ -197,9 +419,42 @@ class RecordingResponseSchema(BaseModel):
|
|||
is_active: Annotated[bool, Field(title='Is Active')]
|
||||
|
||||
|
||||
class Type1(Enum):
|
||||
"""
|
||||
JSON type for the parameter value.
|
||||
"""
|
||||
|
||||
string = 'string'
|
||||
number = 'number'
|
||||
boolean = 'boolean'
|
||||
|
||||
|
||||
class ToolParameter(BaseModel):
|
||||
"""
|
||||
A parameter that the tool accepts from the model at call time.
|
||||
"""
|
||||
|
||||
name: Annotated[str, Field(title='Name')]
|
||||
"""
|
||||
Parameter name used as a key in the tool request body.
|
||||
"""
|
||||
type: Annotated[Type1, Field(title='Type')]
|
||||
"""
|
||||
JSON type for the parameter value.
|
||||
"""
|
||||
description: Annotated[str, Field(title='Description')]
|
||||
"""
|
||||
Description shown to the model for this parameter.
|
||||
"""
|
||||
required: Annotated[bool | None, Field(title='Required')] = True
|
||||
"""
|
||||
Whether this parameter is required when the tool is called.
|
||||
"""
|
||||
|
||||
|
||||
class ToolResponse(BaseModel):
|
||||
"""
|
||||
Response schema for a tool.
|
||||
Response schema for a reusable tool.
|
||||
"""
|
||||
|
||||
id: Annotated[int, Field(title='Id')]
|
||||
|
|
@ -216,6 +471,62 @@ class ToolResponse(BaseModel):
|
|||
created_by: CreatedByResponse | None = None
|
||||
|
||||
|
||||
class MessageType1(Enum):
|
||||
"""
|
||||
Type of message to play before transfer.
|
||||
"""
|
||||
|
||||
none = 'none'
|
||||
custom = 'custom'
|
||||
audio = 'audio'
|
||||
|
||||
|
||||
class TransferCallConfig(BaseModel):
|
||||
"""
|
||||
Configuration for Transfer Call tools.
|
||||
"""
|
||||
|
||||
destination: Annotated[str, Field(title='Destination')]
|
||||
"""
|
||||
Phone number or SIP endpoint to transfer the call to, e.g. +1234567890 or PJSIP/1234.
|
||||
"""
|
||||
messageType: Annotated[MessageType1 | None, Field(title='Messagetype')] = 'none'
|
||||
"""
|
||||
Type of message to play before transfer.
|
||||
"""
|
||||
customMessage: Annotated[str | None, Field(title='Custommessage')] = None
|
||||
"""
|
||||
Custom message to play before transferring.
|
||||
"""
|
||||
audioRecordingId: Annotated[str | None, Field(title='Audiorecordingid')] = None
|
||||
"""
|
||||
Recording ID for audio message before transfer.
|
||||
"""
|
||||
timeout: Annotated[int | None, Field(ge=5, le=120, title='Timeout')] = 30
|
||||
"""
|
||||
Maximum seconds to wait for the destination to answer.
|
||||
"""
|
||||
|
||||
|
||||
class TransferCallToolDefinition(BaseModel):
|
||||
"""
|
||||
Tool definition for Transfer Call tools.
|
||||
"""
|
||||
|
||||
schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
|
||||
"""
|
||||
Schema version.
|
||||
"""
|
||||
type: Annotated[Literal['transfer_call'], Field(title='Type')]
|
||||
"""
|
||||
Tool type.
|
||||
"""
|
||||
config: TransferCallConfig
|
||||
"""
|
||||
Transfer Call configuration.
|
||||
"""
|
||||
|
||||
|
||||
class UpdateWorkflowRequest(BaseModel):
|
||||
name: Annotated[str | None, Field(title='Name')] = None
|
||||
workflow_definition: Annotated[
|
||||
|
|
@ -286,6 +597,80 @@ class HTTPValidationError(BaseModel):
|
|||
detail: Annotated[list[ValidationError] | None, Field(title='Detail')] = None
|
||||
|
||||
|
||||
class HttpApiConfig(BaseModel):
|
||||
"""
|
||||
Configuration for HTTP API tools.
|
||||
"""
|
||||
|
||||
method: Annotated[Method, Field(title='Method')]
|
||||
"""
|
||||
HTTP method to use for the request.
|
||||
"""
|
||||
url: Annotated[str, Field(title='Url')]
|
||||
"""
|
||||
Target HTTP or HTTPS URL.
|
||||
"""
|
||||
headers: Annotated[dict[str, str] | None, Field(title='Headers')] = None
|
||||
"""
|
||||
Static headers to include with every request.
|
||||
"""
|
||||
credential_uuid: Annotated[str | None, Field(title='Credential Uuid')] = None
|
||||
"""
|
||||
Reference to an external credential for request authentication.
|
||||
"""
|
||||
parameters: Annotated[list[ToolParameter] | None, Field(title='Parameters')] = None
|
||||
"""
|
||||
Parameters the model must provide when calling this tool.
|
||||
"""
|
||||
preset_parameters: Annotated[
|
||||
list[PresetToolParameter] | None, Field(title='Preset Parameters')
|
||||
] = None
|
||||
"""
|
||||
Parameters injected by Dograh from fixed values or workflow context templates.
|
||||
"""
|
||||
timeout_ms: Annotated[
|
||||
TimeoutMs | None, Field(title='Timeout Ms', validate_default=True)
|
||||
] = 5000
|
||||
"""
|
||||
Request timeout in milliseconds.
|
||||
"""
|
||||
customMessage: Annotated[str | None, Field(title='Custommessage')] = None
|
||||
"""
|
||||
Custom message to play after tool execution.
|
||||
"""
|
||||
customMessageType: Annotated[
|
||||
CustomMessageType | None, Field(title='Custommessagetype')
|
||||
] = None
|
||||
"""
|
||||
Type of custom message.
|
||||
"""
|
||||
customMessageRecordingId: Annotated[
|
||||
str | None, Field(title='Custommessagerecordingid')
|
||||
] = None
|
||||
"""
|
||||
Recording ID for an audio custom message.
|
||||
"""
|
||||
|
||||
|
||||
class HttpApiToolDefinition(BaseModel):
|
||||
"""
|
||||
Tool definition for HTTP API tools.
|
||||
"""
|
||||
|
||||
schema_version: Annotated[int | None, Field(title='Schema Version')] = 1
|
||||
"""
|
||||
Schema version.
|
||||
"""
|
||||
type: Annotated[Literal['http_api'], Field(title='Type')]
|
||||
"""
|
||||
Tool type.
|
||||
"""
|
||||
config: HttpApiConfig
|
||||
"""
|
||||
HTTP API configuration.
|
||||
"""
|
||||
|
||||
|
||||
class PropertySpec(BaseModel):
|
||||
"""
|
||||
Single field on a node.
|
||||
|
|
@ -338,6 +723,46 @@ class RecordingListResponseSchema(BaseModel):
|
|||
total: Annotated[int, Field(title='Total')]
|
||||
|
||||
|
||||
class CreateToolRequest(BaseModel):
|
||||
"""
|
||||
Request schema for creating a reusable tool.
|
||||
"""
|
||||
|
||||
name: Annotated[str, Field(max_length=255, title='Name')]
|
||||
"""
|
||||
Display name for the tool.
|
||||
"""
|
||||
description: Annotated[str | None, Field(title='Description')] = None
|
||||
"""
|
||||
Description shown to the agent when deciding whether to call it.
|
||||
"""
|
||||
category: Annotated[Category | None, Field(title='Category')] = 'http_api'
|
||||
"""
|
||||
Tool category. Must match definition.type.
|
||||
"""
|
||||
icon: Annotated[Icon | None, Field(title='Icon', validate_default=True)] = 'globe'
|
||||
"""
|
||||
Lucide icon identifier.
|
||||
"""
|
||||
icon_color: Annotated[
|
||||
IconColor | None, Field(title='Icon Color', validate_default=True)
|
||||
] = '#3B82F6'
|
||||
"""
|
||||
Hex color for the tool icon.
|
||||
"""
|
||||
definition: Annotated[
|
||||
HttpApiToolDefinition
|
||||
| EndCallToolDefinition
|
||||
| TransferCallToolDefinition
|
||||
| CalculatorToolDefinition
|
||||
| McpToolDefinition,
|
||||
Field(discriminator='type', title='Definition'),
|
||||
]
|
||||
"""
|
||||
Typed tool definition.
|
||||
"""
|
||||
|
||||
|
||||
class NodeSpec(BaseModel):
|
||||
"""
|
||||
Single source of truth for a node type.
|
||||
|
|
|
|||
|
|
@ -65,7 +65,8 @@ class StartCall(TypedNode):
|
|||
greeting: Optional[str] = None
|
||||
"""
|
||||
Text spoken via TTS at the start of the call. Supports
|
||||
{{template_variables}}. Leave empty to skip the greeting.
|
||||
{{template_variables}}. Leave empty to skip the greeting. Not supported
|
||||
with realtime (speech-to-speech) models.
|
||||
"""
|
||||
|
||||
greeting_recording_id: Optional[str] = None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue