Skip to content

Commit 926598e

Browse files
committed
feat!: split track_metrics_of into sync and async (track_metrics_of_async) variants
feat: add optional graph_key to all LDAIConfigTracker track_* methods for graph correlation feat: add track_tool_call/track_tool_calls to LDAIConfigTracker feat: add graph_key property to AIGraphTracker feat: make AIGraphTracker.track_total_tokens accept Optional[TokenUsage], skip when None or total <= 0 feat: add LangChainHelper.get_tool_calls_from_response and sum_token_usage_from_messages feat: extract OpenAIHelper.get_ai_usage_from_response; delegate get_ai_metrics_from_response to it refactor: remove node-scoped methods from AIGraphTracker (track_node_invocation, track_tool_call, track_node_judge_response) refactor: use time.time_ns() for sub-millisecond precision in duration calculations
1 parent 9b6f06a commit 926598e

8 files changed

Lines changed: 346 additions & 132 deletions

File tree

packages/ai-providers/server-ai-langchain/src/ldai_langchain/langchain_helper.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,41 @@ def get_ai_metrics_from_response(response: Any) -> LDAIMetrics:
115115
:return: LDAIMetrics with success status and token usage
116116
"""
117117
return LDAIMetrics(success=True, usage=get_ai_usage_from_response(response))
118+
119+
120+
def get_tool_calls_from_response(response: Any) -> List[str]:
121+
"""
122+
Get tool call names from a LangChain provider response.
123+
124+
:param response: The response from the LangChain model
125+
:return: List of tool names in order, or empty list if none
126+
"""
127+
names: List[str] = []
128+
if hasattr(response, 'tool_calls') and response.tool_calls:
129+
for tc in response.tool_calls:
130+
n = tc.get('name')
131+
if n:
132+
names.append(str(n))
133+
return names
134+
135+
136+
def sum_token_usage_from_messages(messages: List[Any]) -> Optional[TokenUsage]:
137+
"""
138+
Sum token usage across LangChain messages using get_ai_usage_from_response per message.
139+
140+
:param messages: List of message objects (e.g. from a graph state)
141+
:return: Aggregated TokenUsage, or None if no usage on any message
142+
"""
143+
in_sum = 0
144+
out_sum = 0
145+
total_sum = 0
146+
for m in messages:
147+
u = get_ai_usage_from_response(m)
148+
if u is None:
149+
continue
150+
in_sum += u.input
151+
out_sum += u.output
152+
total_sum += u.total
153+
if in_sum == 0 and out_sum == 0 and total_sum == 0:
154+
return None
155+
return TokenUsage(total=total_sum, input=in_sum, output=out_sum)

packages/sdk/server-ai/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ async def main():
150150
# Create LangChain model from configuration
151151
llm = await LangChainProvider.create_langchain_model(ai_config)
152152

153-
# Use with tracking
154-
response = await ai_config.tracker.track_metrics_of(
153+
# Use with tracking (sync invoke)
154+
response = ai_config.tracker.track_metrics_of(
155155
lambda: llm.invoke(messages),
156156
lambda result: LangChainProvider.get_ai_metrics_from_response(result)
157157
)
@@ -190,7 +190,7 @@ async def main():
190190
temperature=ai_config.model.get_parameter('temperature') if ai_config.model else 0.5,
191191
)
192192

193-
result = await ai_config.tracker.track_metrics_of(
193+
result = await ai_config.tracker.track_metrics_of_async(
194194
call_custom_provider,
195195
map_custom_provider_metrics
196196
)

packages/sdk/server-ai/src/ldai/judge/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ async def evaluate(
7171
messages = self._construct_evaluation_messages(input_text, output_text)
7272
assert self._evaluation_response_structure is not None
7373

74-
response = await self._ai_config_tracker.track_metrics_of(
74+
response = await self._ai_config_tracker.track_metrics_of_async(
7575
lambda: self._model_runner.invoke_structured_model(messages, self._evaluation_response_structure),
7676
lambda result: result.metrics,
7777
)

packages/sdk/server-ai/src/ldai/managed_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async def invoke(self, prompt: str) -> ModelResponse:
4848
config_messages = self._ai_config.messages or []
4949
all_messages = config_messages + self._messages
5050

51-
response = await self._tracker.track_metrics_of(
51+
response = await self._tracker.track_metrics_of_async(
5252
lambda: self._model_runner.invoke_model(all_messages),
5353
lambda result: result.metrics,
5454
)

packages/sdk/server-ai/src/ldai/providers/runner_factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _with_fallback(
7777
continue
7878
result = fn(provider_factory)
7979
if result is not None:
80-
log.debug(f"Successfully created capability using provider '{provider_type}'")
80+
log.debug(f"Successfully invoked create function with provider '{provider_type}'")
8181
return result
8282
except Exception as exc:
8383
log.warning(f"Provider '{provider_type}' failed: {exc}")

0 commit comments

Comments
 (0)