hyperforge 1.0.0.post56__tar.gz → 1.0.0.post60__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.
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/PKG-INFO +1 -1
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/pyproject.toml +1 -1
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/mcp_content.py +14 -0
- hyperforge-1.0.0.post60/src/hyperforge/api/v1/oauth.py +163 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/interaction.py +1 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/memory/memory.py +5 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/models.py +21 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/session.py +5 -1
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/utils.py +2 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/settings.py +6 -0
- hyperforge-1.0.0.post56/src/hyperforge/api/v1/oauth.py +0 -60
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/README.md +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/VERSION +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/agent.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/README +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/env.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/script.py.mako +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/049a4aed19e1_create_generation_table.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/1416cb41bd49_add_downloads_table.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/2847934e2d59_unique_driver.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/4d89a36c8bda_memory.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/72b997edb05d_identifier_for_drivers.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/9c6f6a1b4e7f_workflows_default_fk.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/b8edb72295e0_.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/f3d2c1b0a9e8_soft_delete_workflows.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic.ini +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/app.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/authentication.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/commands.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/internal/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/internal/inspect.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/internal/router.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/logging.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/models.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/session.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/settings.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/utils.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/agents.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/interaction.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/mcp_interaction.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/prompt.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/router.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/schema.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/session.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/utils.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/workflows.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/arag.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/broker/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/broker/local.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/broker/redis.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/configure.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/context/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/context/agent.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/context/config.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/database.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/agents.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/encryption.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/exceptions.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/settings.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/db/workflow_cleanup.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/definition.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/driver.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/dummy.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/engine.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/exceptions.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/feature_flag.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/fixtures.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/llm.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/manager.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/memory/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/minimal_fixtures.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/nua.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/openapi.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/prompts.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/pubsub.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/py.typed +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/redis_utils.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/retrieval/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/retrieval/agent.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/retrieval/config.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/cache.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/run.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/sandbox.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/settings.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/server/web.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/agent.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/app.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/config.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/const.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/run.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/settings.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/standalone/ui_router.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/assets/index-DLejS5jC.js +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/assets/index-MoxkZ1_3.css +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/favicon.svg +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/index.html +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/trace.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/utils/__init__.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/utils/http.py +0 -0
- {hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/workflows.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hyperforge"
|
|
7
|
-
version = "1.0.0.
|
|
7
|
+
version = "1.0.0.post60"
|
|
8
8
|
authors = [{ name = "AI Data Team", email = "learning@nuclia.com" }]
|
|
9
9
|
description = "Agentic Framework for Orchestrated Runtime, Governance, and Execution"
|
|
10
10
|
readme = "README.md"
|
|
@@ -229,6 +229,19 @@ def convert_arag_answer_to_content(
|
|
|
229
229
|
)
|
|
230
230
|
)
|
|
231
231
|
|
|
232
|
+
if context.json_objects:
|
|
233
|
+
for idx, json_obj in enumerate(context.json_objects):
|
|
234
|
+
contents.append(
|
|
235
|
+
EmbeddedResource(
|
|
236
|
+
type="resource",
|
|
237
|
+
resource=TextResourceContents(
|
|
238
|
+
uri=f"rao-response://context/{context.id}/json-objects/{idx}", # type: ignore[arg-type]
|
|
239
|
+
text=json.dumps(pydantic_core.to_jsonable_python(json_obj)),
|
|
240
|
+
mimeType="application/json",
|
|
241
|
+
),
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
|
|
232
245
|
if context.image_urls:
|
|
233
246
|
contents.append(
|
|
234
247
|
EmbeddedResource(
|
|
@@ -272,6 +285,7 @@ def convert_arag_answer_to_content(
|
|
|
272
285
|
type="text",
|
|
273
286
|
text="\n".join(parts),
|
|
274
287
|
annotations=Annotations(audience=["assistant"]),
|
|
288
|
+
_meta=step.metadata,
|
|
275
289
|
)
|
|
276
290
|
)
|
|
277
291
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from urllib.parse import urlencode
|
|
3
|
+
|
|
4
|
+
from cryptography.fernet import InvalidToken
|
|
5
|
+
from fastapi import Query
|
|
6
|
+
from starlette.requests import Request
|
|
7
|
+
from starlette.responses import HTMLResponse
|
|
8
|
+
|
|
9
|
+
from hyperforge.api.settings import Settings
|
|
10
|
+
from hyperforge.api.v1.router import router
|
|
11
|
+
from hyperforge.api.v1.utils import tracer
|
|
12
|
+
from hyperforge_mcp.http import _fingerprint, decrypt_mcp_oauth_state
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
RENDER = "<html><body><h1>OAuth Completed</h1><p>You can close this window and return to the application.</p></body></html>"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _build_oauth_subject(
|
|
20
|
+
settings: Settings,
|
|
21
|
+
account_id: str,
|
|
22
|
+
agent_id: str,
|
|
23
|
+
workflow_id: str,
|
|
24
|
+
session: str,
|
|
25
|
+
question_id: str,
|
|
26
|
+
oauth_uuid: str,
|
|
27
|
+
) -> str:
|
|
28
|
+
return settings.oauth_subject.format(
|
|
29
|
+
account=account_id,
|
|
30
|
+
agent_id=agent_id,
|
|
31
|
+
session=session,
|
|
32
|
+
question=question_id,
|
|
33
|
+
oauth_uuid=oauth_uuid,
|
|
34
|
+
workflow_id=workflow_id,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@router.get(
|
|
39
|
+
"/api/auth/agent/{agent_id}/workflow/{workflow_id}/session/{session}/oauth/{oauth_uuid}/callback",
|
|
40
|
+
status_code=200,
|
|
41
|
+
description="Get Agent Schema",
|
|
42
|
+
tags=["Retrieval Agent"],
|
|
43
|
+
include_in_schema=False,
|
|
44
|
+
)
|
|
45
|
+
async def oauth_callback(
|
|
46
|
+
request: Request,
|
|
47
|
+
agent_id: str,
|
|
48
|
+
session: str,
|
|
49
|
+
workflow_id: str,
|
|
50
|
+
oauth_uuid: str,
|
|
51
|
+
question_id: str = Query(..., include_in_schema=False),
|
|
52
|
+
state: str = Query(..., include_in_schema=False),
|
|
53
|
+
account_id: str = Query(..., include_in_schema=False),
|
|
54
|
+
):
|
|
55
|
+
"""
|
|
56
|
+
Callback from oauth flow on RAO that requires to send creds to websocket
|
|
57
|
+
"""
|
|
58
|
+
settings: Settings = request.app.settings
|
|
59
|
+
subject = _build_oauth_subject(
|
|
60
|
+
settings,
|
|
61
|
+
account_id,
|
|
62
|
+
agent_id,
|
|
63
|
+
workflow_id,
|
|
64
|
+
session,
|
|
65
|
+
question_id,
|
|
66
|
+
oauth_uuid,
|
|
67
|
+
)
|
|
68
|
+
# Request a question
|
|
69
|
+
with tracer().start_as_current_span("Request activation"):
|
|
70
|
+
logger.info(
|
|
71
|
+
"OAuth callback received for agent=%s, session=%s, oauth_uuid=%s, question_id=%s",
|
|
72
|
+
agent_id,
|
|
73
|
+
session,
|
|
74
|
+
oauth_uuid,
|
|
75
|
+
question_id,
|
|
76
|
+
)
|
|
77
|
+
await request.app.broker.send_reply(subject, state)
|
|
78
|
+
logger.info(
|
|
79
|
+
"OAuth callback published to stream %s",
|
|
80
|
+
subject,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return HTMLResponse(content=RENDER)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@router.get(
|
|
87
|
+
"/api/auth/mcp/callback",
|
|
88
|
+
status_code=200,
|
|
89
|
+
description="Generic MCP OAuth callback (fixed redirect URI, state-routed)",
|
|
90
|
+
tags=["Retrieval Agent"],
|
|
91
|
+
include_in_schema=False,
|
|
92
|
+
)
|
|
93
|
+
async def mcp_oauth_callback_generic(
|
|
94
|
+
request: Request,
|
|
95
|
+
code: str | None = Query(None, include_in_schema=False),
|
|
96
|
+
state: str | None = Query(None, include_in_schema=False),
|
|
97
|
+
error: str | None = Query(None, include_in_schema=False),
|
|
98
|
+
error_description: str | None = Query(None, include_in_schema=False),
|
|
99
|
+
):
|
|
100
|
+
settings: Settings = request.app.settings
|
|
101
|
+
|
|
102
|
+
if state is None:
|
|
103
|
+
logger.warning("MCP generic OAuth callback received without state parameter")
|
|
104
|
+
return HTMLResponse(content="Missing OAuth state parameter", status_code=400)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
routing = decrypt_mcp_oauth_state(state)
|
|
108
|
+
except InvalidToken:
|
|
109
|
+
logger.warning(
|
|
110
|
+
"MCP generic OAuth callback: invalid or expired state (Fernet decryption failed)"
|
|
111
|
+
)
|
|
112
|
+
return HTMLResponse(content="Invalid or expired OAuth state", status_code=400)
|
|
113
|
+
|
|
114
|
+
sdk_state = routing.sdk_state or None
|
|
115
|
+
if sdk_state is None:
|
|
116
|
+
logger.warning(
|
|
117
|
+
"MCP generic OAuth callback: decrypted state missing sdk_state field"
|
|
118
|
+
)
|
|
119
|
+
return HTMLResponse(content="Malformed OAuth state", status_code=400)
|
|
120
|
+
|
|
121
|
+
subject = _build_oauth_subject(
|
|
122
|
+
settings,
|
|
123
|
+
routing.account_id,
|
|
124
|
+
routing.agent_id,
|
|
125
|
+
routing.workflow_id,
|
|
126
|
+
routing.session_id,
|
|
127
|
+
routing.question_id,
|
|
128
|
+
routing.oauth_uuid,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
payload_data: dict[str, str] = {}
|
|
132
|
+
if code is not None:
|
|
133
|
+
payload_data["code"] = code
|
|
134
|
+
if sdk_state is not None:
|
|
135
|
+
payload_data["state"] = sdk_state
|
|
136
|
+
if error is not None:
|
|
137
|
+
payload_data["error"] = error
|
|
138
|
+
if error_description is not None:
|
|
139
|
+
payload_data["error_description"] = error_description
|
|
140
|
+
|
|
141
|
+
payload = urlencode(payload_data)
|
|
142
|
+
|
|
143
|
+
with tracer().start_as_current_span("MCP generic OAuth callback"):
|
|
144
|
+
logger.info(
|
|
145
|
+
"MCP generic OAuth callback: agent=%s workflow=%s session=%s question_id=%s oauth_uuid=%s sdk_state_fp=%s has_code=%s has_error=%s",
|
|
146
|
+
routing.agent_id,
|
|
147
|
+
routing.workflow_id,
|
|
148
|
+
routing.session_id,
|
|
149
|
+
routing.question_id,
|
|
150
|
+
routing.oauth_uuid,
|
|
151
|
+
_fingerprint(sdk_state),
|
|
152
|
+
code is not None,
|
|
153
|
+
error is not None,
|
|
154
|
+
)
|
|
155
|
+
await request.app.broker.send_reply(subject, payload)
|
|
156
|
+
logger.info("mcp_oauth send_reply: published to stream %s", subject)
|
|
157
|
+
|
|
158
|
+
if error is not None:
|
|
159
|
+
desc = f": {error_description}" if error_description else ""
|
|
160
|
+
return HTMLResponse(
|
|
161
|
+
content=f"OAuth authorization failed ({error}{desc})", status_code=400
|
|
162
|
+
)
|
|
163
|
+
return HTMLResponse(content=RENDER)
|
|
@@ -85,6 +85,7 @@ class BaseSessionMemory:
|
|
|
85
85
|
|
|
86
86
|
agent_id: str = ""
|
|
87
87
|
workflow_id: str = ""
|
|
88
|
+
account_id: str = ""
|
|
88
89
|
kbid: Optional[str] = None
|
|
89
90
|
|
|
90
91
|
# User information dictionary
|
|
@@ -638,6 +639,10 @@ class QuestionMemory:
|
|
|
638
639
|
"""Returns the workflow ID for the current question. The workflow ID is a unique identifier that is shared across all questions and interactions that belong to the same workflow. This can be used to group related interactions together, and to keep track of the conversation history in a coherent way."""
|
|
639
640
|
return self.session.workflow_id
|
|
640
641
|
|
|
642
|
+
def get_account_id(self) -> str:
|
|
643
|
+
"""Returns the account ID for the current question."""
|
|
644
|
+
return self.session.account_id
|
|
645
|
+
|
|
641
646
|
def context_user_info(self) -> str:
|
|
642
647
|
"""Returns a string with user information that can be used in the context of the agent. This can include information such as user preferences, user history, or any other relevant information about the user that can help the agent to generate a more personalized and accurate response."""
|
|
643
648
|
return self.session.context_user_info()
|
|
@@ -122,6 +122,7 @@ class Step(BaseModel):
|
|
|
122
122
|
input_nuclia_tokens: Optional[float]
|
|
123
123
|
output_nuclia_tokens: Optional[float]
|
|
124
124
|
error: Optional[str] = None
|
|
125
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
125
126
|
|
|
126
127
|
def __str__(self):
|
|
127
128
|
return f"({self.timeit:.2f}s) {self.module}: {self.title} \n {self.value} \n {self.reason} \n NT:({self.input_nuclia_tokens}:{self.output_nuclia_tokens})"
|
|
@@ -248,6 +249,25 @@ CONTEXT_TEMPLATE = """
|
|
|
248
249
|
CONTEXT_PROMPT_TEMPLATE = PROMPT_ENVIRONMENT.from_string(CONTEXT_TEMPLATE)
|
|
249
250
|
|
|
250
251
|
|
|
252
|
+
class JSONObject(BaseModel):
|
|
253
|
+
json_schema: Optional[Dict[str, Any]] = Field(
|
|
254
|
+
default=None,
|
|
255
|
+
description="JSON schema that defines the structure of the JSON object.",
|
|
256
|
+
)
|
|
257
|
+
json_object: Dict[str, Any] = Field(
|
|
258
|
+
default_factory=dict,
|
|
259
|
+
description="The actual JSON object that conforms to the provided JSON schema.",
|
|
260
|
+
)
|
|
261
|
+
metadata: Optional[Dict[str, Any]] = Field(
|
|
262
|
+
default_factory=dict,
|
|
263
|
+
description="Optional metadata associated with the JSON object.",
|
|
264
|
+
)
|
|
265
|
+
id: Optional[str] = Field(
|
|
266
|
+
default_factory=lambda: uuid.uuid4().hex,
|
|
267
|
+
description="Unique identifier for this JSON object instance.",
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
|
|
251
271
|
class Context(BaseModel):
|
|
252
272
|
id: str = Field(
|
|
253
273
|
default_factory=lambda: uuid.uuid4().hex,
|
|
@@ -260,6 +280,7 @@ class Context(BaseModel):
|
|
|
260
280
|
images: Dict[str, Image] = Field(default_factory=dict)
|
|
261
281
|
prompts: List[Prompt] = Field(default_factory=list)
|
|
262
282
|
structured: List[str] = Field(default_factory=list)
|
|
283
|
+
json_objects: List[JSONObject] = Field(default_factory=list)
|
|
263
284
|
source: str
|
|
264
285
|
agent: str
|
|
265
286
|
# XXX: This is not actually a summary, but an answer attempt for now!
|
|
@@ -181,8 +181,12 @@ class SessionManager:
|
|
|
181
181
|
config=config.memory,
|
|
182
182
|
agent=message.agent_id,
|
|
183
183
|
workflow_id=message.workflow_id,
|
|
184
|
+
account_id=message.account,
|
|
184
185
|
)
|
|
185
|
-
|
|
186
|
+
# Ephemeral sessions are short-lived and should not be persisted in
|
|
187
|
+
# the shared LRU cache across activations.
|
|
188
|
+
if message.session != "ephemeral":
|
|
189
|
+
self.memory[message.session] = memory
|
|
186
190
|
else:
|
|
187
191
|
memory = self.memory[message.session]
|
|
188
192
|
|
|
@@ -16,6 +16,7 @@ async def get_memory(
|
|
|
16
16
|
config: MemoryConfig,
|
|
17
17
|
agent: str,
|
|
18
18
|
workflow_id: str,
|
|
19
|
+
account_id: str = "",
|
|
19
20
|
) -> BaseSessionMemory:
|
|
20
21
|
memory: BaseSessionMemory
|
|
21
22
|
|
|
@@ -53,5 +54,6 @@ async def get_memory(
|
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
memory.init(session=session)
|
|
57
|
+
memory.account_id = account_id
|
|
56
58
|
|
|
57
59
|
return memory
|
|
@@ -2,17 +2,23 @@ from pydantic import model_validator
|
|
|
2
2
|
from pydantic_settings import BaseSettings
|
|
3
3
|
|
|
4
4
|
_REDIRECT_PATH = "/api/auth/agent/{agent_id}/workflow/{workflow_id}/session/{session_id}/oauth/{oauth_uuid}/callback"
|
|
5
|
+
_MCP_CALLBACK_PATH = "/api/auth/mcp/callback"
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class OAuthSettings(BaseSettings):
|
|
8
9
|
nuclia_public_url: str = "https://{zone}.nuclia.com"
|
|
9
10
|
nuclia_zone: str = "arag"
|
|
10
11
|
rao_redirect_url: str = ""
|
|
12
|
+
mcp_callback_url: str = ""
|
|
11
13
|
|
|
12
14
|
@model_validator(mode="after")
|
|
13
15
|
def _resolve_urls(self) -> "OAuthSettings":
|
|
14
16
|
self.nuclia_public_url = self.nuclia_public_url.format(zone=self.nuclia_zone)
|
|
15
17
|
if not self.rao_redirect_url:
|
|
16
18
|
self.rao_redirect_url = self.nuclia_public_url.rstrip("/") + _REDIRECT_PATH
|
|
19
|
+
if not self.mcp_callback_url:
|
|
20
|
+
self.mcp_callback_url = (
|
|
21
|
+
self.nuclia_public_url.rstrip("/") + _MCP_CALLBACK_PATH
|
|
22
|
+
)
|
|
17
23
|
|
|
18
24
|
return self
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from fastapi import Query
|
|
4
|
-
from starlette.requests import Request
|
|
5
|
-
from starlette.responses import HTMLResponse
|
|
6
|
-
|
|
7
|
-
from hyperforge.api.settings import Settings
|
|
8
|
-
from hyperforge.api.v1.router import router
|
|
9
|
-
from hyperforge.api.v1.utils import tracer
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
RENDER = "<html><body><h1>OAuth Completed</h1><p>You can close this window and return to the application.</p></body></html>"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@router.get(
|
|
17
|
-
"/api/auth/agent/{agent_id}/workflow/{workflow_id}/session/{session}/oauth/{oauth_uuid}/callback",
|
|
18
|
-
status_code=200,
|
|
19
|
-
description="Get Agent Schema",
|
|
20
|
-
tags=["Retrieval Agent"],
|
|
21
|
-
include_in_schema=False,
|
|
22
|
-
)
|
|
23
|
-
async def oauth_callback(
|
|
24
|
-
request: Request,
|
|
25
|
-
agent_id: str,
|
|
26
|
-
session: str,
|
|
27
|
-
workflow_id: str,
|
|
28
|
-
oauth_uuid: str,
|
|
29
|
-
question_id: str = Query(..., include_in_schema=False),
|
|
30
|
-
state: str = Query(..., include_in_schema=False),
|
|
31
|
-
account_id: str = Query(..., include_in_schema=False),
|
|
32
|
-
):
|
|
33
|
-
"""
|
|
34
|
-
Callback from oauth flow on RAO that requires to send creds to websocket
|
|
35
|
-
"""
|
|
36
|
-
settings: Settings = request.app.settings
|
|
37
|
-
subject = settings.oauth_subject.format(
|
|
38
|
-
account=account_id,
|
|
39
|
-
agent_id=agent_id,
|
|
40
|
-
session=session,
|
|
41
|
-
question=question_id,
|
|
42
|
-
oauth_uuid=oauth_uuid,
|
|
43
|
-
workflow_id=workflow_id,
|
|
44
|
-
)
|
|
45
|
-
# Request a question
|
|
46
|
-
with tracer().start_as_current_span("Request activation"):
|
|
47
|
-
logger.info(
|
|
48
|
-
"OAuth callback received for agent=%s, session=%s, oauth_uuid=%s, question_id=%s",
|
|
49
|
-
agent_id,
|
|
50
|
-
session,
|
|
51
|
-
oauth_uuid,
|
|
52
|
-
question_id,
|
|
53
|
-
)
|
|
54
|
-
await request.app.broker.send_reply(subject, state)
|
|
55
|
-
logger.info(
|
|
56
|
-
"OAuth callback published to stream %s",
|
|
57
|
-
subject,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
return HTMLResponse(content=RENDER)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/alembic/versions/b8edb72295e0_.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/api/v1/mcp_interaction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/assets/index-DLejS5jC.js
RENAMED
|
File without changes
|
{hyperforge-1.0.0.post56 → hyperforge-1.0.0.post60}/src/hyperforge/static/assets/index-MoxkZ1_3.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|