Migrating From API v1 to API v2

This guide serves as a reference for developers looking to update their code that uses Cohere API v1 in favor of the new v2 standard. It outlines the key differences and necessary changes when migrating from Cohere API v1 to v2 and the various aspects of the API, including chat functionality, RAG (Retrieval-Augmented Generation), and tool use. Each section provides code examples for both v1 and v2, highlighting the structural changes in request formats, response handling, and new features introduced in v2.

PYTHON
1# ! pip install -U cohere
2
3import cohere
4
5# instantiating the old client
6co_v1 = cohere.Client(api_key="<YOUR API KEY>")
7
8# instantiating the new client
9co_v2 = cohere.ClientV2(api_key="<YOUR API KEY>")

General

  • v2: model is a required field for Embed, Rerank, Classify, and Chat.

Embed

  • v2: embedding_types is a required field for Embed.

Chat

Messages and preamble

  • Message structure:

    • v1: uses separate preamble and message parameters.
    • v2: uses a single messages parameter consisting of a list of roles (system, user, assistant, or tool). The system role in v2 replaces the preamble parameter in v1.
  • Chat history:

    • v1: manages the chat history via the chat_history parameter.
    • v2: manages the chat history via the messages list.

v1

PYTHON
1res = co_v1.chat(
2 model="command-r-plus-08-2024",
3 preamble="You respond in concise sentences.",
4 chat_history=[
5 {
6 "role": "user",
7 "message": "Hello"
8 },
9 {
10 "role": "chatbot",
11 "message": "Hi, how can I help you today?"
12 }
13 ],
14 message="I'm joining a new startup called Co1t today. Could you help me write a one-sentence introduction message to my teammates?")
15
16print(res.text)
Excited to join the team at Co1t, where I look forward to contributing my skills and collaborating with everyone to drive innovation and success.

v2

PYTHON
1res = co_v2.chat(
2 model="command-r-plus-08-2024",
3 messages=[
4 {
5 "role": "system",
6 "content": "You respond in concise sentences."
7 },
8 {
9 "role": "user",
10 "content": "Hello"
11 },
12 {
13 "role": "assistant",
14 "content": "Hi, how can I help you today?"
15 },
16 {
17 "role": "user",
18 "content": "I'm joining a new startup called Co1t today. Could you help me write a one-sentence introduction message to my teammates."
19 }
20 ])
21
22print(res.message.content[0].text)
Excited to join the team at Co1t, bringing my passion for innovation and a background in [your expertise] to contribute to the company's success!

Response content

  • v1: Accessed via text
  • v2: Accessed via message.content[0].text

v1

PYTHON
1res = co_v1.chat(model="command-r-plus-08-2024",
2 message="What is 2 + 2")
3
4print(res.text)
The answer is 4.

v2

PYTHON
1res = co_v2.chat(model="command-r-plus-08-2024",
2 messages=[
3 {
4 "role": "user",
5 "content": "What is 2 + 2"
6 }
7 ])
8
9print(res.message.content[0].text)
The answer is 4.

Streaming

  • Events containing content:

    • v1: chunk.event_type == "text-generation"
    • v2: chunk.type == "content-delta"
  • Accessing response content:

    • v1: chunk.text
    • v2: chunk.delta.message.content.text

v1

PYTHON
1message = "I'm joining a new startup called Co1t today. Could you help me write a one-sentence introduction message to my teammates."
2
3res = co_v1.chat_stream(model="command-r-plus-08-2024",
4 message=message)
5
6for chunk in res:
7 if chunk.event_type == "text-generation":
8 print(chunk.text, end="")
"Hi, I'm [your name] and I'm thrilled to join the Co1t team today as a [your role], eager to contribute my skills and ideas to help drive innovation and success for our startup!"

v2

PYTHON
1message = "I'm joining a new startup called Co1t today. Could you help me write a one-sentence introduction message to my teammates."
2
3res = co_v2.chat_stream(model="command-r-plus-08-2024",
4 messages=[{"role": "user", "content": message}])
5
6for chunk in res:
7 if chunk:
8 if chunk.type == "content-delta":
9 print(chunk.delta.message.content.text, end="")
"Hi everyone, I'm thrilled to join the Co1t team today and look forward to contributing my skills and ideas to drive innovation and success!"

RAG

Documents

  • v1: the documents parameter supports a list of objects with multiple fields per document.
  • v2: the documents parameter supports a few different options for structuring documents:
    • List of objects with data object: same as v1 described above, but each document passed as a data object (with an optional id field to be used in citations).
    • List of objects with data string (with an optional id field to be used in citations).
    • List of strings.

v1

PYTHON
1# Define the documents
2documents_v1 = [
3 {"text": "Reimbursing Travel Expenses: Easily manage your travel expenses by submitting them through our finance tool. Approvals are prompt and straightforward."},
4 {"text": "Health and Wellness Benefits: We care about your well-being and offer gym memberships, on-site yoga classes, and comprehensive health insurance."}
5]
6
7# The user query
8message = "Are there fitness-related benefits?"
9
10# Generate the response
11res_v1 = co_v1.chat(model="command-r-plus-08-2024",
12 message=message,
13 documents=documents_v1)
14
15print(res_v1.text)
Yes, there are fitness-related benefits. We offer gym memberships, on-site yoga classes, and comprehensive health insurance.

v2

PYTHON
1# Define the documents
2documents_v2 = [
3 {
4 "data": {
5 "text": "Reimbursing Travel Expenses: Easily manage your travel expenses by submitting them through our finance tool. Approvals are prompt and straightforward."
6 }
7 },
8 {
9 "data": {
10 "text": "Health and Wellness Benefits: We care about your well-being and offer gym memberships, on-site yoga classes, and comprehensive health insurance."
11 }
12 }
13]
14
15# The user query
16message = "Are there fitness-related benefits?"
17
18# Generate the response
19res_v2 = co_v2.chat(model="command-r-plus-08-2024",
20 messages=[{"role": "user", "content": message}],
21 documents=documents_v2)
22
23print(res_v2.message.content[0].text)
Yes, we offer gym memberships, on-site yoga classes, and comprehensive health insurance.

The following is a list of the the different options for structuring documents for RAG in v2.

PYTHON
1documents_v2 = [
2# List of objects with data string
3{
4 "id": "123"
5 "data": "I love penguins. they are fluffy",
6},
7# List of objects with data object
8{"id": "456", "data": {
9 "text": "I love penguins. they are fluffy",
10 "author": "Abdullah",
11 "create_date": "09021989"
12 }
13},
14# List of strings
15"just a string"
16]

Citations

  • Citations access:
    • v1: citations
    • v2: message.citations
  • Cited documents access:
    • v1: documents
    • v2: as part of message.citations, in the sources field

v1

PYTHON
1# Yes, there are fitness-related benefits. We offer gym memberships, on-site yoga classes, and comprehensive health insurance.
2
3print(res_v1.citations)
4print(res_v1.documents)
[ChatCitation(start=50, end=124, text='gym memberships, on-site yoga classes, and comprehensive health insurance.', document_ids=['doc_1'])]
[{'id': 'doc_1', 'text': 'Health and Wellness Benefits: We care about your well-being and offer gym memberships, on-site yoga classes, and comprehensive health insurance.'}]

v2

PYTHON
1# Yes, we offer gym memberships, on-site yoga classes, and comprehensive health insurance.
2
3print(res_v2.message.citations)
[Citation(start=14, end=88, text='gym memberships, on-site yoga classes, and comprehensive health insurance.', sources=[DocumentSource(type='document', id='doc:1', document={'id': 'doc:1', 'text': 'Health and Wellness Benefits: We care about your well-being and offer gym memberships, on-site yoga classes, and comprehensive health insurance.'})])]

Search query generation

  • v1: Uses search_queries_only parameter
  • v2: Supported via tools. We recommend using the v1 API for this functionality in order to leverage the force_single_step feature. Support in v2 will be coming soon.

Connectors

  • v1: Supported via the web-search connector in the connectors parameter
  • v2: Supported via user-defined tools.

v1

Uses the web search connector to search the internet for information relevant to the user’s query.

PYTHON
1res_v1 = co_v1.chat(
2 message="who won euro 2024",
3 connectors=[{"id": "web-search"}],
4)
5
6print(res_v1.text)
Spain won the UEFA Euro 2024, defeating England 2-1 in the final.

v2

Web search functionality is supported via tools.

PYTHON
1# Any search engine can be used. This example uses the Tavily API.
2from tavily import TavilyClient
3
4tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
5
6
7# Create a web search function
8def web_search(queries: list[str]) -> list[dict]:
9
10 documents = []
11
12 for query in queries:
13 response = tavily_client.search(query, max_results=2)
14
15 results = [
16 {"title": r["title"], "content": r["content"], "url": r["url"]}
17 for r in response["results"]
18 ]
19
20 for idx, result in enumerate(results):
21 document = {"id": str(idx), "data": result}
22 documents.append(document)
23
24 return documents
25
26
27# Define the web search tool
28web_search_tool = [
29 {
30 "type": "function",
31 "function": {
32 "name": "web_search",
33 "description": "Returns a list of relevant document snippets for a textual query retrieved from the internet",
34 "parameters": {
35 "type": "object",
36 "properties": {
37 "queries": {
38 "type": "array",
39 "items": {"type": "string"},
40 "description": "a list of queries to search the internet with.",
41 }
42 },
43 "required": ["queries"],
44 },
45 },
46 }
47]
48
49# The user query
50query = "who won euro 2024"
51
52# Define a preamble to optimize search query generation
53instructions = "Write a search query that will find helpful information for answering the user's question accurately. If you need more than one search query, write a list of search queries. If you decide that a search is very unlikely to find information that would be useful in constructing a response to the user, you should instead directly answer."
54
55messages = [
56 {"role": "system", "content": instructions},
57 {"role": "user", "content": query},
58]
59
60model = "command-r-plus-08-2024"
61
62# Generate search queries (if any)
63response = co_v2.chat(model=model, messages=messages, tools=web_search_tool)
64
65search_queries = []
66
67while response.message.tool_calls:
68
69 print("Tool plan:")
70 print(response.message.tool_plan, "\n")
71 print("Tool calls:")
72 for tc in response.message.tool_calls:
73 print(f"Tool name: {tc.function.name} | Parameters: {tc.function.arguments}")
74 print("=" * 50)
75
76 messages.append(
77 {
78 "role": "assistant",
79 "tool_calls": response.message.tool_calls,
80 "tool_plan": response.message.tool_plan,
81 }
82 )
83
84 # Step 3: Get tool results
85 for idx, tc in enumerate(response.message.tool_calls):
86 tool_result = web_search(**json.loads(tc.function.arguments))
87 tool_content = []
88 for data in tool_result:
89 tool_content.append({"type": "document", "document": {"data": json.dumps(data)}})
90 # Optional: add an "id" field in the "document" object, otherwise IDs are auto-generated
91 messages.append(
92 {"role": "tool", "tool_call_id": tc.id, "content": tool_content}
93 )
94
95 # Step 4: Generate response and citations
96 response = co_v2.chat(model=model, messages=messages, tools=web_search_tool)
97
98print(response.message.content[0].text)
Tool plan:
I will search for 'who won euro 2024' to find out who won the competition.
Tool calls:
Tool name: web_search | Parameters: {"queries":["who won euro 2024"]}
==================================================
Spain won the 2024 European Championship. They beat England in the final, with substitute Mikel Oyarzabal scoring the winning goal.

Streaming

  • Event containing content:

    • v1: chunk.event_type == "text-generation"
    • v2: chunk.type == "content-delta"
  • Accessing response content:

    • v1: chunk.text
    • v2: chunk.delta.message.content.text
  • Events containing citations:

    • v1: chunk.event_type == "citation-generation"
    • v2: chunk.type == "citation-start"
  • Accessing citations:

    • v1: chunk.citations
    • v2: chunk.delta.message.citations

v1

PYTHON
1message = "Are there fitness-related benefits?"
2
3res_v1 = co_v1.chat_stream(model="command-r-plus-08-2024",
4 message=message,
5 documents=documents_v1)
6
7for chunk in res_v1:
8 if chunk.event_type == "text-generation":
9 print(chunk.text, end="")
10 if chunk.event_type == "citation-generation":
11 print(f"\n{chunk.citations}")
Yes, we offer gym memberships, on-site yoga classes, and comprehensive health insurance as part of our health and wellness benefits.
[ChatCitation(start=14, end=87, text='gym memberships, on-site yoga classes, and comprehensive health insurance', document_ids=['doc_1'])]
[ChatCitation(start=103, end=132, text='health and wellness benefits.', document_ids=['doc_1'])]

v2

PYTHON
1message = "Are there fitness-related benefits?"
2
3messages = [{"role": "user", "content": message}]
4
5res_v2 = co_v2.chat_stream(
6 model="command-r-plus-08-2024", messages=messages, documents=documents_v2
7)
8
9for chunk in res_v2:
10 if chunk:
11 if chunk.type == "content-delta":
12 print(chunk.delta.message.content.text, end="")
13 if chunk.type == "citation-start":
14 print(f"\n{chunk.delta.message.citations}")
Yes, we offer gym memberships, on-site yoga classes, and comprehensive health insurance.
start=14 end=88 text='gym memberships, on-site yoga classes, and comprehensive health insurance.' sources=[DocumentSource(type='document', id='doc:1', document={'id': 'doc:1', 'text': 'Health and Wellness Benefits: We care about your well-being and offer gym memberships, on-site yoga classes, and comprehensive health insurance.'})]

Tool use

Tool definition

  • v1: uses Python types to define tools.
  • v2: uses JSON schema to define tools.

v1

PYTHON
1def get_weather(location):
2 return {"temperature": "20C"}
3
4functions_map = {"get_weather": get_weather}
5
6tools_v1 = [
7 {
8 "name": "get_weather",
9 "description": "Gets the weather of a given location",
10 "parameter_definitions": {
11 "location": {
12 "description": "The location to get weather, example: San Francisco, CA",
13 "type": "str",
14 "required": True
15 }
16 }
17 },
18]

v2

PYTHON
1def get_weather(location):
2 return [{"temperature": "20C"}]
3 # You can return a list of objects e.g. [{"url": "abc.com", "text": "..."}, {"url": "xyz.com", "text": "..."}]
4
5functions_map = {"get_weather": get_weather}
6
7tools_v2 = [
8 {
9 "type": "function",
10 "function": {
11 "name": "get_weather",
12 "description" : "gets the weather of a given location",
13 "parameters": {
14 "type": "object",
15 "properties": {
16 "location": {
17 "type" : "str",
18 "description": "the location to get weather, example: San Fransisco, CA"
19 }
20 },
21 "required": ["location"]
22 }
23 }
24 },
25]

Tool calling

  • Response handling

    • v1: Tool calls accessed through response.tool_calls
    • v2: Tool calls accessed through response.message.tool_calls
  • Chat history management

    • v1: Tool calls stored in the response’s chat_history
    • v2: Append the tool call details (tool_calls and tool_plan) to the messages list

v1

PYTHON
1message = "What's the weather in Toronto?"
2
3res_v1 = co_v1.chat(model="command-r-plus-08-2024",
4 message=message,
5 tools=tools_v1)
6
7print(res_v1.tool_calls)
[ToolCall(name='get_weather', parameters={'location': 'Toronto'})]

v2

PYTHON
1messages = [{"role": "user", "content": "What's the weather in Toronto?"}]
2
3res_v2 = co_v2.chat(model="command-r-plus-08-2024", messages=messages, tools=tools_v2)
4
5if res_v2.message.tool_calls:
6 messages.append(
7 {
8 "role": "assistant",
9 "tool_calls": res_v2.message.tool_calls,
10 "tool_plan": res_v2.message.tool_plan,
11 }
12 )
13
14 print(res_v2.message.tool_calls)
[ToolCallV2(id='get_weather_k88p0m8504w5', type='function', function=ToolCallV2Function(name='get_weather', arguments='{"location":"Toronto"}'))]

Tool call ID

  • v1: Tool calls do not emit tool call IDs
  • v2: Tool calls emit tool call IDs. This will help the model match tool results to the right tool call.

v1

PYTHON
1tool_results = [
2 {
3 "call": {
4 "name": "<tool name>",
5 "parameters": {
6 "<param name>": "<param value>"
7 }
8 },
9 "outputs": [{
10 "<key>": "<value>"
11 }]
12 },
13]

v2

PYTHON
1messages = [
2 {
3 "role": "tool",
4 "tool_call_id": "123",
5 "content": [
6 {
7 "type": "document",
8 "document": {
9 "id": "123",
10 "data": {
11 "<key>": "<value>"
12 }
13 }
14 }
15 ]
16 }
17]

Response generation

  • Tool execution: Chat history management

    • v1: Append call and outputs to the chat history
    • v2: Append tool_call_id and tool_content to messages to the chat history
  • Tool execution: Tool results

    • v1: Passed as tool_results parameter
    • v2: Incorporated into the messages list as tool responses
  • User message

    • v1: Set as empty ("")
    • v2: No action required

v1

PYTHON
1tool_content_v1 = []
2if res_v1.tool_calls:
3 for tc in res_v1.tool_calls:
4 tool_call = {"name": tc.name, "parameters": tc.parameters}
5 tool_result = functions_map[tc.name](**tc.parameters)
6 tool_content_v1.append({"call": tool_call, "outputs": [tool_result]})
7
8res_v1 = co_v1.chat(
9 model="command-r-plus-08-2024",
10 message="",
11 tools=tools_v1,
12 tool_results=tool_content_v1,
13 chat_history=res_v1.chat_history
14)
15
16print(res_v1.text)
It is currently 20°C in Toronto.

v2

PYTHON
1if res_v2.message.tool_calls:
2 for tc in res_v2.message.tool_calls:
3 tool_result = functions_map[tc.function.name](
4 **json.loads(tc.function.arguments)
5 )
6 tool_content_v2 = []
7 for data in tool_result:
8 tool_content_v2.append({"type": "document", "document": {"data": json.dumps(data)}})
9 # Optional: add an "id" field in the "document" object, otherwise IDs are auto-generated
10 messages.append(
11 {"role": "tool", "tool_call_id": tc.id, "content": tool_content_v2}
12 )
13
14res_v2 = co_v2.chat(
15 model="command-r-plus-08-2024",
16 messages=messages,
17 tools=tools_v2
18)
19
20print(res_v2.message.content[0].text)
It's 20°C in Toronto.

Citations

  • Citations access:
    • v1: citations
    • v2: message.citations
  • Cited tools access:
    • v1: documents
    • v2: as part of message.citations, in the sources field

v1

PYTHON
1print(res_v1.citations)
2print(res_v1.documents)
[ChatCitation(start=16, end=20, text='20°C', document_ids=['get_weather:0:2:0'])]
[{'id': 'get_weather:0:2:0', 'temperature': '20C', 'tool_name': 'get_weather'}]

v2

PYTHON
1print(res_v2.message.citations)
[Citation(start=5, end=9, text='20°C', sources=[ToolSource(type='tool', id='get_weather_k88p0m8504w5:0', tool_output={'temperature': '20C'})])]

Streaming

  • Event containing content:

    • v1: chunk.event_type == "text-generation"
    • v2: chunk.type == "content-delta"
  • Accessing response content:

    • v1: chunk.text
    • v2: chunk.delta.message.content.text
  • Events containing citations:

    • v1: chunk.event_type == "citation-generation"
    • v2: chunk.type == "citation-start"
  • Accessing citations:

    • v1: chunk.citations
    • v2: chunk.delta.message.citations

v1

PYTHON
1tool_content_v1 = []
2if res_v1.tool_calls:
3 for tc in res_v1.tool_calls:
4 tool_call = {"name": tc.name, "parameters": tc.parameters}
5 tool_result = functions_map[tc.name](**tc.parameters)
6 tool_content_v1.append({"call": tool_call, "outputs": [tool_result]})
7
8res_v1 = co_v1.chat_stream(
9 message="",
10 tools=tools_v1,
11 tool_results=tool_content_v1,
12 chat_history=res_v1.chat_history
13)
14
15for chunk in res_v1:
16 if chunk.event_type == "text-generation":
17 print(chunk.text, end="")
18 if chunk.event_type == "citation-generation":
19 print(f"\n{chunk.citations}")
It's 20°C in Toronto.
[ChatCitation(start=5, end=9, text='20°C', document_ids=['get_weather:0:2:0', 'get_weather:0:4:0'])]

v2

PYTHON
1if res_v2.message.tool_calls:
2 for tc in res_v2.message.tool_calls:
3 tool_result = functions_map[tc.function.name](
4 **json.loads(tc.function.arguments)
5 )
6 tool_content_v2 = []
7 for data in tool_result:
8 tool_content_v2.append({"type": "document", "document": {"data": json.dumps(data)}})
9 # Optional: add an "id" field in the "document" object, otherwise IDs are auto-generated
10 messages.append(
11 {"role": "tool", "tool_call_id": tc.id, "content": tool_content_v2}
12 )
13
14res_v2 = co_v2.chat_stream(
15 model="command-r-plus-08-2024",
16 messages=messages,
17 tools=tools_v2
18)
19
20for chunk in res_v2:
21 if chunk:
22 if chunk.type == "content-delta":
23 print(chunk.delta.message.content.text, end="")
24 elif chunk.type == "citation-start":
25 print(f"\n{chunk.delta.message.citations}")
It's 20°C in Toronto.
start=5 end=9 text='20°C' sources=[ToolSource(type='tool', id='get_weather_k88p0m8504w5:0', tool_output={'temperature': '20C'})]

Citation quality (both RAG and tool use)

  • v1: controlled via citation_quality parameter
  • v2: controlled via citation_options parameter (with mode as a key)

Unsupported features in v2

The following v1 features are not supported in v2:

  • General chat
    • conversation_id parameter (chat history is now managed by the developer via the messages parameter)
  • RAG
    • search_queries_only parameter
    • connectors parameter
    • prompt_truncation parameter
  • Tool use
    • force_single_step parameter (all tool calls are now multi-step by default)