polaris-python-ai 0.0.1.dev2__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.
- polaris_ai/__init__.py +34 -0
- polaris_ai/_async.py +39 -0
- polaris_ai/_version.py +18 -0
- polaris_ai/a2a/__init__.py +31 -0
- polaris_ai/a2a/_card.py +44 -0
- polaris_ai/a2a/registry.py +240 -0
- polaris_ai/a2a/resolver.py +198 -0
- polaris_ai/a2a/server.py +92 -0
- polaris_ai/agentscope/__init__.py +76 -0
- polaris_ai/agentscope/a2a.py +276 -0
- polaris_ai/agentscope/cards.py +106 -0
- polaris_ai/agentscope/config.py +221 -0
- polaris_ai/agentscope/context.py +195 -0
- polaris_ai/agentscope/mcp.py +598 -0
- polaris_ai/agentscope/middleware.py +103 -0
- polaris_ai/agentscope/runtime.py +291 -0
- polaris_ai/agentscope/skill.py +464 -0
- polaris_ai/langgraph/__init__.py +50 -0
- polaris_ai/langgraph/config.py +160 -0
- polaris_ai/langgraph/context.py +152 -0
- polaris_ai/langgraph/registry.py +258 -0
- polaris_ai/langgraph/remote.py +315 -0
- polaris_ai/langgraph/resolver.py +226 -0
- polaris_ai/log.py +408 -0
- polaris_ai/metrics.py +154 -0
- polaris_python_ai-0.0.1.dev2.dist-info/METADATA +351 -0
- polaris_python_ai-0.0.1.dev2.dist-info/RECORD +30 -0
- polaris_python_ai-0.0.1.dev2.dist-info/WHEEL +5 -0
- polaris_python_ai-0.0.1.dev2.dist-info/licenses/LICENSE +27 -0
- polaris_python_ai-0.0.1.dev2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Tencent is pleased to support the open source community by making polaris-python-ai available.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2026 Tencent. All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the BSD 3-Clause License (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# https://opensource.org/licenses/BSD-3-Clause
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software distributed
|
|
12
|
+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
13
|
+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
14
|
+
# specific language governing permissions and limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Compose the Polaris AgentScope adapters from application options."""
|
|
17
|
+
|
|
18
|
+
from polaris.api.log import LogOptions
|
|
19
|
+
|
|
20
|
+
from polaris_ai._async import await_completion
|
|
21
|
+
from polaris_ai.a2a import PolarisA2ARegistrar, PolarisA2AResolver
|
|
22
|
+
from polaris_ai.agentscope.config import PolarisAgentConfig
|
|
23
|
+
from polaris_ai.agentscope.context import PolarisAgentContext
|
|
24
|
+
from polaris_ai.agentscope.middleware import (
|
|
25
|
+
PolarisDynamicSkillMiddleware,
|
|
26
|
+
get_shared_snapshot_loader,
|
|
27
|
+
)
|
|
28
|
+
from polaris_ai.agentscope.skill import PolarisSkillLoader
|
|
29
|
+
from polaris_ai.log import PolarisAILogOptions, configure_ai_logging
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class PolarisAgentRuntime:
|
|
33
|
+
"""Own configured adapters while preserving borrowed-context semantics."""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
config: PolarisAgentConfig,
|
|
38
|
+
*,
|
|
39
|
+
sdk_context=None,
|
|
40
|
+
log_options: LogOptions | None = None,
|
|
41
|
+
ai_log_options: PolarisAILogOptions | None = None,
|
|
42
|
+
):
|
|
43
|
+
if not isinstance(config, PolarisAgentConfig):
|
|
44
|
+
raise TypeError("config must be a PolarisAgentConfig")
|
|
45
|
+
if not config.enabled:
|
|
46
|
+
raise ValueError("Polaris AgentScope integration is disabled")
|
|
47
|
+
self.config = config
|
|
48
|
+
self.context = None
|
|
49
|
+
self.ai_logger = None
|
|
50
|
+
self.skill_loader: PolarisSkillLoader | None = None
|
|
51
|
+
self.resolver: PolarisA2AResolver | None = None
|
|
52
|
+
self.registrar: PolarisA2ARegistrar | None = None
|
|
53
|
+
self.mcp_resolver = None
|
|
54
|
+
self._skill_toolkit = None
|
|
55
|
+
self._closed = False
|
|
56
|
+
try:
|
|
57
|
+
self.context = PolarisAgentContext(
|
|
58
|
+
config.namespace,
|
|
59
|
+
address=config.addresses,
|
|
60
|
+
connector_token=config.connector_token,
|
|
61
|
+
skill_address=config.skill.addresses,
|
|
62
|
+
log_options=log_options,
|
|
63
|
+
sdk_context=sdk_context,
|
|
64
|
+
)
|
|
65
|
+
if ai_log_options is not None:
|
|
66
|
+
client_id_getter = getattr(self.context.context, "get_client_id", None)
|
|
67
|
+
client_id = (
|
|
68
|
+
client_id_getter() if callable(client_id_getter)
|
|
69
|
+
else f"runtime-{id(self.context.context)}"
|
|
70
|
+
)
|
|
71
|
+
self.ai_logger = configure_ai_logging(client_id, ai_log_options)
|
|
72
|
+
if config.skill.enabled:
|
|
73
|
+
self.skill_loader = PolarisSkillLoader(
|
|
74
|
+
self.context.context,
|
|
75
|
+
config.namespace,
|
|
76
|
+
service_name=(
|
|
77
|
+
config.skill.mounted_service_name if config.skill.mounted_enabled else ""
|
|
78
|
+
),
|
|
79
|
+
names=config.skill.names,
|
|
80
|
+
version=config.skill.version,
|
|
81
|
+
list_limit=config.skill.list_limit,
|
|
82
|
+
max_skills=config.skill.max_skills,
|
|
83
|
+
refresh_interval=config.skill.refresh_interval,
|
|
84
|
+
logger=self._category_logger("skill"),
|
|
85
|
+
)
|
|
86
|
+
if config.a2a.enabled and config.a2a.discovery.enabled:
|
|
87
|
+
self.resolver = PolarisA2AResolver(
|
|
88
|
+
self.context.context, config.namespace,
|
|
89
|
+
logger=self._category_logger("a2a"),
|
|
90
|
+
)
|
|
91
|
+
if config.a2a.enabled and config.a2a.registry.enabled:
|
|
92
|
+
self.registrar = PolarisA2ARegistrar(
|
|
93
|
+
self.context.context,
|
|
94
|
+
config.namespace,
|
|
95
|
+
service_token=config.service_token,
|
|
96
|
+
ttl=config.a2a.registry.ttl,
|
|
97
|
+
logger=self._category_logger("a2a"),
|
|
98
|
+
)
|
|
99
|
+
if config.mcp.enabled:
|
|
100
|
+
from polaris_ai.agentscope.mcp import PolarisMCPResolver
|
|
101
|
+
|
|
102
|
+
self.mcp_resolver = PolarisMCPResolver(
|
|
103
|
+
self.context.context,
|
|
104
|
+
config.namespace,
|
|
105
|
+
caller_service=config.mcp.caller_service,
|
|
106
|
+
labels=config.mcp.labels,
|
|
107
|
+
protocol_version=config.mcp.protocol_version,
|
|
108
|
+
scheme=config.mcp.scheme,
|
|
109
|
+
timeout=config.mcp.timeout,
|
|
110
|
+
filter_contract=config.mcp.filter_contract,
|
|
111
|
+
headers=dict(config.mcp.headers),
|
|
112
|
+
logger=self._category_logger("mcp"),
|
|
113
|
+
metrics_logger=self._category_logger("metrics"),
|
|
114
|
+
)
|
|
115
|
+
if self.ai_logger is not None:
|
|
116
|
+
self.ai_logger.get_logger("base").info(
|
|
117
|
+
"Initialized Polaris AI runtime: namespace=%s skill=%s "
|
|
118
|
+
"a2aRegistry=%s a2aDiscovery=%s mcp=%s",
|
|
119
|
+
config.namespace, config.skill.enabled,
|
|
120
|
+
config.a2a.enabled and config.a2a.registry.enabled,
|
|
121
|
+
config.a2a.enabled and config.a2a.discovery.enabled,
|
|
122
|
+
config.mcp.enabled,
|
|
123
|
+
)
|
|
124
|
+
self.ai_logger.get_logger("base").debug(
|
|
125
|
+
"Polaris AI runtime settings: addresses=%s skillMounted=%s "
|
|
126
|
+
"skillNames=%d mcpScheme=%s",
|
|
127
|
+
config.addresses, config.skill.mounted_enabled,
|
|
128
|
+
len(config.skill.names), config.mcp.scheme or "<instance>",
|
|
129
|
+
)
|
|
130
|
+
except BaseException:
|
|
131
|
+
self.close()
|
|
132
|
+
raise
|
|
133
|
+
|
|
134
|
+
def _category_logger(self, category):
|
|
135
|
+
return self.ai_logger.get_logger(category) if self.ai_logger is not None else None
|
|
136
|
+
|
|
137
|
+
def _log_close_start(self):
|
|
138
|
+
ai_logger = getattr(self, "ai_logger", None)
|
|
139
|
+
if ai_logger is None:
|
|
140
|
+
return
|
|
141
|
+
ai_logger.get_logger("base").info(
|
|
142
|
+
"Closing Polaris AI runtime: namespace=%s", self.config.namespace,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def provider(self):
|
|
147
|
+
return self.context.provider
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def consumer(self):
|
|
151
|
+
return self.context.consumer
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def skill(self):
|
|
155
|
+
return self.context.skill
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def skill_toolkit(self):
|
|
159
|
+
"""Build the Toolkit selected by ``skill.attach_to_agent``."""
|
|
160
|
+
self._check_open()
|
|
161
|
+
if (not self.config.skill.enabled or not self.config.skill.attach_to_agent
|
|
162
|
+
or self.skill_loader is None):
|
|
163
|
+
return None
|
|
164
|
+
if self._skill_toolkit is None:
|
|
165
|
+
from agentscope.tool import Toolkit
|
|
166
|
+
|
|
167
|
+
self._skill_toolkit = Toolkit(skills_or_loaders=[self.skill_loader])
|
|
168
|
+
return self._skill_toolkit
|
|
169
|
+
|
|
170
|
+
def _attach_skill_loader(self, toolkit):
|
|
171
|
+
for group in toolkit.tool_groups:
|
|
172
|
+
if group.name == "basic":
|
|
173
|
+
snapshot = get_shared_snapshot_loader(self.skill_loader)
|
|
174
|
+
if snapshot is not None:
|
|
175
|
+
normalized = []
|
|
176
|
+
snapshot_present = False
|
|
177
|
+
for item in group.skills_or_loaders:
|
|
178
|
+
if item is self.skill_loader:
|
|
179
|
+
continue
|
|
180
|
+
if item is snapshot:
|
|
181
|
+
if snapshot_present:
|
|
182
|
+
continue
|
|
183
|
+
snapshot_present = True
|
|
184
|
+
normalized.append(item)
|
|
185
|
+
if not snapshot_present:
|
|
186
|
+
normalized.append(snapshot)
|
|
187
|
+
group.skills_or_loaders[:] = normalized
|
|
188
|
+
return
|
|
189
|
+
if self.skill_loader not in group.skills_or_loaders:
|
|
190
|
+
group.skills_or_loaders.append(self.skill_loader)
|
|
191
|
+
return
|
|
192
|
+
raise ValueError("Toolkit has no basic tool group")
|
|
193
|
+
|
|
194
|
+
def create_agent(self, *, name: str, system_prompt: str, model, toolkit=None,
|
|
195
|
+
middlewares=(), **kwargs):
|
|
196
|
+
"""Create a native Agent with the configured Polaris Skill attachment."""
|
|
197
|
+
self._check_open()
|
|
198
|
+
from agentscope.agent import Agent
|
|
199
|
+
|
|
200
|
+
selected_toolkit = toolkit
|
|
201
|
+
selected_middlewares = list(middlewares)
|
|
202
|
+
if (self.config.skill.enabled and self.config.skill.attach_to_agent
|
|
203
|
+
and self.skill_loader is not None):
|
|
204
|
+
if selected_toolkit is None:
|
|
205
|
+
selected_toolkit = self.skill_toolkit
|
|
206
|
+
else:
|
|
207
|
+
self._attach_skill_loader(selected_toolkit)
|
|
208
|
+
selected_middlewares.append(PolarisDynamicSkillMiddleware(
|
|
209
|
+
self.skill_loader,
|
|
210
|
+
logger=self._category_logger("agentscope"),
|
|
211
|
+
))
|
|
212
|
+
return Agent(
|
|
213
|
+
name=name,
|
|
214
|
+
system_prompt=system_prompt,
|
|
215
|
+
model=model,
|
|
216
|
+
toolkit=selected_toolkit,
|
|
217
|
+
middlewares=selected_middlewares,
|
|
218
|
+
**kwargs,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
def _check_open(self):
|
|
222
|
+
if getattr(self, "_closed", True):
|
|
223
|
+
raise RuntimeError("PolarisAgentRuntime is closed")
|
|
224
|
+
|
|
225
|
+
async def _close_adapters(self):
|
|
226
|
+
if self.registrar is not None:
|
|
227
|
+
await self.registrar.async_close()
|
|
228
|
+
if self.resolver is not None:
|
|
229
|
+
await self.resolver.async_close()
|
|
230
|
+
if self.skill_loader is not None:
|
|
231
|
+
await self.skill_loader.async_close()
|
|
232
|
+
|
|
233
|
+
def _close_adapters_sync(self):
|
|
234
|
+
if self.registrar is not None:
|
|
235
|
+
self.registrar.close()
|
|
236
|
+
if self.resolver is not None:
|
|
237
|
+
self.resolver.close()
|
|
238
|
+
if self.skill_loader is not None:
|
|
239
|
+
self.skill_loader.close()
|
|
240
|
+
|
|
241
|
+
async def _close_all_async(self):
|
|
242
|
+
try:
|
|
243
|
+
await self._close_adapters()
|
|
244
|
+
finally:
|
|
245
|
+
try:
|
|
246
|
+
context = getattr(self, "context", None)
|
|
247
|
+
if context is not None:
|
|
248
|
+
await context.async_close()
|
|
249
|
+
finally:
|
|
250
|
+
ai_logger = getattr(self, "ai_logger", None)
|
|
251
|
+
if ai_logger is not None:
|
|
252
|
+
await ai_logger.async_close()
|
|
253
|
+
|
|
254
|
+
def close(self):
|
|
255
|
+
"""Close adapters, then the shared context only if this runtime owns it."""
|
|
256
|
+
if getattr(self, "_closed", True):
|
|
257
|
+
return
|
|
258
|
+
self._log_close_start()
|
|
259
|
+
self._closed = True
|
|
260
|
+
try:
|
|
261
|
+
self._close_adapters_sync()
|
|
262
|
+
finally:
|
|
263
|
+
try:
|
|
264
|
+
context = getattr(self, "context", None)
|
|
265
|
+
if context is not None:
|
|
266
|
+
context.close()
|
|
267
|
+
finally:
|
|
268
|
+
ai_logger = getattr(self, "ai_logger", None)
|
|
269
|
+
if ai_logger is not None:
|
|
270
|
+
ai_logger.close()
|
|
271
|
+
|
|
272
|
+
async def async_close(self):
|
|
273
|
+
if getattr(self, "_closed", True):
|
|
274
|
+
return
|
|
275
|
+
self._log_close_start()
|
|
276
|
+
self._closed = True
|
|
277
|
+
await await_completion(self._close_all_async())
|
|
278
|
+
|
|
279
|
+
def __enter__(self):
|
|
280
|
+
self._check_open()
|
|
281
|
+
return self
|
|
282
|
+
|
|
283
|
+
def __exit__(self, *_):
|
|
284
|
+
self.close()
|
|
285
|
+
|
|
286
|
+
async def __aenter__(self):
|
|
287
|
+
self._check_open()
|
|
288
|
+
return self
|
|
289
|
+
|
|
290
|
+
async def __aexit__(self, *_):
|
|
291
|
+
await self.async_close()
|