diff --git a/examples/README.md b/examples/README.md index b15977d8..22e5c918 100644 --- a/examples/README.md +++ b/examples/README.md @@ -27,6 +27,10 @@ python python/fetch_workflow_and_call.py # Create a new workflow from a definition. python python/create_workflow.py +# Build a 3-node agent with the Workflow SDK and save it as a draft. +# Edit WORKFLOW_ID at the top of the file first. +python python/build_workflow_with_sdk.py + # Load an existing workflow, edit the startCall prompt, and save as a draft. # Edit WORKFLOW_ID at the top of the file first. python python/load_and_edit_workflow.py @@ -45,5 +49,6 @@ export DOGRAH_API_TOKEN=sk-... npm run call # fetch_workflow_and_call.ts npm run create # create_workflow.ts +npm run build # build_workflow_with_sdk.ts (edit WORKFLOW_ID in the file first) npm run edit # load_and_edit_workflow.ts (edit WORKFLOW_ID in the file first) ``` diff --git a/examples/python/build_workflow_with_sdk.py b/examples/python/build_workflow_with_sdk.py new file mode 100644 index 00000000..78d47955 --- /dev/null +++ b/examples/python/build_workflow_with_sdk.py @@ -0,0 +1,101 @@ +"""Build a multi-node voice agent using the Workflow SDK and save it as a draft. + +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 build_workflow_with_sdk.py +""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path + +from dotenv import load_dotenv + +from dograh_sdk import DograhClient, Workflow + +load_dotenv(Path(__file__).parent / ".env") + +# Replace with the numeric ID of an existing agent in your Dograh account. +# Create one via the UI or with create_workflow.py if you don't have one yet. +WORKFLOW_ID = 0 + + +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 + + if WORKFLOW_ID == 0: + print("Set WORKFLOW_ID at the top of this file to an existing workflow ID", file=sys.stderr) + return 1 + + with DograhClient(base_url=api_endpoint, api_key=api_token) as client: + existing = client.get_workflow(WORKFLOW_ID) + # Preserve the live workflow name; save_workflow sends name with the draft update. + wf = Workflow(client=client, name=existing.name) + + greeting = wf.add( + type="startCall", + name="greeting", + 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" + "## Flow\n" + "Greet the caller warmly and ask whether they would like to continue." + ), + ) + qualify = wf.add( + type="agentNode", + name="qualify", + prompt=( + "# Goal\n" + "Qualify the lead by asking about their needs, budget, and timeline.\n\n" + "## Rules\n" + "- Keep responses short — 2-3 sentences max\n" + "- Confirm all three answers before moving on" + ), + ) + done = wf.add( + type="endCall", + name="done", + prompt="Thank the caller for their time and let them know the team will follow up shortly.", + ) + + wf.edge( + greeting, + qualify, + label="interested", + condition="Caller confirms they want to continue.", + ) + wf.edge( + qualify, + done, + label="qualified", + condition="All qualification questions have been answered.", + ) + + result = client.save_workflow(workflow_id=WORKFLOW_ID, workflow=wf) + node_count = len(result.workflow_definition.get("nodes", [])) + print( + f"Saved workflow {result.id}: {result.name!r} " + f"(version={result.version_number}, status={result.version_status}, " + f"nodes={node_count})" + ) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/typescript/build_workflow_with_sdk.ts b/examples/typescript/build_workflow_with_sdk.ts new file mode 100644 index 00000000..4dfb77a7 --- /dev/null +++ b/examples/typescript/build_workflow_with_sdk.ts @@ -0,0 +1,84 @@ +// Build a multi-node voice agent using the Workflow SDK and save it as a draft. +// +// 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 build_workflow_with_sdk.ts + +import { DograhClient, Workflow } from "@dograh/sdk"; + +// Replace with the numeric ID of an existing agent in your Dograh account. +// Create one via the UI or with create_workflow.ts if you don't have one yet. +const WORKFLOW_ID = 0; + +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"); + if (WORKFLOW_ID === 0) throw new Error("Set WORKFLOW_ID at the top of this file to an existing workflow ID"); + + const client = new DograhClient({ + baseUrl: apiEndpoint, + apiKey: apiToken, + }); + + const existing = await client.getWorkflow(WORKFLOW_ID); + // Preserve the live workflow name; saveWorkflow sends name with the draft update. + const wf = new Workflow({ client, name: existing.name }); + + const greeting = await wf.add({ + type: "startCall", + name: "greeting", + 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.", + "", + "## Flow", + "Greet the caller warmly and ask whether they would like to continue.", + ].join("\n"), + }); + const qualify = await wf.add({ + type: "agentNode", + name: "qualify", + prompt: [ + "# Goal", + "Qualify the lead by asking about their needs, budget, and timeline.", + "", + "## Rules", + "- Keep responses short — 2-3 sentences max", + "- Confirm all three answers before moving on", + ].join("\n"), + }); + const done = await wf.add({ + type: "endCall", + name: "done", + prompt: "Thank the caller for their time and let them know the team will follow up shortly.", + }); + + wf.edge(greeting, qualify, { + label: "interested", + condition: "Caller confirms they want to continue.", + }); + wf.edge(qualify, done, { + label: "qualified", + condition: "All qualification questions have been answered.", + }); + + const result = await client.saveWorkflow(WORKFLOW_ID, wf); + const nodeCount = ((result.workflow_definition?.nodes as unknown[]) ?? []).length; + console.log( + `Saved workflow ${result.id}: ${JSON.stringify(result.name)} ` + + `(version=${result.version_number}, status=${result.version_status}, nodes=${nodeCount})`, + ); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 75d95e5a..68e3782e 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -6,6 +6,7 @@ "scripts": { "call": "tsx --env-file=.env fetch_workflow_and_call.ts", "create": "tsx --env-file=.env create_workflow.ts", + "build": "tsx --env-file=.env build_workflow_with_sdk.ts", "edit": "tsx --env-file=.env load_and_edit_workflow.ts" }, "dependencies": {