From 3b063fa189c7f3b231b0fa1e7b6d37e2129bf497 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Wed, 29 Jul 2026 13:21:38 +0530 Subject: [PATCH 1/4] feat: add composio/cognee SDK methods Add composio and cognee integration to the Python SDK: - composio_cognee.py: ComposioTool, ComposioToolResult, ComposioCredential - CogneeQAEntry, CogneeTraceEntry, CogneeFeedbackEntry, CogneeSkillRunEntry - CogneeImproveResult types - search_composio_tools, execute_composio_tool, list_composio_credentials - remember_qa, remember_trace, remember_feedback, remember_skill_run - improve, sync_session_to_permanent, recall_with_session - Exported from hawk/__init__.py --- src/hawk/__init__.py | 38 ++++ src/hawk/composio_cognee.py | 421 ++++++++++++++++++++++++++++++++++++ 2 files changed, 459 insertions(+) create mode 100644 src/hawk/composio_cognee.py diff --git a/src/hawk/__init__.py b/src/hawk/__init__.py index 9b451a3..b552b74 100644 --- a/src/hawk/__init__.py +++ b/src/hawk/__init__.py @@ -71,6 +71,26 @@ ToolCall, Usage, ) +from .composio_cognee import ( + CogneeFeedbackEntry, + CogneeImproveResult, + CogneeQAEntry, + CogneeSkillRunEntry, + CogneeTraceEntry, + ComposioCredential, + ComposioTool, + ComposioToolResult, + execute_composio_tool, + improve, + list_composio_credentials, + recall_with_session, + remember_feedback, + remember_qa, + remember_skill_run, + remember_trace, + search_composio_tools, + sync_session_to_permanent, +) from .workflow import AsyncWorkflow, Workflow __all__ = [ @@ -144,6 +164,24 @@ "is_tracing_enabled", "run_benchmark", "run_benchmark_async", + "search_composio_tools", + "execute_composio_tool", + "list_composio_credentials", + "remember_qa", + "remember_trace", + "remember_feedback", + "remember_skill_run", + "improve", + "sync_session_to_permanent", + "recall_with_session", + "ComposioTool", + "ComposioToolResult", + "ComposioCredential", + "CogneeQAEntry", + "CogneeTraceEntry", + "CogneeFeedbackEntry", + "CogneeSkillRunEntry", + "CogneeImproveResult", "tool", "trace", "trace_chat", diff --git a/src/hawk/composio_cognee.py b/src/hawk/composio_cognee.py new file mode 100644 index 0000000..a56c1e2 --- /dev/null +++ b/src/hawk/composio_cognee.py @@ -0,0 +1,421 @@ +"""Composio and cognee integration for the Hawk SDK. + +This module provides Python methods for: + - Searching composio tools + - Executing composio tools + - Listing composio credentials + - Storing and recalling cognee structured memory entries (QA, trace, feedback, skill run) + - Improving memories (re-process for quality) + - Syncing session memories to permanent graph +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + +from .client import DEFAULT_BASE_URL, DEFAULT_TIMEOUT +from .errors import parse_error +from .retry import DEFAULT_RETRY_CONFIG, RetryConfig, with_retry_sync + + +# --- Composio Types --- + +@dataclass +class ComposioTool: + name: str + description: str = "" + scope: str = "read" + auth_required: bool = False + params: dict[str, Any] = field(default_factory=dict) + tags: list[str] = field(default_factory=list) + category: str = "" + + +@dataclass +class ComposioToolResult: + success: bool = False + data: dict[str, Any] = field(default_factory=dict) + error: str = "" + + +@dataclass +class ComposioCredential: + id: str + service_name: str + type: str + scope: str = "" + expires_at: str | None = None + metadata: dict[str, str] = field(default_factory=dict) + + +# --- Cognee Entry Types --- + +@dataclass +class CogneeQAEntry: + question: str + answer: str + project: str + context: str = "" + feedback_text: str = "" + feedback_score: int | None = None + used_graph_ids: list[str] = field(default_factory=list) + session_id: str = "" + source_agent: str = "" + + +@dataclass +class CogneeTraceEntry: + origin_function: str + project: str + session_id: str = "" + status: str = "success" + method_params: str = "" + method_return_value: str = "" + memory_query: str = "" + memory_context: str = "" + error_message: str = "" + source_agent: str = "" + + +@dataclass +class CogneeFeedbackEntry: + target_node_id: str + project: str + feedback_text: str = "" + score: int | None = None + session_id: str = "" + source_agent: str = "" + + +@dataclass +class CogneeSkillRunEntry: + skill_name: str + project: str + status: str = "success" + skill_version: str = "" + params: str = "" + result: str = "" + duration_ms: int = 0 + error: str = "" + session_id: str = "" + source_agent: str = "" + + +@dataclass +class CogneeImproveResult: + nodes_processed: int = 0 + nodes_improved: int = 0 + summaries_generated: int = 0 + embeddings_refreshed: int = 0 + duplicates_merged: int = 0 + errors: int = 0 + duration_ms: int = 0 + + +# --- Composio Methods --- + +def search_composio_tools( + base_url: str = DEFAULT_BASE_URL, + query: str = "", + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> list[ComposioTool]: + """Search the composio tool catalog.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + + def _do_search() -> list[ComposioTool]: + with httpx.Client(timeout=timeout) as client: + resp = client.post( + f"{base_url}/composio/search", + json={"query": query}, + ) + if resp.status_code != 200: + raise parse_error(resp) + data = resp.json() + return [ComposioTool(**t) for t in data.get("tools", [])] + + return with_retry_sync(_do_search, retry_config) + + +def execute_composio_tool( + base_url: str = DEFAULT_BASE_URL, + name: str = "", + params: dict[str, Any] | None = None, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> ComposioToolResult: + """Execute a composio tool by name.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + if params is None: + params = {} + + def _do_execute() -> ComposioToolResult: + with httpx.Client(timeout=timeout) as client: + resp = client.post( + f"{base_url}/composio/execute", + json={"name": name, "params": params}, + ) + if resp.status_code != 200: + raise parse_error(resp) + return ComposioToolResult(**resp.json()) + + return with_retry_sync(_do_execute, retry_config) + + +def list_composio_credentials( + base_url: str = DEFAULT_BASE_URL, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> list[ComposioCredential]: + """List all composio credentials.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + + def _do_list() -> list[ComposioCredential]: + with httpx.Client(timeout=timeout) as client: + resp = client.get(f"{base_url}/composio/credentials") + if resp.status_code != 200: + raise parse_error(resp) + return [ComposioCredential(**c) for c in resp.json()] + + return with_retry_sync(_do_list, retry_config) + + +# --- Cognee Memory Methods --- + +def remember_qa( + base_url: str = DEFAULT_BASE_URL, + qa: CogneeQAEntry | None = None, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> str: + """Store a Q&A entry as a structured memory node.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + if qa is None: + raise ValueError("qa entry is required") + + def _do_remember() -> str: + with httpx.Client(timeout=timeout) as client: + resp = client.post( + f"{base_url}/cognee/qa", + json={ + "question": qa.question, + "answer": qa.answer, + "context": qa.context, + "feedback_text": qa.feedback_text, + "feedback_score": qa.feedback_score, + "used_graph_ids": qa.used_graph_ids, + "session_id": qa.session_id, + "project": qa.project, + "source_agent": qa.source_agent, + }, + ) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("id", "") + + return with_retry_sync(_do_remember, retry_config) + + +def remember_trace( + base_url: str = DEFAULT_BASE_URL, + trace: CogneeTraceEntry | None = None, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> str: + """Store a trace entry as a structured memory node.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + if trace is None: + raise ValueError("trace entry is required") + + def _do_remember() -> str: + with httpx.Client(timeout=timeout) as client: + resp = client.post(f"{base_url}/cognee/trace", json={ + "origin_function": trace.origin_function, + "status": trace.status, + "method_params": trace.method_params, + "method_return_value": trace.method_return_value, + "memory_query": trace.memory_query, + "memory_context": trace.memory_context, + "error_message": trace.error_message, + "session_id": trace.session_id, + "project": trace.project, + "source_agent": trace.source_agent, + }) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("id", "") + + return with_retry_sync(_do_remember, retry_config) + + +def remember_feedback( + base_url: str = DEFAULT_BASE_URL, + feedback: CogneeFeedbackEntry | None = None, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> str: + """Store feedback on an existing QA entry.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + if feedback is None: + raise ValueError("feedback entry is required") + + def _do_remember() -> str: + with httpx.Client(timeout=timeout) as client: + resp = client.post(f"{base_url}/cognee/feedback", json={ + "target_node_id": feedback.target_node_id, + "feedback_text": feedback.feedback_text, + "score": feedback.score, + "project": feedback.project, + "session_id": feedback.session_id, + "source_agent": feedback.source_agent, + }) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("id", "") + + return with_retry_sync(_do_remember, retry_config) + + +def remember_skill_run( + base_url: str = DEFAULT_BASE_URL, + skill_run: CogneeSkillRunEntry | None = None, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> str: + """Store a skill run entry as a structured memory node.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + if skill_run is None: + raise ValueError("skill_run entry is required") + + def _do_remember() -> str: + with httpx.Client(timeout=timeout) as client: + resp = client.post(f"{base_url}/cognee/skill_run", json={ + "skill_name": skill_run.skill_name, + "skill_version": skill_run.skill_version, + "params": skill_run.params, + "result": skill_run.result, + "status": skill_run.status, + "duration_ms": skill_run.duration_ms, + "error": skill_run.error, + "project": skill_run.project, + "session_id": skill_run.session_id, + "source_agent": skill_run.source_agent, + }) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("id", "") + + return with_retry_sync(_do_remember, retry_config) + + +def improve( + base_url: str = DEFAULT_BASE_URL, + project: str = "", + min_confidence: float = 0.0, + min_access_count: int = 0, + consolidate_duplicates: bool = True, + regenerate_summaries: bool = True, + refresh_embeddings: bool = False, + limit: int = 1000, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> CogneeImproveResult: + """Re-process memories to enhance their quality.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + + def _do_improve() -> CogneeImproveResult: + with httpx.Client(timeout=timeout) as client: + resp = client.post(f"{base_url}/cognee/improve", json={ + "project": project, + "min_confidence": min_confidence, + "min_access_count": min_access_count, + "consolidate_duplicates": consolidate_duplicates, + "regenerate_summaries": regenerate_summaries, + "refresh_embeddings": refresh_embeddings, + "limit": limit, + }) + if resp.status_code != 200: + raise parse_error(resp) + return CogneeImproveResult(**resp.json()) + + return with_retry_sync(_do_improve, retry_config) + + +def sync_session_to_permanent( + base_url: str = DEFAULT_BASE_URL, + session_id: str = "", + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> int: + """Sync session-scoped memories to the permanent graph.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + + def _do_sync() -> int: + with httpx.Client(timeout=timeout) as client: + resp = client.post( + f"{base_url}/cognee/sync_session", + json={"session_id": session_id}, + ) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("promoted", 0) + + return with_retry_sync(_do_sync, retry_config) + + +def recall_with_session( + base_url: str = DEFAULT_BASE_URL, + query: str = "", + session_id: str = "", + project: str = "", + limit: int = 10, + timeout: float = DEFAULT_TIMEOUT, + retry_config: RetryConfig | None = None, +) -> str: + """Perform session-aware recall.""" + import httpx + + if retry_config is None: + retry_config = DEFAULT_RETRY_CONFIG + + def _do_recall() -> str: + with httpx.Client(timeout=timeout) as client: + resp = client.post(f"{base_url}/cognee/recall_session", json={ + "query": query, + "session_id": session_id, + "project": project, + "limit": limit, + }) + if resp.status_code != 200: + raise parse_error(resp) + return resp.json().get("context", "") + + return with_retry_sync(_do_recall, retry_config) From 50acea144f35b82ca5ac5eb79755f6a1c8985710 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Wed, 29 Jul 2026 13:37:05 +0530 Subject: [PATCH 2/4] fix: resolve ruff lint and mypy strict typecheck issues - Fix import sorting (ruff I001) - Add explicit str()/int() casts for resp.json().get() returns (mypy no-any-return in strict mode) --- src/hawk/composio_cognee.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/hawk/composio_cognee.py b/src/hawk/composio_cognee.py index a56c1e2..7379fc9 100644 --- a/src/hawk/composio_cognee.py +++ b/src/hawk/composio_cognee.py @@ -18,7 +18,6 @@ from .errors import parse_error from .retry import DEFAULT_RETRY_CONFIG, RetryConfig, with_retry_sync - # --- Composio Types --- @dataclass @@ -224,7 +223,7 @@ def _do_remember() -> str: ) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("id", "") + return str(resp.json().get("id", "")) return with_retry_sync(_do_remember, retry_config) @@ -259,7 +258,7 @@ def _do_remember() -> str: }) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("id", "") + return str(resp.json().get("id", "")) return with_retry_sync(_do_remember, retry_config) @@ -290,7 +289,7 @@ def _do_remember() -> str: }) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("id", "") + return str(resp.json().get("id", "")) return with_retry_sync(_do_remember, retry_config) @@ -325,7 +324,7 @@ def _do_remember() -> str: }) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("id", "") + return str(resp.json().get("id", "")) return with_retry_sync(_do_remember, retry_config) @@ -386,7 +385,7 @@ def _do_sync() -> int: ) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("promoted", 0) + return int(resp.json().get("promoted", 0)) return with_retry_sync(_do_sync, retry_config) @@ -416,6 +415,6 @@ def _do_recall() -> str: }) if resp.status_code != 200: raise parse_error(resp) - return resp.json().get("context", "") + return str(resp.json().get("context", "")) return with_retry_sync(_do_recall, retry_config) From 4518f981230adfeaf5d28e6a55639aacf88bda7d Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Wed, 29 Jul 2026 13:48:45 +0530 Subject: [PATCH 3/4] fix: sort imports and __all__ in __init__.py (ruff I001, RUF022) - Fix import block sorting in src/hawk/__init__.py - Fix __all__ list sorting (RUF022) - Re-run ruff check --fix to resolve both issues --- src/hawk/__init__.py | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/hawk/__init__.py b/src/hawk/__init__.py index b552b74..645ac00 100644 --- a/src/hawk/__init__.py +++ b/src/hawk/__init__.py @@ -3,6 +3,26 @@ from ._version import __version__ from .agent import Agent, AgentConfig, AsyncAgent from .client import AsyncHawkClient, HawkClient +from .composio_cognee import ( + CogneeFeedbackEntry, + CogneeImproveResult, + CogneeQAEntry, + CogneeSkillRunEntry, + CogneeTraceEntry, + ComposioCredential, + ComposioTool, + ComposioToolResult, + execute_composio_tool, + improve, + list_composio_credentials, + recall_with_session, + remember_feedback, + remember_qa, + remember_skill_run, + remember_trace, + search_composio_tools, + sync_session_to_permanent, +) from .discovery import ( AgentCard, AgentResolver, @@ -71,26 +91,6 @@ ToolCall, Usage, ) -from .composio_cognee import ( - CogneeFeedbackEntry, - CogneeImproveResult, - CogneeQAEntry, - CogneeSkillRunEntry, - CogneeTraceEntry, - ComposioCredential, - ComposioTool, - ComposioToolResult, - execute_composio_tool, - improve, - list_composio_credentials, - recall_with_session, - remember_feedback, - remember_qa, - remember_skill_run, - remember_trace, - search_composio_tools, - sync_session_to_permanent, -) from .workflow import AsyncWorkflow, Workflow __all__ = [ @@ -109,6 +109,14 @@ "BenchmarkResults", "ChatRequest", "ChatResponse", + "CogneeFeedbackEntry", + "CogneeImproveResult", + "CogneeQAEntry", + "CogneeSkillRunEntry", + "CogneeTraceEntry", + "ComposioCredential", + "ComposioTool", + "ComposioToolResult", "CompositeResolver", "EvalResult", "EvalTask", @@ -161,27 +169,19 @@ "chat_with_tools_async", "configure_tracing", "detect_provider", - "is_tracing_enabled", - "run_benchmark", - "run_benchmark_async", - "search_composio_tools", "execute_composio_tool", + "improve", + "is_tracing_enabled", "list_composio_credentials", - "remember_qa", - "remember_trace", + "recall_with_session", "remember_feedback", + "remember_qa", "remember_skill_run", - "improve", + "remember_trace", + "run_benchmark", + "run_benchmark_async", + "search_composio_tools", "sync_session_to_permanent", - "recall_with_session", - "ComposioTool", - "ComposioToolResult", - "ComposioCredential", - "CogneeQAEntry", - "CogneeTraceEntry", - "CogneeFeedbackEntry", - "CogneeSkillRunEntry", - "CogneeImproveResult", "tool", "trace", "trace_chat", From 599255cd37670e3c836b13327be46312fff83822 Mon Sep 17 00:00:00 2001 From: Lakshman Patel Date: Wed, 29 Jul 2026 13:53:31 +0530 Subject: [PATCH 4/4] fix: apply ruff format to composio_cognee.py --- src/hawk/composio_cognee.py | 113 +++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/src/hawk/composio_cognee.py b/src/hawk/composio_cognee.py index 7379fc9..5c05303 100644 --- a/src/hawk/composio_cognee.py +++ b/src/hawk/composio_cognee.py @@ -20,6 +20,7 @@ # --- Composio Types --- + @dataclass class ComposioTool: name: str @@ -50,6 +51,7 @@ class ComposioCredential: # --- Cognee Entry Types --- + @dataclass class CogneeQAEntry: question: str @@ -114,6 +116,7 @@ class CogneeImproveResult: # --- Composio Methods --- + def search_composio_tools( base_url: str = DEFAULT_BASE_URL, query: str = "", @@ -191,6 +194,7 @@ def _do_list() -> list[ComposioCredential]: # --- Cognee Memory Methods --- + def remember_qa( base_url: str = DEFAULT_BASE_URL, qa: CogneeQAEntry | None = None, @@ -244,18 +248,21 @@ def remember_trace( def _do_remember() -> str: with httpx.Client(timeout=timeout) as client: - resp = client.post(f"{base_url}/cognee/trace", json={ - "origin_function": trace.origin_function, - "status": trace.status, - "method_params": trace.method_params, - "method_return_value": trace.method_return_value, - "memory_query": trace.memory_query, - "memory_context": trace.memory_context, - "error_message": trace.error_message, - "session_id": trace.session_id, - "project": trace.project, - "source_agent": trace.source_agent, - }) + resp = client.post( + f"{base_url}/cognee/trace", + json={ + "origin_function": trace.origin_function, + "status": trace.status, + "method_params": trace.method_params, + "method_return_value": trace.method_return_value, + "memory_query": trace.memory_query, + "memory_context": trace.memory_context, + "error_message": trace.error_message, + "session_id": trace.session_id, + "project": trace.project, + "source_agent": trace.source_agent, + }, + ) if resp.status_code != 200: raise parse_error(resp) return str(resp.json().get("id", "")) @@ -279,14 +286,17 @@ def remember_feedback( def _do_remember() -> str: with httpx.Client(timeout=timeout) as client: - resp = client.post(f"{base_url}/cognee/feedback", json={ - "target_node_id": feedback.target_node_id, - "feedback_text": feedback.feedback_text, - "score": feedback.score, - "project": feedback.project, - "session_id": feedback.session_id, - "source_agent": feedback.source_agent, - }) + resp = client.post( + f"{base_url}/cognee/feedback", + json={ + "target_node_id": feedback.target_node_id, + "feedback_text": feedback.feedback_text, + "score": feedback.score, + "project": feedback.project, + "session_id": feedback.session_id, + "source_agent": feedback.source_agent, + }, + ) if resp.status_code != 200: raise parse_error(resp) return str(resp.json().get("id", "")) @@ -310,18 +320,21 @@ def remember_skill_run( def _do_remember() -> str: with httpx.Client(timeout=timeout) as client: - resp = client.post(f"{base_url}/cognee/skill_run", json={ - "skill_name": skill_run.skill_name, - "skill_version": skill_run.skill_version, - "params": skill_run.params, - "result": skill_run.result, - "status": skill_run.status, - "duration_ms": skill_run.duration_ms, - "error": skill_run.error, - "project": skill_run.project, - "session_id": skill_run.session_id, - "source_agent": skill_run.source_agent, - }) + resp = client.post( + f"{base_url}/cognee/skill_run", + json={ + "skill_name": skill_run.skill_name, + "skill_version": skill_run.skill_version, + "params": skill_run.params, + "result": skill_run.result, + "status": skill_run.status, + "duration_ms": skill_run.duration_ms, + "error": skill_run.error, + "project": skill_run.project, + "session_id": skill_run.session_id, + "source_agent": skill_run.source_agent, + }, + ) if resp.status_code != 200: raise parse_error(resp) return str(resp.json().get("id", "")) @@ -349,15 +362,18 @@ def improve( def _do_improve() -> CogneeImproveResult: with httpx.Client(timeout=timeout) as client: - resp = client.post(f"{base_url}/cognee/improve", json={ - "project": project, - "min_confidence": min_confidence, - "min_access_count": min_access_count, - "consolidate_duplicates": consolidate_duplicates, - "regenerate_summaries": regenerate_summaries, - "refresh_embeddings": refresh_embeddings, - "limit": limit, - }) + resp = client.post( + f"{base_url}/cognee/improve", + json={ + "project": project, + "min_confidence": min_confidence, + "min_access_count": min_access_count, + "consolidate_duplicates": consolidate_duplicates, + "regenerate_summaries": regenerate_summaries, + "refresh_embeddings": refresh_embeddings, + "limit": limit, + }, + ) if resp.status_code != 200: raise parse_error(resp) return CogneeImproveResult(**resp.json()) @@ -407,12 +423,15 @@ def recall_with_session( def _do_recall() -> str: with httpx.Client(timeout=timeout) as client: - resp = client.post(f"{base_url}/cognee/recall_session", json={ - "query": query, - "session_id": session_id, - "project": project, - "limit": limit, - }) + resp = client.post( + f"{base_url}/cognee/recall_session", + json={ + "query": query, + "session_id": session_id, + "project": project, + "limit": limit, + }, + ) if resp.status_code != 200: raise parse_error(resp) return str(resp.json().get("context", ""))