Skip to content

Commit b7369dc

Browse files
authored
refactor: Together AI using beta client for structured output & support llama4 (camel-ai#2168)
1 parent 9124073 commit b7369dc

File tree

4 files changed

+149
-44
lines changed

4 files changed

+149
-44
lines changed

camel/models/togetherai_model.py

Lines changed: 106 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,70 +96,145 @@ def __init__(
9696
base_url=self._url,
9797
)
9898

99-
async def _arun(
99+
@property
100+
def token_counter(self) -> BaseTokenCounter:
101+
r"""Initialize the token counter for the model backend.
102+
103+
Returns:
104+
BaseTokenCounter: The token counter following the model's
105+
tokenization style.
106+
"""
107+
if not self._token_counter:
108+
self._token_counter = OpenAITokenCounter(ModelType.GPT_4O_MINI)
109+
return self._token_counter
110+
111+
def _run(
100112
self,
101113
messages: List[OpenAIMessage],
102114
response_format: Optional[Type[BaseModel]] = None,
103115
tools: Optional[List[Dict[str, Any]]] = None,
104-
) -> Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
116+
) -> Union[ChatCompletion, Stream[ChatCompletionChunk]]:
105117
r"""Runs inference of OpenAI chat completion.
106118
107119
Args:
108120
messages (List[OpenAIMessage]): Message list with the chat history
109121
in OpenAI API format.
122+
response_format (Optional[Type[BaseModel]]): The format of the
123+
response.
124+
tools (Optional[List[Dict[str, Any]]]): The schema of the tools to
125+
use for the request.
110126
111127
Returns:
112-
Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
128+
Union[ChatCompletion, Stream[ChatCompletionChunk]]:
113129
`ChatCompletion` in the non-stream mode, or
114-
`AsyncStream[ChatCompletionChunk]` in the stream mode.
130+
`Stream[ChatCompletionChunk]` in the stream mode.
115131
"""
116-
# Use OpenAI client as interface call Together AI
117-
# Reference: https://docs.together.ai/docs/openai-api-compatibility
118-
response = await self._async_client.chat.completions.create(
119-
messages=messages,
120-
model=self.model_type,
121-
**self.model_config_dict,
132+
response_format = response_format or self.model_config_dict.get(
133+
"response_format", None
122134
)
123-
return response
135+
if response_format:
136+
return self._request_parse(messages, response_format, tools)
137+
else:
138+
return self._request_chat_completion(messages, tools)
124139

125-
def _run(
140+
async def _arun(
126141
self,
127142
messages: List[OpenAIMessage],
128143
response_format: Optional[Type[BaseModel]] = None,
129144
tools: Optional[List[Dict[str, Any]]] = None,
130-
) -> Union[ChatCompletion, Stream[ChatCompletionChunk]]:
131-
r"""Runs inference of OpenAI chat completion.
145+
) -> Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
146+
r"""Runs inference of OpenAI chat completion in async mode.
132147
133148
Args:
134149
messages (List[OpenAIMessage]): Message list with the chat history
135150
in OpenAI API format.
151+
response_format (Optional[Type[BaseModel]]): The format of the
152+
response.
153+
tools (Optional[List[Dict[str, Any]]]): The schema of the tools to
154+
use for the request.
136155
137156
Returns:
138-
Union[ChatCompletion, Stream[ChatCompletionChunk]]:
157+
Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
139158
`ChatCompletion` in the non-stream mode, or
140-
`Stream[ChatCompletionChunk]` in the stream mode.
159+
`AsyncStream[ChatCompletionChunk]` in the stream mode.
141160
"""
142-
# Use OpenAI client as interface call Together AI
143-
# Reference: https://docs.together.ai/docs/openai-api-compatibility
144-
response = self._client.chat.completions.create(
161+
response_format = response_format or self.model_config_dict.get(
162+
"response_format", None
163+
)
164+
if response_format:
165+
return await self._arequest_parse(messages, response_format, tools)
166+
else:
167+
return await self._arequest_chat_completion(messages, tools)
168+
169+
def _request_chat_completion(
170+
self,
171+
messages: List[OpenAIMessage],
172+
tools: Optional[List[Dict[str, Any]]] = None,
173+
) -> Union[ChatCompletion, Stream[ChatCompletionChunk]]:
174+
request_config = self.model_config_dict.copy()
175+
176+
if tools:
177+
request_config["tools"] = tools
178+
179+
return self._client.chat.completions.create(
145180
messages=messages,
146181
model=self.model_type,
147-
**self.model_config_dict,
182+
**request_config,
148183
)
149-
return response
150184

151-
@property
152-
def token_counter(self) -> BaseTokenCounter:
153-
r"""Initialize the token counter for the model backend.
185+
async def _arequest_chat_completion(
186+
self,
187+
messages: List[OpenAIMessage],
188+
tools: Optional[List[Dict[str, Any]]] = None,
189+
) -> Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]:
190+
request_config = self.model_config_dict.copy()
154191

155-
Returns:
156-
OpenAITokenCounter: The token counter following the model's
157-
tokenization style.
158-
"""
192+
if tools:
193+
request_config["tools"] = tools
159194

160-
if not self._token_counter:
161-
self._token_counter = OpenAITokenCounter(ModelType.GPT_4O_MINI)
162-
return self._token_counter
195+
return await self._async_client.chat.completions.create(
196+
messages=messages,
197+
model=self.model_type,
198+
**request_config,
199+
)
200+
201+
def _request_parse(
202+
self,
203+
messages: List[OpenAIMessage],
204+
response_format: Type[BaseModel],
205+
tools: Optional[List[Dict[str, Any]]] = None,
206+
) -> ChatCompletion:
207+
request_config = self.model_config_dict.copy()
208+
209+
request_config["response_format"] = response_format
210+
211+
if tools is not None:
212+
request_config["tools"] = tools
213+
214+
return self._client.beta.chat.completions.parse(
215+
messages=messages,
216+
model=self.model_type,
217+
**request_config,
218+
)
219+
220+
async def _arequest_parse(
221+
self,
222+
messages: List[OpenAIMessage],
223+
response_format: Type[BaseModel],
224+
tools: Optional[List[Dict[str, Any]]] = None,
225+
) -> ChatCompletion:
226+
request_config = self.model_config_dict.copy()
227+
228+
request_config["response_format"] = response_format
229+
230+
if tools is not None:
231+
request_config["tools"] = tools
232+
233+
return await self._async_client.beta.chat.completions.parse(
234+
messages=messages,
235+
model=self.model_type,
236+
**request_config,
237+
)
163238

164239
def check_model_config(self):
165240
r"""Check whether the model configuration contains any

camel/toolkits/browser_toolkit.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ def _observe(
11751175
message = BaseMessage.make_user_message(
11761176
role_name='user', content=observe_prompt, image_list=[img]
11771177
)
1178-
r""" Reset the history message of web_agent. Important history information is already included in the history field in observe_prompt."""
1178+
# Reset the history message of web_agent.
11791179
self.web_agent.reset()
11801180
resp = self.web_agent.step(message)
11811181

@@ -1406,7 +1406,7 @@ def _task_replanning(
14061406
- `if_need_replan`: bool, A boolean value indicating whether the task needs to be fundamentally replanned.
14071407
- `replanned_schema`: str, The replanned schema for the task, which should not be changed too much compared with the original one. If the task does not need to be replanned, the value should be an empty string.
14081408
"""
1409-
r""" Reset the history message of planning_agent. Important history information is already included in the history field in replanning_prompt."""
1409+
# Reset the history message of planning_agent.
14101410
self.planning_agent.reset()
14111411
resp = self.planning_agent.step(replanning_prompt)
14121412
resp_dict = _parse_json_output(resp.msgs[0].content)

camel/types/enums.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ class ModelType(UnifiedModelType, Enum):
7979
TOGETHER_LLAMA_3_3_70B = "meta-llama/Llama-3.3-70B-Instruct-Turbo"
8080
TOGETHER_MIXTRAL_8_7B = "mistralai/Mixtral-8x7B-Instruct-v0.1"
8181
TOGETHER_MISTRAL_7B = "mistralai/Mistral-7B-Instruct-v0.1"
82+
TOGETHER_LLAMA_4_MAVERICK = (
83+
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8"
84+
)
85+
TOGETHER_LLAMA_4_SCOUT = "meta-llama/Llama-4-Scout-17B-16E-Instruct"
8286

8387
# PPIO platform models support tool calling
8488
PPIO_DEEPSEEK_R1_TURBO = "deepseek/deepseek-r1-turbo"
@@ -851,11 +855,13 @@ def token_limit(self) -> int:
851855
ModelType.GEMINI_2_0_FLASH_LITE_PREVIEW,
852856
ModelType.GEMINI_2_0_PRO_EXP, # Not given in doc, assume the same
853857
ModelType.GLM_4_LONG,
858+
ModelType.TOGETHER_LLAMA_4_MAVERICK,
859+
ModelType.OPENROUTER_LLAMA_4_MAVERICK,
854860
}:
855861
return 1_048_576
856862
elif self in {
857863
ModelType.QWEN_LONG,
858-
ModelType.OPENROUTER_LLAMA_4_MAVERICK,
864+
ModelType.TOGETHER_LLAMA_4_SCOUT,
859865
}:
860866
return 10_000_000
861867
else:

examples/models/togetherai_model_example.py

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@
1414
from camel.agents import ChatAgent
1515
from camel.configs import TogetherAIConfig
1616
from camel.models import ModelFactory
17-
from camel.types import ModelPlatformType
17+
from camel.types import ModelPlatformType, ModelType
1818

1919
model = ModelFactory.create(
2020
model_platform=ModelPlatformType.TOGETHER,
21-
model_type="meta-llama/Llama-3-8b-chat-hf",
21+
model_type=ModelType.TOGETHER_LLAMA_4_MAVERICK,
2222
model_config_dict=TogetherAIConfig(temperature=0.2).as_dict(),
2323
)
2424

2525
# Define system message
2626
sys_msg = "You are a helpful assistant."
2727

2828
# Set agent
29-
camel_agent = ChatAgent(system_message=sys_msg, model=model, token_limit=500)
29+
camel_agent = ChatAgent(system_message=sys_msg, model=model)
3030

3131
user_msg = """Say hi to CAMEL AI, one open-source community dedicated to the
3232
study of autonomous and communicative agents."""
@@ -36,14 +36,38 @@
3636
print(response.msgs[0].content)
3737
'''
3838
===============================================================================
39-
Hello CAMEL AI community!
39+
Hello CAMEL AI! It's great to connect with an open-source community that's
40+
pushing the boundaries of autonomous and communicative agents. I'm excited to
41+
learn more about the innovative work being done here. What are some of the
42+
most interesting projects or research areas that CAMEL AI is currently
43+
exploring?
44+
===============================================================================
45+
'''
46+
47+
model = ModelFactory.create(
48+
model_platform=ModelPlatformType.TOGETHER,
49+
model_type=ModelType.TOGETHER_LLAMA_3_3_70B,
50+
model_config_dict=TogetherAIConfig(temperature=0.2).as_dict(),
51+
)
4052

41-
I'm thrilled to be here and assist you with any questions or topics related to
42-
autonomous and communicative agents. As an open-source community, I'm excited
43-
to see the innovative projects and research being developed by your members.
53+
# Define system message
54+
sys_msg = "You are a helpful assistant."
4455

45-
What's on your mind? Do you have a specific question, project, or topic you'd
46-
like to discuss? I'm here to help and provide any assistance I can. Let's get
47-
started!
56+
# Set agent
57+
camel_agent = ChatAgent(system_message=sys_msg, model=model)
58+
59+
user_msg = """Say hi to CAMEL AI, one open-source community dedicated to the
60+
study of autonomous and communicative agents."""
61+
62+
# Get response information
63+
response = camel_agent.step(user_msg)
64+
print(response.msgs[0].content)
65+
'''
66+
===============================================================================
67+
Hello CAMEL AI community. It's great to connect with a group of like-minded
68+
individuals dedicated to advancing the field of autonomous and communicative
69+
agents. Your open-source approach to sharing knowledge and resources is truly
70+
commendable, and I'm excited to see the innovative projects and research that
71+
come out of your community. How can I assist or contribute to your endeavors?
4872
===============================================================================
4973
'''

0 commit comments

Comments
 (0)