cortex-agent-sdk 0.2.1__tar.gz → 0.3.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 (19) hide show
  1. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/PKG-INFO +27 -9
  2. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/README.md +25 -5
  3. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/pyproject.toml +2 -5
  4. cortex_agent_sdk-0.3.0/src/cortex_agent_sdk/capabilities.py +62 -0
  5. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/.gitignore +0 -0
  6. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/LICENSE +0 -0
  7. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/__init__.py +0 -0
  8. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/errores/__init__.py +0 -0
  9. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/errores/catalogo.py +0 -0
  10. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/errores/excepcion.py +0 -0
  11. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/py.typed +0 -0
  12. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/redis/__init__.py +0 -0
  13. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/redis/scripts.py +0 -0
  14. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/redis/store.py +0 -0
  15. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/sessions/__init__.py +0 -0
  16. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/sessions/codec.py +0 -0
  17. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/sessions/memory.py +0 -0
  18. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/sessions/models.py +0 -0
  19. {cortex_agent_sdk-0.2.1 → cortex_agent_sdk-0.3.0}/src/cortex_agent_sdk/sessions/store.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cortex-agent-sdk
3
- Version: 0.2.1
4
- Summary: Sesiones Memory y Redis para agentes multiprovider con Pydantic AI
3
+ Version: 0.3.0
4
+ Summary: Sesiones y capacidades puntuales para agentes multiprovider con Pydantic AI
5
5
  Project-URL: Repository, https://github.com/epok200/cortex_agent_sdk
6
6
  Project-URL: Issues, https://github.com/epok200/cortex_agent_sdk/issues
7
7
  Author: EPOK
@@ -17,8 +17,6 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Typing :: Typed
18
18
  Requires-Python: >=3.13
19
19
  Requires-Dist: pydantic-ai-slim[google,openai]<3,>=2.27
20
- Provides-Extra: all
21
- Requires-Dist: redis>=8.1.0; extra == 'all'
22
20
  Provides-Extra: openai
23
21
  Provides-Extra: redis
24
22
  Requires-Dist: redis>=8.1.0; extra == 'redis'
@@ -26,13 +24,13 @@ Description-Content-Type: text/markdown
26
24
 
27
25
  # Cortex Agent SDK
28
26
 
29
- Cortex agrega sesiones Memory y Redis a agentes multiprovider construidos directamente con
30
- Pydantic AI.
27
+ Cortex agrega sesiones Memory y Redis, junto con capacidades puntuales que Pydantic AI no incluye,
28
+ a agentes multiprovider construidos directamente con Pydantic AI.
31
29
 
32
30
  No implementa otro loop, otra capa de tools ni otra API de agentes. Pydantic AI conserva el control
33
31
  de providers, modelos, tools, tipado, `RunContext`, hooks, límites, approvals, outputs, usage e
34
- historial. Cortex sólo cubre la pieza que Pydantic AI no incluye: persistencia conversacional con un
35
- turno activo por sesión.
32
+ historial. Cortex aporta persistencia conversacional con un turno activo por sesión y capacidades
33
+ opcionales construidas sobre sus hooks públicos.
36
34
 
37
35
  > Cortex Agent SDK está en alfa. La API puede cambiar antes de la versión `1.0.0`.
38
36
 
@@ -138,6 +136,25 @@ agent = Agent(model)
138
136
 
139
137
  El context manager de `Agent` administra el transporte del provider.
140
138
 
139
+ ## Fallback del resultado de una tool
140
+
141
+ Pydantic AI reintenta cuando un modelo termina sin texto. Para tools cuyo resultado ya es una
142
+ respuesta completa, Cortex puede reutilizar el último resultado exitoso del mismo run:
143
+
144
+ ```python
145
+ from pydantic_ai import Agent
146
+
147
+ from cortex_agent_sdk.capabilities import last_tool_result_fallback
148
+
149
+ agent = Agent(
150
+ "openai-responses:gpt-5.6-luna",
151
+ capabilities=[last_tool_result_fallback({"confirmar_agenda"})],
152
+ )
153
+ ```
154
+
155
+ La aplicación conserva la decisión sobre las tools elegibles. La capacidad no usa resultados
156
+ fallidos, vacíos ni pertenecientes a otro run, y no reemplaza texto o nuevas llamadas del modelo.
157
+
141
158
  ## Migración desde el runtime anterior
142
159
 
143
160
  | Antes | Ahora |
@@ -151,7 +168,7 @@ El context manager de `Agent` administra el transporte del provider.
151
168
  | `AgentHooks` | `pydantic_ai.capabilities.Hooks` |
152
169
  | `turn_finished` | `Hooks(after_run=...)` |
153
170
  | `history_transform` | `Hooks(before_model_request=...)` |
154
- | `fallback_answer` | política local del producto sobre `AgentRunResult` |
171
+ | `fallback_answer` | `last_tool_result_fallback(...)` opcional |
155
172
  | `AgentOptions` | `UsageLimits`, settings del modelo y argumentos de `Agent` |
156
173
  | `AgentResult.text` | `AgentRunResult.output` |
157
174
  | `SessionStore.acquire` | `SessionStore.turn` + `Session.replace` |
@@ -166,6 +183,7 @@ Pydantic AI.
166
183
  - `cortex_agent_sdk.sessions.SessionStore`
167
184
  - `cortex_agent_sdk.sessions.MemorySessionStore`
168
185
  - `cortex_agent_sdk.redis.RedisSessionStore`
186
+ - `cortex_agent_sdk.capabilities.last_tool_result_fallback`
169
187
  - `cortex_agent_sdk.errores.AppError`
170
188
  - `cortex_agent_sdk.errores.CodigoError`
171
189
  - `cortex_agent_sdk.errores.Severidad`
@@ -1,12 +1,12 @@
1
1
  # Cortex Agent SDK
2
2
 
3
- Cortex agrega sesiones Memory y Redis a agentes multiprovider construidos directamente con
4
- Pydantic AI.
3
+ Cortex agrega sesiones Memory y Redis, junto con capacidades puntuales que Pydantic AI no incluye,
4
+ a agentes multiprovider construidos directamente con Pydantic AI.
5
5
 
6
6
  No implementa otro loop, otra capa de tools ni otra API de agentes. Pydantic AI conserva el control
7
7
  de providers, modelos, tools, tipado, `RunContext`, hooks, límites, approvals, outputs, usage e
8
- historial. Cortex sólo cubre la pieza que Pydantic AI no incluye: persistencia conversacional con un
9
- turno activo por sesión.
8
+ historial. Cortex aporta persistencia conversacional con un turno activo por sesión y capacidades
9
+ opcionales construidas sobre sus hooks públicos.
10
10
 
11
11
  > Cortex Agent SDK está en alfa. La API puede cambiar antes de la versión `1.0.0`.
12
12
 
@@ -112,6 +112,25 @@ agent = Agent(model)
112
112
 
113
113
  El context manager de `Agent` administra el transporte del provider.
114
114
 
115
+ ## Fallback del resultado de una tool
116
+
117
+ Pydantic AI reintenta cuando un modelo termina sin texto. Para tools cuyo resultado ya es una
118
+ respuesta completa, Cortex puede reutilizar el último resultado exitoso del mismo run:
119
+
120
+ ```python
121
+ from pydantic_ai import Agent
122
+
123
+ from cortex_agent_sdk.capabilities import last_tool_result_fallback
124
+
125
+ agent = Agent(
126
+ "openai-responses:gpt-5.6-luna",
127
+ capabilities=[last_tool_result_fallback({"confirmar_agenda"})],
128
+ )
129
+ ```
130
+
131
+ La aplicación conserva la decisión sobre las tools elegibles. La capacidad no usa resultados
132
+ fallidos, vacíos ni pertenecientes a otro run, y no reemplaza texto o nuevas llamadas del modelo.
133
+
115
134
  ## Migración desde el runtime anterior
116
135
 
117
136
  | Antes | Ahora |
@@ -125,7 +144,7 @@ El context manager de `Agent` administra el transporte del provider.
125
144
  | `AgentHooks` | `pydantic_ai.capabilities.Hooks` |
126
145
  | `turn_finished` | `Hooks(after_run=...)` |
127
146
  | `history_transform` | `Hooks(before_model_request=...)` |
128
- | `fallback_answer` | política local del producto sobre `AgentRunResult` |
147
+ | `fallback_answer` | `last_tool_result_fallback(...)` opcional |
129
148
  | `AgentOptions` | `UsageLimits`, settings del modelo y argumentos de `Agent` |
130
149
  | `AgentResult.text` | `AgentRunResult.output` |
131
150
  | `SessionStore.acquire` | `SessionStore.turn` + `Session.replace` |
@@ -140,6 +159,7 @@ Pydantic AI.
140
159
  - `cortex_agent_sdk.sessions.SessionStore`
141
160
  - `cortex_agent_sdk.sessions.MemorySessionStore`
142
161
  - `cortex_agent_sdk.redis.RedisSessionStore`
162
+ - `cortex_agent_sdk.capabilities.last_tool_result_fallback`
143
163
  - `cortex_agent_sdk.errores.AppError`
144
164
  - `cortex_agent_sdk.errores.CodigoError`
145
165
  - `cortex_agent_sdk.errores.Severidad`
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "cortex-agent-sdk"
3
- version = "0.2.1"
4
- description = "Sesiones Memory y Redis para agentes multiprovider con Pydantic AI"
3
+ version = "0.3.0"
4
+ description = "Sesiones y capacidades puntuales para agentes multiprovider con Pydantic AI"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
7
7
  requires-python = ">=3.13"
@@ -26,9 +26,6 @@ Issues = "https://github.com/epok200/cortex_agent_sdk/issues"
26
26
 
27
27
  [project.optional-dependencies]
28
28
  openai = []
29
- all = [
30
- "redis>=8.1.0",
31
- ]
32
29
  redis = [
33
30
  "redis>=8.1.0",
34
31
  ]
@@ -0,0 +1,62 @@
1
+ """Capacidades opcionales para agentes Pydantic AI."""
2
+
3
+ from collections.abc import Collection
4
+ from dataclasses import replace
5
+ from typing import Any
6
+
7
+ from pydantic_ai import ModelResponse, RunContext, TextPart
8
+ from pydantic_ai.capabilities.hooks import Hooks
9
+ from pydantic_ai.messages import ModelRequest, ToolReturnPart
10
+ from pydantic_ai.models import ModelRequestContext
11
+
12
+ __all__ = ["last_tool_result_fallback"]
13
+
14
+
15
+ def last_tool_result_fallback(tool_names: str | Collection[str]) -> Hooks[Any]:
16
+ """Usa el último resultado elegible si el modelo termina sin texto."""
17
+ if isinstance(tool_names, str):
18
+ eligible_tools = frozenset((tool_names,))
19
+ else:
20
+ eligible_tools = frozenset(tool_names)
21
+
22
+ def use_last_tool_result(
23
+ ctx: RunContext[Any],
24
+ *,
25
+ request_context: ModelRequestContext,
26
+ response: ModelResponse,
27
+ ) -> ModelResponse:
28
+ if response.finish_reason not in {None, "stop"}:
29
+ return response
30
+ if response.text and response.text.strip():
31
+ return response
32
+ if response.tool_calls:
33
+ return response
34
+
35
+ result = _last_tool_result(request_context, ctx.run_id, eligible_tools)
36
+ if result is None:
37
+ return response
38
+ return replace(response, parts=[*response.parts, TextPart(result)])
39
+
40
+ return Hooks(after_model_request=use_last_tool_result)
41
+
42
+
43
+ def _last_tool_result(
44
+ request_context: ModelRequestContext,
45
+ run_id: str | None,
46
+ tool_names: Collection[str],
47
+ ) -> str | None:
48
+ if run_id is None:
49
+ return None
50
+ for message in reversed(request_context.messages):
51
+ if not isinstance(message, ModelRequest) or message.run_id != run_id:
52
+ continue
53
+ for part in reversed(message.parts):
54
+ if (
55
+ isinstance(part, ToolReturnPart)
56
+ and part.outcome == "success"
57
+ and part.tool_name in tool_names
58
+ and isinstance(part.content, str)
59
+ and part.content.strip()
60
+ ):
61
+ return part.content
62
+ return None