Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update cohere to use tool call attribute on AIMessage #7

Merged
merged 5 commits into from
Apr 10, 2024
Merged

Conversation

ccurme
Copy link
Contributor

@ccurme ccurme commented Apr 8, 2024

No description provided.

baskaryan added a commit to langchain-ai/langchain that referenced this pull request Apr 9, 2024
core[minor], langchain[patch], openai[minor], anthropic[minor], fireworks[minor], groq[minor], mistralai[minor]

```python
class ToolCall(TypedDict):
    name: str
    args: Dict[str, Any]
    id: Optional[str]

class InvalidToolCall(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    error: Optional[str]

class ToolCallChunk(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    index: Optional[int]


class AIMessage(BaseMessage):
    ...
    tool_calls: List[ToolCall] = []
    invalid_tool_calls: List[InvalidToolCall] = []
    ...


class AIMessageChunk(AIMessage, BaseMessageChunk):
    ...
    tool_call_chunks: Optional[List[ToolCallChunk]] = None
    ...
```
Important considerations:
- Parsing logic occurs within different providers;
- ~Changing output type is a breaking change for anyone doing explicit
type checking;~
- ~Langsmith rendering will need to be updated:
langchain-ai/langchainplus#3561
- ~Langserve will need to be updated~
- Adding chunks:
- ~AIMessage + ToolCallsMessage = ToolCallsMessage if either has
non-null .tool_calls.~
- Tool call chunks are appended, merging when having equal values of
`index`.
  - additional_kwargs accumulate the normal way.
- During streaming:
- ~Messages can change types (e.g., from AIMessageChunk to
AIToolCallsMessageChunk)~
- Output parsers parse additional_kwargs (during .invoke they read off
tool calls).

Packages outside of `partners/`:
- langchain-ai/langchain-cohere#7
- https://github.com/langchain-ai/langchain-google/pull/123/files

---------

Co-authored-by: Chester Curme <chester.curme@gmail.com>
@ccurme ccurme changed the title (WIP) update cohere to use tool call attribute on AIMessage update cohere to use tool call attribute on AIMessage Apr 10, 2024
@ccurme ccurme marked this pull request as ready for review April 10, 2024 12:25
harry-cohere
harry-cohere previously approved these changes Apr 10, 2024
Copy link
Collaborator

@harry-cohere harry-cohere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks a lot!

Signed-off-by: harry-cohere <127103098+harry-cohere@users.noreply.github.com>
Copy link
Collaborator

@harry-cohere harry-cohere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks a lot!

@ccurme ccurme merged commit d2cb334 into main Apr 10, 2024
12 checks passed
@ccurme ccurme deleted the cc/tool_calls branch April 10, 2024 16:56
junkeon pushed a commit to UpstageAI/langchain that referenced this pull request Apr 16, 2024
core[minor], langchain[patch], openai[minor], anthropic[minor], fireworks[minor], groq[minor], mistralai[minor]

```python
class ToolCall(TypedDict):
    name: str
    args: Dict[str, Any]
    id: Optional[str]

class InvalidToolCall(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    error: Optional[str]

class ToolCallChunk(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    index: Optional[int]


class AIMessage(BaseMessage):
    ...
    tool_calls: List[ToolCall] = []
    invalid_tool_calls: List[InvalidToolCall] = []
    ...


class AIMessageChunk(AIMessage, BaseMessageChunk):
    ...
    tool_call_chunks: Optional[List[ToolCallChunk]] = None
    ...
```
Important considerations:
- Parsing logic occurs within different providers;
- ~Changing output type is a breaking change for anyone doing explicit
type checking;~
- ~Langsmith rendering will need to be updated:
https://github.com/langchain-ai/langchainplus/pull/3561~
- ~Langserve will need to be updated~
- Adding chunks:
- ~AIMessage + ToolCallsMessage = ToolCallsMessage if either has
non-null .tool_calls.~
- Tool call chunks are appended, merging when having equal values of
`index`.
  - additional_kwargs accumulate the normal way.
- During streaming:
- ~Messages can change types (e.g., from AIMessageChunk to
AIToolCallsMessageChunk)~
- Output parsers parse additional_kwargs (during .invoke they read off
tool calls).

Packages outside of `partners/`:
- langchain-ai/langchain-cohere#7
- https://github.com/langchain-ai/langchain-google/pull/123/files

---------

Co-authored-by: Chester Curme <chester.curme@gmail.com>
ccurme added a commit that referenced this pull request Apr 19, 2024
Langchain today released a new [tool_calls
attribute](https://python.langchain.com/docs/modules/model_io/chat/function_calling/)
on AIMessage, and these were supported by ChatCohere on release (see
#7).

Langchain also released a new function for building [tool-calling
agents](https://python.langchain.com/docs/modules/agents/agent_types/tool_calling/)
that is intended to work with any chat model that supports the new tool
calling feature. However, it does not yet work with ChatCohere, and
users will receive
`ApiError: status_code: 400, body: {'message': 'invalid request: all
elements in history must have a message.'}` if they attempt to use it. A
typical flow of messages in this agent framework might look like this:
```python
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langchain_cohere import ChatCohere


llm = ChatCohere(temperature=0)

messages = [
    HumanMessage(content="what is the value of magic_function(3)?"),
    AIMessage(
        content="",
        tool_calls=[
            {
                "name": "magic_function",
                "args": {"input": 3},
                "id": "d86e6098-21e1-44c7-8431-40cfc6d35590",
            }
        ],
    ),
    ToolMessage(
        name="magic_function",
        content="5",
        tool_call_id="d86e6098-21e1-44c7-8431-40cfc6d35590",
    ),
]

response = llm.invoke(messages)
assert isinstance(response, AIMessage)
```
This currently gives the above ApiError. Here we add support for
processing tool-calling AI messages and ToolMessages (analogous to
Cohere's `tool_result` field). This enables the new tool-calling agent
constructor for Cohere:
```python
from langchain.agents import AgentExecutor, create_tool_calling_agent, tool
from langchain_cohere import ChatCohere
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder


prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a helpful assistant"),
        MessagesPlaceholder("chat_history", optional=True),
        ("human", "{input}"),
        MessagesPlaceholder("agent_scratchpad"),
    ]
)

model = ChatCohere()

@tool
def magic_function(input: int) -> int:
    """Applies a magic function to an input."""
    return input + 2


@tool
def get_word_length(word: str) -> int:
    """Returns the length of a word."""
    return len(word)


tools = [magic_function, get_word_length]


agent = create_tool_calling_agent(model, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

agent_executor.invoke(
    {
        "input": (
            "what is the value of magic_function(3)? "
            "also, what is the length of the word 'pumpernickel'?"
        )
    }
)
```
```
> Entering new AgentExecutor chain...

Invoking: `magic_function` with `{'input': 3}`


5
Invoking: `get_word_length` with `{'word': 'pumpernickel'}`


12The value of `magic_function(3)` is 5 and the length of the word 'pumpernickel' is 12.

> Finished chain.
{'input': "what is the value of magic_function(3)? also, what is the length of the word 'pumpernickel'?",
 'output': "The value of `magic_function(3)` is 5 and the length of the word 'pumpernickel' is 12."}
```

### Requests:
- If you have test cases for `cohere_agent.create_cohere_tools_agent`,
please supply them so I can compare functionality.
- Please review the `_get_tool_results` function and my changes to the
composition of `chat_history` to ensure they make sense.
- Please voice any other feedback or concerns.

Thank you!

---------

Signed-off-by: ccurme <chester.curme@gmail.com>
Co-authored-by: harry-cohere <127103098+harry-cohere@users.noreply.github.com>
hinthornw pushed a commit to langchain-ai/langchain that referenced this pull request Apr 26, 2024
core[minor], langchain[patch], openai[minor], anthropic[minor], fireworks[minor], groq[minor], mistralai[minor]

```python
class ToolCall(TypedDict):
    name: str
    args: Dict[str, Any]
    id: Optional[str]

class InvalidToolCall(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    error: Optional[str]

class ToolCallChunk(TypedDict):
    name: Optional[str]
    args: Optional[str]
    id: Optional[str]
    index: Optional[int]


class AIMessage(BaseMessage):
    ...
    tool_calls: List[ToolCall] = []
    invalid_tool_calls: List[InvalidToolCall] = []
    ...


class AIMessageChunk(AIMessage, BaseMessageChunk):
    ...
    tool_call_chunks: Optional[List[ToolCallChunk]] = None
    ...
```
Important considerations:
- Parsing logic occurs within different providers;
- ~Changing output type is a breaking change for anyone doing explicit
type checking;~
- ~Langsmith rendering will need to be updated:
langchain-ai/langchainplus#3561
- ~Langserve will need to be updated~
- Adding chunks:
- ~AIMessage + ToolCallsMessage = ToolCallsMessage if either has
non-null .tool_calls.~
- Tool call chunks are appended, merging when having equal values of
`index`.
  - additional_kwargs accumulate the normal way.
- During streaming:
- ~Messages can change types (e.g., from AIMessageChunk to
AIToolCallsMessageChunk)~
- Output parsers parse additional_kwargs (during .invoke they read off
tool calls).

Packages outside of `partners/`:
- langchain-ai/langchain-cohere#7
- https://github.com/langchain-ai/langchain-google/pull/123/files

---------

Co-authored-by: Chester Curme <chester.curme@gmail.com>
Anirudh31415926535 added a commit to Anirudh31415926535/langchain-cohere-fork that referenced this pull request Jul 30, 2024
* support streaming for tool calling

* nit

* Add streaming for tool call

* nit

* replace cassettes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants