quraite 0.0.2__py3-none-any.whl → 0.1.0__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.
- quraite/__init__.py +3 -3
- quraite/adapters/__init__.py +134 -134
- quraite/adapters/agno_adapter.py +159 -159
- quraite/adapters/base.py +123 -123
- quraite/adapters/bedrock_agents_adapter.py +343 -343
- quraite/adapters/flowise_adapter.py +275 -275
- quraite/adapters/google_adk_adapter.py +209 -209
- quraite/adapters/http_adapter.py +239 -239
- quraite/adapters/langflow_adapter.py +192 -192
- quraite/adapters/langgraph_adapter.py +304 -304
- quraite/adapters/langgraph_server_adapter.py +252 -252
- quraite/adapters/n8n_adapter.py +220 -220
- quraite/adapters/openai_agents_adapter.py +269 -269
- quraite/adapters/pydantic_ai_adapter.py +312 -312
- quraite/adapters/smolagents_adapter.py +152 -152
- quraite/logger.py +61 -64
- quraite/schema/message.py +91 -54
- quraite/schema/response.py +16 -16
- quraite/serve/__init__.py +1 -1
- quraite/serve/cloudflared.py +210 -210
- quraite/serve/local_agent.py +360 -360
- quraite/tracing/__init__.py +24 -24
- quraite/tracing/constants.py +16 -16
- quraite/tracing/span_exporter.py +115 -115
- quraite/tracing/span_processor.py +49 -49
- quraite/tracing/tool_extractors.py +290 -290
- quraite/tracing/trace.py +564 -494
- quraite/tracing/types.py +179 -179
- quraite/tracing/utils.py +170 -170
- quraite/utils/json_utils.py +269 -269
- {quraite-0.0.2.dist-info → quraite-0.1.0.dist-info}/METADATA +9 -9
- quraite-0.1.0.dist-info/RECORD +35 -0
- {quraite-0.0.2.dist-info → quraite-0.1.0.dist-info}/WHEEL +1 -1
- quraite/traces/traces_adk_openinference.json +0 -379
- quraite/traces/traces_agno_multi_agent.json +0 -669
- quraite/traces/traces_agno_openinference.json +0 -321
- quraite/traces/traces_crewai_openinference.json +0 -155
- quraite/traces/traces_langgraph_openinference.json +0 -349
- quraite/traces/traces_langgraph_openinference_multi_agent.json +0 -2705
- quraite/traces/traces_langgraph_traceloop.json +0 -510
- quraite/traces/traces_openai_agents_multi_agent_1.json +0 -402
- quraite/traces/traces_openai_agents_openinference.json +0 -341
- quraite/traces/traces_pydantic_openinference.json +0 -286
- quraite/traces/traces_pydantic_openinference_multi_agent_1.json +0 -399
- quraite/traces/traces_pydantic_openinference_multi_agent_2.json +0 -398
- quraite/traces/traces_smol_agents_openinference.json +0 -397
- quraite/traces/traces_smol_agents_tool_calling_openinference.json +0 -704
- quraite-0.0.2.dist-info/RECORD +0 -49
|
@@ -1,152 +1,152 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import uuid
|
|
3
|
-
from typing import List, Optional
|
|
4
|
-
|
|
5
|
-
from opentelemetry.trace import TracerProvider
|
|
6
|
-
from smolagents import CodeAgent
|
|
7
|
-
|
|
8
|
-
from quraite.adapters.base import BaseAdapter
|
|
9
|
-
from quraite.logger import get_logger
|
|
10
|
-
from quraite.schema.message import AgentMessage
|
|
11
|
-
from quraite.schema.response import AgentInvocationResponse
|
|
12
|
-
from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
|
|
13
|
-
from quraite.tracing.trace import AgentSpan, AgentTrace
|
|
14
|
-
|
|
15
|
-
logger = get_logger(__name__)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class SmolagentsAdapter(BaseAdapter):
|
|
19
|
-
"""
|
|
20
|
-
Smolagents adapter wrapper that converts any Smolagents CodeAgent
|
|
21
|
-
to a standardized callable interface (ainvoke) with tracing support.
|
|
22
|
-
|
|
23
|
-
This class wraps any CodeAgent and provides:
|
|
24
|
-
- Asynchronous invocation via ainvoke()
|
|
25
|
-
- OpenTelemetry tracing integration
|
|
26
|
-
- Required tracing (returns AgentTrace containing spans)
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
agent: CodeAgent,
|
|
32
|
-
agent_name: str = "Smolagents Agent",
|
|
33
|
-
tracer_provider: Optional[TracerProvider] = None,
|
|
34
|
-
):
|
|
35
|
-
"""
|
|
36
|
-
Initialize with a pre-configured Smolagents CodeAgent
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
agent: A Smolagents CodeAgent instance
|
|
40
|
-
agent_name: Name of the agent for trajectory metadata
|
|
41
|
-
tracer_provider: TracerProvider for tracing (required)
|
|
42
|
-
"""
|
|
43
|
-
logger.debug(
|
|
44
|
-
"Initializing SmolagentsAdapter with agent_name=%s (tracing_required=True)",
|
|
45
|
-
agent_name,
|
|
46
|
-
)
|
|
47
|
-
self._init_tracing(tracer_provider, required=True)
|
|
48
|
-
|
|
49
|
-
self.agent = agent
|
|
50
|
-
self.agent_name = agent_name
|
|
51
|
-
logger.info("SmolagentsAdapter initialized successfully")
|
|
52
|
-
|
|
53
|
-
def _prepare_input(self, input: List[AgentMessage]) -> str:
|
|
54
|
-
"""
|
|
55
|
-
Prepare input for Smolagents CodeAgent from List[AgentMessage].
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
input: List[AgentMessage] containing user_message
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
str: User message text
|
|
62
|
-
"""
|
|
63
|
-
logger.debug("Preparing Smolagents input from %d messages", len(input))
|
|
64
|
-
if not input or input[-1].role != "user":
|
|
65
|
-
logger.error("Smolagents input missing user message")
|
|
66
|
-
raise ValueError("No user message found in the input")
|
|
67
|
-
|
|
68
|
-
last_user_message = input[-1]
|
|
69
|
-
if not last_user_message.content:
|
|
70
|
-
logger.error("Smolagents user message missing content")
|
|
71
|
-
raise ValueError("User message has no content")
|
|
72
|
-
|
|
73
|
-
text_content = None
|
|
74
|
-
for content_item in last_user_message.content:
|
|
75
|
-
if content_item.type == "text" and content_item.text:
|
|
76
|
-
text_content = content_item.text
|
|
77
|
-
break
|
|
78
|
-
|
|
79
|
-
if not text_content:
|
|
80
|
-
logger.error("Smolagents user message missing text content")
|
|
81
|
-
raise ValueError("No text content found in user message")
|
|
82
|
-
|
|
83
|
-
logger.debug("Prepared Smolagents input (text_length=%d)", len(text_content))
|
|
84
|
-
return text_content
|
|
85
|
-
|
|
86
|
-
async def ainvoke(
|
|
87
|
-
self,
|
|
88
|
-
input: List[AgentMessage],
|
|
89
|
-
session_id: Optional[str] = None,
|
|
90
|
-
) -> AgentInvocationResponse:
|
|
91
|
-
"""
|
|
92
|
-
Asynchronous invocation method - invokes the Smolagents CodeAgent with tracing
|
|
93
|
-
|
|
94
|
-
Args:
|
|
95
|
-
input: List[AgentMessage] containing user_message
|
|
96
|
-
session_id: Optional conversation ID (for parity with other adapters)
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
AgentTrace - trace with spans captured during invocation
|
|
100
|
-
"""
|
|
101
|
-
_ = session_id # Currently unused but kept for interface compatibility
|
|
102
|
-
logger.info(
|
|
103
|
-
"Smolagents ainvoke called (session_id=%s, input_messages=%d)",
|
|
104
|
-
session_id,
|
|
105
|
-
len(input),
|
|
106
|
-
)
|
|
107
|
-
agent_input = self._prepare_input(input)
|
|
108
|
-
|
|
109
|
-
try:
|
|
110
|
-
return await self._ainvoke_with_tracing(agent_input)
|
|
111
|
-
except Exception as exc:
|
|
112
|
-
logger.exception("Error invoking Smolagents agent")
|
|
113
|
-
raise RuntimeError(f"Error invoking Smolagents agent: {exc}") from exc
|
|
114
|
-
|
|
115
|
-
async def _ainvoke_with_tracing(self, agent_input: str) -> AgentInvocationResponse:
|
|
116
|
-
"""Execute ainvoke with tracing enabled."""
|
|
117
|
-
adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
|
|
118
|
-
logger.debug(
|
|
119
|
-
"Starting Smolagents traced invocation (trace_id=%s)", adapter_trace_id
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
with self.tracer.start_as_current_span(name=adapter_trace_id):
|
|
123
|
-
# Run the agent synchronously inside a thread to avoid blocking
|
|
124
|
-
await asyncio.to_thread(self.agent.run, agent_input)
|
|
125
|
-
|
|
126
|
-
trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
|
|
127
|
-
adapter_trace_id
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
if trace_readable_spans:
|
|
131
|
-
logger.info(
|
|
132
|
-
"Smolagents trace collected %d spans for trace_id=%s",
|
|
133
|
-
len(trace_readable_spans),
|
|
134
|
-
adapter_trace_id,
|
|
135
|
-
)
|
|
136
|
-
agent_trace = AgentTrace(
|
|
137
|
-
spans=[
|
|
138
|
-
AgentSpan.from_readable_oi_span(span)
|
|
139
|
-
for span in trace_readable_spans
|
|
140
|
-
],
|
|
141
|
-
)
|
|
142
|
-
else:
|
|
143
|
-
logger.warning(
|
|
144
|
-
"No spans captured for Smolagents trace_id=%s", adapter_trace_id
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
return AgentInvocationResponse(
|
|
148
|
-
agent_trace=agent_trace,
|
|
149
|
-
agent_trajectory=agent_trace.to_agent_trajectory(
|
|
150
|
-
framework=Framework.SMOLAGENTS
|
|
151
|
-
),
|
|
152
|
-
)
|
|
1
|
+
import asyncio
|
|
2
|
+
import uuid
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from opentelemetry.trace import TracerProvider
|
|
6
|
+
from smolagents import CodeAgent
|
|
7
|
+
|
|
8
|
+
from quraite.adapters.base import BaseAdapter
|
|
9
|
+
from quraite.logger import get_logger
|
|
10
|
+
from quraite.schema.message import AgentMessage
|
|
11
|
+
from quraite.schema.response import AgentInvocationResponse
|
|
12
|
+
from quraite.tracing.constants import QURAITE_ADAPTER_TRACE_PREFIX, Framework
|
|
13
|
+
from quraite.tracing.trace import AgentSpan, AgentTrace
|
|
14
|
+
|
|
15
|
+
logger = get_logger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SmolagentsAdapter(BaseAdapter):
|
|
19
|
+
"""
|
|
20
|
+
Smolagents adapter wrapper that converts any Smolagents CodeAgent
|
|
21
|
+
to a standardized callable interface (ainvoke) with tracing support.
|
|
22
|
+
|
|
23
|
+
This class wraps any CodeAgent and provides:
|
|
24
|
+
- Asynchronous invocation via ainvoke()
|
|
25
|
+
- OpenTelemetry tracing integration
|
|
26
|
+
- Required tracing (returns AgentTrace containing spans)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
agent: CodeAgent,
|
|
32
|
+
agent_name: str = "Smolagents Agent",
|
|
33
|
+
tracer_provider: Optional[TracerProvider] = None,
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Initialize with a pre-configured Smolagents CodeAgent
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
agent: A Smolagents CodeAgent instance
|
|
40
|
+
agent_name: Name of the agent for trajectory metadata
|
|
41
|
+
tracer_provider: TracerProvider for tracing (required)
|
|
42
|
+
"""
|
|
43
|
+
logger.debug(
|
|
44
|
+
"Initializing SmolagentsAdapter with agent_name=%s (tracing_required=True)",
|
|
45
|
+
agent_name,
|
|
46
|
+
)
|
|
47
|
+
self._init_tracing(tracer_provider, required=True)
|
|
48
|
+
|
|
49
|
+
self.agent = agent
|
|
50
|
+
self.agent_name = agent_name
|
|
51
|
+
logger.info("SmolagentsAdapter initialized successfully")
|
|
52
|
+
|
|
53
|
+
def _prepare_input(self, input: List[AgentMessage]) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Prepare input for Smolagents CodeAgent from List[AgentMessage].
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
input: List[AgentMessage] containing user_message
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
str: User message text
|
|
62
|
+
"""
|
|
63
|
+
logger.debug("Preparing Smolagents input from %d messages", len(input))
|
|
64
|
+
if not input or input[-1].role != "user":
|
|
65
|
+
logger.error("Smolagents input missing user message")
|
|
66
|
+
raise ValueError("No user message found in the input")
|
|
67
|
+
|
|
68
|
+
last_user_message = input[-1]
|
|
69
|
+
if not last_user_message.content:
|
|
70
|
+
logger.error("Smolagents user message missing content")
|
|
71
|
+
raise ValueError("User message has no content")
|
|
72
|
+
|
|
73
|
+
text_content = None
|
|
74
|
+
for content_item in last_user_message.content:
|
|
75
|
+
if content_item.type == "text" and content_item.text:
|
|
76
|
+
text_content = content_item.text
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
if not text_content:
|
|
80
|
+
logger.error("Smolagents user message missing text content")
|
|
81
|
+
raise ValueError("No text content found in user message")
|
|
82
|
+
|
|
83
|
+
logger.debug("Prepared Smolagents input (text_length=%d)", len(text_content))
|
|
84
|
+
return text_content
|
|
85
|
+
|
|
86
|
+
async def ainvoke(
|
|
87
|
+
self,
|
|
88
|
+
input: List[AgentMessage],
|
|
89
|
+
session_id: Optional[str] = None,
|
|
90
|
+
) -> AgentInvocationResponse:
|
|
91
|
+
"""
|
|
92
|
+
Asynchronous invocation method - invokes the Smolagents CodeAgent with tracing
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
input: List[AgentMessage] containing user_message
|
|
96
|
+
session_id: Optional conversation ID (for parity with other adapters)
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
AgentTrace - trace with spans captured during invocation
|
|
100
|
+
"""
|
|
101
|
+
_ = session_id # Currently unused but kept for interface compatibility
|
|
102
|
+
logger.info(
|
|
103
|
+
"Smolagents ainvoke called (session_id=%s, input_messages=%d)",
|
|
104
|
+
session_id,
|
|
105
|
+
len(input),
|
|
106
|
+
)
|
|
107
|
+
agent_input = self._prepare_input(input)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
return await self._ainvoke_with_tracing(agent_input)
|
|
111
|
+
except Exception as exc:
|
|
112
|
+
logger.exception("Error invoking Smolagents agent")
|
|
113
|
+
raise RuntimeError(f"Error invoking Smolagents agent: {exc}") from exc
|
|
114
|
+
|
|
115
|
+
async def _ainvoke_with_tracing(self, agent_input: str) -> AgentInvocationResponse:
|
|
116
|
+
"""Execute ainvoke with tracing enabled."""
|
|
117
|
+
adapter_trace_id = f"{QURAITE_ADAPTER_TRACE_PREFIX}-{uuid.uuid4()}"
|
|
118
|
+
logger.debug(
|
|
119
|
+
"Starting Smolagents traced invocation (trace_id=%s)", adapter_trace_id
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
with self.tracer.start_as_current_span(name=adapter_trace_id):
|
|
123
|
+
# Run the agent synchronously inside a thread to avoid blocking
|
|
124
|
+
await asyncio.to_thread(self.agent.run, agent_input)
|
|
125
|
+
|
|
126
|
+
trace_readable_spans = self.quraite_span_exporter.get_trace_by_testcase(
|
|
127
|
+
adapter_trace_id
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if trace_readable_spans:
|
|
131
|
+
logger.info(
|
|
132
|
+
"Smolagents trace collected %d spans for trace_id=%s",
|
|
133
|
+
len(trace_readable_spans),
|
|
134
|
+
adapter_trace_id,
|
|
135
|
+
)
|
|
136
|
+
agent_trace = AgentTrace(
|
|
137
|
+
spans=[
|
|
138
|
+
AgentSpan.from_readable_oi_span(span)
|
|
139
|
+
for span in trace_readable_spans
|
|
140
|
+
],
|
|
141
|
+
)
|
|
142
|
+
else:
|
|
143
|
+
logger.warning(
|
|
144
|
+
"No spans captured for Smolagents trace_id=%s", adapter_trace_id
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return AgentInvocationResponse(
|
|
148
|
+
agent_trace=agent_trace,
|
|
149
|
+
agent_trajectory=agent_trace.to_agent_trajectory(
|
|
150
|
+
framework=Framework.SMOLAGENTS
|
|
151
|
+
),
|
|
152
|
+
)
|
quraite/logger.py
CHANGED
|
@@ -1,64 +1,61 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import os
|
|
3
|
-
|
|
4
|
-
_logger = logging.getLogger("quraite")
|
|
5
|
-
_logger.addHandler(logging.NullHandler())
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def set_log_level(level: int | str) -> None:
|
|
9
|
-
"""
|
|
10
|
-
Configure the root quraite logger programmatically.
|
|
11
|
-
|
|
12
|
-
Args:
|
|
13
|
-
level: Either a logging level integer or its string name (e.g. "INFO").
|
|
14
|
-
"""
|
|
15
|
-
resolved_level: int
|
|
16
|
-
if isinstance(level, str):
|
|
17
|
-
try:
|
|
18
|
-
resolved_level = getattr(logging, level.upper())
|
|
19
|
-
except AttributeError as exc:
|
|
20
|
-
raise ValueError(f"Invalid log level: {level}") from exc
|
|
21
|
-
else:
|
|
22
|
-
resolved_level = level
|
|
23
|
-
|
|
24
|
-
_logger.setLevel(resolved_level)
|
|
25
|
-
|
|
26
|
-
# Ensure a stream handler is attached so logs are emitted somewhere useful.
|
|
27
|
-
if not any(
|
|
28
|
-
isinstance(handler, logging.StreamHandler) for handler in _logger.handlers
|
|
29
|
-
):
|
|
30
|
-
handler = logging.StreamHandler()
|
|
31
|
-
handler.setFormatter(
|
|
32
|
-
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
33
|
-
)
|
|
34
|
-
_logger.addHandler(handler)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def get_logger(name: str | None = None) -> logging.Logger:
|
|
38
|
-
"""
|
|
39
|
-
Get a logger for quraite submodules.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
name: Module name (typically __name__)
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
A logging.Logger instance for the quraite package.
|
|
46
|
-
"""
|
|
47
|
-
if name is None:
|
|
48
|
-
return _logger
|
|
49
|
-
|
|
50
|
-
if name.startswith("quraite"):
|
|
51
|
-
return logging.getLogger(name)
|
|
52
|
-
|
|
53
|
-
return logging.getLogger(f"quraite.{name}")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Set level from environment variable if provided
|
|
57
|
-
_env_level = os.getenv("LOG_LEVEL")
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pass
|
|
63
|
-
else:
|
|
64
|
-
set_log_level("INFO")
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
_logger = logging.getLogger("quraite")
|
|
5
|
+
_logger.addHandler(logging.NullHandler())
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def set_log_level(level: int | str) -> None:
|
|
9
|
+
"""
|
|
10
|
+
Configure the root quraite logger programmatically.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
level: Either a logging level integer or its string name (e.g. "INFO").
|
|
14
|
+
"""
|
|
15
|
+
resolved_level: int
|
|
16
|
+
if isinstance(level, str):
|
|
17
|
+
try:
|
|
18
|
+
resolved_level = getattr(logging, level.upper())
|
|
19
|
+
except AttributeError as exc:
|
|
20
|
+
raise ValueError(f"Invalid log level: {level}") from exc
|
|
21
|
+
else:
|
|
22
|
+
resolved_level = level
|
|
23
|
+
|
|
24
|
+
_logger.setLevel(resolved_level)
|
|
25
|
+
|
|
26
|
+
# Ensure a stream handler is attached so logs are emitted somewhere useful.
|
|
27
|
+
if not any(
|
|
28
|
+
isinstance(handler, logging.StreamHandler) for handler in _logger.handlers
|
|
29
|
+
):
|
|
30
|
+
handler = logging.StreamHandler()
|
|
31
|
+
handler.setFormatter(
|
|
32
|
+
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
|
33
|
+
)
|
|
34
|
+
_logger.addHandler(handler)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_logger(name: str | None = None) -> logging.Logger:
|
|
38
|
+
"""
|
|
39
|
+
Get a logger for quraite submodules.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
name: Module name (typically __name__)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
A logging.Logger instance for the quraite package.
|
|
46
|
+
"""
|
|
47
|
+
if name is None:
|
|
48
|
+
return _logger
|
|
49
|
+
|
|
50
|
+
if name.startswith("quraite"):
|
|
51
|
+
return logging.getLogger(name)
|
|
52
|
+
|
|
53
|
+
return logging.getLogger(f"quraite.{name}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# Set level from environment variable if provided
|
|
57
|
+
_env_level = os.getenv("LOG_LEVEL") or "INFO"
|
|
58
|
+
try:
|
|
59
|
+
set_log_level(_env_level)
|
|
60
|
+
except ValueError:
|
|
61
|
+
pass
|
quraite/schema/message.py
CHANGED
|
@@ -1,54 +1,91 @@
|
|
|
1
|
-
from typing import Any, List, Literal, Optional, TypeAlias, Union
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class MessageContentText(BaseModel):
|
|
7
|
-
type: Literal["text"] = "text"
|
|
8
|
-
text: str
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class MessageContentReasoning(BaseModel):
|
|
12
|
-
type: Literal["reasoning"] = "reasoning"
|
|
13
|
-
reasoning: str
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class UserMessage(BaseModel):
|
|
17
|
-
role: Literal["user"] = "user"
|
|
18
|
-
name: Optional[str] = None
|
|
19
|
-
content: List[MessageContentText]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DeveloperMessage(BaseModel):
|
|
23
|
-
role: Literal["developer"] = "developer"
|
|
24
|
-
content: List[MessageContentText]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class SystemMessage(BaseModel):
|
|
28
|
-
role: Literal["system"] = "system"
|
|
29
|
-
content: List[MessageContentText]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class ToolCall(BaseModel):
|
|
33
|
-
id: str
|
|
34
|
-
name: str
|
|
35
|
-
arguments: dict[str, Any]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
1
|
+
from typing import Any, List, Literal, Optional, TypeAlias, Union
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MessageContentText(BaseModel):
|
|
7
|
+
type: Literal["text"] = "text"
|
|
8
|
+
text: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MessageContentReasoning(BaseModel):
|
|
12
|
+
type: Literal["reasoning"] = "reasoning"
|
|
13
|
+
reasoning: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class UserMessage(BaseModel):
|
|
17
|
+
role: Literal["user"] = "user"
|
|
18
|
+
name: Optional[str] = None
|
|
19
|
+
content: List[MessageContentText]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DeveloperMessage(BaseModel):
|
|
23
|
+
role: Literal["developer"] = "developer"
|
|
24
|
+
content: List[MessageContentText]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SystemMessage(BaseModel):
|
|
28
|
+
role: Literal["system"] = "system"
|
|
29
|
+
content: List[MessageContentText]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ToolCall(BaseModel):
|
|
33
|
+
id: str
|
|
34
|
+
name: str
|
|
35
|
+
arguments: dict[str, Any]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ModelInfo(BaseModel):
|
|
39
|
+
model_name: str = Field(default="")
|
|
40
|
+
model_provider: str = Field(default="")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class CostInfo(BaseModel):
|
|
44
|
+
input_cost: float = Field(default=0.0)
|
|
45
|
+
output_cost: float = Field(default=0.0)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TokenInfo(BaseModel):
|
|
49
|
+
input_tokens: int = Field(default=0)
|
|
50
|
+
output_tokens: int = Field(default=0)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class LatencyInfo(BaseModel):
|
|
54
|
+
start_time: float = Field(default=0.0)
|
|
55
|
+
end_time: float = Field(default=0.0)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class AssistantMessageMetadata(BaseModel):
|
|
59
|
+
"""Structured metadata for assistant messages."""
|
|
60
|
+
|
|
61
|
+
tokens: TokenInfo = Field(default_factory=TokenInfo)
|
|
62
|
+
cost: CostInfo = Field(default_factory=CostInfo)
|
|
63
|
+
latency: LatencyInfo = Field(default_factory=LatencyInfo)
|
|
64
|
+
model_info: ModelInfo = Field(default_factory=ModelInfo)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ToolMessageMetadata(BaseModel):
|
|
68
|
+
"""Structured metadata for tool messages."""
|
|
69
|
+
|
|
70
|
+
latency: LatencyInfo = Field(default_factory=LatencyInfo)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AssistantMessage(BaseModel):
|
|
74
|
+
role: Literal["assistant"] = "assistant"
|
|
75
|
+
agent_name: Optional[str] = None
|
|
76
|
+
content: Optional[List[Union[MessageContentText, MessageContentReasoning]]] = None
|
|
77
|
+
tool_calls: Optional[List[ToolCall]] = None
|
|
78
|
+
metadata: AssistantMessageMetadata = Field(default_factory=AssistantMessageMetadata)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ToolMessage(BaseModel):
|
|
82
|
+
role: Literal["tool"] = "tool"
|
|
83
|
+
tool_name: Optional[str] = None
|
|
84
|
+
tool_call_id: Optional[str] = None
|
|
85
|
+
content: List[MessageContentText]
|
|
86
|
+
metadata: ToolMessageMetadata = Field(default_factory=ToolMessageMetadata)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
AgentMessage: TypeAlias = Union[
|
|
90
|
+
UserMessage, DeveloperMessage, SystemMessage, AssistantMessage, ToolMessage
|
|
91
|
+
]
|
quraite/schema/response.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from quraite.schema.message import AgentMessage
|
|
6
|
-
from quraite.tracing.trace import AgentTrace
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class AgentInvocationResponse(BaseModel):
|
|
10
|
-
"""
|
|
11
|
-
Response model for agent invocation.
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
agent_trace: Optional[AgentTrace] = None
|
|
15
|
-
agent_trajectory: Optional[List[AgentMessage]] = None
|
|
16
|
-
agent_final_response: Optional[str] = None
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from quraite.schema.message import AgentMessage
|
|
6
|
+
from quraite.tracing.trace import AgentTrace
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AgentInvocationResponse(BaseModel):
|
|
10
|
+
"""
|
|
11
|
+
Response model for agent invocation.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
agent_trace: Optional[AgentTrace] = None
|
|
15
|
+
agent_trajectory: Optional[List[AgentMessage]] = None
|
|
16
|
+
agent_final_response: Optional[str] = None
|
quraite/serve/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
|