diff --git a/api/routes/workflow.py b/api/routes/workflow.py index f5dbdf2..cc9ec52 100644 --- a/api/routes/workflow.py +++ b/api/routes/workflow.py @@ -273,7 +273,13 @@ def _transform_schema_errors( return out -@router.post("/create/definition") +@router.post( + "/create/definition", + **sdk_expose( + method="create_workflow", + description="Create a new workflow from a workflow definition.", + ), +) async def create_workflow( request: CreateWorkflowRequest, user: UserModel = Depends(get_user) ) -> WorkflowResponse: diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..802ed73 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,44 @@ +# Dograh SDK Examples + +Runnable examples of the Dograh SDK in Python and TypeScript. + +## Shared environment variables + +Copy `.env.example` to `.env` in each example directory and fill in your values, then `source .env` (or use your preferred dotenv loader). + +| Variable | Description | +| --------------------- | ------------------------------------------------------------ | +| `DOGRAH_API_ENDPOINT` | Dograh API base URL (e.g. `http://localhost:8000`) | +| `DOGRAH_API_TOKEN` | API token — sent as `X-API-Key` | + +The workflow ID and destination phone number are set as constants at the top of each example script — edit them there. + +## Python + +```bash +pip install dograh-sdk + +export DOGRAH_API_ENDPOINT=http://localhost:8000 +export DOGRAH_API_TOKEN=sk-... + +# Fetch a workflow by ID and place a test phone call. +python python/fetch_workflow_and_call.py + +# Create a new workflow from a definition. +python python/create_workflow.py +``` + +## TypeScript + +Uses `tsx` to run directly. + +```bash +cd typescript +npm install + +export DOGRAH_API_ENDPOINT=http://localhost:8000 +export DOGRAH_API_TOKEN=sk-... + +npm run call # fetch_workflow_and_call.ts +npm run create # create_workflow.ts +``` diff --git a/examples/python/.env.example b/examples/python/.env.example new file mode 100644 index 0000000..93a62d7 --- /dev/null +++ b/examples/python/.env.example @@ -0,0 +1,2 @@ +DOGRAH_API_ENDPOINT=http://localhost:8000 +DOGRAH_API_TOKEN=sk-your-api-token diff --git a/examples/python/create_workflow.py b/examples/python/create_workflow.py new file mode 100644 index 0000000..2dc0ad3 --- /dev/null +++ b/examples/python/create_workflow.py @@ -0,0 +1,92 @@ +"""Create a new workflow using the Python SDK. + +Requirements: + pip install -r requirements.txt + +Environment variables (loaded from `.env` in this directory): + DOGRAH_API_ENDPOINT - Dograh API base URL (e.g. http://localhost:8000) + DOGRAH_API_TOKEN - API token sent as X-API-Key + +Run: + python create_workflow.py +""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path + +from dotenv import load_dotenv + +from dograh_sdk import DograhClient +from dograh_sdk._generated_models import CreateWorkflowRequest + +load_dotenv(Path(__file__).parent / ".env") + +WORKFLOW_NAME = "My SDK-created agent" + +# A minimal starter agent with a single `startCall` node that greets the user. +# Open the new agent in the Dograh UI to extend it, or edit this dict and +# re-run to tweak the starting definition. +WORKFLOW_DEFINITION: dict = { + "nodes": [ + { + "id": "1", + "type": "startCall", + "position": {"x": 271, "y": 4}, + "data": { + "name": "start call", + "greeting_type": "text", + "prompt": ( + "# Goal\n" + "You are a helpful agent having a conversation over voice with a human. " + "This is a voice conversation, so transcripts can be error prone.\n\n" + "## Rules\n" + "- Language: UK English\n" + "- Keep responses short — 2-3 sentences max\n" + "- If you have to repeat something you said in your previous two turns, " + "rephrase while keeping the same meaning.\n\n" + "## Speech Handling\n" + "- Accept variations: yes/yeah/yep/aye, no/nah/nope\n" + "- If user says \"sorry?\" or \"pardon me\" or \"can you repeat\", " + "just repeat what you just said.\n\n" + "### Flow\n" + "Start by saying \"Hi\". Be polite and courteous." + ), + "allow_interrupt": False, + "add_global_prompt": False, + "delayed_start": False, + "delayed_start_duration": 2, + "extraction_enabled": False, + "pre_call_fetch_enabled": False, + }, + }, + ], + "edges": [], + "viewport": {"x": 0, "y": 0, "zoom": 1}, +} + + +def main() -> int: + api_endpoint = os.environ.get("DOGRAH_API_ENDPOINT", "http://localhost:8000") + api_token = os.environ.get("DOGRAH_API_TOKEN") + + if not api_token: + print("DOGRAH_API_TOKEN is required", file=sys.stderr) + return 1 + + with DograhClient(base_url=api_endpoint, api_key=api_token) as client: + workflow = client.create_workflow( + body=CreateWorkflowRequest( + name=WORKFLOW_NAME, + workflow_definition=WORKFLOW_DEFINITION, + ) + ) + print(f"Created workflow {workflow.id}: {workflow.name!r} (status={workflow.status})") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/python/fetch_workflow_and_call.py b/examples/python/fetch_workflow_and_call.py new file mode 100644 index 0000000..5d044e7 --- /dev/null +++ b/examples/python/fetch_workflow_and_call.py @@ -0,0 +1,57 @@ +"""Fetch a workflow by ID and place a test phone call using the Python SDK. + +Requirements: + pip install -r requirements.txt + +Environment variables (loaded from `.env` in this directory): + DOGRAH_API_ENDPOINT - Dograh API base URL (e.g. http://localhost:8000) + DOGRAH_API_TOKEN - API token sent as X-API-Key + +Run: + python fetch_workflow_and_call.py +""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path + +from dotenv import load_dotenv + +from dograh_sdk import DograhClient +from dograh_sdk._generated_models import InitiateCallRequest + +load_dotenv(Path(__file__).parent / ".env") + +# Numeric workflow ID to fetch and call with. +WORKFLOW_ID = 1 +# E.164 destination number — set this to the number you want to call. +PHONE_NUMBER = "+1113144411" + + +def main() -> int: + api_endpoint = os.environ.get("DOGRAH_API_ENDPOINT", "http://localhost:8000") + api_token = os.environ.get("DOGRAH_API_TOKEN") + + if not api_token: + print("DOGRAH_API_TOKEN is required", file=sys.stderr) + return 1 + + with DograhClient(base_url=api_endpoint, api_key=api_token) as client: + workflow = client.get_workflow(WORKFLOW_ID) + print(f"Fetched workflow {workflow.id}: {workflow.name!r} (status={workflow.status})") + + response = client.test_phone_call( + body=InitiateCallRequest( + workflow_id=WORKFLOW_ID, + phone_number=PHONE_NUMBER, + ) + ) + print(f"Call initiated: {response}") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/python/requirements.txt b/examples/python/requirements.txt new file mode 100644 index 0000000..0fbd842 --- /dev/null +++ b/examples/python/requirements.txt @@ -0,0 +1,2 @@ +dograh-sdk +python-dotenv diff --git a/examples/typescript/.env.example b/examples/typescript/.env.example new file mode 100644 index 0000000..93a62d7 --- /dev/null +++ b/examples/typescript/.env.example @@ -0,0 +1,2 @@ +DOGRAH_API_ENDPOINT=http://localhost:8000 +DOGRAH_API_TOKEN=sk-your-api-token diff --git a/examples/typescript/create_workflow.ts b/examples/typescript/create_workflow.ts new file mode 100644 index 0000000..e29ea3f --- /dev/null +++ b/examples/typescript/create_workflow.ts @@ -0,0 +1,83 @@ +// Create a new workflow using the TypeScript SDK. +// +// Requirements: +// npm install @dograh/sdk +// +// Environment variables: +// DOGRAH_API_ENDPOINT - Dograh API base URL (e.g. http://localhost:8000) +// DOGRAH_API_TOKEN - API token sent as X-API-Key +// +// Run: +// npx tsx create_workflow.ts + +import { DograhClient } from "@dograh/sdk"; + +const WORKFLOW_NAME = "My SDK-created agent"; + +// A minimal starter agent with a single `startCall` node that greets the user. +// Open the new agent in the Dograh UI to extend it, or edit this object and +// re-run to tweak the starting definition. +const WORKFLOW_DEFINITION = { + nodes: [ + { + id: "1", + type: "startCall", + position: { x: 271, y: 4 }, + data: { + name: "start call", + greeting_type: "text", + prompt: [ + "# Goal", + "You are a helpful agent having a conversation over voice with a human. This is a voice conversation, so transcripts can be error prone.", + "", + "## Rules", + "- Language: UK English", + "- Keep responses short — 2-3 sentences max", + "- If you have to repeat something you said in your previous two turns, rephrase while keeping the same meaning.", + "", + "## Speech Handling", + "- Accept variations: yes/yeah/yep/aye, no/nah/nope", + '- If user says "sorry?" or "pardon me" or "can you repeat", just repeat what you just said.', + "", + "### Flow", + 'Start by saying "Hi". Be polite and courteous.', + ].join("\n"), + allow_interrupt: false, + add_global_prompt: false, + delayed_start: false, + delayed_start_duration: 2, + extraction_enabled: false, + pre_call_fetch_enabled: false, + }, + }, + ], + edges: [], + viewport: { x: 0, y: 0, zoom: 1 }, +}; + +async function main(): Promise { + const apiEndpoint = process.env.DOGRAH_API_ENDPOINT ?? "http://localhost:8000"; + const apiToken = process.env.DOGRAH_API_TOKEN; + + if (!apiToken) throw new Error("DOGRAH_API_TOKEN is required"); + + const client = new DograhClient({ + baseUrl: apiEndpoint, + apiKey: apiToken, + }); + + const workflow = await client.createWorkflow({ + body: { + name: WORKFLOW_NAME, + workflow_definition: WORKFLOW_DEFINITION, + }, + }); + console.log( + `Created workflow ${workflow.id}: ${JSON.stringify(workflow.name)} (status=${workflow.status})`, + ); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/examples/typescript/fetch_workflow_and_call.ts b/examples/typescript/fetch_workflow_and_call.ts new file mode 100644 index 0000000..ee9e55d --- /dev/null +++ b/examples/typescript/fetch_workflow_and_call.ts @@ -0,0 +1,48 @@ +// Fetch a workflow by ID and place a test phone call using the TypeScript SDK. +// +// Requirements: +// npm install @dograh/sdk +// +// Environment variables: +// DOGRAH_API_ENDPOINT - Dograh API base URL (e.g. http://localhost:8000) +// DOGRAH_API_TOKEN - API token sent as X-API-Key +// +// Run: +// npx tsx fetch_workflow_and_call.ts + +import { DograhClient } from "@dograh/sdk"; + +// Numeric workflow ID to fetch and call with. +const WORKFLOW_ID = 1; +// E.164 destination number — set this to the number you want to call. +const PHONE_NUMBER = "+11187619471"; + +async function main(): Promise { + const apiEndpoint = process.env.DOGRAH_API_ENDPOINT ?? "http://localhost:8000"; + const apiToken = process.env.DOGRAH_API_TOKEN; + + if (!apiToken) throw new Error("DOGRAH_API_TOKEN is required"); + + const client = new DograhClient({ + baseUrl: apiEndpoint, + apiKey: apiToken, + }); + + const workflow = await client.getWorkflow(WORKFLOW_ID); + console.log( + `Fetched workflow ${workflow.id}: ${JSON.stringify(workflow.name)} (status=${workflow.status})`, + ); + + const response = await client.testPhoneCall({ + body: { + workflow_id: WORKFLOW_ID, + phone_number: PHONE_NUMBER, + }, + }); + console.log("Call initiated:", response); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/examples/typescript/package-lock.json b/examples/typescript/package-lock.json new file mode 100644 index 0000000..58e9686 --- /dev/null +++ b/examples/typescript/package-lock.json @@ -0,0 +1,584 @@ +{ + "name": "dograh-examples-typescript", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dograh-examples-typescript", + "version": "0.0.0", + "dependencies": { + "@dograh/sdk": "latest" + }, + "devDependencies": { + "tsx": "^4.7.0", + "typescript": "^5.4.0" + } + }, + "node_modules/@dograh/sdk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@dograh/sdk/-/sdk-0.1.2.tgz", + "integrity": "sha512-TB2qoTZP8Zbw8WfCrMiUDrC510KJE/tFocvhA84f71lYEpMwAjbLLe2gdz8Jnwq8Zu+NXYsoWaZFCKHIyRy+xw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/examples/typescript/package.json b/examples/typescript/package.json new file mode 100644 index 0000000..c48f228 --- /dev/null +++ b/examples/typescript/package.json @@ -0,0 +1,17 @@ +{ + "name": "dograh-examples-typescript", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "call": "tsx --env-file=.env fetch_workflow_and_call.ts", + "create": "tsx --env-file=.env create_workflow.ts" + }, + "dependencies": { + "@dograh/sdk": "latest" + }, + "devDependencies": { + "tsx": "^4.7.0", + "typescript": "^5.4.0" + } +} diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 0968b1a..a22f682 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dograh-sdk" -version = "0.1.2" +version = "0.1.3" description = "Typed builder for Dograh voice-AI workflows" readme = "README.md" requires-python = ">=3.10" diff --git a/sdk/python/src/dograh_sdk/_generated_client.py b/sdk/python/src/dograh_sdk/_generated_client.py index 82c2031..a303f64 100644 --- a/sdk/python/src/dograh_sdk/_generated_client.py +++ b/sdk/python/src/dograh_sdk/_generated_client.py @@ -12,6 +12,7 @@ from __future__ import annotations from typing import Any from dograh_sdk._generated_models import ( + CreateWorkflowRequest, CredentialResponse, DocumentListResponseSchema, InitiateCallRequest, @@ -28,6 +29,11 @@ from dograh_sdk._generated_models import ( class _GeneratedClient: # `DograhClient.__init__` installs `self._request` (see client.py). + 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)) + return WorkflowResponse.model_validate(data) + def get_node_type(self, name: str) -> NodeSpec: """Fetch a single node spec by name.""" data = self._request("GET", f"/node-types/{name}") diff --git a/sdk/python/src/dograh_sdk/_generated_models.py b/sdk/python/src/dograh_sdk/_generated_models.py index c675ec9..574c2d3 100644 --- a/sdk/python/src/dograh_sdk/_generated_models.py +++ b/sdk/python/src/dograh_sdk/_generated_models.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: -# filename: dograh-openapi-XXXXXX.json.oPRfLAwVZP -# timestamp: 2026-04-21T02:15:12+00:00 +# filename: dograh-openapi-XXXXXX.json.YcuMTcSn5P +# timestamp: 2026-04-24T08:26:45+00:00 from __future__ import annotations @@ -16,6 +16,11 @@ class CallDispositionCodes(BaseModel): ) +class CreateWorkflowRequest(BaseModel): + name: Annotated[str, Field(title='Name')] + workflow_definition: Annotated[dict[str, Any], Field(title='Workflow Definition')] + + class CreatedByResponse(BaseModel): """ Response schema for the user who created a tool. diff --git a/sdk/typescript/package-lock.json b/sdk/typescript/package-lock.json index 921002e..0cd36cf 100644 --- a/sdk/typescript/package-lock.json +++ b/sdk/typescript/package-lock.json @@ -1,12 +1,12 @@ { "name": "@dograh/sdk", - "version": "0.1.1", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@dograh/sdk", - "version": "0.1.1", + "version": "0.1.3", "license": "BSD-2-Clause", "devDependencies": { "openapi-typescript": "^7.13.0", diff --git a/sdk/typescript/package.json b/sdk/typescript/package.json index 51e98fb..37b0746 100644 --- a/sdk/typescript/package.json +++ b/sdk/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@dograh/sdk", - "version": "0.1.2", + "version": "0.1.3", "description": "Typed builder for Dograh voice-AI workflows", "license": "BSD-2-Clause", "author": "Zansat Technologies Private Limited", diff --git a/sdk/typescript/src/_generated_client.ts b/sdk/typescript/src/_generated_client.ts index 717dd10..c6f00c7 100644 --- a/sdk/typescript/src/_generated_client.ts +++ b/sdk/typescript/src/_generated_client.ts @@ -7,6 +7,7 @@ // `_generated_models` (openapi-typescript output, --root-types). import type { + CreateWorkflowRequest, CredentialResponse, DocumentListResponseSchema, InitiateCallRequest, @@ -26,6 +27,11 @@ export abstract class _GeneratedClient { opts?: { json?: unknown; params?: Record }, ): Promise; + /** Create a new workflow from a workflow definition. */ + async createWorkflow(opts: { body: CreateWorkflowRequest }): Promise { + return this.request("POST", "/workflow/create/definition", { json: opts.body }); + } + /** Fetch a single node spec by name. */ async getNodeType(name: string): Promise { return this.request("GET", `/node-types/${name}`); diff --git a/sdk/typescript/src/_generated_models.ts b/sdk/typescript/src/_generated_models.ts index 7b5e039..4d4e09d 100644 --- a/sdk/typescript/src/_generated_models.ts +++ b/sdk/typescript/src/_generated_models.ts @@ -25,6 +25,30 @@ export interface paths { patch?: never; trace?: never; }; + "/api/v1/workflow/create/definition": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create Workflow + * @description Create a new workflow from the client + * + * Args: + * request: The create workflow request + * user: The user to create the workflow for + */ + post: operations["create_workflow_api_v1_workflow_create_definition_post"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/api/v1/workflow/fetch": { parameters: { query?: never; @@ -246,6 +270,15 @@ export interface components { */ disposition_codes: string[]; }; + /** CreateWorkflowRequest */ + CreateWorkflowRequest: { + /** Name */ + name: string; + /** Workflow Definition */ + workflow_definition: { + [key: string]: unknown; + }; + }; /** * CreatedByResponse * @description Response schema for the user who created a tool. @@ -714,6 +747,7 @@ export interface components { pathItems: never; } export type CallDispositionCodes = components['schemas']['CallDispositionCodes']; +export type CreateWorkflowRequest = components['schemas']['CreateWorkflowRequest']; export type CreatedByResponse = components['schemas']['CreatedByResponse']; export type CredentialResponse = components['schemas']['CredentialResponse']; export type DisplayOptions = components['schemas']['DisplayOptions']; @@ -781,6 +815,49 @@ export interface operations { }; }; }; + create_workflow_api_v1_workflow_create_definition_post: { + parameters: { + query?: never; + header?: { + authorization?: string | null; + "X-API-Key"?: string | null; + }; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateWorkflowRequest"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WorkflowResponse"]; + }; + }; + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; get_workflows_api_v1_workflow_fetch_get: { parameters: { query?: {