isage-middleware 0.2.4.3__cp311-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.
- isage_middleware-0.2.4.3.dist-info/METADATA +266 -0
- isage_middleware-0.2.4.3.dist-info/RECORD +94 -0
- isage_middleware-0.2.4.3.dist-info/WHEEL +5 -0
- isage_middleware-0.2.4.3.dist-info/top_level.txt +1 -0
- sage/middleware/__init__.py +59 -0
- sage/middleware/_version.py +6 -0
- sage/middleware/components/__init__.py +30 -0
- sage/middleware/components/extensions_compat.py +141 -0
- sage/middleware/components/sage_db/__init__.py +116 -0
- sage/middleware/components/sage_db/backend.py +136 -0
- sage/middleware/components/sage_db/service.py +15 -0
- sage/middleware/components/sage_flow/__init__.py +76 -0
- sage/middleware/components/sage_flow/python/__init__.py +14 -0
- sage/middleware/components/sage_flow/python/micro_service/__init__.py +4 -0
- sage/middleware/components/sage_flow/python/micro_service/sage_flow_service.py +88 -0
- sage/middleware/components/sage_flow/python/sage_flow.py +30 -0
- sage/middleware/components/sage_flow/service.py +14 -0
- sage/middleware/components/sage_mem/__init__.py +83 -0
- sage/middleware/components/sage_sias/__init__.py +59 -0
- sage/middleware/components/sage_sias/continual_learner.py +184 -0
- sage/middleware/components/sage_sias/coreset_selector.py +302 -0
- sage/middleware/components/sage_sias/types.py +94 -0
- sage/middleware/components/sage_tsdb/__init__.py +81 -0
- sage/middleware/components/sage_tsdb/python/__init__.py +21 -0
- sage/middleware/components/sage_tsdb/python/_sage_tsdb.pyi +17 -0
- sage/middleware/components/sage_tsdb/python/algorithms/__init__.py +17 -0
- sage/middleware/components/sage_tsdb/python/algorithms/base.py +51 -0
- sage/middleware/components/sage_tsdb/python/algorithms/out_of_order_join.py +248 -0
- sage/middleware/components/sage_tsdb/python/algorithms/window_aggregator.py +296 -0
- sage/middleware/components/sage_tsdb/python/micro_service/__init__.py +7 -0
- sage/middleware/components/sage_tsdb/python/micro_service/sage_tsdb_service.py +365 -0
- sage/middleware/components/sage_tsdb/python/sage_tsdb.py +523 -0
- sage/middleware/components/sage_tsdb/service.py +17 -0
- sage/middleware/components/vector_stores/__init__.py +25 -0
- sage/middleware/components/vector_stores/chroma.py +483 -0
- sage/middleware/components/vector_stores/chroma_adapter.py +185 -0
- sage/middleware/components/vector_stores/milvus.py +677 -0
- sage/middleware/operators/__init__.py +56 -0
- sage/middleware/operators/agent/__init__.py +24 -0
- sage/middleware/operators/agent/planning/__init__.py +5 -0
- sage/middleware/operators/agent/planning/llm_adapter.py +41 -0
- sage/middleware/operators/agent/planning/planner_adapter.py +98 -0
- sage/middleware/operators/agent/planning/router.py +107 -0
- sage/middleware/operators/agent/runtime.py +296 -0
- sage/middleware/operators/agentic/__init__.py +41 -0
- sage/middleware/operators/agentic/config.py +254 -0
- sage/middleware/operators/agentic/planning_operator.py +125 -0
- sage/middleware/operators/agentic/refined_searcher.py +132 -0
- sage/middleware/operators/agentic/runtime.py +241 -0
- sage/middleware/operators/agentic/timing_operator.py +125 -0
- sage/middleware/operators/agentic/tool_selection_operator.py +127 -0
- sage/middleware/operators/context/__init__.py +17 -0
- sage/middleware/operators/context/critic_evaluation.py +16 -0
- sage/middleware/operators/context/model_context.py +565 -0
- sage/middleware/operators/context/quality_label.py +12 -0
- sage/middleware/operators/context/search_query_results.py +61 -0
- sage/middleware/operators/context/search_result.py +42 -0
- sage/middleware/operators/context/search_session.py +79 -0
- sage/middleware/operators/filters/__init__.py +26 -0
- sage/middleware/operators/filters/context_sink.py +387 -0
- sage/middleware/operators/filters/context_source.py +376 -0
- sage/middleware/operators/filters/evaluate_filter.py +83 -0
- sage/middleware/operators/filters/tool_filter.py +74 -0
- sage/middleware/operators/llm/__init__.py +18 -0
- sage/middleware/operators/llm/sagellm_generator.py +432 -0
- sage/middleware/operators/rag/__init__.py +147 -0
- sage/middleware/operators/rag/arxiv.py +331 -0
- sage/middleware/operators/rag/chunk.py +13 -0
- sage/middleware/operators/rag/document_loaders.py +23 -0
- sage/middleware/operators/rag/evaluate.py +658 -0
- sage/middleware/operators/rag/generator.py +340 -0
- sage/middleware/operators/rag/index_builder/__init__.py +48 -0
- sage/middleware/operators/rag/index_builder/builder.py +363 -0
- sage/middleware/operators/rag/index_builder/manifest.py +101 -0
- sage/middleware/operators/rag/index_builder/storage.py +131 -0
- sage/middleware/operators/rag/pipeline.py +46 -0
- sage/middleware/operators/rag/profiler.py +59 -0
- sage/middleware/operators/rag/promptor.py +400 -0
- sage/middleware/operators/rag/refiner.py +231 -0
- sage/middleware/operators/rag/reranker.py +364 -0
- sage/middleware/operators/rag/retriever.py +1308 -0
- sage/middleware/operators/rag/searcher.py +37 -0
- sage/middleware/operators/rag/types.py +28 -0
- sage/middleware/operators/rag/writer.py +80 -0
- sage/middleware/operators/tools/__init__.py +71 -0
- sage/middleware/operators/tools/arxiv_paper_searcher.py +175 -0
- sage/middleware/operators/tools/arxiv_searcher.py +102 -0
- sage/middleware/operators/tools/duckduckgo_searcher.py +105 -0
- sage/middleware/operators/tools/image_captioner.py +104 -0
- sage/middleware/operators/tools/nature_news_fetcher.py +224 -0
- sage/middleware/operators/tools/searcher_tool.py +514 -0
- sage/middleware/operators/tools/text_detector.py +185 -0
- sage/middleware/operators/tools/url_text_extractor.py +104 -0
- sage/middleware/py.typed +2 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""Agent Runtime Operator Configuration.
|
|
2
|
+
|
|
3
|
+
Provides dataclass-based configuration for AgentRuntimeOperator.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Any, Literal
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class GeneratorConfig:
|
|
14
|
+
"""Generator configuration for agent LLM calls.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
engine_type: Engine type to use:
|
|
18
|
+
- "sagellm" (default): SageLLMGenerator with configurable backend
|
|
19
|
+
- "openai": OpenAIGenerator for OpenAI-compatible APIs
|
|
20
|
+
- "hf": HFGenerator for HuggingFace models
|
|
21
|
+
backend_type: Backend type for sagellm engine:
|
|
22
|
+
- "auto" (default): Automatically select best available backend
|
|
23
|
+
- "mock": Mock backend for testing without GPU
|
|
24
|
+
- "cuda": NVIDIA CUDA backend
|
|
25
|
+
- "ascend": Huawei Ascend NPU backend
|
|
26
|
+
model_path: Model path or HuggingFace model ID (sagellm only)
|
|
27
|
+
device_map: Device mapping strategy (auto/cuda:0/cpu)
|
|
28
|
+
dtype: Data type (auto/float16/bfloat16)
|
|
29
|
+
max_tokens: Maximum generation tokens
|
|
30
|
+
temperature: Sampling temperature
|
|
31
|
+
top_p: Nucleus sampling parameter
|
|
32
|
+
top_k: Top-k sampling parameter
|
|
33
|
+
timeout: Request timeout in seconds
|
|
34
|
+
default_options: Default generation options
|
|
35
|
+
model_name: Model name for OpenAI (openai only)
|
|
36
|
+
base_url: API base URL (openai only)
|
|
37
|
+
api_key: API key (openai only)
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
engine_type: Literal["sagellm", "openai", "hf"] = "sagellm"
|
|
41
|
+
|
|
42
|
+
# SageLLM options
|
|
43
|
+
backend_type: str = "auto"
|
|
44
|
+
model_path: str = ""
|
|
45
|
+
device_map: str = "auto"
|
|
46
|
+
dtype: str = "auto"
|
|
47
|
+
max_tokens: int = 2048
|
|
48
|
+
temperature: float = 0.7
|
|
49
|
+
top_p: float = 0.95
|
|
50
|
+
top_k: int = 50
|
|
51
|
+
timeout: float = 120.0
|
|
52
|
+
default_options: dict[str, Any] = field(default_factory=dict)
|
|
53
|
+
|
|
54
|
+
# OpenAI options
|
|
55
|
+
model_name: str = ""
|
|
56
|
+
base_url: str = ""
|
|
57
|
+
api_key: str = ""
|
|
58
|
+
|
|
59
|
+
def to_dict(self) -> dict[str, Any]:
|
|
60
|
+
"""Convert to dictionary for operator initialization."""
|
|
61
|
+
return {
|
|
62
|
+
"engine_type": self.engine_type,
|
|
63
|
+
"backend_type": self.backend_type,
|
|
64
|
+
"model_path": self.model_path,
|
|
65
|
+
"device_map": self.device_map,
|
|
66
|
+
"dtype": self.dtype,
|
|
67
|
+
"max_tokens": self.max_tokens,
|
|
68
|
+
"temperature": self.temperature,
|
|
69
|
+
"top_p": self.top_p,
|
|
70
|
+
"top_k": self.top_k,
|
|
71
|
+
"timeout": self.timeout,
|
|
72
|
+
"default_options": self.default_options,
|
|
73
|
+
"model_name": self.model_name,
|
|
74
|
+
"base_url": self.base_url,
|
|
75
|
+
"api_key": self.api_key,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class ProfileConfig:
|
|
81
|
+
"""Agent profile configuration.
|
|
82
|
+
|
|
83
|
+
Attributes:
|
|
84
|
+
name: Agent name
|
|
85
|
+
description: Agent description
|
|
86
|
+
role: Agent role (assistant/user/system)
|
|
87
|
+
system_prompt: System prompt for the agent
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
name: str = "DefaultAgent"
|
|
91
|
+
description: str = "A general-purpose AI assistant"
|
|
92
|
+
role: str = "assistant"
|
|
93
|
+
system_prompt: str = "You are a helpful assistant."
|
|
94
|
+
|
|
95
|
+
def to_dict(self) -> dict[str, Any]:
|
|
96
|
+
"""Convert to dictionary for operator initialization."""
|
|
97
|
+
return {
|
|
98
|
+
"name": self.name,
|
|
99
|
+
"description": self.description,
|
|
100
|
+
"role": self.role,
|
|
101
|
+
"system_prompt": self.system_prompt,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class RuntimeSettings:
|
|
107
|
+
"""Runtime settings for agent execution.
|
|
108
|
+
|
|
109
|
+
Attributes:
|
|
110
|
+
max_steps: Maximum execution steps
|
|
111
|
+
summarizer: Summarizer config (null/"reuse_generator"/dict)
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
max_steps: int = 6
|
|
115
|
+
summarizer: str | dict[str, Any] | None = "reuse_generator"
|
|
116
|
+
|
|
117
|
+
def to_dict(self) -> dict[str, Any]:
|
|
118
|
+
"""Convert to dictionary for operator initialization."""
|
|
119
|
+
return {
|
|
120
|
+
"max_steps": self.max_steps,
|
|
121
|
+
"summarizer": self.summarizer,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class AgentRuntimeConfig:
|
|
127
|
+
"""Complete configuration for AgentRuntimeOperator.
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
```python
|
|
131
|
+
# Create config with mock backend for testing
|
|
132
|
+
config = AgentRuntimeConfig(
|
|
133
|
+
generator=GeneratorConfig(
|
|
134
|
+
engine_type="sagellm",
|
|
135
|
+
backend_type="mock",
|
|
136
|
+
),
|
|
137
|
+
profile=ProfileConfig(name="TestBot"),
|
|
138
|
+
)
|
|
139
|
+
operator = AgentRuntimeOperator(config=config.to_dict())
|
|
140
|
+
|
|
141
|
+
# Create config with OpenAI
|
|
142
|
+
config = AgentRuntimeConfig(
|
|
143
|
+
generator=GeneratorConfig(
|
|
144
|
+
engine_type="openai",
|
|
145
|
+
model_name="gpt-4o-mini",
|
|
146
|
+
api_key="sk-xxx", # pragma: allowlist secret
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Attributes:
|
|
152
|
+
generator: Generator configuration
|
|
153
|
+
profile: Agent profile configuration
|
|
154
|
+
planner: Planner configuration (optional)
|
|
155
|
+
tools: List of tool specifications
|
|
156
|
+
runtime: Runtime settings
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
generator: GeneratorConfig = field(default_factory=GeneratorConfig)
|
|
160
|
+
profile: ProfileConfig = field(default_factory=ProfileConfig)
|
|
161
|
+
planner: dict[str, Any] = field(default_factory=dict)
|
|
162
|
+
tools: list[dict[str, Any]] = field(default_factory=list)
|
|
163
|
+
runtime: RuntimeSettings = field(default_factory=RuntimeSettings)
|
|
164
|
+
|
|
165
|
+
def to_dict(self) -> dict[str, Any]:
|
|
166
|
+
"""Convert to dictionary for operator initialization."""
|
|
167
|
+
return {
|
|
168
|
+
"generator": self.generator.to_dict(),
|
|
169
|
+
"profile": self.profile.to_dict(),
|
|
170
|
+
"planner": self.planner,
|
|
171
|
+
"tools": self.tools,
|
|
172
|
+
"runtime": self.runtime.to_dict(),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@classmethod
|
|
176
|
+
def for_mock_testing(cls, profile_name: str = "TestBot") -> AgentRuntimeConfig:
|
|
177
|
+
"""Create a configuration for mock testing.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
profile_name: Name for the test agent profile
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
AgentRuntimeConfig configured for mock backend
|
|
184
|
+
"""
|
|
185
|
+
return cls(
|
|
186
|
+
generator=GeneratorConfig(
|
|
187
|
+
engine_type="sagellm",
|
|
188
|
+
backend_type="mock",
|
|
189
|
+
),
|
|
190
|
+
profile=ProfileConfig(name=profile_name),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def for_openai(
|
|
195
|
+
cls,
|
|
196
|
+
model_name: str = "gpt-4o-mini",
|
|
197
|
+
api_key: str = "",
|
|
198
|
+
base_url: str = "https://api.openai.com/v1",
|
|
199
|
+
profile_name: str = "OpenAIAgent",
|
|
200
|
+
) -> AgentRuntimeConfig:
|
|
201
|
+
"""Create a configuration for OpenAI.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
model_name: OpenAI model name
|
|
205
|
+
api_key: OpenAI API key
|
|
206
|
+
base_url: API base URL
|
|
207
|
+
profile_name: Name for the agent profile
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
AgentRuntimeConfig configured for OpenAI
|
|
211
|
+
"""
|
|
212
|
+
return cls(
|
|
213
|
+
generator=GeneratorConfig(
|
|
214
|
+
engine_type="openai",
|
|
215
|
+
model_name=model_name,
|
|
216
|
+
api_key=api_key,
|
|
217
|
+
base_url=base_url,
|
|
218
|
+
),
|
|
219
|
+
profile=ProfileConfig(name=profile_name),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
@classmethod
|
|
223
|
+
def for_sagellm(
|
|
224
|
+
cls,
|
|
225
|
+
model_path: str,
|
|
226
|
+
backend_type: str = "auto",
|
|
227
|
+
profile_name: str = "SageLLMAgent",
|
|
228
|
+
) -> AgentRuntimeConfig:
|
|
229
|
+
"""Create a configuration for SageLLM.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
model_path: Model path or HuggingFace model ID
|
|
233
|
+
backend_type: Backend type (auto/mock/cuda/ascend)
|
|
234
|
+
profile_name: Name for the agent profile
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
AgentRuntimeConfig configured for SageLLM
|
|
238
|
+
"""
|
|
239
|
+
return cls(
|
|
240
|
+
generator=GeneratorConfig(
|
|
241
|
+
engine_type="sagellm",
|
|
242
|
+
backend_type=backend_type,
|
|
243
|
+
model_path=model_path,
|
|
244
|
+
),
|
|
245
|
+
profile=ProfileConfig(name=profile_name),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
__all__ = [
|
|
250
|
+
"AgentRuntimeConfig",
|
|
251
|
+
"GeneratorConfig",
|
|
252
|
+
"ProfileConfig",
|
|
253
|
+
"RuntimeSettings",
|
|
254
|
+
]
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Planning Operator
|
|
3
|
+
|
|
4
|
+
Middleware operator for planning using runtime components.
|
|
5
|
+
|
|
6
|
+
Supports engine_type switching:
|
|
7
|
+
- sagellm (default): SageLLMGenerator with configurable backend
|
|
8
|
+
- backend_type="auto": Automatically select best available backend
|
|
9
|
+
- backend_type="mock": Mock backend for testing without GPU
|
|
10
|
+
- backend_type="cuda": NVIDIA CUDA backend
|
|
11
|
+
- backend_type="ascend": Huawei Ascend NPU backend
|
|
12
|
+
- openai: OpenAIGenerator for OpenAI-compatible APIs
|
|
13
|
+
- hf: HFGenerator for HuggingFace models
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Any, Optional
|
|
17
|
+
|
|
18
|
+
from sage_libs.sage_agentic.agents.runtime import BenchmarkAdapter, Orchestrator, RuntimeConfig
|
|
19
|
+
from sage_libs.sage_agentic.agents.runtime.config import PlannerConfig
|
|
20
|
+
|
|
21
|
+
from sage.common.core.functions import MapFunction
|
|
22
|
+
|
|
23
|
+
from .runtime import _build_generator
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PlanningOperator(MapFunction):
|
|
27
|
+
"""
|
|
28
|
+
Operator for planning.
|
|
29
|
+
|
|
30
|
+
Wraps runtime planner in a middleware operator interface.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
planner: Planner instance (optional)
|
|
34
|
+
config: Configuration dictionary with optional keys:
|
|
35
|
+
- planner: Planner-specific config
|
|
36
|
+
- generator: Generator config with engine_type/backend_type
|
|
37
|
+
- engine_type: Shorthand for generator.engine_type (sagellm/openai/hf)
|
|
38
|
+
- backend_type: Shorthand for generator.backend_type (auto/mock/cuda/ascend)
|
|
39
|
+
|
|
40
|
+
Example:
|
|
41
|
+
```python
|
|
42
|
+
# Using sagellm with mock backend (for testing)
|
|
43
|
+
operator = PlanningOperator(config={
|
|
44
|
+
"generator": {
|
|
45
|
+
"engine_type": "sagellm",
|
|
46
|
+
"backend_type": "mock",
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
# Using default sagellm with auto backend
|
|
51
|
+
operator = PlanningOperator(config={
|
|
52
|
+
"engine_type": "sagellm",
|
|
53
|
+
"backend_type": "auto",
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
planner: Optional[Any] = None,
|
|
61
|
+
config: Optional[dict[str, Any]] = None,
|
|
62
|
+
):
|
|
63
|
+
"""Initialize planning operator.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
planner: Planner instance (optional)
|
|
67
|
+
config: Configuration dictionary
|
|
68
|
+
"""
|
|
69
|
+
super().__init__()
|
|
70
|
+
|
|
71
|
+
# Parse configuration
|
|
72
|
+
if config is None:
|
|
73
|
+
config = {}
|
|
74
|
+
|
|
75
|
+
self.config = config
|
|
76
|
+
|
|
77
|
+
# Build generator if config provided
|
|
78
|
+
generator_conf = config.get("generator", {})
|
|
79
|
+
# Allow shorthand engine_type/backend_type at top level
|
|
80
|
+
if "engine_type" in config and "engine_type" not in generator_conf:
|
|
81
|
+
generator_conf["engine_type"] = config["engine_type"]
|
|
82
|
+
if "backend_type" in config and "backend_type" not in generator_conf:
|
|
83
|
+
generator_conf["backend_type"] = config["backend_type"]
|
|
84
|
+
|
|
85
|
+
# Build generator (defaults to sagellm with auto backend)
|
|
86
|
+
if generator_conf or not planner:
|
|
87
|
+
engine_type = generator_conf.get("engine_type", "sagellm")
|
|
88
|
+
# Ensure we have at least minimal config
|
|
89
|
+
if not generator_conf:
|
|
90
|
+
generator_conf = {"engine_type": "sagellm", "backend_type": "auto"}
|
|
91
|
+
self.generator = _build_generator(generator_conf, engine_type=engine_type)
|
|
92
|
+
else:
|
|
93
|
+
self.generator = None
|
|
94
|
+
|
|
95
|
+
planner_config = PlannerConfig(**config.get("planner", {}))
|
|
96
|
+
runtime_config = RuntimeConfig(planner=planner_config)
|
|
97
|
+
|
|
98
|
+
# Create orchestrator
|
|
99
|
+
self.orchestrator = Orchestrator(config=runtime_config, planner=planner)
|
|
100
|
+
|
|
101
|
+
# Create adapter for easy use
|
|
102
|
+
self.adapter = BenchmarkAdapter(self.orchestrator)
|
|
103
|
+
|
|
104
|
+
def __call__(self, request: Any) -> Any:
|
|
105
|
+
"""Execute planning.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
request: Planning request
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Generated plan
|
|
112
|
+
"""
|
|
113
|
+
return self.adapter.run_planning(request)
|
|
114
|
+
|
|
115
|
+
def execute(self, data: Any) -> Any:
|
|
116
|
+
"""Execute map function interface."""
|
|
117
|
+
return self.__call__(data)
|
|
118
|
+
|
|
119
|
+
def get_metrics(self) -> dict[str, Any]:
|
|
120
|
+
"""Get performance metrics.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Dictionary of metrics
|
|
124
|
+
"""
|
|
125
|
+
return self.adapter.get_metrics()
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RefinedSearcherOperator - Search with optional context compression.
|
|
3
|
+
|
|
4
|
+
Uses isage-refiner for context compression if enabled.
|
|
5
|
+
|
|
6
|
+
Installation:
|
|
7
|
+
pip install isage-refiner # Optional, only if refiner is used
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, AsyncGenerator, Optional
|
|
12
|
+
|
|
13
|
+
from sage_libs.sage_agentic.agents.bots.searcher_bot import SearcherBot
|
|
14
|
+
|
|
15
|
+
from sage.libs.foundation.tools.tool import BaseTool
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RefinedSearcherOperator:
|
|
21
|
+
"""
|
|
22
|
+
L4 Operator that wraps L3 SearcherBot and adds optional refiner capabilities.
|
|
23
|
+
|
|
24
|
+
Uses isage-refiner for context compression when refiner_config is provided.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
name = "search_internet"
|
|
28
|
+
description = "Search the internet for information using multiple sources (Arxiv, etc)."
|
|
29
|
+
input_schema = {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {"query": {"type": "string", "description": "The search query"}},
|
|
32
|
+
"required": ["query"],
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
input_types = {"query": "str - The search query"}
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self, tools: list[BaseTool], refiner_config: Optional[dict[str, Any]] = None, **kwargs
|
|
39
|
+
):
|
|
40
|
+
self.bot = SearcherBot(tools=tools, **kwargs)
|
|
41
|
+
|
|
42
|
+
self.compressor = None
|
|
43
|
+
if refiner_config:
|
|
44
|
+
try:
|
|
45
|
+
algorithm = refiner_config.get("algorithm", "long_refiner").lower()
|
|
46
|
+
self._init_compressor(algorithm, refiner_config)
|
|
47
|
+
logger.info(f"RefinedSearcherOperator: Initialized {algorithm} compressor")
|
|
48
|
+
except ImportError as e:
|
|
49
|
+
logger.warning(
|
|
50
|
+
f"RefinedSearcherOperator: isage-refiner not installed: {e}\n"
|
|
51
|
+
f"Install with: pip install isage-refiner"
|
|
52
|
+
)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
logger.warning(f"RefinedSearcherOperator: Failed to init compressor: {e}")
|
|
55
|
+
|
|
56
|
+
def _init_compressor(self, algorithm: str, config: dict[str, Any]):
|
|
57
|
+
"""Initialize compressor from isage-refiner."""
|
|
58
|
+
if algorithm == "long_refiner":
|
|
59
|
+
from sage_refiner import LongRefinerCompressor
|
|
60
|
+
|
|
61
|
+
self.compressor = LongRefinerCompressor(
|
|
62
|
+
base_model_path=config.get("base_model_path", "Qwen/Qwen2.5-3B-Instruct"),
|
|
63
|
+
score_model_path=config.get("score_model_path", "BAAI/bge-reranker-v2-m3"),
|
|
64
|
+
max_model_len=config.get("max_model_len", 25000),
|
|
65
|
+
gpu_memory_utilization=config.get("gpu_memory_utilization", 0.5),
|
|
66
|
+
)
|
|
67
|
+
elif algorithm == "reform":
|
|
68
|
+
from sage_refiner import REFORMCompressor
|
|
69
|
+
|
|
70
|
+
self.compressor = REFORMCompressor(**config.get("reform_config", {}))
|
|
71
|
+
elif algorithm == "provence":
|
|
72
|
+
from sage_refiner import ProvenceCompressor
|
|
73
|
+
|
|
74
|
+
self.compressor = ProvenceCompressor(**config.get("provence_config", {}))
|
|
75
|
+
else:
|
|
76
|
+
raise ValueError(f"Unsupported algorithm: {algorithm}")
|
|
77
|
+
|
|
78
|
+
self.budget = config.get("budget", 2048)
|
|
79
|
+
|
|
80
|
+
def call(self, arguments: dict) -> Any:
|
|
81
|
+
"""MCP compatible call method"""
|
|
82
|
+
import asyncio
|
|
83
|
+
|
|
84
|
+
query = arguments.get("query")
|
|
85
|
+
try:
|
|
86
|
+
loop = asyncio.get_running_loop()
|
|
87
|
+
if loop.is_running():
|
|
88
|
+
return asyncio.run(self.execute(query))
|
|
89
|
+
except RuntimeError:
|
|
90
|
+
return asyncio.run(self.execute(query))
|
|
91
|
+
|
|
92
|
+
return asyncio.run(self.execute(query))
|
|
93
|
+
|
|
94
|
+
async def execute(self, query: str) -> dict[str, Any]:
|
|
95
|
+
"""Execute search and optionally compress results."""
|
|
96
|
+
data = query
|
|
97
|
+
# 1. Execute L3 Bot
|
|
98
|
+
raw_result = await self.bot.execute(data)
|
|
99
|
+
results = raw_result.get("results", [])
|
|
100
|
+
|
|
101
|
+
# 2. Compress if enabled
|
|
102
|
+
if self.compressor and results:
|
|
103
|
+
query_str = data if isinstance(data, str) else data.get("query", "")
|
|
104
|
+
try:
|
|
105
|
+
logger.info(f"Compressing {len(results)} results for query: {query_str}")
|
|
106
|
+
|
|
107
|
+
# Normalize documents to isage-refiner format
|
|
108
|
+
documents = [
|
|
109
|
+
{"contents": r.get("contents") or r.get("text") or str(r)} for r in results
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
compress_result = self.compressor.compress(
|
|
113
|
+
question=query_str,
|
|
114
|
+
document_list=documents,
|
|
115
|
+
budget=self.budget,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
"results": compress_result.get("compressed_context", ""),
|
|
120
|
+
"original_count": len(results),
|
|
121
|
+
"compressed": True,
|
|
122
|
+
}
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Compression failed: {e}")
|
|
125
|
+
return raw_result
|
|
126
|
+
|
|
127
|
+
return raw_result
|
|
128
|
+
|
|
129
|
+
async def execute_stream(self, data: Any) -> AsyncGenerator[dict[str, Any], None]:
|
|
130
|
+
"""Stream execution. Compression is batch, so just stream search events."""
|
|
131
|
+
async for event in self.bot.execute_stream(data):
|
|
132
|
+
yield event
|