avalan 1.0.3__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.
- avalan/__init__.py +32 -0
- avalan/agent/__init__.py +54 -0
- avalan/agent/blueprint.toml +30 -0
- avalan/agent/engine.py +160 -0
- avalan/agent/loader.py +303 -0
- avalan/agent/orchestrator.py +284 -0
- avalan/agent/orchestrators/default.py +60 -0
- avalan/agent/orchestrators/json.py +133 -0
- avalan/agent/renderer.py +125 -0
- avalan/agent/templates/agent.md +35 -0
- avalan/agent/templates/agent_json.md +24 -0
- avalan/cli/__init__.py +66 -0
- avalan/cli/__main__.py +1131 -0
- avalan/cli/commands/__init__.py +0 -0
- avalan/cli/commands/agent.py +374 -0
- avalan/cli/commands/cache.py +73 -0
- avalan/cli/commands/memory.py +324 -0
- avalan/cli/commands/model.py +424 -0
- avalan/cli/commands/tokenizer.py +72 -0
- avalan/cli/download.py +61 -0
- avalan/cli/theme/__init__.py +402 -0
- avalan/cli/theme/fancy.py +1593 -0
- avalan/compat.py +14 -0
- avalan/event/__init__.py +15 -0
- avalan/event/manager.py +27 -0
- avalan/flow/__init__.py +0 -0
- avalan/flow/connection.py +29 -0
- avalan/flow/flow.py +155 -0
- avalan/flow/node.py +80 -0
- avalan/memory/__init__.py +63 -0
- avalan/memory/manager.py +174 -0
- avalan/memory/partitioner/__init__.py +8 -0
- avalan/memory/partitioner/code.py +333 -0
- avalan/memory/partitioner/text.py +102 -0
- avalan/memory/permanent/__init__.py +241 -0
- avalan/memory/permanent/migrations/pgsql/down/00001-messages-down.sql +29 -0
- avalan/memory/permanent/migrations/pgsql/up/00001-messages-up.sql +168 -0
- avalan/memory/permanent/pgsql/__init__.py +216 -0
- avalan/memory/permanent/pgsql/message.py +284 -0
- avalan/memory/permanent/pgsql/raw.py +235 -0
- avalan/model/__init__.py +86 -0
- avalan/model/audio.py +81 -0
- avalan/model/criteria.py +34 -0
- avalan/model/engine.py +329 -0
- avalan/model/entities.py +402 -0
- avalan/model/hubs/__init__.py +2 -0
- avalan/model/hubs/huggingface.py +255 -0
- avalan/model/manager.py +180 -0
- avalan/model/nlp/__init__.py +122 -0
- avalan/model/nlp/question.py +76 -0
- avalan/model/nlp/sentence.py +76 -0
- avalan/model/nlp/sequence.py +183 -0
- avalan/model/nlp/text/__init__.py +88 -0
- avalan/model/nlp/text/generation.py +424 -0
- avalan/model/nlp/text/vendor/__init__.py +111 -0
- avalan/model/nlp/text/vendor/anthropic.py +77 -0
- avalan/model/nlp/text/vendor/google.py +64 -0
- avalan/model/nlp/text/vendor/openai.py +58 -0
- avalan/model/nlp/text/vendor/openrouter.py +23 -0
- avalan/model/nlp/text/vllm.py +117 -0
- avalan/model/nlp/token.py +70 -0
- avalan/model/transformer.py +163 -0
- avalan/model/vision/__init__.py +20 -0
- avalan/model/vision/detection.py +68 -0
- avalan/model/vision/image.py +79 -0
- avalan/model/vision/segmentation.py +41 -0
- avalan/server/__init__.py +91 -0
- avalan/server/entities.py +64 -0
- avalan/server/routers/__init__.py +0 -0
- avalan/server/routers/chat.py +98 -0
- avalan/tool/__init__.py +21 -0
- avalan/tool/manager.py +87 -0
- avalan/tool/parser.py +175 -0
- avalan/utils.py +19 -0
- avalan-1.0.3.dist-info/LICENSE +21 -0
- avalan-1.0.3.dist-info/METADATA +901 -0
- avalan-1.0.3.dist-info/RECORD +79 -0
- avalan-1.0.3.dist-info/WHEEL +4 -0
- avalan-1.0.3.dist-info/entry_points.txt +3 -0
avalan/__init__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from packaging.version import parse, Version
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from tomllib import load
|
|
4
|
+
from urllib.parse import urlparse
|
|
5
|
+
from urllib.parse import ParseResult
|
|
6
|
+
|
|
7
|
+
def _config() -> dict:
|
|
8
|
+
project_path = Path(__file__).resolve().parents[2] / 'pyproject.toml'
|
|
9
|
+
with open(project_path, "rb") as file:
|
|
10
|
+
config = load(file)
|
|
11
|
+
return config
|
|
12
|
+
|
|
13
|
+
config = _config()
|
|
14
|
+
|
|
15
|
+
def license() -> str:
|
|
16
|
+
assert "project" in config and "license" in config["project"] and "text" in config["project"]["license"]
|
|
17
|
+
return config["project"]["license"]["text"]
|
|
18
|
+
|
|
19
|
+
def name() -> str:
|
|
20
|
+
assert "project" in config and "name" in config["project"]
|
|
21
|
+
return config["project"]["name"]
|
|
22
|
+
|
|
23
|
+
def version() -> Version:
|
|
24
|
+
assert "project" in config and "version" in config["project"]
|
|
25
|
+
version = config["project"]["version"]
|
|
26
|
+
return parse(version)
|
|
27
|
+
|
|
28
|
+
def site() -> ParseResult:
|
|
29
|
+
assert "project" in config and "urls" in config["project"] and "homepage" in config["project"]["urls"]
|
|
30
|
+
homepage = config["project"]["urls"]["homepage"]
|
|
31
|
+
return urlparse(homepage)
|
|
32
|
+
|
avalan/agent/__init__.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from avalan.model.entities import (
|
|
2
|
+
EngineSettings,
|
|
3
|
+
EngineUri,
|
|
4
|
+
GenerationSettings,
|
|
5
|
+
TransformerEngineSettings
|
|
6
|
+
)
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from enum import StrEnum
|
|
9
|
+
from typing import Optional, Union
|
|
10
|
+
|
|
11
|
+
class NoOperationAvailableException(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
class EngineType(StrEnum):
|
|
15
|
+
TEXT_GENERATION = "text_generation"
|
|
16
|
+
|
|
17
|
+
class InputType(StrEnum):
|
|
18
|
+
TEXT = "text"
|
|
19
|
+
|
|
20
|
+
class OutputType(StrEnum):
|
|
21
|
+
JSON = "json"
|
|
22
|
+
TEXT = "text"
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True, kw_only=True)
|
|
25
|
+
class Goal:
|
|
26
|
+
task: str
|
|
27
|
+
instructions: list[str]
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True, kw_only=True)
|
|
30
|
+
class Role:
|
|
31
|
+
persona: list[str]
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True, kw_only=True)
|
|
34
|
+
class Specification:
|
|
35
|
+
role: Role
|
|
36
|
+
goal: Optional[Goal]
|
|
37
|
+
rules: list[str]=field(default_factory=list)
|
|
38
|
+
input_type: InputType=InputType.TEXT
|
|
39
|
+
output_type: OutputType=OutputType.TEXT
|
|
40
|
+
settings: Optional[GenerationSettings]=None
|
|
41
|
+
template_id: Optional[str]=None
|
|
42
|
+
template_vars: Optional[dict]=None
|
|
43
|
+
|
|
44
|
+
@dataclass(frozen=True, kw_only=True)
|
|
45
|
+
class EngineEnvironment:
|
|
46
|
+
engine_uri: EngineUri
|
|
47
|
+
settings: Union[EngineSettings, TransformerEngineSettings]
|
|
48
|
+
type: EngineType=EngineType.TEXT_GENERATION
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True, kw_only=True)
|
|
51
|
+
class Operation:
|
|
52
|
+
specification: Specification
|
|
53
|
+
environment: EngineEnvironment
|
|
54
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[agent]
|
|
2
|
+
{% if name %}name = "{{ name }}"{% endif %}
|
|
3
|
+
role = """
|
|
4
|
+
{{ role | indent(4) }}
|
|
5
|
+
"""
|
|
6
|
+
{% if task %}
|
|
7
|
+
task = """
|
|
8
|
+
{{ task | indent(4) }}
|
|
9
|
+
"""
|
|
10
|
+
{% endif %}
|
|
11
|
+
{% if instructions %}
|
|
12
|
+
instructions = """
|
|
13
|
+
{{ instructions | indent(4) }}
|
|
14
|
+
"""
|
|
15
|
+
{% endif %}
|
|
16
|
+
|
|
17
|
+
[memory]
|
|
18
|
+
recent = {{ memory_recent | lower }}
|
|
19
|
+
{% if memory_permanent %}permanent = "{{ memory_permanent }}"{% endif %}
|
|
20
|
+
|
|
21
|
+
[memory.engine]
|
|
22
|
+
model_id = "{{ memory_engine_model_id }}"
|
|
23
|
+
|
|
24
|
+
[engine]
|
|
25
|
+
uri = "{{ engine_uri }}"
|
|
26
|
+
|
|
27
|
+
[run]
|
|
28
|
+
use_cache = {{ run_use_cache | lower }}
|
|
29
|
+
max_new_tokens = {{ max_new_tokens }}
|
|
30
|
+
skip_special_tokens = {{ run_skip_special_tokens | lower }}
|
avalan/agent/engine.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from avalan.agent import Specification
|
|
3
|
+
from avalan.memory.manager import MemoryManager
|
|
4
|
+
from avalan.model.engine import Engine
|
|
5
|
+
from avalan.model.entities import (
|
|
6
|
+
EngineMessage,
|
|
7
|
+
GenerationSettings,
|
|
8
|
+
Input,
|
|
9
|
+
Message,
|
|
10
|
+
MessageRole,
|
|
11
|
+
)
|
|
12
|
+
from avalan.model.nlp.text import TextGenerationResponse
|
|
13
|
+
from avalan.model.nlp.text.vendor import TextGenerationVendorModel
|
|
14
|
+
from avalan.tool.manager import ToolManager
|
|
15
|
+
from dataclasses import replace
|
|
16
|
+
from typing import Any, Optional, Union, Tuple
|
|
17
|
+
from uuid import UUID, uuid4
|
|
18
|
+
|
|
19
|
+
class EngineAgent(ABC):
|
|
20
|
+
_id: UUID
|
|
21
|
+
_name: Optional[str]
|
|
22
|
+
_model: Engine
|
|
23
|
+
_memory: MemoryManager
|
|
24
|
+
_tool: ToolManager
|
|
25
|
+
_last_output: Optional[TextGenerationResponse]=None
|
|
26
|
+
_last_prompt: Optional[Tuple[Input,Optional[str]]]=None
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def _prepare_call(
|
|
30
|
+
self,
|
|
31
|
+
specification: Specification,
|
|
32
|
+
input: str,
|
|
33
|
+
**kwargs: Any
|
|
34
|
+
) -> Any:
|
|
35
|
+
raise NotImplementedError()
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def memory(self) -> MemoryManager:
|
|
39
|
+
return self._memory
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def engine(self) -> Engine:
|
|
43
|
+
return self._model
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def output(self) -> Optional[TextGenerationResponse]:
|
|
47
|
+
return self._last_output
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def input_token_count(self) -> Optional[int]:
|
|
51
|
+
return self._model.input_token_count(
|
|
52
|
+
self._last_prompt[0],
|
|
53
|
+
system_prompt=self._last_prompt[1]
|
|
54
|
+
) if self._last_prompt else None
|
|
55
|
+
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
model: Engine,
|
|
59
|
+
memory: MemoryManager,
|
|
60
|
+
tool: ToolManager,
|
|
61
|
+
*args,
|
|
62
|
+
name: Optional[str]=None,
|
|
63
|
+
id: Optional[UUID]=None,
|
|
64
|
+
):
|
|
65
|
+
self._id = id or uuid4()
|
|
66
|
+
self._name = name
|
|
67
|
+
self._model = model
|
|
68
|
+
self._memory = memory
|
|
69
|
+
self._tool = tool
|
|
70
|
+
|
|
71
|
+
async def __call__(
|
|
72
|
+
self,
|
|
73
|
+
specification: Specification,
|
|
74
|
+
input: str,
|
|
75
|
+
**kwargs
|
|
76
|
+
) -> Union[
|
|
77
|
+
TextGenerationResponse,
|
|
78
|
+
str
|
|
79
|
+
]:
|
|
80
|
+
run_args = self._prepare_call(specification, input, **kwargs)
|
|
81
|
+
return await self._run(input, **run_args)
|
|
82
|
+
|
|
83
|
+
async def _run(
|
|
84
|
+
self,
|
|
85
|
+
input: str,
|
|
86
|
+
*args,
|
|
87
|
+
settings: Optional[GenerationSettings]=None,
|
|
88
|
+
system_prompt: Optional[str]=None,
|
|
89
|
+
skip_special_tokens=True,
|
|
90
|
+
**kwargs
|
|
91
|
+
) -> Union[
|
|
92
|
+
TextGenerationResponse
|
|
93
|
+
]:
|
|
94
|
+
# Process settings
|
|
95
|
+
if settings and kwargs:
|
|
96
|
+
settings = replace(settings, **kwargs)
|
|
97
|
+
elif not settings:
|
|
98
|
+
kwargs.setdefault("temperature", None)
|
|
99
|
+
kwargs.setdefault("do_sample", False)
|
|
100
|
+
settings = GenerationSettings(**kwargs)
|
|
101
|
+
assert settings
|
|
102
|
+
|
|
103
|
+
# Prepare memory
|
|
104
|
+
assert not self._memory.has_recent_message \
|
|
105
|
+
or self._memory.recent_message is not None
|
|
106
|
+
|
|
107
|
+
# Should always be stored, with or without memory
|
|
108
|
+
self._last_prompt = (input, system_prompt)
|
|
109
|
+
|
|
110
|
+
# Transform input (by adding memory, if necessary)
|
|
111
|
+
if (
|
|
112
|
+
self._memory.has_permanent_message or
|
|
113
|
+
self._memory.has_recent_message
|
|
114
|
+
) and isinstance(input,Message):
|
|
115
|
+
previous_message: Optional[Message]=None
|
|
116
|
+
new_message: Message = input
|
|
117
|
+
|
|
118
|
+
# Handle last message if not already consumed
|
|
119
|
+
previous_output = self._last_output
|
|
120
|
+
if previous_output \
|
|
121
|
+
and isinstance(previous_output, TextGenerationResponse):
|
|
122
|
+
previous_message = Message(
|
|
123
|
+
role=MessageRole.ASSISTANT,
|
|
124
|
+
content=await previous_output.to_str()
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Append messages
|
|
128
|
+
if previous_message:
|
|
129
|
+
await self._memory.append_message(EngineMessage(
|
|
130
|
+
agent_id=self._id,
|
|
131
|
+
model_id=self._model.model_id,
|
|
132
|
+
message=previous_message
|
|
133
|
+
))
|
|
134
|
+
await self._memory.append_message(EngineMessage(
|
|
135
|
+
agent_id=self._id,
|
|
136
|
+
model_id=self._model.model_id,
|
|
137
|
+
message=new_message
|
|
138
|
+
))
|
|
139
|
+
|
|
140
|
+
# Make recent memory the new model input
|
|
141
|
+
input = [ rm.message for rm in self._memory.recent_messages ]
|
|
142
|
+
|
|
143
|
+
# Have model generate output from input
|
|
144
|
+
|
|
145
|
+
model_settings = dict(
|
|
146
|
+
system_prompt=system_prompt,
|
|
147
|
+
settings=settings,
|
|
148
|
+
tool=self._tool
|
|
149
|
+
)
|
|
150
|
+
if not isinstance(self._model, TextGenerationVendorModel):
|
|
151
|
+
model_settings["skip_special_tokens"] = skip_special_tokens
|
|
152
|
+
|
|
153
|
+
output = await self._model(input, **model_settings)
|
|
154
|
+
|
|
155
|
+
# Update memory
|
|
156
|
+
if self._memory.has_recent_message:
|
|
157
|
+
self._last_output = output
|
|
158
|
+
|
|
159
|
+
return output
|
|
160
|
+
|
avalan/agent/loader.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
from avalan.agent.orchestrator import Orchestrator
|
|
2
|
+
from avalan.agent.orchestrators.default import DefaultOrchestrator
|
|
3
|
+
from avalan.agent.orchestrators.json import JsonOrchestrator, Property
|
|
4
|
+
from avalan.memory.manager import MemoryManager
|
|
5
|
+
from avalan.memory.partitioner.text import TextPartitioner
|
|
6
|
+
from avalan.model.entities import EngineUri, TransformerEngineSettings
|
|
7
|
+
from avalan.model.hubs.huggingface import HuggingfaceHub
|
|
8
|
+
from avalan.model.manager import ModelManager
|
|
9
|
+
from avalan.model.nlp.sentence import SentenceTransformerModel
|
|
10
|
+
from avalan.tool.manager import ToolManager
|
|
11
|
+
from avalan.event.manager import EventManager
|
|
12
|
+
from contextlib import AsyncExitStack
|
|
13
|
+
from logging import Logger
|
|
14
|
+
from os import access, R_OK
|
|
15
|
+
from os.path import exists
|
|
16
|
+
from tomllib import load
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from uuid import UUID, uuid4
|
|
19
|
+
|
|
20
|
+
class Loader:
|
|
21
|
+
DEFAULT_SENTENCE_MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
async def from_file(
|
|
25
|
+
cls,
|
|
26
|
+
path: str,
|
|
27
|
+
*args,
|
|
28
|
+
agent_id: Optional[UUID],
|
|
29
|
+
hub: HuggingfaceHub,
|
|
30
|
+
logger: Logger,
|
|
31
|
+
participant_id: UUID,
|
|
32
|
+
stack: AsyncExitStack,
|
|
33
|
+
disable_memory: bool=False
|
|
34
|
+
) -> Orchestrator:
|
|
35
|
+
if not exists(path):
|
|
36
|
+
raise FileNotFoundError(path)
|
|
37
|
+
elif not access(path, R_OK):
|
|
38
|
+
raise PermissionError(path)
|
|
39
|
+
|
|
40
|
+
logger.debug(f"Loading agent from {path}")
|
|
41
|
+
|
|
42
|
+
with open(path, "rb") as file:
|
|
43
|
+
config = load(file)
|
|
44
|
+
|
|
45
|
+
# Validate settings
|
|
46
|
+
|
|
47
|
+
assert "agent" in config, "No agent section in configuration"
|
|
48
|
+
assert "engine" in config, \
|
|
49
|
+
"No engine section defined in configuration"
|
|
50
|
+
assert "uri" in config["engine"], \
|
|
51
|
+
"No uri defined in engine section of configuration"
|
|
52
|
+
|
|
53
|
+
agent_config = config["agent"]
|
|
54
|
+
for setting in ["role"]:
|
|
55
|
+
assert setting in agent_config, \
|
|
56
|
+
f"No {setting} defined in agent section of configuration"
|
|
57
|
+
|
|
58
|
+
assert "engine" in config, \
|
|
59
|
+
"No engine section defined in configuration"
|
|
60
|
+
assert "uri" in config["engine"], \
|
|
61
|
+
"No uri defined in engine section of configuration"
|
|
62
|
+
|
|
63
|
+
uri = config["engine"]["uri"]
|
|
64
|
+
engine_config = config["engine"]
|
|
65
|
+
enable_tools = (
|
|
66
|
+
engine_config["tools"]
|
|
67
|
+
if "tools" in engine_config
|
|
68
|
+
else None
|
|
69
|
+
)
|
|
70
|
+
engine_config.pop("uri", None)
|
|
71
|
+
engine_config.pop("tools", None)
|
|
72
|
+
orchestrator_type = (
|
|
73
|
+
config["agent"]["type"] if "type" in config["agent"]
|
|
74
|
+
else None
|
|
75
|
+
)
|
|
76
|
+
agent_id = (
|
|
77
|
+
agent_id if agent_id
|
|
78
|
+
else config["agent"]["id"] if "id" in config["agent"]
|
|
79
|
+
else uuid4()
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
assert orchestrator_type is None or orchestrator_type in ["json"], \
|
|
83
|
+
f"Unknown type {config['agent']['type']} in agent section " + \
|
|
84
|
+
"of configuration"
|
|
85
|
+
assert "role" in agent_config, \
|
|
86
|
+
"No role defined in agent section of configuration"
|
|
87
|
+
|
|
88
|
+
call_options = config["run"] if "run" in config else None
|
|
89
|
+
template_vars = config["template"] \
|
|
90
|
+
if "template" in config else None
|
|
91
|
+
|
|
92
|
+
# Tool configuration
|
|
93
|
+
|
|
94
|
+
tool = ToolManager.create_instance(
|
|
95
|
+
enable_tools=enable_tools
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Memory configuration
|
|
99
|
+
|
|
100
|
+
memory_options = (
|
|
101
|
+
config["memory"]
|
|
102
|
+
if "memory" in config and not disable_memory
|
|
103
|
+
else None
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
memory_permanent = (
|
|
107
|
+
memory_options["permanent"]
|
|
108
|
+
if memory_options and "permanent" in memory_options
|
|
109
|
+
else None
|
|
110
|
+
)
|
|
111
|
+
assert not memory_permanent or isinstance(memory_permanent,str), \
|
|
112
|
+
"Permanent message memory should be a string"
|
|
113
|
+
memory_recent = (
|
|
114
|
+
memory_options["recent"]
|
|
115
|
+
if memory_options and "recent" in memory_options
|
|
116
|
+
else False
|
|
117
|
+
)
|
|
118
|
+
assert isinstance(memory_recent,bool), \
|
|
119
|
+
"Recent message memory can only be set or unset"
|
|
120
|
+
|
|
121
|
+
sentence_model_id = (
|
|
122
|
+
config["memory.engine"]["model_id"]
|
|
123
|
+
if "memory.engine" in config and
|
|
124
|
+
"model_id" in config["memory.engine"]
|
|
125
|
+
else Loader.DEFAULT_SENTENCE_MODEL_ID
|
|
126
|
+
)
|
|
127
|
+
sentence_model_engine_config = (
|
|
128
|
+
config["memory.engine"]
|
|
129
|
+
if "memory.engine" in config
|
|
130
|
+
else None
|
|
131
|
+
)
|
|
132
|
+
sentence_model_max_tokens = (
|
|
133
|
+
config["memory.engine"]["max_tokens"]
|
|
134
|
+
if sentence_model_engine_config
|
|
135
|
+
and "max_tokens" in sentence_model_engine_config
|
|
136
|
+
else 500
|
|
137
|
+
)
|
|
138
|
+
sentence_model_overlap_size = (
|
|
139
|
+
config["memory.engine"]["overlap_size"]
|
|
140
|
+
if sentence_model_engine_config
|
|
141
|
+
and "overlap_size" in sentence_model_engine_config
|
|
142
|
+
else 125
|
|
143
|
+
)
|
|
144
|
+
sentence_model_window_size = (
|
|
145
|
+
config["memory.engine"]["window_size"]
|
|
146
|
+
if sentence_model_engine_config
|
|
147
|
+
and "window_size" in sentence_model_engine_config
|
|
148
|
+
else 250
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if sentence_model_engine_config:
|
|
152
|
+
sentence_model_engine_config.pop("model_id", None)
|
|
153
|
+
sentence_model_engine_config.pop("max_tokens", None)
|
|
154
|
+
sentence_model_engine_config.pop("overlap_size", None)
|
|
155
|
+
sentence_model_engine_config.pop("window_size", None)
|
|
156
|
+
|
|
157
|
+
sentence_model_engine_settings = (
|
|
158
|
+
TransformerEngineSettings(**sentence_model_engine_config)
|
|
159
|
+
if sentence_model_engine_config
|
|
160
|
+
else TransformerEngineSettings()
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
logger.debug("Loading sentence transformer "
|
|
164
|
+
f"model {sentence_model_id} for agent {agent_id}")
|
|
165
|
+
|
|
166
|
+
sentence_model = SentenceTransformerModel(
|
|
167
|
+
model_id=sentence_model_id,
|
|
168
|
+
settings=sentence_model_engine_settings,
|
|
169
|
+
logger=logger
|
|
170
|
+
)
|
|
171
|
+
sentence_model = stack.enter_context(sentence_model)
|
|
172
|
+
|
|
173
|
+
logger.debug("Loading text partitioner for "
|
|
174
|
+
f"model {sentence_model_id} for agent {agent_id} "
|
|
175
|
+
f"with settings ({sentence_model_max_tokens}, "
|
|
176
|
+
f"{sentence_model_overlap_size}, "
|
|
177
|
+
f"{sentence_model_window_size})")
|
|
178
|
+
|
|
179
|
+
text_partitioner = TextPartitioner(
|
|
180
|
+
model=sentence_model,
|
|
181
|
+
logger=logger,
|
|
182
|
+
max_tokens=sentence_model_max_tokens,
|
|
183
|
+
overlap_size=sentence_model_overlap_size,
|
|
184
|
+
window_size=sentence_model_window_size
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
logger.debug(f"Loading memory manager for agent {agent_id}")
|
|
188
|
+
|
|
189
|
+
memory = await MemoryManager.create_instance(
|
|
190
|
+
agent_id=agent_id,
|
|
191
|
+
participant_id=participant_id,
|
|
192
|
+
text_partitioner=text_partitioner,
|
|
193
|
+
with_permanent_message_memory=memory_permanent,
|
|
194
|
+
with_recent_message_memory=memory_recent,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
event_manager = EventManager()
|
|
198
|
+
event_manager.add_listener(
|
|
199
|
+
lambda e: logger.debug(f"Event {e.type}: {e.payload}")
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Agent creation
|
|
203
|
+
|
|
204
|
+
logger.debug(f"Creating agent {orchestrator_type} #{agent_id}")
|
|
205
|
+
|
|
206
|
+
model_manager = ModelManager(hub, logger)
|
|
207
|
+
model_manager = stack.enter_context(model_manager)
|
|
208
|
+
|
|
209
|
+
engine_uri = model_manager.parse_uri(uri)
|
|
210
|
+
engine_settings = model_manager.get_engine_settings(
|
|
211
|
+
engine_uri,
|
|
212
|
+
settings=engine_config
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
agent = \
|
|
216
|
+
cls._load_json_orchestrator(
|
|
217
|
+
engine_uri=engine_uri,
|
|
218
|
+
engine_settings=engine_settings,
|
|
219
|
+
logger=logger,
|
|
220
|
+
model_manager=model_manager,
|
|
221
|
+
memory=memory,
|
|
222
|
+
tool=tool,
|
|
223
|
+
event_manager=event_manager,
|
|
224
|
+
config=config,
|
|
225
|
+
agent_config=agent_config,
|
|
226
|
+
call_options=call_options,
|
|
227
|
+
template_vars=template_vars
|
|
228
|
+
) if orchestrator_type == "json" else \
|
|
229
|
+
DefaultOrchestrator(
|
|
230
|
+
engine_uri,
|
|
231
|
+
logger,
|
|
232
|
+
model_manager,
|
|
233
|
+
memory,
|
|
234
|
+
tool,
|
|
235
|
+
event_manager,
|
|
236
|
+
name=agent_config["name"] \
|
|
237
|
+
if "name" in agent_config else None,
|
|
238
|
+
role=agent_config["role"],
|
|
239
|
+
task=agent_config["task"]
|
|
240
|
+
if "task" in agent_config else None,
|
|
241
|
+
instructions=agent_config["instructions"]
|
|
242
|
+
if "instructions" in agent_config else None,
|
|
243
|
+
rules=agent_config["rules"]
|
|
244
|
+
if "rules" in agent_config else None,
|
|
245
|
+
settings=engine_settings,
|
|
246
|
+
call_options=call_options,
|
|
247
|
+
template_vars=template_vars
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
return agent
|
|
251
|
+
|
|
252
|
+
@staticmethod
|
|
253
|
+
def _load_json_orchestrator(
|
|
254
|
+
engine_uri: EngineUri,
|
|
255
|
+
engine_settings: TransformerEngineSettings,
|
|
256
|
+
logger: Logger,
|
|
257
|
+
model_manager: ModelManager,
|
|
258
|
+
memory: MemoryManager,
|
|
259
|
+
tool: ToolManager,
|
|
260
|
+
event_manager: EventManager,
|
|
261
|
+
config: dict,
|
|
262
|
+
agent_config: dict,
|
|
263
|
+
call_options: Optional[dict],
|
|
264
|
+
template_vars: Optional[dict]
|
|
265
|
+
) -> JsonOrchestrator:
|
|
266
|
+
assert "json" in config, "No json section in configuration"
|
|
267
|
+
assert "instructions" in agent_config, \
|
|
268
|
+
"No instructions defined in agent section of configuration"
|
|
269
|
+
assert "task" in agent_config, \
|
|
270
|
+
"No task defined in agent section of configuration"
|
|
271
|
+
assert "role" in agent_config, \
|
|
272
|
+
"No role defined in agent section of configuration"
|
|
273
|
+
|
|
274
|
+
properties : list[Property] = []
|
|
275
|
+
for property_name in config.get("json", []):
|
|
276
|
+
output_property = config["json"][property_name]
|
|
277
|
+
properties.append(Property(
|
|
278
|
+
name=property_name,
|
|
279
|
+
data_type=output_property["type"],
|
|
280
|
+
description=output_property["description"]
|
|
281
|
+
))
|
|
282
|
+
|
|
283
|
+
assert properties, "No properties defined in configuration"
|
|
284
|
+
|
|
285
|
+
agent = JsonOrchestrator(
|
|
286
|
+
engine_uri,
|
|
287
|
+
logger,
|
|
288
|
+
model_manager,
|
|
289
|
+
memory,
|
|
290
|
+
tool,
|
|
291
|
+
event_manager,
|
|
292
|
+
properties,
|
|
293
|
+
name=agent_config["name"] if "name" in agent_config else None,
|
|
294
|
+
role=agent_config["role"],
|
|
295
|
+
task=agent_config["task"],
|
|
296
|
+
instructions=agent_config["instructions"],
|
|
297
|
+
rules=agent_config["rules"] if "rules" in agent_config else None,
|
|
298
|
+
settings=engine_settings,
|
|
299
|
+
call_options=call_options,
|
|
300
|
+
template_vars=template_vars
|
|
301
|
+
)
|
|
302
|
+
return agent
|
|
303
|
+
|