diff --git a/apps/python-sdk/README.md b/apps/python-sdk/README.md index f6e3fab3..43a2fa49 100644 --- a/apps/python-sdk/README.md +++ b/apps/python-sdk/README.md @@ -81,4 +81,39 @@ chat = StatefulChat( response = chat.run("Hello, how are you?") print(response) # I'm good, thanks! How can I help you today? -``` \ No newline at end of file +``` + +### Advanced Usage + +#### Using a specific workflow + +```python +response_messages, state = client.chat( + messages=messages, + workflow_id="" +) + +# or + +chat = StatefulChat( + client, + workflow_id="" +) +``` + +#### Skip tool call runs +This will surface the tool calls to the SDK instead of running them automatically on the Rowboat server. + +```python +response_messages, state = client.chat( + messages=messages, + skip_tool_calls=True +) + +# or + +chat = StatefulChat( + client, + skip_tool_calls=True +) +``` diff --git a/apps/python-sdk/pyproject.toml b/apps/python-sdk/pyproject.toml index 202c1896..ad669041 100644 --- a/apps/python-sdk/pyproject.toml +++ b/apps/python-sdk/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "rowboat" -version = "1.0.2" +version = "1.0.4" authors = [ { name = "Your Name", email = "your.email@example.com" }, ] diff --git a/apps/python-sdk/src/rowboat/client.py b/apps/python-sdk/src/rowboat/client.py index 9a203df2..d73c01a9 100644 --- a/apps/python-sdk/src/rowboat/client.py +++ b/apps/python-sdk/src/rowboat/client.py @@ -26,13 +26,15 @@ class Client: messages: List[ApiMessage], state: Optional[Dict[str, Any]] = None, skip_tool_calls: bool = False, - max_turns: int = 3 + max_turns: int = 3, + workflow_id: Optional[str] = None ) -> ApiResponse: request = ApiRequest( messages=messages, state=state, skipToolCalls=skip_tool_calls, - maxTurns=max_turns + maxTurns=max_turns, + workflowId=workflow_id ) response = requests.post(self.base_url, headers=self.headers, data=request.model_dump_json()) @@ -80,7 +82,8 @@ class Client: tools: Optional[Dict[str, Callable[..., str]]] = None, state: Optional[Dict[str, Any]] = None, max_turns: int = 3, - skip_tool_calls: bool = False + skip_tool_calls: bool = False, + workflow_id: Optional[str] = None ) -> Tuple[List[ApiMessage], Optional[Dict[str, Any]]]: """Stateless chat method that handles a single conversation turn with multiple tool call rounds""" @@ -98,7 +101,8 @@ class Client: messages=current_messages, state=current_state, skip_tool_calls=skip_tool_calls, - max_turns=max_turns + max_turns=max_turns, + workflow_id=workflow_id ) current_messages.extend(response_data.messages) @@ -136,7 +140,8 @@ class StatefulChat: tools: Optional[Dict[str, Callable[..., str]]] = None, system_prompt: Optional[str] = None, max_turns: int = 3, - skip_tool_calls: bool = False + skip_tool_calls: bool = False, + workflow_id: Optional[str] = None ) -> None: self.client = client self.tools = tools @@ -144,7 +149,7 @@ class StatefulChat: self.state: Optional[Dict[str, Any]] = None self.max_turns = max_turns self.skip_tool_calls = skip_tool_calls - + self.workflow_id = workflow_id if system_prompt: self.messages.append(SystemMessage(role='system', content=system_prompt)) @@ -161,7 +166,8 @@ class StatefulChat: tools=self.tools, state=self.state, max_turns=self.max_turns, - skip_tool_calls=self.skip_tool_calls + skip_tool_calls=self.skip_tool_calls, + workflow_id=self.workflow_id ) # Update internal state diff --git a/apps/python-sdk/src/rowboat/schema.py b/apps/python-sdk/src/rowboat/schema.py index 1afa725a..75f928b0 100644 --- a/apps/python-sdk/src/rowboat/schema.py +++ b/apps/python-sdk/src/rowboat/schema.py @@ -50,6 +50,7 @@ class ApiRequest(BaseModel): state: Any skipToolCalls: Optional[bool] = None maxTurns: Optional[int] = None + workflowId: Optional[str] = None class ApiResponse(BaseModel): messages: List[ApiMessage] diff --git a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts index 8b80ff88..e6414cf9 100644 --- a/apps/rowboat/app/api/v1/[projectId]/chat/route.ts +++ b/apps/rowboat/app/api/v1/[projectId]/chat/route.ts @@ -52,17 +52,23 @@ export async function POST( logger.log(`Project ${projectId} not found`); return Response.json({ error: "Project not found" }, { status: 404 }); } - if (!project.publishedWorkflowId) { + + // if workflow id is provided in the request, use it, else use the published workflow id + let workflowId = result.data.workflowId; + if (!workflowId) { + workflowId = project.publishedWorkflowId; + } + if (!workflowId) { logger.log(`Project ${projectId} has no published workflow`); return Response.json({ error: "Project has no published workflow" }, { status: 404 }); } // fetch workflow const workflow = await agentWorkflowsCollection.findOne({ projectId: projectId, - _id: new ObjectId(project.publishedWorkflowId), + _id: new ObjectId(workflowId), }); if (!workflow) { - logger.log(`Workflow ${project.publishedWorkflowId} not found for project ${projectId}`); + logger.log(`Workflow ${workflowId} not found for project ${projectId}`); return Response.json({ error: "Workflow not found" }, { status: 404 }); } diff --git a/apps/rowboat/app/lib/types/types.ts b/apps/rowboat/app/lib/types/types.ts index 8122cb31..d12f97c1 100644 --- a/apps/rowboat/app/lib/types/types.ts +++ b/apps/rowboat/app/lib/types/types.ts @@ -109,6 +109,7 @@ export const ApiRequest = z.object({ state: z.unknown(), skipToolCalls: z.boolean().optional(), maxTurns: z.number().optional(), + workflowId: z.string().optional(), }); export const ApiResponse = z.object({