interloper-api 0.110.2__tar.gz → 0.111.0__tar.gz

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.
Files changed (32) hide show
  1. {interloper_api-0.110.2 → interloper_api-0.111.0}/PKG-INFO +1 -1
  2. {interloper_api-0.110.2 → interloper_api-0.111.0}/pyproject.toml +1 -1
  3. {interloper_api-0.110.2 → interloper_api-0.111.0}/pyproject.toml.orig +1 -1
  4. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/agent.py +28 -1
  5. {interloper_api-0.110.2 → interloper_api-0.111.0}/README.md +0 -0
  6. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/__init__.py +0 -0
  7. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/app.py +0 -0
  8. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/dependencies/__init__.py +0 -0
  9. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/dependencies/auth.py +0 -0
  10. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/dependencies/rbac.py +0 -0
  11. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/dependencies/state.py +0 -0
  12. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/notifications/__init__.py +0 -0
  13. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/notifications/base.py +0 -0
  14. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/notifications/invitations.py +0 -0
  15. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/notifications/super_admins.py +0 -0
  16. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/__init__.py +0 -0
  17. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/admin.py +0 -0
  18. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/auth.py +0 -0
  19. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/backfills.py +0 -0
  20. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/catalog.py +0 -0
  21. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/components.py +0 -0
  22. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/executions.py +0 -0
  23. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/health.py +0 -0
  24. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/oauth.py +0 -0
  25. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/organisations.py +0 -0
  26. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/overview.py +0 -0
  27. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/relations.py +0 -0
  28. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/runs.py +0 -0
  29. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/tokens.py +0 -0
  30. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/routes/websocket.py +0 -0
  31. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/utils/__init__.py +0 -0
  32. {interloper_api-0.110.2 → interloper_api-0.111.0}/src/interloper_api/utils/time.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: interloper-api
3
- Version: 0.110.2
3
+ Version: 0.111.0
4
4
  Summary: Interloper FastAPI routes
5
5
  Author: Guillaume Onfroy
6
6
  Author-email: Guillaume Onfroy <guillaume@digitlcloud.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "interloper-api"
3
- version = "0.110.2"
3
+ version = "0.111.0"
4
4
  description = "Interloper FastAPI routes"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -3,7 +3,7 @@
3
3
  # ###############
4
4
  [project]
5
5
  name = "interloper-api"
6
- version = "0.110.2"
6
+ version = "0.111.0"
7
7
  description = "Interloper FastAPI routes"
8
8
  readme = "README.md"
9
9
  authors = [{ name = "Guillaume Onfroy", email = "guillaume@digitlcloud.com" }]
@@ -20,12 +20,13 @@ from typing import Annotated, Any
20
20
  from uuid import UUID
21
21
 
22
22
  from fastapi import APIRouter, Query, Request, Response
23
+ from interloper.telemetry import meter
23
24
  from interloper_agent import TURN_LIMITS, summary_of
24
25
  from interloper_db import Page, PageQuery
25
26
  from interloper_db.models import Conversation
26
27
  from interloper_toolkit import ToolkitContext
27
28
  from pydantic import BaseModel
28
- from pydantic_ai import DeferredToolResults
29
+ from pydantic_ai import Agent, DeferredToolResults
29
30
  from pydantic_ai.agent import AgentRunResult
30
31
  from pydantic_ai.messages import (
31
32
  ModelMessage,
@@ -49,6 +50,12 @@ router = APIRouter(prefix="/agent", tags=["agent"])
49
50
  SDK_VERSION = 7
50
51
  """The AI SDK major version the app speaks; tool approvals need at least 6."""
51
52
 
53
+ _turns = meter().create_counter("interloper.agent.turns", unit="{turn}", description="Agent turns, by outcome")
54
+ _tokens = meter().create_counter("interloper.agent.tokens", unit="{token}", description="Tokens agent turns spent")
55
+ _requests = meter().create_histogram(
56
+ "interloper.agent.requests", unit="{request}", description="Model requests one agent turn took"
57
+ )
58
+
52
59
 
53
60
  class LoggedEventStream(VercelAIEventStream[ToolkitContext, Any]):
54
61
  """The Vercel event stream, with a run's failure in the server log too.
@@ -68,6 +75,7 @@ class LoggedEventStream(VercelAIEventStream[ToolkitContext, Any]):
68
75
  The protocol's error chunks.
69
76
  """
70
77
  logger.error("Agent turn failed: %s", error, exc_info=error)
78
+ _turns.add(1, {"status": "failed"})
71
79
  async for chunk in super().on_error(error):
72
80
  yield chunk
73
81
 
@@ -327,6 +335,11 @@ async def chat(
327
335
  usage.output_tokens,
328
336
  len(messages),
329
337
  )
338
+ model = _model_name(agent)
339
+ _turns.add(1, {"status": "completed", "model": model})
340
+ _tokens.add(usage.input_tokens, {"kind": "input", "model": model})
341
+ _tokens.add(usage.output_tokens, {"kind": "output", "model": model})
342
+ _requests.record(usage.requests, {"model": model})
330
343
 
331
344
  history = ModelMessagesTypeAdapter.validate_python(conversation.messages)
332
345
  return await ConversationAdapter.dispatch_request(
@@ -342,6 +355,20 @@ async def chat(
342
355
  )
343
356
 
344
357
 
358
+ def _model_name(agent: Agent[ToolkitContext, Any]) -> str:
359
+ """The model an agent answers with, as a metric attribute.
360
+
361
+ Args:
362
+ agent: The assistant; its model is the ``provider:model`` string it
363
+ was built with until the first turn resolves it.
364
+
365
+ Returns:
366
+ The model's name.
367
+ """
368
+ model = agent.model
369
+ return model if isinstance(model, str) else getattr(model, "model_name", str(model))
370
+
371
+
345
372
  def _fold_turns(messages: list[UIMessage]) -> list[UIMessage]:
346
373
  """Merge each turn's assistant messages into one, as the stream builds them.
347
374