agently 4.0.7__py3-none-any.whl → 4.0.7.2__py3-none-any.whl

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.
Files changed (37) hide show
  1. agently/_default_init.py +4 -0
  2. agently/_default_settings.yaml +3 -1
  3. agently/base.py +19 -1
  4. agently/builtins/agent_extensions/ChatSessionExtension.py +2 -2
  5. agently/builtins/agent_extensions/SessionExtension.py +294 -0
  6. agently/builtins/agent_extensions/__init__.py +1 -0
  7. agently/builtins/plugins/PromptGenerator/AgentlyPromptGenerator.py +57 -17
  8. agently/builtins/plugins/Session/AgentlyMemoSession.py +652 -0
  9. agently/builtins/tools/Browse.py +11 -3
  10. agently/builtins/tools/Cmd.py +112 -0
  11. agently/builtins/tools/Search.py +28 -2
  12. agently/builtins/tools/__init__.py +1 -0
  13. agently/core/Agent.py +7 -7
  14. agently/core/ModelRequest.py +6 -5
  15. agently/core/Prompt.py +1 -1
  16. agently/core/Session.py +85 -0
  17. agently/core/TriggerFlow/TriggerFlow.py +1 -1
  18. agently/core/TriggerFlow/process/BaseProcess.py +8 -4
  19. agently/integrations/chromadb.py +4 -4
  20. agently/types/data/__init__.py +2 -0
  21. agently/types/data/prompt.py +6 -1
  22. agently/types/data/tool.py +9 -0
  23. agently/types/plugins/BuiltInTool.py +22 -0
  24. agently/types/plugins/Session.py +159 -0
  25. agently/types/plugins/__init__.py +21 -0
  26. agently/types/plugins/base.py +1 -1
  27. agently/utils/AGENT_UTILS_GUIDE.md +175 -0
  28. agently/utils/DataFormatter.py +14 -4
  29. agently/utils/DataLocator.py +108 -31
  30. agently/utils/FunctionShifter.py +3 -2
  31. agently/utils/TimeInfo.py +22 -0
  32. agently/utils/__init__.py +1 -0
  33. agently-4.0.7.2.dist-info/METADATA +433 -0
  34. {agently-4.0.7.dist-info → agently-4.0.7.2.dist-info}/RECORD +36 -28
  35. {agently-4.0.7.dist-info → agently-4.0.7.2.dist-info}/WHEEL +1 -1
  36. agently-4.0.7.dist-info/METADATA +0 -194
  37. {agently-4.0.7.dist-info → agently-4.0.7.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,112 @@
1
+ # Copyright 2023-2025 AgentEra(Agently.Tech)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ import shlex
17
+ import subprocess
18
+ from pathlib import Path
19
+ from typing import Iterable, Sequence
20
+
21
+ from agently.types.plugins import BuiltInTool
22
+
23
+
24
+ class Cmd(BuiltInTool):
25
+ def __init__(
26
+ self,
27
+ *,
28
+ allowed_cmd_prefixes: Sequence[str] | None = None,
29
+ allowed_workdir_roots: Iterable[str | Path] | None = None,
30
+ timeout: int = 20,
31
+ env: dict[str, str] | None = None,
32
+ ):
33
+ self.tool_info_list = [
34
+ {
35
+ "name": "cmd",
36
+ "desc": "Run a shell command with allowlist checks.",
37
+ "kwargs": {
38
+ "cmd": ("str | list[str]", "Command to run"),
39
+ "workdir": ("str | None", "Working directory"),
40
+ "allow_unsafe": ("bool", "Allow command outside allowlist"),
41
+ },
42
+ "func": self.run,
43
+ }
44
+ ]
45
+
46
+ self.allowed_cmd_prefixes = set(
47
+ allowed_cmd_prefixes
48
+ if allowed_cmd_prefixes is not None
49
+ else ["ls", "rg", "cat", "pwd", "whoami", "date", "head", "tail"]
50
+ )
51
+ roots = allowed_workdir_roots if allowed_workdir_roots is not None else [Path.cwd()]
52
+ self.allowed_workdir_roots = [Path(root).resolve() for root in roots]
53
+ self.timeout = timeout
54
+ self.env = env
55
+
56
+ def _normalize_cmd(self, cmd: str | Sequence[str]) -> list[str]:
57
+ if isinstance(cmd, str):
58
+ return shlex.split(cmd)
59
+ return list(cmd)
60
+
61
+ def _is_cmd_allowed(self, args: list[str]) -> bool:
62
+ if not args:
63
+ return False
64
+ cmd = args[0]
65
+ base = Path(cmd).name
66
+ return base in self.allowed_cmd_prefixes
67
+
68
+ def _is_workdir_allowed(self, workdir: str | Path | None) -> bool:
69
+ workdir_path = Path(workdir or Path.cwd()).resolve()
70
+ for root in self.allowed_workdir_roots:
71
+ try:
72
+ workdir_path.relative_to(root)
73
+ return True
74
+ except ValueError:
75
+ continue
76
+ return False
77
+
78
+ async def run(
79
+ self,
80
+ cmd: str | Sequence[str],
81
+ workdir: str | Path | None = None,
82
+ allow_unsafe: bool = False,
83
+ ) -> dict:
84
+ args = self._normalize_cmd(cmd)
85
+ if not self._is_workdir_allowed(workdir):
86
+ return {
87
+ "ok": False,
88
+ "need_approval": True,
89
+ "reason": "workdir_not_allowed",
90
+ "workdir": str(workdir or Path.cwd()),
91
+ }
92
+ if not self._is_cmd_allowed(args) and not allow_unsafe:
93
+ return {
94
+ "ok": False,
95
+ "need_approval": True,
96
+ "reason": "cmd_not_allowed",
97
+ "cmd": args,
98
+ }
99
+ result = subprocess.run(
100
+ args,
101
+ cwd=str(Path(workdir).resolve()) if workdir else None,
102
+ capture_output=True,
103
+ text=True,
104
+ timeout=self.timeout,
105
+ env=self.env,
106
+ )
107
+ return {
108
+ "ok": result.returncode == 0,
109
+ "returncode": result.returncode,
110
+ "stdout": result.stdout,
111
+ "stderr": result.stderr,
112
+ }
@@ -19,7 +19,6 @@ from agently.utils import LazyImport, FunctionShifter
19
19
 
20
20
 
21
21
  class Search:
22
-
23
22
  def __init__(
24
23
  self,
25
24
  *,
@@ -103,7 +102,34 @@ class Search:
103
102
  ] = "us-en",
104
103
  options: dict[str, Any] | None = None,
105
104
  ):
106
- LazyImport.import_package("ddgs")
105
+ self.tool_info_list = [
106
+ {
107
+ "name": "search",
108
+ "desc": "Search the web with {query}",
109
+ "kwargs": {"query": [("str", "search query")]},
110
+ "func": self.search,
111
+ },
112
+ {
113
+ "name": "search_news",
114
+ "desc": "Search news with {query}",
115
+ "kwargs": {"query": [("str", "search query")]},
116
+ "func": self.search_news,
117
+ },
118
+ {
119
+ "name": "search_wikipedia",
120
+ "desc": "Search wikipedia with {query}",
121
+ "kwargs": {"query": [("str", "search query")]},
122
+ "func": self.search_wikipedia,
123
+ },
124
+ {
125
+ "name": "search_arxiv",
126
+ "desc": "Search arXiv with {query}",
127
+ "kwargs": {"query": [("str", "search query")]},
128
+ "func": self.search_arxiv,
129
+ },
130
+ ]
131
+
132
+ LazyImport.import_package("ddgs", version_constraint=">=9.10.0")
107
133
  from ddgs import DDGS
108
134
 
109
135
  self.proxy = proxy
@@ -15,3 +15,4 @@
15
15
 
16
16
  from .Search import Search
17
17
  from .Browse import Browse
18
+ from .Cmd import Cmd
agently/core/Agent.py CHANGED
@@ -16,7 +16,7 @@ import uuid
16
16
  import yaml
17
17
  import json
18
18
 
19
- from typing import Any, TYPE_CHECKING
19
+ from typing import Any, Sequence, TYPE_CHECKING
20
20
 
21
21
  from agently.core import Prompt, ExtensionHandlers, ModelRequest
22
22
  from agently.utils import Settings
@@ -116,15 +116,15 @@ class BaseAgent:
116
116
  self.agent_prompt.set("chat_history", [])
117
117
  return self
118
118
 
119
- def set_chat_history(self, chat_history: "list[dict[str, Any] | ChatMessage]"):
119
+ def set_chat_history(self, chat_history: "Sequence[dict[str, Any] | ChatMessage]"):
120
120
  self.reset_chat_history()
121
- if not isinstance(chat_history, list):
121
+ if not isinstance(chat_history, Sequence):
122
122
  chat_history = [chat_history]
123
123
  self.agent_prompt.set("chat_history", chat_history)
124
124
  return self
125
125
 
126
- def add_chat_history(self, chat_history: "list[dict[str, Any] | ChatMessage] | dict[str, Any] | ChatMessage"):
127
- if not isinstance(chat_history, list):
126
+ def add_chat_history(self, chat_history: "Sequence[dict[str, Any] | ChatMessage] | dict[str, Any] | ChatMessage"):
127
+ if not isinstance(chat_history, Sequence):
128
128
  chat_history = [chat_history]
129
129
  self.agent_prompt.set("chat_history", chat_history)
130
130
  return self
@@ -151,9 +151,9 @@ class BaseAgent:
151
151
  always: bool = False,
152
152
  ):
153
153
  if always:
154
- self.agent_prompt.set("input", prompt, mappings)
154
+ self.agent_prompt.set("system", prompt, mappings)
155
155
  else:
156
- self.request.prompt.set("input", prompt, mappings)
156
+ self.request.prompt.set("system", prompt, mappings)
157
157
  return self
158
158
 
159
159
  def rule(
@@ -61,10 +61,6 @@ class ModelResponseResult:
61
61
  self.async_get_meta = self._response_parser.async_get_meta
62
62
  self.get_text = self._response_parser.get_text
63
63
  self.async_get_text = self._response_parser.async_get_text
64
- # self.get_data = self._response_parser.get_data
65
- # self.async_get_data = self._response_parser.async_get_data
66
- # self.get_data_object = self._response_parser.get_data_object
67
- # self.async_get_data_object = self._response_parser.async_get_data_object
68
64
  self.get_data = FunctionShifter.syncify(self.async_get_data)
69
65
  self.get_data_object = FunctionShifter.syncify(self.async_get_data_object)
70
66
  self.get_generator = self._response_parser.get_generator
@@ -153,6 +149,11 @@ class ModelResponseResult:
153
149
  return await self._response_parser.async_get_data(type=type)
154
150
  return await self._response_parser.async_get_data(type=type)
155
151
 
152
+ @overload
153
+ async def async_get_data_object(
154
+ self,
155
+ ) -> "BaseModel | None": ...
156
+
156
157
  @overload
157
158
  async def async_get_data_object(
158
159
  self,
@@ -467,7 +468,7 @@ class ModelRequest:
467
468
  prompt: Any,
468
469
  mappings: dict[str, Any] | None = None,
469
470
  ):
470
- self.prompt.set("system", ["YOU MUST REACT AND RESPOND AS {system.role}!"])
471
+ self.prompt.set("system", ["YOU MUST REACT AND RESPOND AS {system.your_role}!"])
471
472
  self.prompt.set("system.your_role", prompt, mappings)
472
473
  return self
473
474
 
agently/core/Prompt.py CHANGED
@@ -161,5 +161,5 @@ class Prompt(RuntimeData):
161
161
  else:
162
162
  super().append(key, value)
163
163
 
164
- def get(self, key: "PromptStandardSlot | None" = None, default: T = None, inherit: bool = True) -> Any | T:
164
+ def get(self, key: "PromptStandardSlot | str | None" = None, default: T = None, inherit: bool = True) -> Any | T:
165
165
  return super().get(key, default=default, inherit=inherit)
@@ -0,0 +1,85 @@
1
+ # Copyright 2023-2025 AgentEra(Agently.Tech)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING, Literal, cast
18
+
19
+ from agently.utils import Settings
20
+
21
+ if TYPE_CHECKING:
22
+ from agently.core import PluginManager, BaseAgent
23
+ from agently.types.plugins import (
24
+ SessionProtocol,
25
+ MemoResizePolicyHandler,
26
+ MemoResizeHandler,
27
+ AttachmentSummaryHandler,
28
+ MemoUpdateHandler,
29
+ )
30
+
31
+
32
+ class Session:
33
+ def __init__(
34
+ self,
35
+ *,
36
+ policy_handler: "MemoResizePolicyHandler | None" = None,
37
+ resize_handlers: "dict[Literal['lite', 'deep'] | str, MemoResizeHandler] | None" = None,
38
+ attachment_summary_handler: "AttachmentSummaryHandler | None" = None,
39
+ memo_update_handler: "MemoUpdateHandler | None" = None,
40
+ parent_settings: Settings | None = None,
41
+ agent: "BaseAgent | None" = None,
42
+ plugin_manager: "PluginManager | None" = None,
43
+ ):
44
+ if plugin_manager is None:
45
+ from agently.base import plugin_manager as global_plugin_manager, settings as global_settings
46
+
47
+ plugin_manager = global_plugin_manager
48
+ if parent_settings is None:
49
+ parent_settings = global_settings
50
+
51
+ if parent_settings is None:
52
+ parent_settings = Settings(name="Session-Settings")
53
+
54
+ session_settings = Settings(
55
+ name="Session-Settings",
56
+ parent=parent_settings,
57
+ )
58
+ plugin_name = str(session_settings.get("plugins.Session.activate", "AgentlyMemoSession"))
59
+ SessionPlugin = cast(
60
+ type["SessionProtocol"],
61
+ plugin_manager.get_plugin("Session", plugin_name),
62
+ )
63
+ impl = SessionPlugin(
64
+ policy_handler=policy_handler,
65
+ resize_handlers=resize_handlers,
66
+ attachment_summary_handler=attachment_summary_handler,
67
+ memo_update_handler=memo_update_handler,
68
+ parent_settings=session_settings,
69
+ agent=agent,
70
+ )
71
+ object.__setattr__(self, "_impl", impl)
72
+ object.__setattr__(self, "settings", impl.settings)
73
+ object.__setattr__(self, "plugin_manager", plugin_manager)
74
+
75
+ def __getattr__(self, name: str):
76
+ return getattr(self._impl, name)
77
+
78
+ def __setattr__(self, name: str, value):
79
+ if name in {"_impl", "settings", "plugin_manager"}:
80
+ object.__setattr__(self, name, value)
81
+ return
82
+ if "_impl" in self.__dict__ and hasattr(self._impl, name):
83
+ setattr(self._impl, name, value)
84
+ return
85
+ object.__setattr__(self, name, value)
@@ -227,7 +227,7 @@ class TriggerFlow:
227
227
  self,
228
228
  initial_value: Any = None,
229
229
  *,
230
- timeout: int | None = 10,
230
+ timeout: float | None = 10.0,
231
231
  concurrency: int | None = None,
232
232
  ):
233
233
  execution = self.create_execution(concurrency=concurrency)
@@ -294,16 +294,20 @@ class TriggerFlowBaseProcess:
294
294
  chunk = self._flow_chunk(chunk_name)(chunk_func)
295
295
  else:
296
296
  chunk = self._flow_chunk(chunk.__name__)(chunk) if callable(chunk) else chunk
297
+ typed_chunk = cast(TriggerFlowChunk, chunk)
297
298
  triggers_to_wait[chunk.trigger] = False
298
299
  trigger_to_chunk_name[chunk.trigger] = chunk.name
299
300
  results[chunk.name] = None
300
301
 
301
302
  if semaphore is None:
302
- handler = chunk.async_call
303
+ handler = typed_chunk.async_call
303
304
  else:
304
- async def handler(data: "TriggerFlowEventData", _chunk=chunk):
305
- async with semaphore:
306
- return await _chunk.async_call(data)
305
+ def make_handler(bound_chunk: TriggerFlowChunk):
306
+ async def handler(data: "TriggerFlowEventData"):
307
+ async with semaphore:
308
+ return await bound_chunk.async_call(data)
309
+ return handler
310
+ handler = make_handler(typed_chunk)
307
311
 
308
312
  self._blue_print.add_handler(
309
313
  self.trigger_type,
@@ -38,7 +38,7 @@ if TYPE_CHECKING:
38
38
  )
39
39
  from chromadb.api.collection_configuration import CreateCollectionConfiguration
40
40
  from chromadb.api import ClientAPI
41
- from agently.core import BaseAgent
41
+ from agently.base import Agent
42
42
 
43
43
 
44
44
  class ChromaDataDictOptional(TypedDict, total=False):
@@ -57,7 +57,7 @@ class ChromaData:
57
57
  original_data: ChromaDataDict | list[ChromaDataDict],
58
58
  *,
59
59
  embedding_function: "Callable[[str | list[str]], Embeddings] | None" = None,
60
- agent: "BaseAgent | None" = None,
60
+ agent: "Agent | None" = None,
61
61
  ):
62
62
  self._original_data = original_data if isinstance(original_data, list) else [original_data]
63
63
  if embedding_function:
@@ -157,7 +157,7 @@ class ChromaEmbeddingFunction(EmbeddingFunction):
157
157
  def __init__(
158
158
  self,
159
159
  *,
160
- embedding_agent: "BaseAgent",
160
+ embedding_agent: "Agent",
161
161
  ):
162
162
  def embedding_function_by_agent(texts: list[str]) -> "Embeddings":
163
163
  return embedding_agent.input(texts).start()
@@ -180,7 +180,7 @@ class ChromaCollection:
180
180
  schema: "Schema | None" = None,
181
181
  configuration: "CreateCollectionConfiguration | None" = None,
182
182
  metadata: dict[str, Any] | None = None,
183
- embedding_agent: "BaseAgent | None" = None,
183
+ embedding_agent: "Agent | None" = None,
184
184
  data_loader: "DataLoader[Loadable] | None" = None,
185
185
  get_or_create: bool = False,
186
186
  hnsw_space: Literal["l2", "cosine", "ip"] = "cosine",
@@ -36,6 +36,7 @@ EMPTY = AVOID_COPY()
36
36
  from .serializable import SerializableData, SerializableValue
37
37
  from .prompt import (
38
38
  ChatMessage,
39
+ ChatMessageDict,
39
40
  ChatMessageContent,
40
41
  TextMessageContent,
41
42
  PromptModel,
@@ -71,4 +72,5 @@ from .tool import (
71
72
  ReturnType,
72
73
  MCPConfig,
73
74
  MCPConfigs,
75
+ ToolInfo,
74
76
  )
@@ -52,8 +52,13 @@ ChatMessageContent = TextMessageContent | AttachmentMessageContent
52
52
  ChatMessageContentAdapter = TypeAdapter(Annotated[ChatMessageContent, Field(union_mode="left_to_right")])
53
53
 
54
54
 
55
+ class ChatMessageDict(TypedDict):
56
+ role: Literal["system", "developer", "tool", "user", "assistant"] | str
57
+ content: str | list[dict[str, Any] | ChatMessageContent]
58
+
59
+
55
60
  class ChatMessage(BaseModel):
56
- role: str = "user"
61
+ role: Literal["system", "developer", "tool", "user", "assistant"] | str = "user"
57
62
  content: str | list[dict[str, Any] | ChatMessageContent]
58
63
 
59
64
  model_config = ConfigDict(extra="allow")
@@ -40,3 +40,12 @@ class MCPConfig(TypedDict):
40
40
 
41
41
  class MCPConfigs(TypedDict):
42
42
  mcpServers: dict[str, MCPConfig]
43
+
44
+
45
+ class ToolInfo(TypedDict, total=False):
46
+ name: str
47
+ desc: str
48
+ kwargs: dict[str, Any]
49
+ func: Callable[..., Any]
50
+ returns: ReturnType
51
+ tags: str | list[str]
@@ -0,0 +1,22 @@
1
+ # Copyright 2023-2025 AgentEra(Agently.Tech)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ from typing import Protocol
17
+
18
+ from agently.types.data import ToolInfo
19
+
20
+
21
+ class BuiltInTool(Protocol):
22
+ tool_info_list: list[ToolInfo]
@@ -0,0 +1,159 @@
1
+ # Copyright 2023-2025 AgentEra(Agently.Tech)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any, Literal, Awaitable, Callable, TypeAlias, TYPE_CHECKING, Protocol
19
+ from typing_extensions import TypedDict, NotRequired, Self
20
+
21
+ if TYPE_CHECKING:
22
+ from agently.utils import Settings
23
+ from agently.types.data import SerializableData, ChatMessage
24
+
25
+ MemoResizeType: TypeAlias = Literal["lite", "deep"] | str
26
+ SessionMode: TypeAlias = Literal["lite", "memo"] | str
27
+
28
+
29
+ class SessionLimit(TypedDict, total=False):
30
+ chars: int
31
+ messages: int
32
+
33
+
34
+ class SessionConfig(TypedDict, total=False):
35
+ mode: SessionMode
36
+ limit: SessionLimit
37
+ every_n_turns: int
38
+
39
+
40
+ class MemoResizeDecision(TypedDict):
41
+ type: MemoResizeType
42
+ reason: NotRequired[str]
43
+ severity: NotRequired[int]
44
+ meta: NotRequired[dict[str, Any]]
45
+
46
+
47
+ MemoResizePolicyResult: TypeAlias = "MemoResizeType | MemoResizeDecision | None"
48
+
49
+ MemoResizePolicyHandler: TypeAlias = (
50
+ "Callable[[list[ChatMessage], list[ChatMessage], Settings], MemoResizePolicyResult | Awaitable[MemoResizePolicyResult]]"
51
+ )
52
+
53
+ MemoResizePolicyAsyncHandler: TypeAlias = (
54
+ "Callable[[list[ChatMessage], list[ChatMessage], Settings], Awaitable[MemoResizePolicyResult]]"
55
+ )
56
+
57
+ MemoResizeHandlerResult: TypeAlias = "tuple[list[ChatMessage], list[ChatMessage], SerializableData]"
58
+
59
+ MemoResizeHandler: TypeAlias = (
60
+ "Callable[[list[ChatMessage], list[ChatMessage], SerializableData, Settings], MemoResizeHandlerResult | Awaitable[MemoResizeHandlerResult]]"
61
+ )
62
+
63
+ MemoResizeAsyncHandler: TypeAlias = (
64
+ "Callable[[list[ChatMessage], list[ChatMessage], SerializableData, Settings], Awaitable[MemoResizeHandlerResult]]"
65
+ )
66
+
67
+ MemoUpdateResult: TypeAlias = "dict[str, Any]"
68
+ MemoUpdateHandler: TypeAlias = (
69
+ "Callable[[dict[str, Any], list[ChatMessage], list[AttachmentSummary], Settings], MemoUpdateResult | Awaitable[MemoUpdateResult]]"
70
+ )
71
+ MemoUpdateAsyncHandler: TypeAlias = (
72
+ "Callable[[dict[str, Any], list[ChatMessage], list[AttachmentSummary], Settings], Awaitable[MemoUpdateResult]]"
73
+ )
74
+
75
+ AttachmentSummary: TypeAlias = "dict[str, Any]"
76
+ AttachmentSummaryHandler: TypeAlias = (
77
+ "Callable[[ChatMessage], list[AttachmentSummary] | Awaitable[list[AttachmentSummary]]]"
78
+ )
79
+
80
+ AttachmentSummaryAsyncHandler: TypeAlias = "Callable[[ChatMessage], Awaitable[list[AttachmentSummary]]]"
81
+
82
+
83
+ class SessionProtocol(Protocol):
84
+ id: str
85
+ settings: "Settings"
86
+ memo: "SerializableData"
87
+ full_chat_history: "list[ChatMessage]"
88
+ current_chat_history: "list[ChatMessage]"
89
+ set_settings: Callable[..., Any]
90
+ judge_resize: Callable[..., Any]
91
+ resize: Callable[..., Any]
92
+
93
+ def __init__(
94
+ self,
95
+ *,
96
+ policy_handler: MemoResizePolicyHandler | None = None,
97
+ resize_handlers: dict[Literal["lite", "deep"] | str, MemoResizeHandler] | None = None,
98
+ attachment_summary_handler: AttachmentSummaryHandler | None = None,
99
+ memo_update_handler: MemoUpdateHandler | None = None,
100
+ parent_settings: "Settings | None" = None,
101
+ agent: Any | None = None,
102
+ ): ...
103
+
104
+ def configure(
105
+ self,
106
+ *,
107
+ mode: SessionMode | None = None,
108
+ limit: SessionLimit | None = None,
109
+ every_n_turns: int | None = None,
110
+ ) -> Self: ...
111
+
112
+ def set_limit(
113
+ self,
114
+ *,
115
+ chars: int | None = None,
116
+ messages: int | None = None,
117
+ ) -> Self: ...
118
+
119
+ def use_lite(
120
+ self,
121
+ *,
122
+ chars: int | None = None,
123
+ messages: int | None = None,
124
+ every_n_turns: int | None = None,
125
+ ) -> Self: ...
126
+
127
+ def use_memo(
128
+ self,
129
+ *,
130
+ chars: int | None = None,
131
+ messages: int | None = None,
132
+ every_n_turns: int | None = None,
133
+ ) -> Self: ...
134
+
135
+ def append_message(self, message: "ChatMessage | dict[str, Any]") -> Self: ...
136
+
137
+ def set_policy_handler(self, policy_handler: MemoResizePolicyHandler) -> Self: ...
138
+
139
+ def set_resize_handlers(
140
+ self,
141
+ resize_type: Literal["lite", "deep"] | str,
142
+ resize_handler: MemoResizeHandler,
143
+ ) -> Self: ...
144
+
145
+ def set_attachment_summary_handler(self, attachment_summary_handler: AttachmentSummaryHandler) -> Self: ...
146
+
147
+ def set_memo_update_handler(self, memo_update_handler: MemoUpdateHandler) -> Self: ...
148
+
149
+ async def async_judge_resize(self, force: Literal["lite", "deep", False, None] | str = False): ...
150
+
151
+ async def async_resize(self, force: Literal["lite", "deep", False, None] | str = False): ...
152
+
153
+ def to_json(self) -> str: ...
154
+
155
+ def to_yaml(self) -> str: ...
156
+
157
+ def load_json(self, value: str) -> Self: ...
158
+
159
+ def load_yaml(self, value: str) -> Self: ...
@@ -18,3 +18,24 @@ from .PromptGenerator import PromptGenerator
18
18
  from .ModelRequester import ModelRequester
19
19
  from .ResponseParser import ResponseParser
20
20
  from .ToolManager import ToolManager
21
+ from .BuiltInTool import BuiltInTool
22
+ from .Session import (
23
+ SessionProtocol,
24
+ SessionMode,
25
+ SessionLimit,
26
+ SessionConfig,
27
+ MemoResizePolicyHandler,
28
+ MemoResizePolicyAsyncHandler,
29
+ MemoResizePolicyResult,
30
+ MemoResizeHandler,
31
+ MemoResizeAsyncHandler,
32
+ MemoResizeHandlerResult,
33
+ MemoResizeType,
34
+ MemoResizeDecision,
35
+ MemoUpdateHandler,
36
+ MemoUpdateAsyncHandler,
37
+ MemoUpdateResult,
38
+ AttachmentSummaryHandler,
39
+ AttachmentSummaryAsyncHandler,
40
+ AttachmentSummary,
41
+ )
@@ -14,7 +14,7 @@
14
14
 
15
15
  from typing import Any, Literal, Protocol, runtime_checkable
16
16
 
17
- AgentlyPluginType = Literal["PromptGenerator", "ModelRequester", "ResponseParser", "ToolManager"]
17
+ AgentlyPluginType = Literal["PromptGenerator", "ModelRequester", "ResponseParser", "ToolManager", "Session"]
18
18
 
19
19
 
20
20
  @runtime_checkable