diff --git a/apps/docs/docs/img/dev-config.png b/apps/docs/docs/img/dev-config.png index 3010566d..d9b45efa 100644 Binary files a/apps/docs/docs/img/dev-config.png and b/apps/docs/docs/img/dev-config.png differ diff --git a/apps/docs/docs/img/prod-deploy.png b/apps/docs/docs/img/prod-deploy.png index fa22f93a..f1745213 100644 Binary files a/apps/docs/docs/img/prod-deploy.png and b/apps/docs/docs/img/prod-deploy.png differ diff --git a/apps/docs/docs/index.md b/apps/docs/docs/index.md index ffadc7b7..89626228 100644 --- a/apps/docs/docs/index.md +++ b/apps/docs/docs/index.md @@ -28,8 +28,8 @@ RowBoat Studio lets you create AI agents in minutes, using a visual interface an | Copilot | AI-powered concierge that creates and
updates agents and tools on your behalf |• Context-aware of all components including playground
• Improves agents based on conversations and feedback
• Understands your requests in plain language| ### RowBoat Chat API & SDK -- RowBoat Chat API is a stateless HTTP API to interface with the assistant created on RowBoat Studio. You can use the API to drive end-user facing conversations in your app or website. -- RowBoat Chat SDK is a simple SDK (currently available in Python) which wraps the HTTP API under the hood. It offers both stateful and stateless (OpenAI-style) implementations. +- [RowBoat Chat API](/using_the_api) is a stateless HTTP API to interface with the assistant created on RowBoat Studio. You can use the API to drive end-user facing conversations in your app or website. +- [RowBoat Chat SDK](/using_the_sdk) is a simple SDK (currently available in Python) which wraps the HTTP API under the hood. It offers both stateful and stateless (OpenAI-style) implementations. ### Steps **RowBoat Studio:** diff --git a/apps/docs/docs/using_the_api.md b/apps/docs/docs/using_the_api.md index 5e599a3a..413540ab 100644 --- a/apps/docs/docs/using_the_api.md +++ b/apps/docs/docs/using_the_api.md @@ -10,27 +10,27 @@ This is a guide on using the HTTP API to power conversations with the assistant Generate API keys via the developer configs in your project. Copy the Project ID from the same page. ![Developer Configs](img/dev-config.png) -## Call the API +## API Endpoint -When you provide your Project ID in the API call, RowBoat uses the version of your assistant deployed to production. +``` +POST /api/v1//chat +``` -**Request parameters:** +Where: -- `messages`: history of all messages in the conversation till now (system, user, tool and assistant messages) -- `state`: generated from the previous turn (this is needed because the API does not maintain state on its own) +- For self-hosted: `` is `http://localhost:3000` -**Response parameters:** +## Authentication -- `messages`: assistant responses for the current turn (the last message in `messages` is either the user-facing response or a tool call by the assistant) -- `state`: to be passed to the next turn +Include your API key in the Authorization header: -### API Host -- For the open source installation, the `` is [http://localhost:3000](http://localhost:3000) -- When using the hosted app, the `` is [https://app.rowboatlabs.com](https://app.rowboatlabs.com) - -### Example first turn of a chat +``` +Authorization: Bearer +``` -#### Request +## Examples + +### First Turn ```bash curl --location '/api/v1//chat' \ @@ -38,206 +38,129 @@ curl --location '/api/v1//chat' \ --header 'Authorization: Bearer ' \ --data '{ "messages": [ - { - "role": "system", - "content": "UserID: 345227" - // Provide context to be passed to all agents in the assistant - // E.g. user identity info (user ID) for logged in users - }, { "role": "user", - "content": "What is my outstanding balance and how do I make the payment?" + "content": "Hello, can you help me?" } ], - "state": { - "last_agent_name": "Credit Card Hub" - // Last agent used in the previous turn - // Set to the "start agent" for first turn of chats - } + "state": null }' ``` -#### Response + +Response: ```json { "messages": [ { - "sender": "Credit Card Hub", "role": "assistant", - "response_type": "internal", - "content": null, - "current_turn": true, - "tool_calls": [ - { - "function": { - // Internal tool calls are used to transfer between agents - "name": "transfer_to_outstanding_payments", - "arguments": "{\"args\":\"\",\"kwargs\":\"\"}" - }, - "id": "call_SLyQKXt9ZMqnxSqJjo9j1fU5", - "type": "function" - } - ] - }, - { - "role": "tool", - "tool_name": "transfer_to_outstanding_payments", - "content": "{\"assistant\": \"Outstanding Payments\"}", - "tool_call_id": "call_SLyQKXt9ZMqnxSqJjo9j1fU5" - }, - { - // Last message in response messages is a tool call - "sender": "Outstanding Payments", - "role": "assistant", - "response_type": "internal", - "content": null, - "current_turn": true, - "tool_calls": [ - { - "function": { - "name": "get_outstanding_balance", - "arguments": "{\"user_id\":\"345227\"}" - }, - "id": "call_MNAUg7UTszYMt5RL4n5QqUTw", - "type": "function" - } - ] + "content": "Hello! Yes, I'd be happy to help you. What can I assist you with today?", + "agenticResponseType": "external" } ], "state": { - "agent_data": [ - // Agents that were involved in this turn - { - "name": "Credit Card Hub", - "instructions": "// agent instructions", - "history": [ - // History of agent-relevant messages - // in the same format as "messages" - ], - "child_functions": [ - "transfer_to_outstanding_payments", - "transfer_to_transaction_disputes", - "transfer_to_rewards_redemption" - ], - }, - { - "name": "Outstanding Payments", - "instructions": // Agent instructions, - "history": [ - // History of agent-relevant messages - // in the same format as "messages" - ], - "external_tools": [ - "get_outstanding_balance", - "get_saved_credit_card" - ], - }, - - // Other agents - have not yet participated in the conversation - { - "name": "Rewards Redemption", - "instructions": // Agent instructions, - "history": [], // - } - ], - "last_agent_name": "Outstanding Payments" + "last_agent_name": "MainAgent" } } - ``` -### Example where the assistant is expecting a tool response -#### Request +### Subsequent Turn + +Notice how we include both the previous messages and the state from the last response: + ```bash -curl --location 'http://localhost:3000/api/v1//chat' \ +curl --location '/api/v1//chat' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "messages": [ { - "role": "system", - "content": "UserID: 345227" + "role": "user", + "content": "Hello, can you help me?" + }, + { + "role": "assistant", + "content": "Hello! Yes, I'd be happy to help you. What can I assist you with today?", + "agenticResponseType": "external" }, { "role": "user", - "content": "What is my outstanding balance and how do I make the payment?" - }, - { - "sender": "Credit Card Hub", - "role": "assistant", - "response_type": "internal", - "content": null, - "tool_calls": [ - { - "function": { - "arguments": "{\"args\":\"\",\"kwargs\":\"\"}", - "name": "transfer_to_outstanding_payments" - }, - "id": "call_SLyQKXt9ZMqnxSqJjo9j1fU5", - "type": "function" - } - ], - }, - { - "role": "tool", - "tool_name": "transfer_to_outstanding_payments", - "content": "{\"assistant\": \"Outstanding Payments\"}", - "tool_call_id": "call_SLyQKXt9ZMqnxSqJjo9j1fU5" - }, - { - "sender": "Outstanding Payments", - "role": "assistant", - "response_type": "internal", - "content": null, - "tool_calls": [ - { - "function": { - "arguments": "{\"user_id\":\"345227\"}", - "name": "get_outstanding_balance" - }, - "id": "call_MNAUg7UTszYMt5RL4n5QqUTw", - "type": "function" - } - ], - }, - { - // New message is a tool response to the previous tool call - "role": "tool", - "tool_name": "get_outstanding_balance" - "content": "{\"result\":{\"outstanding_balance\":\"$250.00\",\"due_date\":\"2025-02-15\",\"payment_methods\":[\"Credit Card\",\"Bank Transfer\",\"PayPal\"]}}", - "tool_call_id": "call_MNAUg7UTszYMt5RL4n5QqUTw", - }, - ], - "state": { - // State returned by the API in the previous turn - } -}' -``` -#### Response -```json -{ - "messages": [ - { - "sender": "Outstanding Payments", - "role": "assistant", - // Response is not user-facing, to enable further post processing - "response_type": "internal", - "content": "Your outstanding balance is $250.00, due by February 15, 2025.\n\nYou have several payment options available, including:\n- **Credit Card**\n- **Bank Transfer**\n- **PayPal**\n\nPlease let me know which option you'd like to use, and I'll guide you through the process!", - "current_turn": true - }, - { - "sender": "Outstanding Payments >> Post process", - "role": "assistant", - // Response is user-facing - "response_type": "external", - "content": "Your outstanding balance is $250.00, due by February 15, 2025. \n\nPayment options include:\n- **Credit Card:** You can use your saved Visa card ending in 1234.\n- **Bank Transfer**\n- **PayPal**\n\nLet me know your preferred payment method, and I’ll assist you!", - "current_turn": true, + "content": "What services do you offer?" } ], "state": { - "agent_data": [ - // Omitted for brevity - ], - "last_agent_name": "Outstanding Payments" + "last_agent_name": "MainAgent" } +}' +``` + +## API Specification + +### Request Schema + +```typescript +{ + // Required fields + messages: Message[]; // Array of message objects representing the conversation history + state: any; // State object from previous response, or null for first message + + // Optional fields + workflowId?: string; // Specific workflow ID to use (defaults to production workflow) + testProfileId?: string; // Test profile ID for simulation } -``` \ No newline at end of file +``` + +### Message Types + +Messages can be one of the following types: + +1. System Message +```typescript +{ + role: "system"; + content: string; +} +``` + +2. User Message +```typescript +{ + role: "user"; + content: string; +} +``` + +3. Assistant Message +```typescript +{ + role: "assistant"; + content: string; + agenticResponseType: "internal" | "external"; + agenticSender?: string | null; +} +``` + +### Response Schema + +```typescript +{ + messages: Message[]; // Array of new messages from this turn + state: any; // State object to pass in the next request +} +``` + +## Important Notes + +1. Always pass the complete conversation history in the `messages` array +2. Always include the `state` from the previous response in your next request +3. The last message in the response's `messages` array will be a user-facing assistant message (`agenticResponseType: "external"`) + +## Rate Limiting + +The API has rate limits per project. If exceeded, you'll receive a 429 status code. + +## Error Responses + +- 400: Invalid request body or missing/invalid Authorization header +- 403: Invalid API key +- 404: Project or workflow not found +- 429: Rate limit exceeded \ No newline at end of file diff --git a/apps/docs/docs/using_the_sdk.md b/apps/docs/docs/using_the_sdk.md index 802b5a3e..c867bcbc 100644 --- a/apps/docs/docs/using_the_sdk.md +++ b/apps/docs/docs/using_the_sdk.md @@ -13,13 +13,68 @@ This is a guide on using the RowBoat Python SDK as an alternative to the [RowBoa ## Usage -### Basic Usage +### Basic Usage with StatefulChat -Initialize a client and use the chat method directly: +The easiest way to interact with Rowboat is using the `StatefulChat` class, which maintains conversation state automatically: ```python -from rowboat import Client -from rowboat.schema import UserMessage, SystemMessage +from rowboat import Client, StatefulChat + +# Initialize the client +client = Client( + host="", + project_id="", + api_key="" +) + +# Create a stateful chat session +chat = StatefulChat(client) + +# Have a conversation +response = chat.run("What is the capital of France?") +print(response) +# The capital of France is Paris. + +# Continue the conversation - the context is maintained automatically +response = chat.run("What other major cities are in that country?") +print(response) +# Other major cities in France include Lyon, Marseille, Toulouse, and Nice. + +response = chat.run("What's the population of the first city you mentioned?") +print(response) +# Lyon has a population of approximately 513,000 in the city proper. +``` + +### Advanced Usage + +#### Using a specific workflow + +You can specify a workflow ID to use a particular conversation configuration: + +```python +chat = StatefulChat( + client, + workflow_id="" +) +``` + +#### Using a test profile + +You can specify a test profile ID to use a specific test configuration: + +```python +chat = StatefulChat( + client, + test_profile_id="" +) +``` + +### Low-Level Usage + +For more control over the conversation, you can use the `Client` class directly: + +```python +from rowboat.schema import UserMessage # Initialize the client client = Client( @@ -30,57 +85,15 @@ client = Client( # Create messages messages = [ - SystemMessage(role='system', content="You are a helpful assistant"), UserMessage(role='user', content="Hello, how are you?") ] # Get response -response_messages, state = client.chat(messages=messages) -print(response_messages[-1].content) +response = client.chat(messages=messages) +print(response.messages[-1].content) -# For subsequent messages, include previous messages and state -messages.extend(response_messages) +# For subsequent messages, you need to manage the message history and state manually +messages.extend(response.messages) messages.append(UserMessage(role='user', content="What's your name?")) -response_messages, state = client.chat(messages=messages, state=state) -``` - -### Using Tools - -The SDK supports function calling through tools: - -```python -def weather_lookup(city_name: str) -> str: - return f"The weather in {city_name} is 22°C." - -# Create a tools dictionary -tools = { - 'weather_lookup': weather_lookup -} - -# Use tools with the chat method -response_messages, state = client.chat( - messages=messages, - tools=tools -) -``` -The last message in `response_messages` is either a user-facing response or a tool call by the assistant. - -### Stateful Chat (Convenience Wrapper) - -For simpler use cases, the SDK provides a `StatefulChat` class that maintains conversation state automatically: - -```python -from rowboat import StatefulChat - -# Initialize stateful chat -chat = StatefulChat( - client, - tools=tools, - system_prompt="You are a helpful assistant." -) - -# Simply send messages and get responses -response = chat.run("Hello, how are you?") -print(response) -# I'm good, thanks! How can I help you today? +response = client.chat(messages=messages, state=response.state) ``` \ No newline at end of file diff --git a/apps/python-sdk/README.md b/apps/python-sdk/README.md index e4442035..91a0b461 100644 --- a/apps/python-sdk/README.md +++ b/apps/python-sdk/README.md @@ -12,13 +12,68 @@ pip install rowboat ## Usage -### Basic Usage +### Basic Usage with StatefulChat -Initialize a client and use the chat method directly: +The easiest way to interact with Rowboat is using the `StatefulChat` class, which maintains conversation state automatically: ```python -from rowboat import Client -from rowboat.schema import UserMessage, SystemMessage +from rowboat import Client, StatefulChat + +# Initialize the client +client = Client( + host="", + project_id="", + api_key="" +) + +# Create a stateful chat session +chat = StatefulChat(client) + +# Have a conversation +response = chat.run("What is the capital of France?") +print(response) +# The capital of France is Paris. + +# Continue the conversation - the context is maintained automatically +response = chat.run("What other major cities are in that country?") +print(response) +# Other major cities in France include Lyon, Marseille, Toulouse, and Nice. + +response = chat.run("What's the population of the first city you mentioned?") +print(response) +# Lyon has a population of approximately 513,000 in the city proper. +``` + +### Advanced Usage + +#### Using a specific workflow + +You can specify a workflow ID to use a particular conversation configuration: + +```python +chat = StatefulChat( + client, + workflow_id="" +) +``` + +#### Using a test profile + +You can specify a test profile ID to use a specific test configuration: + +```python +chat = StatefulChat( + client, + test_profile_id="" +) +``` + +### Low-Level Usage + +For more control over the conversation, you can use the `Client` class directly: + +```python +from rowboat.schema import UserMessage # Initialize the client client = Client( @@ -29,108 +84,15 @@ client = Client( # Create messages messages = [ - SystemMessage(role='system', content="You are a helpful assistant"), UserMessage(role='user', content="Hello, how are you?") ] # Get response -response_messages, state = client.chat(messages=messages) -print(response_messages[-1].content) +response = client.chat(messages=messages) +print(response.messages[-1].content) -# For subsequent messages, include previous messages and state -messages.extend(response_messages) +# For subsequent messages, you need to manage the message history and state manually +messages.extend(response.messages) messages.append(UserMessage(role='user', content="What's your name?")) -response_messages, state = client.chat(messages=messages, state=state) -``` - -### Using Tools - -The SDK supports function calling through tools: - -```python -def weather_lookup(city_name: str) -> str: - return f"The weather in {city_name} is 22°C." - -# Create a tools dictionary -tools = { - 'weather_lookup': weather_lookup -} - -# Use tools with the chat method -response_messages, state = client.chat( - messages=messages, - tools=tools -) -``` - -### Stateful Chat (Convenience Wrapper) - -For simpler use cases, the SDK provides a `StatefulChat` class that maintains conversation state automatically: - -```python -from rowboat import StatefulChat - -# Initialize stateful chat -chat = StatefulChat( - client, - tools=tools, - system_prompt="You are a helpful assistant." -) - -# Simply send messages and get responses -response = chat.run("Hello, how are you?") -print(response) -# I'm good, thanks! How can I help you today? -``` - -### Advanced Usage - -#### Using a specific workflow - -```python -response_messages, state = client.chat( - messages=messages, - workflow_id="" -) - -# or - -chat = StatefulChat( - client, - workflow_id="" -) -``` - -#### Using a test profile -You can specify a test profile ID to use a specific test configuration: - -```python -response_messages, state = client.chat( - messages=messages, - test_profile_id="" -) - -# or - -chat = StatefulChat( - client, - test_profile_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 -) +response = client.chat(messages=messages, state=response.state) ``` diff --git a/apps/python-sdk/pyproject.toml b/apps/python-sdk/pyproject.toml index 6d1cabdc..b107d8b6 100644 --- a/apps/python-sdk/pyproject.toml +++ b/apps/python-sdk/pyproject.toml @@ -4,9 +4,9 @@ build-backend = "hatchling.build" [project] name = "rowboat" -version = "2.1.0" +version = "3.0.0" authors = [ - { name = "Your Name", email = "your.email@example.com" }, + { name = "Ramnique Singh", email = "ramnique@rowboatlabs.com" }, ] description = "Python sdk for the Rowboat API" readme = "README.md" diff --git a/apps/python-sdk/src/rowboat/client.py b/apps/python-sdk/src/rowboat/client.py index 2997ed08..d270c0c5 100644 --- a/apps/python-sdk/src/rowboat/client.py +++ b/apps/python-sdk/src/rowboat/client.py @@ -1,18 +1,14 @@ -from typing import Dict, List, Optional, Any, Callable, Union, Tuple +from typing import Dict, List, Optional, Any, Union import requests -import json from .schema import ( ApiRequest, ApiResponse, ApiMessage, - ToolMessage, UserMessage, - SystemMessage, AssistantMessage, AssistantMessageWithToolCalls ) - class Client: def __init__(self, host: str, project_id: str, api_key: str) -> None: self.base_url: str = f'{host}/api/v1/{project_id}/chat' @@ -25,16 +21,12 @@ class Client: self, messages: List[ApiMessage], state: Optional[Dict[str, Any]] = None, - skip_tool_calls: bool = False, - max_turns: int = 3, workflow_id: Optional[str] = None, test_profile_id: Optional[str] = None ) -> ApiResponse: request = ApiRequest( messages=messages, state=state, - skipToolCalls=skip_tool_calls, - maxTurns=max_turns, workflowId=workflow_id, testProfileId=test_profile_id ) @@ -55,86 +47,27 @@ class Client: return response_data - def _process_tool_calls( - self, - tool_calls: List[Any], - tools: Dict[str, Callable[..., str]] - ) -> List[ToolMessage]: - """Process tool calls and return a list of tool response messages""" - tool_messages = [] - for tool_call in tool_calls: - tool_name = tool_call.function.name - tool_arguments = json.loads(tool_call.function.arguments) - - if tool_name not in tools: - raise ValueError(f'Missing tool: {tool_name}') - - tool_response = tools[tool_name](**tool_arguments) - tool_msg = ToolMessage( - role='tool', - content=tool_response, - tool_call_id=tool_call.id, - tool_name=tool_name - ) - tool_messages.append(tool_msg) - return tool_messages - def chat( self, messages: List[ApiMessage], - tools: Optional[Dict[str, Callable[..., str]]] = None, state: Optional[Dict[str, Any]] = None, - max_turns: int = 3, - skip_tool_calls: bool = False, workflow_id: Optional[str] = None, test_profile_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""" + ) -> ApiResponse: + """Stateless chat method that handles a single conversation turn""" - current_messages = messages[:] - current_state = state - turns = 0 + # call api + response_data = self._call_api( + messages=messages, + state=state, + workflow_id=workflow_id, + test_profile_id=test_profile_id + ) - response_messages = [] - response_state = None - has_tool_calls = False - - while turns < max_turns: - # call api - response_data = self._call_api( - messages=current_messages, - state=current_state, - skip_tool_calls=skip_tool_calls, - max_turns=max_turns, - workflow_id=workflow_id, - test_profile_id=test_profile_id - ) - - current_messages.extend(response_data.messages) - current_state = response_data.state - response_messages = response_data.messages - response_state = response_data.state - - # Process tool calls if present and tools are provided - last_message = response_data.messages[-1] - has_tool_calls = hasattr(last_message, 'tool_calls') and last_message.tool_calls - if has_tool_calls: - tool_messages = self._process_tool_calls(last_message.tool_calls, tools) - current_messages.extend(tool_messages) - - # If no tool calls were made, we're done - if not has_tool_calls: - break - - turns += 1 - - if turns == max_turns and has_tool_calls: - raise ValueError("Max turns reached") - - if not last_message.agenticResponseType == 'external': + if not response_data.messages[-1].agenticResponseType == 'external': raise ValueError("Last message was not an external message") - return response_messages, response_state + return response_data class StatefulChat: """Maintains conversation state across multiple turns""" @@ -142,23 +75,14 @@ class StatefulChat: def __init__( self, client: Client, - tools: Optional[Dict[str, Callable[..., str]]] = None, - system_prompt: Optional[str] = None, - max_turns: int = 3, - skip_tool_calls: bool = False, workflow_id: Optional[str] = None, test_profile_id: Optional[str] = None ) -> None: self.client = client - self.tools = tools self.messages: List[ApiMessage] = [] self.state: Optional[Dict[str, Any]] = None - self.max_turns = max_turns - self.skip_tool_calls = skip_tool_calls self.workflow_id = workflow_id self.test_profile_id = test_profile_id - if system_prompt: - self.messages.append(SystemMessage(role='system', content=system_prompt)) def run(self, message: Union[str]) -> str: """Handle a single user turn in the conversation""" @@ -168,22 +92,19 @@ class StatefulChat: self.messages.append(user_msg) # Get response using the client's chat method - new_messages, new_state = self.client.chat( + response_data = self.client.chat( messages=self.messages, - tools=self.tools, state=self.state, - max_turns=self.max_turns, - skip_tool_calls=self.skip_tool_calls, workflow_id=self.workflow_id, test_profile_id=self.test_profile_id ) # Update internal state - self.messages = new_messages - self.state = new_state + self.messages = response_data.messages + self.state = response_data.state # Return only the final message content - last_message = new_messages[-1] + last_message = self.messages[-1] return last_message.content @@ -197,9 +118,13 @@ if __name__ == "__main__": api_key: str = "" client = Client(host, project_id, api_key) - tools: Dict[str, Callable[..., str]] = { - 'weather_lookup': weather_lookup_tool - } - chat_session = StatefulChat(client, tools) - resp = chat_session.run("whats the weather in london?") + result = client.chat( + messages=[ + UserMessage(role='user', content="Hello") + ] + ) + print(result.messages[-1].content) + + chat_session = StatefulChat(client) + resp = chat_session.run("Hello") print(resp) \ No newline at end of file diff --git a/apps/python-sdk/src/rowboat/schema.py b/apps/python-sdk/src/rowboat/schema.py index c95d4554..0ee959dc 100644 --- a/apps/python-sdk/src/rowboat/schema.py +++ b/apps/python-sdk/src/rowboat/schema.py @@ -48,8 +48,6 @@ ApiMessage = Union[ class ApiRequest(BaseModel): messages: List[ApiMessage] state: Any - skipToolCalls: Optional[bool] = None - maxTurns: Optional[int] = None workflowId: Optional[str] = None testProfileId: Optional[str] = None diff --git a/apps/rowboat/app/lib/types/types.ts b/apps/rowboat/app/lib/types/types.ts index 911d857c..c4544d6b 100644 --- a/apps/rowboat/app/lib/types/types.ts +++ b/apps/rowboat/app/lib/types/types.ts @@ -111,8 +111,6 @@ export const ApiMessage = z.union([ export const ApiRequest = z.object({ messages: z.array(ApiMessage), state: z.unknown(), - skipToolCalls: z.boolean().nullable().optional(), - maxTurns: z.number().nullable().optional(), workflowId: z.string().nullable().optional(), testProfileId: z.string().nullable().optional(), });