dm-aioaiagent 0.3.6__tar.gz → 0.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dm-aioaiagent
3
- Version: 0.3.6
3
+ Version: 0.4.1
4
4
  Summary: This is my custom aioaiagent client
5
5
  Home-page: https://pypi.org/project/dm-aioaiagent
6
6
  Author: dimka4621
@@ -18,9 +18,22 @@ Requires-Dist: pydantic<3.0.0,>=2.9.2
18
18
  Requires-Dist: langchain~=0.3.0
19
19
  Requires-Dist: langchain-core~=0.3.5
20
20
  Requires-Dist: langgraph~=0.2.23
21
+ Requires-Dist: langsmith~=0.1.144
21
22
  Requires-Dist: grandalf>=0.8
22
23
  Requires-Dist: langchain-community~=0.3.0
23
24
  Requires-Dist: langchain-openai~=0.2.0
25
+ Requires-Dist: langchain-anthropic~=0.3.0
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: project-url
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
24
37
 
25
38
  # DM-aioaiagent
26
39
 
@@ -35,7 +48,7 @@ Requires-Dist: langchain-openai~=0.2.0
35
48
 
36
49
  Analogue to `DMAioAIAgent` is the synchronous client `DMAIAgent`.
37
50
 
38
- ### Use agent *with* inner memory
51
+ ### Use agent *with* inner memory and run *single* message
39
52
 
40
53
  By default, agent use inner memory to store the conversation history.
41
54
 
@@ -61,35 +74,24 @@ async def main():
61
74
  # if you don't want to see the input and output messages from agent
62
75
  # you can set `input_output_logging=False` init argument
63
76
 
64
- # define the conversation message
65
- input_messages = [
66
- {"role": "user", "content": "Hello!"},
67
- ]
68
-
69
77
  # call an agent
70
- # specify `memory_id` argument to store the conversation history by your custom id
71
- answer = await ai_agent.run(input_messages)
72
-
73
- # define the next conversation message
74
- input_messages = [
75
- {"role": "user", "content": "I want to know the weather in Kyiv"}
76
- ]
78
+ answer = await ai_agent.run("Hello!")
77
79
 
78
80
  # call an agent
79
- answer = await ai_agent.run(input_messages)
81
+ answer = await ai_agent.run("I want to know the weather in Kyiv")
80
82
 
81
83
  # get full conversation history
82
- conversation_history = ai_agent.get_memory_messages()
84
+ conversation_history = ai_agent.memory_messages
83
85
 
84
86
  # clear conversation history
85
- ai_agent.clear_memory()
87
+ ai_agent.clear_memory_messages()
86
88
 
87
89
 
88
90
  if __name__ == "__main__":
89
91
  asyncio.run(main())
90
92
  ```
91
93
 
92
- ### Use agent *without* inner memory
94
+ ### Use agent *without* inner memory and run *multiple* messages
93
95
 
94
96
  If you want to control the memory of the agent, you can disable it by setting `is_memory_enabled=False`
95
97
 
@@ -114,13 +116,13 @@ async def main():
114
116
  # if you don't want to see the input and output messages from agent
115
117
  # you can set input_output_logging=False
116
118
 
117
- # define the conversation message
119
+ # define the conversation message(s)
118
120
  messages = [
119
121
  {"role": "user", "content": "Hello!"}
120
122
  ]
121
123
 
122
124
  # call an agent
123
- new_messages = await ai_agent.run(messages)
125
+ new_messages = await ai_agent.run_messages(messages)
124
126
 
125
127
  # add new_messages to messages
126
128
  messages.extend(new_messages)
@@ -131,7 +133,7 @@ async def main():
131
133
  )
132
134
 
133
135
  # call an agent
134
- new_messages = await ai_agent.run(messages)
136
+ new_messages = await ai_agent.run_messages(messages)
135
137
 
136
138
 
137
139
  if __name__ == "__main__":
@@ -153,14 +155,15 @@ def main():
153
155
  img_content = OpenAIImageMessageContent(image_url="https://your.domain/image",
154
156
  text="Hello, what is shown in the photo?")
155
157
 
156
- # define the conversation message
158
+ # define the conversation messages
157
159
  messages = [
158
160
  {"role": "user", "content": "Hello!"},
159
161
  {"role": "user", "content": img_content},
160
162
  ]
161
163
 
162
164
  # call an agent
163
- answer = ai_agent.run(messages)
165
+ new_messages = ai_agent.run_messages(messages)
166
+ answer = new_messages[-1].content
164
167
 
165
168
 
166
169
  if __name__ == "__main__":
@@ -11,7 +11,7 @@
11
11
 
12
12
  Analogue to `DMAioAIAgent` is the synchronous client `DMAIAgent`.
13
13
 
14
- ### Use agent *with* inner memory
14
+ ### Use agent *with* inner memory and run *single* message
15
15
 
16
16
  By default, agent use inner memory to store the conversation history.
17
17
 
@@ -37,35 +37,24 @@ async def main():
37
37
  # if you don't want to see the input and output messages from agent
38
38
  # you can set `input_output_logging=False` init argument
39
39
 
40
- # define the conversation message
41
- input_messages = [
42
- {"role": "user", "content": "Hello!"},
43
- ]
44
-
45
40
  # call an agent
46
- # specify `memory_id` argument to store the conversation history by your custom id
47
- answer = await ai_agent.run(input_messages)
48
-
49
- # define the next conversation message
50
- input_messages = [
51
- {"role": "user", "content": "I want to know the weather in Kyiv"}
52
- ]
41
+ answer = await ai_agent.run("Hello!")
53
42
 
54
43
  # call an agent
55
- answer = await ai_agent.run(input_messages)
44
+ answer = await ai_agent.run("I want to know the weather in Kyiv")
56
45
 
57
46
  # get full conversation history
58
- conversation_history = ai_agent.get_memory_messages()
47
+ conversation_history = ai_agent.memory_messages
59
48
 
60
49
  # clear conversation history
61
- ai_agent.clear_memory()
50
+ ai_agent.clear_memory_messages()
62
51
 
63
52
 
64
53
  if __name__ == "__main__":
65
54
  asyncio.run(main())
66
55
  ```
67
56
 
68
- ### Use agent *without* inner memory
57
+ ### Use agent *without* inner memory and run *multiple* messages
69
58
 
70
59
  If you want to control the memory of the agent, you can disable it by setting `is_memory_enabled=False`
71
60
 
@@ -90,13 +79,13 @@ async def main():
90
79
  # if you don't want to see the input and output messages from agent
91
80
  # you can set input_output_logging=False
92
81
 
93
- # define the conversation message
82
+ # define the conversation message(s)
94
83
  messages = [
95
84
  {"role": "user", "content": "Hello!"}
96
85
  ]
97
86
 
98
87
  # call an agent
99
- new_messages = await ai_agent.run(messages)
88
+ new_messages = await ai_agent.run_messages(messages)
100
89
 
101
90
  # add new_messages to messages
102
91
  messages.extend(new_messages)
@@ -107,7 +96,7 @@ async def main():
107
96
  )
108
97
 
109
98
  # call an agent
110
- new_messages = await ai_agent.run(messages)
99
+ new_messages = await ai_agent.run_messages(messages)
111
100
 
112
101
 
113
102
  if __name__ == "__main__":
@@ -129,14 +118,15 @@ def main():
129
118
  img_content = OpenAIImageMessageContent(image_url="https://your.domain/image",
130
119
  text="Hello, what is shown in the photo?")
131
120
 
132
- # define the conversation message
121
+ # define the conversation messages
133
122
  messages = [
134
123
  {"role": "user", "content": "Hello!"},
135
124
  {"role": "user", "content": img_content},
136
125
  ]
137
126
 
138
127
  # call an agent
139
- answer = ai_agent.run(messages)
128
+ new_messages = ai_agent.run_messages(messages)
129
+ answer = new_messages[-1].content
140
130
 
141
131
 
142
132
  if __name__ == "__main__":
@@ -3,4 +3,3 @@ load_dotenv()
3
3
  from .ai_agent import DMAIAgent
4
4
  from .async_ai_agent import DMAioAIAgent
5
5
  from .openai_image_message_content import OpenAIImageMessageContent
6
- from .types import Message
@@ -1,4 +1,6 @@
1
1
  import os
2
+ import uuid
3
+ from typing import Any
2
4
  from pydantic import SecretStr
3
5
  from itertools import dropwhile
4
6
  from threading import Thread
@@ -14,10 +16,7 @@ __all__ = ["DMAIAgent"]
14
16
 
15
17
 
16
18
  class DMAIAgent:
17
- AGENT_NAME = "AIAgent"
18
19
  MAX_MEMORY_MESSAGES = 20 # Only INT greater than 0
19
- RESPONSE_IF_REQUEST_FAIL = "I can't provide a response right now. Please try again later."
20
- RESPONSE_IF_INVALID_IMAGE = "The image is unavailable or the link is incorrect."
21
20
  _ALLOWED_ROLES = ("user", "ai")
22
21
 
23
22
  def __init__(
@@ -28,16 +27,16 @@ class DMAIAgent:
28
27
  model: str = "gpt-4o-mini",
29
28
  temperature: int = 1,
30
29
  parallel_tool_calls: bool = True,
31
- agent_name: str = None,
30
+ agent_name: str = "AIAgent",
32
31
  input_output_logging: bool = True,
33
32
  is_memory_enabled: bool = True,
33
+ max_memory_messages: int = MAX_MEMORY_MESSAGES,
34
34
  save_tools_responses_in_memory: bool = True,
35
- max_memory_messages: int = None,
36
35
  llm_provider_api_key: str = "",
37
- response_if_request_fail: str = None,
38
- response_if_invalid_image: str = None
36
+ response_if_request_fail: str = "I can't provide a response right now. Please try again later.",
37
+ response_if_invalid_image: str = "The image is unavailable or the link is incorrect."
39
38
  ):
40
- self._logger = DMLogger(agent_name or self.AGENT_NAME)
39
+ self._logger = DMLogger(agent_name)
41
40
  self._input_output_logging = bool(input_output_logging)
42
41
 
43
42
  self._system_message = str(system_message)
@@ -48,39 +47,57 @@ class DMAIAgent:
48
47
  self._parallel_tool_calls = bool(parallel_tool_calls)
49
48
  self._llm_provider_api_key = str(llm_provider_api_key)
50
49
 
50
+ self._memory_messages = []
51
51
  self._is_memory_enabled = bool(is_memory_enabled)
52
52
  self._save_tools_responses_in_memory = bool(save_tools_responses_in_memory)
53
53
  self._max_memory_messages = self._validate_max_memory_messages(max_memory_messages)
54
- self._response_if_request_fail = str(response_if_request_fail or self.RESPONSE_IF_REQUEST_FAIL)
55
- self._response_if_invalid_image = str(response_if_invalid_image or self.RESPONSE_IF_INVALID_IMAGE)
54
+ self._response_if_request_fail = str(response_if_request_fail)
55
+ self._response_if_invalid_image = str(response_if_invalid_image)
56
56
 
57
+ self._check_langsmith_envs()
57
58
  self._init_agent()
58
59
  self._init_graph()
59
60
 
60
- def run(self, input_messages: InputMessagesType, memory_id: str = None) -> ResponseType:
61
- state = self._graph.invoke({"input_messages": input_messages, "memory_id": memory_id})
62
- return state["response"]
61
+ def run(self, query: str, **kwargs) -> str:
62
+ new_messages = self.run_messages(messages=[{"role": "user", "content": query}], **kwargs)
63
+ return new_messages[-1].content
63
64
 
64
- def get_memory_messages(
65
+ def run_messages(
65
66
  self,
66
- memory_id: str = None,
67
+ messages: InputMessagesType,
67
68
  *,
68
- without_tool_m: bool = False,
69
- return_str_m: bool = False
70
- ) -> Union[list[BaseMessage], list[str]]:
71
- messages = self._memory.get(self._validate_memory_id(memory_id), [])
72
- if without_tool_m:
73
- messages = [m for m in messages if not (m.type == "tool" or (m.type == "ai" and m.tool_calls))]
74
- if return_str_m:
75
- messages = [m.content for m in messages]
76
- return messages
77
-
78
- def clear_memory(self, memory_id: str = None) -> None:
79
- self._memory[self._validate_memory_id(memory_id)] = []
69
+ ls_metadata: dict[str, Any] = None,
70
+ ls_tags: list[str] = None,
71
+ ls_run_id: uuid.UUID = None,
72
+ ls_thread_id: uuid.UUID = None
73
+ ) -> list[BaseMessage]:
74
+ if ls_metadata is None:
75
+ ls_metadata = {}
76
+ if isinstance(ls_run_id, uuid.UUID):
77
+ ls_run_id = ls_run_id
78
+ if isinstance(ls_thread_id, uuid.UUID):
79
+ ls_metadata["thread_id"] = ls_thread_id
80
+
81
+ config_data = {
82
+ "metadata": ls_metadata,
83
+ "tags": ls_tags,
84
+ "run_id": ls_run_id
85
+ }
86
+ state = self._graph.invoke(input={"messages": messages, "new_messages": []},
87
+ config={k: v for k, v in config_data.items() if v})
88
+ return state["new_messages"]
89
+
90
+ @property
91
+ def memory_messages(self) -> list[BaseMessage]:
92
+ return self._memory_messages
93
+
94
+ def clear_memory_messages(self) -> None:
95
+ self._memory_messages.clear()
80
96
 
81
97
  def _prepare_messages_node(self, state: State) -> State:
82
- state.input_messages = state.input_messages or [{"role": "user", "content": ""}]
83
- for item in state.input_messages:
98
+ messages = state["messages"] or [{"role": "user", "content": ""}]
99
+ state["messages"] = []
100
+ for item in messages:
84
101
  if isinstance(item, dict):
85
102
  role = item.get("role")
86
103
  content = item.get("content")
@@ -90,35 +107,35 @@ class DMAIAgent:
90
107
  MessageClass = AIMessage
91
108
  else:
92
109
  MessageClass = HumanMessage
93
- state.messages.append(MessageClass(content))
110
+ state["messages"].append(MessageClass(content))
94
111
  elif isinstance(item, BaseMessage):
95
- state.messages.append(item)
112
+ state["messages"].append(item)
96
113
 
97
114
  if self._input_output_logging:
98
- log_kwargs = {} if state.memory_id is None else {"memory_id": state.memory_id}
99
- self._logger.debug(f"Query:\n{state.messages[-1].content}", **log_kwargs)
115
+ self._logger.debug(f'Query:\n{state["messages"][-1].content}')
100
116
  if self._is_memory_enabled:
101
- state.messages = self.get_memory_messages(state.memory_id) + state.messages
117
+ state["messages"] = self._memory_messages + state["messages"]
102
118
  return state
103
119
 
104
120
  def _invoke_llm_node(self, state: State, second_attempt: bool = False) -> State:
105
121
  self._logger.debug("Run node: Invoke LLM")
106
122
  try:
107
- ai_response = self._agent.invoke({"messages": state.messages})
123
+ ai_response = self._agent.invoke({"messages": state["messages"]})
108
124
  except Exception as e:
109
125
  self._logger.error(e)
110
126
  if second_attempt:
111
127
  response = self._response_if_invalid_image if "invalid_image_url" in str(e) else self._response_if_request_fail
112
- state.messages.append(AIMessage(content=response))
128
+ state["messages"].append(AIMessage(content=response))
113
129
  return state
114
130
  return self._invoke_llm_node(state, second_attempt=True)
115
- state.messages.append(ai_response)
131
+ state["messages"].append(ai_response)
132
+ state["new_messages"].append(ai_response)
116
133
  return state
117
134
 
118
135
  def _execute_tool_node(self, state: State) -> State:
119
136
  self._logger.debug("Run node: Execute tool")
120
137
  threads = []
121
- for tool_call in state.messages[-1].tool_calls:
138
+ for tool_call in state["messages"][-1].tool_calls:
122
139
  tool_id = tool_call["id"]
123
140
  tool_name = tool_call["name"]
124
141
  tool_args = tool_call["args"]
@@ -136,7 +153,8 @@ class DMAIAgent:
136
153
  self._logger.debug(f"Tool response:\n{tool_response}", tool_id=tool_id)
137
154
 
138
155
  tool_message = ToolMessage(content=str(tool_response), name=tool_name, tool_call_id=tool_id)
139
- state.messages.append(tool_message)
156
+ state["messages"].append(tool_message)
157
+ state["new_messages"].append(tool_message)
140
158
 
141
159
  threads.append(Thread(target=tool_callback, daemon=True))
142
160
 
@@ -144,34 +162,27 @@ class DMAIAgent:
144
162
  t.start()
145
163
  for t in threads:
146
164
  t.join()
147
-
148
165
  return state
149
166
 
150
167
  def _exit_node(self, state: State) -> State:
151
- answer = state.messages[-1].content
152
168
  if self._input_output_logging:
153
- log_kwargs = {} if state.memory_id is None else {"memory_id": state.memory_id}
154
- self._logger.debug(f"Answer:\n{answer}", **log_kwargs)
169
+ self._logger.debug(f'Answer:\n{state["messages"][-1].content}')
155
170
 
156
171
  if self._is_memory_enabled:
157
- memory_id = self._validate_memory_id(state.memory_id)
158
- messages_to_memory = state.messages[-self._max_memory_messages:]
172
+ messages_to_memory = state["messages"][-self._max_memory_messages:]
159
173
  if self._save_tools_responses_in_memory:
160
174
  # drop ToolsMessages from start of list
161
- self._memory[memory_id] = list(dropwhile(lambda x: isinstance(x, ToolMessage), messages_to_memory))
175
+ self._memory_messages = list(dropwhile(lambda x: isinstance(x, ToolMessage), messages_to_memory))
162
176
  else:
163
- self._memory[memory_id] = []
177
+ self._memory_messages.clear()
164
178
  for mes in messages_to_memory:
165
179
  if isinstance(mes, ToolMessage) or (isinstance(mes, AIMessage) and mes.tool_calls):
166
180
  continue
167
- self._memory[memory_id].append(mes)
168
- state.response = answer
169
- else:
170
- state.response = state.messages[len(state.input_messages):]
181
+ self._memory_messages.append(mes)
171
182
  return state
172
183
 
173
184
  def _messages_router(self, state: State) -> str:
174
- if self._is_tools_exists and state.messages[-1].tool_calls:
185
+ if self._is_tools_exists and state["messages"][-1].tool_calls:
175
186
  route = "execute_tool"
176
187
  else:
177
188
  route = "exit"
@@ -202,7 +213,6 @@ class DMAIAgent:
202
213
  MessagesPlaceholder(variable_name="messages")])
203
214
 
204
215
  self._agent = prompt | llm
205
- self._memory = {}
206
216
 
207
217
  def _init_graph(self) -> None:
208
218
  workflow = StateGraph(State)
@@ -221,8 +231,12 @@ class DMAIAgent:
221
231
  self._graph = workflow.compile()
222
232
 
223
233
  @staticmethod
224
- def _validate_memory_id(memory_id: Union[str, None]) -> Union[str, int]:
225
- return str(memory_id) if memory_id else 0
234
+ def _check_langsmith_envs() -> None:
235
+ if os.getenv("LANGCHAIN_API_KEY"):
236
+ if not os.getenv("LANGCHAIN_TRACING_V2"):
237
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
238
+ if not os.getenv("LANGCHAIN_ENDPOINT"):
239
+ os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
226
240
 
227
241
  @classmethod
228
242
  def _validate_max_memory_messages(cls, max_messages_in_memory: int) -> int:
@@ -1,5 +1,7 @@
1
1
  import sys
2
+ import uuid
2
3
  import asyncio
4
+ from typing import Any
3
5
  from langchain_core.messages import AIMessage, ToolMessage
4
6
 
5
7
  from .ai_agent import DMAIAgent
@@ -12,30 +14,54 @@ __all__ = ["DMAioAIAgent"]
12
14
 
13
15
 
14
16
  class DMAioAIAgent(DMAIAgent):
15
- agent_name = "AsyncAIAgent"
17
+ async def run(self, query: str, **kwargs) -> str:
18
+ new_messages = await self.run_messages(messages=[{"role": "user", "content": query}], **kwargs)
19
+ return new_messages[-1].content
16
20
 
17
- async def run(self, input_messages: InputMessagesType, memory_id: str = None) -> ResponseType:
18
- state = await self._graph.ainvoke({"input_messages": input_messages, "memory_id": memory_id})
19
- return state["response"]
21
+ async def run_messages(
22
+ self,
23
+ messages: InputMessagesType,
24
+ *,
25
+ ls_metadata: dict[str, Any] = None,
26
+ ls_tags: list[str] = None,
27
+ ls_run_id: uuid.UUID = None,
28
+ ls_thread_id: uuid.UUID = None
29
+ ) -> list[BaseMessage]:
30
+ if ls_metadata is None:
31
+ ls_metadata = {}
32
+ if isinstance(ls_run_id, uuid.UUID):
33
+ ls_run_id = ls_run_id
34
+ if isinstance(ls_thread_id, uuid.UUID):
35
+ ls_metadata["thread_id"] = ls_thread_id
36
+
37
+ config_data = {
38
+ "metadata": ls_metadata,
39
+ "tags": ls_tags,
40
+ "run_id": ls_run_id
41
+ }
42
+ state = await self._graph.ainvoke(input={"messages": messages, "new_messages": []},
43
+ config={k: v for k, v in config_data.items() if v})
44
+ return state["new_messages"]
20
45
 
21
46
  async def _invoke_llm_node(self, state: State, second_attempt: bool = False) -> State:
22
47
  self._logger.debug("Run node: Invoke LLM")
23
48
  try:
24
- ai_response = await self._agent.ainvoke({"messages": state.messages})
49
+ ai_response = await self._agent.ainvoke({"messages": state["messages"]})
25
50
  except Exception as e:
26
51
  self._logger.error(e)
27
52
  if second_attempt:
28
53
  response = self._response_if_invalid_image if "invalid_image_url" in str(e) else self._response_if_request_fail
29
- state.messages.append(AIMessage(content=response))
54
+ state["messages"].append(AIMessage(content=response))
30
55
  return state
31
56
  return await self._invoke_llm_node(state, second_attempt=True)
32
- state.messages.append(ai_response)
57
+ state["messages"].append(ai_response)
58
+ state["new_messages"].append(ai_response)
33
59
  return state
34
60
 
35
61
  async def _execute_tool_node(self, state: State) -> State:
36
62
  self._logger.debug("Run node: Execute tool")
37
63
  tasks = []
38
- for tool_call in state.messages[-1].tool_calls:
64
+ for tool_call in state["messages"][-1].tool_calls:
39
65
  tool_id = tool_call["id"]
40
66
  tool_name = tool_call["name"]
41
67
  tool_args = tool_call["args"]
@@ -53,7 +79,8 @@ class DMAioAIAgent(DMAIAgent):
53
79
  self._logger.debug(f"Tool response:\n{tool_response}", tool_id=tool_id)
54
80
 
55
81
  tool_message = ToolMessage(content=str(tool_response), name=tool_name, tool_call_id=tool_id)
56
- state.messages.append(tool_message)
82
+ state["messages"].append(tool_message)
83
+ state["new_messages"].append(tool_message)
57
84
 
58
85
  tasks.append(asyncio.create_task(tool_callback()))
59
86
 
@@ -0,0 +1,30 @@
1
+ from typing import Literal, Union
2
+ from typing_extensions import TypedDict
3
+ from langchain_core.messages import BaseMessage
4
+
5
+
6
+ class ImageMessageTextMessage(TypedDict):
7
+ type: Literal['text']
8
+ text: str
9
+
10
+
11
+ class ImageMessageImageItem(TypedDict):
12
+ type: Literal['image_url']
13
+ image_url: dict
14
+
15
+
16
+ class ImageMessage(TypedDict):
17
+ role: Literal["user"]
18
+ content: list[Union[ImageMessageTextMessage, ImageMessageImageItem]]
19
+
20
+
21
+ class TextMessage(TypedDict):
22
+ role: Literal["user", "ai"]
23
+ content: str
24
+
25
+
26
+ InputMessagesType = list[Union[TextMessage, ImageMessage, BaseMessage]]
27
+
28
+ class State(TypedDict):
29
+ messages: InputMessagesType
30
+ new_messages: list[BaseMessage]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dm-aioaiagent
3
- Version: 0.3.6
3
+ Version: 0.4.1
4
4
  Summary: This is my custom aioaiagent client
5
5
  Home-page: https://pypi.org/project/dm-aioaiagent
6
6
  Author: dimka4621
@@ -18,9 +18,22 @@ Requires-Dist: pydantic<3.0.0,>=2.9.2
18
18
  Requires-Dist: langchain~=0.3.0
19
19
  Requires-Dist: langchain-core~=0.3.5
20
20
  Requires-Dist: langgraph~=0.2.23
21
+ Requires-Dist: langsmith~=0.1.144
21
22
  Requires-Dist: grandalf>=0.8
22
23
  Requires-Dist: langchain-community~=0.3.0
23
24
  Requires-Dist: langchain-openai~=0.2.0
25
+ Requires-Dist: langchain-anthropic~=0.3.0
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: project-url
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
24
37
 
25
38
  # DM-aioaiagent
26
39
 
@@ -35,7 +48,7 @@ Requires-Dist: langchain-openai~=0.2.0
35
48
 
36
49
  Analogue to `DMAioAIAgent` is the synchronous client `DMAIAgent`.
37
50
 
38
- ### Use agent *with* inner memory
51
+ ### Use agent *with* inner memory and run *single* message
39
52
 
40
53
  By default, agent use inner memory to store the conversation history.
41
54
 
@@ -61,35 +74,24 @@ async def main():
61
74
  # if you don't want to see the input and output messages from agent
62
75
  # you can set `input_output_logging=False` init argument
63
76
 
64
- # define the conversation message
65
- input_messages = [
66
- {"role": "user", "content": "Hello!"},
67
- ]
68
-
69
77
  # call an agent
70
- # specify `memory_id` argument to store the conversation history by your custom id
71
- answer = await ai_agent.run(input_messages)
72
-
73
- # define the next conversation message
74
- input_messages = [
75
- {"role": "user", "content": "I want to know the weather in Kyiv"}
76
- ]
78
+ answer = await ai_agent.run("Hello!")
77
79
 
78
80
  # call an agent
79
- answer = await ai_agent.run(input_messages)
81
+ answer = await ai_agent.run("I want to know the weather in Kyiv")
80
82
 
81
83
  # get full conversation history
82
- conversation_history = ai_agent.get_memory_messages()
84
+ conversation_history = ai_agent.memory_messages
83
85
 
84
86
  # clear conversation history
85
- ai_agent.clear_memory()
87
+ ai_agent.clear_memory_messages()
86
88
 
87
89
 
88
90
  if __name__ == "__main__":
89
91
  asyncio.run(main())
90
92
  ```
91
93
 
92
- ### Use agent *without* inner memory
94
+ ### Use agent *without* inner memory and run *multiple* messages
93
95
 
94
96
  If you want to control the memory of the agent, you can disable it by setting `is_memory_enabled=False`
95
97
 
@@ -114,13 +116,13 @@ async def main():
114
116
  # if you don't want to see the input and output messages from agent
115
117
  # you can set input_output_logging=False
116
118
 
117
- # define the conversation message
119
+ # define the conversation message(s)
118
120
  messages = [
119
121
  {"role": "user", "content": "Hello!"}
120
122
  ]
121
123
 
122
124
  # call an agent
123
- new_messages = await ai_agent.run(messages)
125
+ new_messages = await ai_agent.run_messages(messages)
124
126
 
125
127
  # add new_messages to messages
126
128
  messages.extend(new_messages)
@@ -131,7 +133,7 @@ async def main():
131
133
  )
132
134
 
133
135
  # call an agent
134
- new_messages = await ai_agent.run(messages)
136
+ new_messages = await ai_agent.run_messages(messages)
135
137
 
136
138
 
137
139
  if __name__ == "__main__":
@@ -153,14 +155,15 @@ def main():
153
155
  img_content = OpenAIImageMessageContent(image_url="https://your.domain/image",
154
156
  text="Hello, what is shown in the photo?")
155
157
 
156
- # define the conversation message
158
+ # define the conversation messages
157
159
  messages = [
158
160
  {"role": "user", "content": "Hello!"},
159
161
  {"role": "user", "content": img_content},
160
162
  ]
161
163
 
162
164
  # call an agent
163
- answer = ai_agent.run(messages)
165
+ new_messages = ai_agent.run_messages(messages)
166
+ answer = new_messages[-1].content
164
167
 
165
168
 
166
169
  if __name__ == "__main__":
@@ -4,6 +4,8 @@ pydantic<3.0.0,>=2.9.2
4
4
  langchain~=0.3.0
5
5
  langchain-core~=0.3.5
6
6
  langgraph~=0.2.23
7
+ langsmith~=0.1.144
7
8
  grandalf>=0.8
8
9
  langchain-community~=0.3.0
9
10
  langchain-openai~=0.2.0
11
+ langchain-anthropic~=0.3.0
@@ -8,7 +8,7 @@ def readme():
8
8
 
9
9
  setup(
10
10
  name='dm-aioaiagent',
11
- version='v0.3.6',
11
+ version='v0.4.1',
12
12
  author='dimka4621',
13
13
  author_email='mismartconfig@gmail.com',
14
14
  description='This is my custom aioaiagent client',
@@ -23,9 +23,11 @@ setup(
23
23
  'langchain~=0.3.0',
24
24
  'langchain-core~=0.3.5',
25
25
  'langgraph~=0.2.23',
26
+ 'langsmith~=0.1.144',
26
27
  'grandalf>=0.8',
27
28
  'langchain-community~=0.3.0',
28
29
  'langchain-openai~=0.2.0',
30
+ 'langchain-anthropic~=0.3.0'
29
31
  ],
30
32
  classifiers=[
31
33
  'Programming Language :: Python :: 3.8',
@@ -1,41 +0,0 @@
1
- from typing import Optional, Literal, Union
2
- from typing_extensions import TypedDict
3
- from pydantic import BaseModel, Field
4
- from langchain_core.messages import BaseMessage
5
-
6
-
7
- class ImageMessageTextMessage(TypedDict):
8
- type: Literal['text']
9
- text: str
10
-
11
-
12
- class ImageMessageImageItem(TypedDict):
13
- type: Literal['image_url']
14
- image_url: dict
15
-
16
-
17
- ImageMessageContent = list[Union[ImageMessageTextMessage, ImageMessageImageItem]]
18
-
19
-
20
- class ImageMessage(TypedDict):
21
- role: Literal["user"]
22
- content: ImageMessageContent
23
-
24
-
25
- class TextMessage(TypedDict):
26
- role: Literal["user", "ai"]
27
- content: str
28
-
29
-
30
- Message = Union[TextMessage, ImageMessage]
31
-
32
- InputMessagesType = list[Union[Message, BaseMessage]]
33
-
34
- ResponseType = Union[str, list[BaseMessage]]
35
-
36
-
37
- class State(BaseModel):
38
- input_messages: InputMessagesType
39
- memory_id: Union[str, int, None] = Field(default=0)
40
- messages: Optional[list[BaseMessage]] = Field(default_factory=list)
41
- response: ResponseType = Field(default="")
File without changes