feat: Persistent with serverless #107
Conversation
WalkthroughThis pull request introduces persistent memory support across the RunAgent SDK, adding Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Areas requiring extra attention:
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/journalist_agent/dart_sdk/.dart_tool/package_graph.json (1)
1-124: Do not commit auto-generated.dart_tool/artifacts to version control.The
.dart_tool/package_graph.jsonfile is auto-generated by Dart's pub tool and should be excluded from version control. Committing these files creates merge conflicts, stale dependency snapshots, and maintenance burden. Add.dart_tool/to the root.gitignore:.dart_tool/This issue affects multiple Dart projects in the repository (
examples/journalist_agent/dart_sdk/,runagent-dart/, andtest_scripts/dart/*/).
🧹 Nitpick comments (31)
examples/trip_planner/agent/runagent.config.json (1)
2-5: Agent metadata overly generic for documentation.The agent configuration has been simplified to generic values: agent_name is now "trip planner" and description is "My AI agent". For an example, these descriptive fields should provide context. Consider whether more meaningful descriptions would better serve users learning from this example.
examples/agno_persistent/requirements.txt (1)
1-2: Requirements are minimal; consider optional pinningThe dependencies are sufficient for the example. If you want more reproducible example runs, consider pinning to known‑good versions in the future.
examples/lightrag_persistent/requirements.txt (1)
1-3: Dependencies cover the LightRAG exampleThe required libraries for the persistent LightRAG example are declared appropriately. As with other examples, pinning versions later could help avoid breakage from upstream changes.
templates/agno/agno_persistent/requirements.txt (1)
1-2: Template requirements are aligned with AGNO usage
agnoandopenaiare the expected deps for the AGNO persistent template. If template stability over time becomes a concern, consider pinning or documenting tested versions.runagent-dart/lib/src/client/rest_client.dart (1)
58-92: Persistent memory parameters are wired correctly
- Adding
userIdandpersistentMemoryas optional named parameters keeps the API backward compatible.- Building a typed
Map<String, dynamic>payload and only includinguser_idwhen non‑null andpersistent_memorywhentruematches the intended server contract and Python parity.- No issues with existing timeout, auth, or error‑translation behavior around this change.
One minor follow‑up you may consider later: extend the method doc comment to mention
userIdandpersistentMemoryso IDE tooltips stay in sync with the API.runagent/utils/schema.py (1)
96-102: Persistent folders field integrates cleanly with existing serializationThe
persistent_foldersfield is well-aligned with howenv_varsand other optional fields are handled, andto_dict()will correctly preserve empty lists while strippingNonevalues. If you expect only relative paths or want to guard against invalid entries, consider adding a small validator onRunAgentConfigto enforce those constraints, but that’s strictly optional.runagent-dart/CHANGELOG.md (1)
8-18: Changelog entry matches API changes; remember to finalize release dateThe 0.1.43 notes accurately describe the new
userId/persistentMemorybehavior and propagation through clients. Before tagging/publishing, replace2024-XX-XXwith the actual release date to keep the changelog consistent.test/rag_test.txt (1)
1-20: Optional wording cleanup in narrative textThis file is fine as‑is functionally. If you care about style polish, you could drop “about” in “estimated at about 8.25 billion people” to avoid redundancy (“estimated at 8.25 billion people” reads a bit tighter), but that’s entirely optional.
runagent-rust/runagent/README.md (1)
48-55: Rust README updates align with new persistence APIThe added example using
.with_user_id()/.with_persistent_memory(true)and the new rows in the settings + builder tables accurately reflect the new config fields and default behavior. If you revisit this snippet later, you might consider also showinguse runagent::{RunAgentClient, RunAgentClientConfig};(anduse std::env;if you keepenv::var) so the example is copy‑paste runnable, but that’s purely a doc nicety.Also applies to: 64-66, 69-71, 275-276
runagent/utils/serializer.py (1)
261-303: Redundant empty payload checks in type branches.After the empty payload check at lines 262-269 returns early, the per-type checks (e.g., lines 276-277, 280-281, 285-286, etc.) can never trigger since we've already handled the empty case. Consider removing these redundant guards.
# Parse payload based on type if data_type == "null": return None elif data_type == "string": # Payload is JSON string, parse to get the actual string - if not payload or not payload.strip(): - return "" return json.loads(payload) elif data_type == "integer": - if not payload or not payload.strip(): - return 0 value = json.loads(payload) return int(value) elif data_type == "number": - if not payload or not payload.strip(): - return 0.0 value = json.loads(payload) return float(value) elif data_type == "boolean": - if not payload or not payload.strip(): - return False return json.loads(payload) elif data_type in ("array", "object"): # Parse JSON to get structured data - if not payload or not payload.strip(): - return [] if data_type == "array" else {} return json.loads(payload) else: # Unknown type, try to parse as JSON self.logger.warning(f"Unknown type '{data_type}', attempting JSON parse") - if not payload or not payload.strip(): - return None return json.loads(payload)templates/agno/agno_persistent/agent.py (2)
73-73: Use explicitOptionaltype hint for nullable parameter.Per PEP 484,
prompt: str = Noneshould beprompt: Optional[str] = None.Optionalis already imported.-def agent_print_response(prompt: str = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs): +def agent_print_response(prompt: Optional[str] = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs):
126-126: Apply the sameOptionaltype hint fix here.-def agent_print_response_stream(prompt: str = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs): +def agent_print_response_stream(prompt: Optional[str] = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs):templates/agno/agno_persistent/runagent.config.json (1)
2-3: Consider a more descriptive agent description.The description
"My AI agent"is generic placeholder text. Consider something like"Persistent chat agent with SQLite-backed session memory"to better describe the agent's capabilities.test_scripts/python/client_test_agno.py (1)
4-7: Align or document differingagent_idvaluesThe commented example and the active
RunAgentClientuse differentagent_idvalues. That can be confusing for someone uncommenting the top block or copying it as a template. Consider either:
- Updating the commented block to use the same
agent_idas the active client, or- Adding a brief comment that the IDs are from different deployments.
Also applies to: 20-23
examples/agno_persistent/runagent.config.json (1)
8-12: Avoid machine-specific paths and clarify deployment‑specificagent_idThe config structure looks correct for a persistent Agno agent, but two minor nits:
template_source.pathis an absolute path to a specific machine (/home/azureuser/...). For templates checked into the repo, a relative path or a more generic value is less confusing for other users.agent_idis deployment‑specific. In docs/scripts that reference this config, it can help to remind readers that this value will change on redeploy and should be updated fromrunagent deployoutput.Also applies to: 28-32
examples/lightrag_persistent/README.md (1)
14-21: Add a language to the fenced code block (markdownlint MD040)The file-structure code block is missing a language spec, which triggers MD040. You can tag it as plain text:
-``` +```text lightrag_agent/ ├── agent.py # Main agent implementation ├── requirements.txt # Python dependencies ├── runagent.config.json # RunAgent configuration ├── test_sdk.py # SDK test script └── README.md # This file</blockquote></details> <details> <summary>examples/lightrag_persistent/runagent.config.json (1)</summary><blockquote> `8-12`: **Polish metadata (path and description text)** The config itself looks structurally correct. Two small metadata cleanups you might consider: - `template_source.path` is machine‑specific (`/home/azureuser/...`); a relative or generic path is friendlier for other environments. - The description string could be tightened, e.g.: - From: `"Lightrag is agentic RAG framework"` - To: `"LightRAG is an agentic RAG framework"` Purely cosmetic, but improves portability and readability. Also applies to: 3-3 </blockquote></details> <details> <summary>runagent/sdk/deployment/remote.py (1)</summary><blockquote> `101-133`: **Input parsing and RestClient delegation look correct; consider noting/mitigating mutation** The new `run_agent` implementation correctly: - Pulls out `user_id`, `persistent_memory`, and `entrypoint_tag`. - Separates `input_args` / `input_kwargs`. - Treats any remaining top‑level keys as entrypoint kwargs. - Forwards everything to `RestClient.run_agent(...)` with the new parameters. One small behavioral detail: this function mutates `input_data` in place via multiple `pop` calls. That’s fine if callers always pass a fresh dict, but if they ever reuse the same object, keys will have been stripped. Two options: - Document in the docstring that `input_data` is consumed/mutated, or - Work on a shallow copy: ```python def run_agent(self, agent_id: str, input_data: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: data = dict(input_data) # shallow copy user_id = data.pop("user_id", None) ...Not required for correctness, but makes the API behavior clearer and more robust.
runagent/sdk/rest_client.py (1)
1481-1482: Use explicitOptionalor union syntax for type hint.PEP 484 prohibits implicit
Optional. UseOptional[str]orstr | Noneinstead ofstr = None.Apply this diff:
- user_id: str = None, + user_id: Optional[str] = None,test_scripts/dart/test_lightrag/.dart_tool/package_config.json (1)
1-106: Consider excluding generated Dart tool files from version control.This is an auto-generated file containing environment-specific absolute paths (e.g.,
/home/azureuser). The.dart_tool/directory is typically added to.gitignoreto avoid:
- Merge conflicts from developer-specific paths
- Repository bloat from generated files
- Build reproducibility issues across environments
Verify that
.dart_tool/is in your.gitignore:#!/bin/bash # Check if .dart_tool is properly ignored if grep -q "^\.dart_tool/" .gitignore; then echo "✓ .dart_tool is already ignored" else echo "✗ .dart_tool is not in .gitignore" echo "Consider adding: echo '.dart_tool/' >> .gitignore" fitest/test_lightrag.py (1)
1-1: Make script executable or remove shebang.The shebang is present but the file is not executable.
Make the file executable:
#!/bin/bash chmod +x test/test_lightrag.pytest_scripts/dart/test_lightrag/lib/main.dart (1)
10-32: Consider consistent error handling across functions.
ingestFromFilereturnsnullon error (line 14), whilequeryRagdoesn't have explicit error handling and would propagate exceptions. For consistency, consider either:
- Both functions return null on error, or
- Both functions throw exceptions
If exceptions are preferred:
if (!await file.exists()) { - print('Error: File not found: $filePath'); - return null; + throw Exception('File not found: $filePath'); }test_scripts/python/client_test_lightrag.py (2)
4-7: Hardcoded configuration may limit test portability.Consider using environment variables for
AGENT_IDandUSER_IDto enable running tests against different agents without code changes:AGENT_ID = os.getenv("RUNAGENT_AGENT_ID", "63751c14-0ed5-426c-ab44-aa94e5505bed") USER_ID = os.getenv("RUNAGENT_USER_ID", "rad123")
48-60: Main block contains commented-out code and incomplete flow.The test executes only
query_ragwhile ingestion and completion messages are commented out. If this is intentional for quick iteration, consider adding a command-line argument or environment variable to control which steps run, rather than relying on commented code.runagent/client/client.py (2)
25-25: Type hints use implicitOptional; consider explicit union syntax.Per PEP 484 and static analysis (RUF013), parameters with
Nonedefaults should use explicit optional types:- def __init__(self, agent_id: str, entrypoint_tag: str, local: bool = True, host: str = None, port: int = None, user_id: str = None, persistent_memory: bool = False): + def __init__(self, agent_id: str, entrypoint_tag: str, local: bool = True, host: str | None = None, port: int | None = None, user_id: str | None = None, persistent_memory: bool = False):
84-86: Remove extraneousfprefix from string without placeholders.Static analysis (F541) correctly flags line 85:
- console.print(f"[cyan]Detected streaming entrypoint, using WebSocket streaming[/cyan]") + console.print("[cyan]Detected streaming entrypoint, using WebSocket streaming[/cyan]")examples/agno_persistent/agent.py (2)
73-73: Type hint uses implicitOptional.Per static analysis (RUF013), use explicit union:
-def agent_print_response(prompt: str = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs): +def agent_print_response(prompt: str | None = None, user: str = "user", session_id: str | None = None, new_session: bool = False, **kwargs):Note: You're mixing
Optional[str](imported) with implicit optional. Pick one style—str | Noneis more modern (Python 3.10+).
126-126: Same type hint issue as line 73.Apply the same fix for consistency:
-def agent_print_response_stream(prompt: str = None, user: str = "user", session_id: Optional[str] = None, new_session: bool = False, **kwargs): +def agent_print_response_stream(prompt: str | None = None, user: str = "user", session_id: str | None = None, new_session: bool = False, **kwargs):examples/lightrag_persistent/agent.py (3)
29-48: Use explicitOptionaltype hints and log cleanup failures.Per static analysis (Ruff RUF013), PEP 484 prohibits implicit
Optional. Additionally, the bareexcept: passsilently swallows cleanup errors, which can hide storage finalization issues.Apply this diff:
+import logging + +logger = logging.getLogger(__name__) + -async def ingest_text_async(text: str = None, **kwargs): +async def ingest_text_async(text: str | None = None, **kwargs): if text is None: text = kwargs.get('content', '') if not text: return {"status": "error", "message": "No text provided"} rag = None try: rag = await get_rag_instance() await rag.ainsert(text) return {"status": "success", "message": f"Ingested {len(text)} characters"} except Exception as e: return {"status": "error", "message": str(e)} finally: if rag: try: await rag.finalize_storages() - except: - pass + except Exception as cleanup_err: + logger.warning("Storage finalization failed: %s", cleanup_err)
51-73: Apply same type hint and logging fixes here.Same issues as
ingest_text_async: implicitOptionaland silent cleanup errors.Apply this diff:
-async def query_rag_async(query: str = None, mode: str = "hybrid", **kwargs): +async def query_rag_async(query: str | None = None, mode: str = "hybrid", **kwargs): if query is None: query = kwargs.get('question', '') if not query: return {"status": "error", "message": "No query provided"} if mode not in ["naive", "local", "global", "hybrid"]: mode = "hybrid" rag = None try: rag = await get_rag_instance() result = await rag.aquery(query, param=QueryParam(mode=mode)) return {"status": "success", "query": query, "mode": mode, "result": result} except Exception as e: return {"status": "error", "message": str(e)} finally: if rag: try: await rag.finalize_storages() - except: - pass + except Exception as cleanup_err: + logger.warning("Storage finalization failed: %s", cleanup_err)
76-81: Update type hints in sync wrappers for consistency.-def ingest_text(text: str = None, **kwargs): +def ingest_text(text: str | None = None, **kwargs): return asyncio.run(ingest_text_async(text, **kwargs)) -def query_rag(query: str = None, mode: str = "hybrid", **kwargs): +def query_rag(query: str | None = None, mode: str = "hybrid", **kwargs): return asyncio.run(query_rag_async(query, mode, **kwargs))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (53)
README.md(3 hunks)examples/agno_persistent/agent.py(1 hunks)examples/agno_persistent/requirements.txt(1 hunks)examples/agno_persistent/runagent.config.json(1 hunks)examples/journalist_agent/agent/runagent.config.json(1 hunks)examples/journalist_agent/dart_sdk/.dart_tool/package_graph.json(4 hunks)examples/journalist_agent/dart_sdk/lib/main.dart(1 hunks)examples/lead-agent/lead-score-flow/runagent.config.json(1 hunks)examples/lead-agent/runagent_sdk/python/test_sdk.py(1 hunks)examples/lightrag_persistent/README.md(1 hunks)examples/lightrag_persistent/agent.py(1 hunks)examples/lightrag_persistent/requirements.txt(1 hunks)examples/lightrag_persistent/runagent.config.json(1 hunks)examples/trip_planner/agent/requirements.txt(1 hunks)examples/trip_planner/agent/runagent.config.json(1 hunks)examples/trip_planner/sdk/python/test.py(2 hunks)runagent-dart/.dart_tool/package_graph.json(1 hunks)runagent-dart/CHANGELOG.md(1 hunks)runagent-dart/lib/src/client/rest_client.dart(2 hunks)runagent-dart/lib/src/client/runagent_client.dart(5 hunks)runagent-dart/lib/src/client/socket_client.dart(2 hunks)runagent-dart/lib/src/types/types.dart(4 hunks)runagent-dart/pubspec.yaml(1 hunks)runagent-rust/runagent/Cargo.toml(1 hunks)runagent-rust/runagent/README.md(3 hunks)runagent-rust/runagent/src/blocking.rs(1 hunks)runagent-rust/runagent/src/client/rest_client.rs(2 hunks)runagent-rust/runagent/src/client/runagent_client.rs(9 hunks)runagent-rust/runagent/src/client/socket_client.rs(3 hunks)runagent/cli/commands/run.py(2 hunks)runagent/cli/commands/run_stream.py(2 hunks)runagent/client/client.py(5 hunks)runagent/sdk/deployment/remote.py(1 hunks)runagent/sdk/rest_client.py(2 hunks)runagent/sdk/sdk.py(3 hunks)runagent/sdk/socket_client.py(4 hunks)runagent/utils/schema.py(1 hunks)runagent/utils/serializer.py(3 hunks)templates/agno/agno_persistent/agent.py(1 hunks)templates/agno/agno_persistent/requirements.txt(1 hunks)templates/agno/agno_persistent/runagent.config.json(1 hunks)templates/agno/default/runagent.config.json(1 hunks)test/rag_test.txt(1 hunks)test/test_lightrag.py(1 hunks)test_scripts/dart/test_lightrag/.dart_tool/package_config.json(1 hunks)test_scripts/dart/test_lightrag/.dart_tool/package_graph.json(1 hunks)test_scripts/dart/test_lightrag/lib/main.dart(1 hunks)test_scripts/dart/test_lightrag/pubspec.yaml(1 hunks)test_scripts/python/client_test_agno.py(2 hunks)test_scripts/python/client_test_agno_persistent.py(1 hunks)test_scripts/python/client_test_lightrag.py(1 hunks)test_scripts/rust/test_lightrag/Cargo.toml(1 hunks)test_scripts/rust/test_lightrag/src/main.rs(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (15)
test_scripts/rust/test_lightrag/src/main.rs (4)
runagent-rust/runagent/src/client/rest_client.rs (1)
new(21-41)runagent-rust/runagent/src/blocking.rs (2)
new(50-57)new(197-224)runagent-rust/runagent/src/client/runagent_client.rs (2)
new(125-139)new(218-326)runagent-rust/runagent/src/client/socket_client.rs (1)
new(23-36)
runagent-rust/runagent/src/blocking.rs (1)
runagent-rust/runagent/src/client/runagent_client.rs (2)
user_id(590-592)persistent_memory(595-597)
runagent-rust/runagent/src/client/socket_client.rs (2)
runagent-rust/runagent/src/blocking.rs (2)
user_id(148-150)persistent_memory(153-155)runagent-rust/runagent/src/client/runagent_client.rs (2)
user_id(590-592)persistent_memory(595-597)
examples/lead-agent/runagent_sdk/python/test_sdk.py (1)
runagent-rust/runagent/src/client/runagent_client.rs (1)
agent_id(575-577)
runagent-rust/runagent/src/client/rest_client.rs (4)
runagent-rust/runagent/src/blocking.rs (2)
user_id(148-150)persistent_memory(153-155)runagent-rust/runagent/src/client/runagent_client.rs (2)
user_id(590-592)persistent_memory(595-597)runagent-rust/runagent/src/utils/serializer.rs (3)
serde_json(44-44)serde_json(71-71)serde_json(95-95)examples/lead-agent/backend-rust/src/main.rs (3)
serde_json(161-161)serde_json(168-168)serde_json(175-175)
runagent/sdk/sdk.py (2)
runagent/sdk/rest_client.py (1)
ValidationError(61-63)runagent/sdk/exceptions.py (1)
ValidationError(23-26)
examples/lightrag_persistent/agent.py (2)
examples/lightrag_agent_(developing)/services/rag_service.py (2)
lightrag(223-227)llm_model_func(77-91)test_scripts/python/client_test_lightrag.py (1)
query_rag(41-45)
runagent/sdk/socket_client.py (1)
runagent/client/client.py (1)
run_stream(159-190)
test_scripts/python/client_test_lightrag.py (1)
runagent/client/client.py (1)
run(72-157)
runagent/cli/commands/run.py (4)
runagent-rust/runagent/src/client/rest_client.rs (1)
default(45-48)runagent-rust/runagent/src/client/runagent_client.rs (6)
default(106-120)run(374-376)agent_id(575-577)user_id(590-592)persistent_memory(595-597)entrypoint_tag(580-582)runagent-rust/runagent/src/blocking.rs (5)
run(62-64)agent_id(133-135)user_id(148-150)persistent_memory(153-155)entrypoint_tag(138-140)runagent/client/client.py (1)
run(72-157)
test_scripts/python/client_test_agno_persistent.py (1)
runagent/client/client.py (2)
RunAgentClient(23-333)run(72-157)
examples/agno_persistent/agent.py (4)
runagent/cli/commands/db.py (1)
db(48-50)runagent/sdk/rest_client.py (1)
get(214-216)runagent/client/client.py (1)
run(72-157)examples/rag_agent/frontend/app.js (1)
content(209-209)
test/test_lightrag.py (2)
examples/lightrag_agent_(developing)/services/rag_service.py (2)
lightrag(223-227)llm_model_func(77-91)runagent/client/client.py (1)
run(72-157)
runagent-rust/runagent/src/client/runagent_client.rs (2)
runagent-rust/runagent/src/blocking.rs (2)
user_id(148-150)persistent_memory(153-155)runagent-rust/runagent/src/types/errors.rs (1)
config(119-123)
test_scripts/python/client_test_agno.py (2)
runagent-rust/runagent/src/blocking.rs (1)
agent_id(133-135)runagent-rust/runagent/src/client/runagent_client.rs (1)
agent_id(575-577)
🪛 LanguageTool
test/rag_test.txt
[style] ~9-~9: This phrase is redundant. Consider writing “estimated at”.
Context: ...s of late 2025, the world population is estimated at about 8.25 billion people. ([DataReportal...
(ESTIMATED_AT_ABOUT)
[uncategorized] ~43-~43: Do not mix variants of the same word (‘organization’ and ‘organisation’) within a single text.
Context: ...* According to the World Meteorological Organization (WMO), **2024 was the warmest year on r...
(EN_WORD_COHERENCY)
[uncategorized] ~43-~43: Do not mix variants of the same word (‘organization’ and ‘organisation’) within a single text.
Context: ... global warming. ([World Meteorological Organization][8]) * The increase in greenhouse-gas ...
(EN_WORD_COHERENCY)
[uncategorized] ~49-~49: Do not mix variants of the same word (‘organization’ and ‘organisation’) within a single text.
Context: ...n more severe exposure). ([World Health Organization][11]) * The environmental challenges g...
(EN_WORD_COHERENCY)
🪛 markdownlint-cli2 (0.18.1)
examples/lightrag_persistent/README.md
14-14: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 Ruff (0.14.7)
runagent/sdk/sdk.py
351-351: Avoid specifying long messages outside the exception class
(TRY003)
runagent/client/client.py
25-25: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
25-25: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
25-25: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
85-85: f-string without any placeholders
Remove extraneous f prefix
(F541)
127-127: Do not catch blind exception: Exception
(BLE001)
135-135: Do not catch blind exception: Exception
(BLE001)
templates/agno/agno_persistent/agent.py
73-73: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
126-126: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
examples/lightrag_persistent/agent.py
29-29: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
41-41: Do not catch blind exception: Exception
(BLE001)
47-47: Do not use bare except
(E722)
47-48: try-except-pass detected, consider logging the exception
(S110)
51-51: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
65-65: Consider moving this statement to an else block
(TRY300)
66-66: Do not catch blind exception: Exception
(BLE001)
72-72: Do not use bare except
(E722)
72-73: try-except-pass detected, consider logging the exception
(S110)
76-76: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
80-80: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
runagent/utils/serializer.py
248-248: Abstract raise to an inner function
(TRY301)
248-248: Avoid specifying long messages outside the exception class
(TRY003)
examples/agno_persistent/agent.py
73-73: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
126-126: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
runagent/sdk/rest_client.py
1481-1481: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
test/test_lightrag.py
1-1: Shebang is present but file is not executable
(EXE001)
23-23: f-string without any placeholders
Remove extraneous f prefix
(F541)
23-23: String contains ambiguous ℹ (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?
(RUF001)
🔇 Additional comments (63)
templates/agno/default/runagent.config.json (1)
28-28: Clarify the purpose of the agent_id change.The
agent_idUUID has been modified, but this change appears unrelated to the persistent memory feature introduced in this PR. Please clarify:
- Is this UUID change intentional or accidental?
- Does this affect any dependent systems or existing agent configurations?
- Should this change be included in this PR, or should it be reverted/moved to a separate issue?
examples/lead-agent/lead-score-flow/runagent.config.json (1)
28-28: Configuration ID update appears intentional.The
agent_idchange aligns with the PR's agent configuration standardization mentioned in the summary.examples/journalist_agent/dart_sdk/.dart_tool/package_graph.json (1)
14-21: No action required: Package version in package_graph.json is correct.The version
0.1.41shown for the runagent package in this file is the accurate, current version. There is no evidence of a PR objective to bump the version to0.1.43. The file is located in.dart_tool/(a generated/cached directory) and correctly reflects the installed package version.Likely an incorrect or invalid review comment.
examples/trip_planner/agent/runagent.config.json (1)
27-32: New persistence configuration fields align with PR objectives.The addition of
env_vars,agent_id,auth_settings, andpersistent_foldersfields supports the persistent memory feature described in the PR. The structure is sound, and the UUID-based agent_id provides appropriate uniqueness. These fields complement the broader persistence support being introduced.runagent-rust/runagent/Cargo.toml (1)
3-3: Version bump looks consistent with the described SDK changes.No issues from this manifest side; keeping dependencies and features unchanged is appropriate for this incremental release.
examples/lead-agent/runagent_sdk/python/test_sdk.py (1)
5-5: Agent ID update looks fineThe new
agent_idwiring is consistent with the rest of the example; no functional issues here.runagent-dart/pubspec.yaml (1)
3-3: Version bump is consistent
version: 0.1.43aligns with the rest of the Dart SDK changes; nothing else to adjust here.runagent-dart/.dart_tool/package_graph.json (1)
8-8: Package graph version matches pubspecThe
runagentpackage version in the package graph is correctly updated to0.1.43and stays consistent withpubspec.yaml.examples/trip_planner/sdk/python/test.py (1)
10-10: Trip planner example updates are consistentThe new
AGENT_IDand the commented streaming block’slocal=Falsesetting both align this script with remote agent usage. The example remains coherent and ready for users to plug in their own agent ID.Also applies to: 46-46
README.md (1)
517-614: Persistent Memory docs are clear and consistent across SDKsThe new Persistent Memory section does a good job explaining the serverless‑memory concept and shows accurate, parallel examples for Python, JavaScript, Rust, and Dart using
user_id/persistent_memory. The adjusted Action Memory copy also correctly positions it as building on this foundation. No issues from a technical/docs perspective.Also applies to: 629-639
runagent-dart/lib/src/client/socket_client.dart (1)
20-28: WebSocket streaming now correctly propagates userId and persistentMemoryAdding
userId/persistentMemoryas optional named parameters and conditionally injectinguser_id/persistent_memoryintorequestDatakeeps the API backward‑compatible while aligning the WebSocket payload with the REST/Python behavior. The typed<String, dynamic>{}map is also a nice touch for clarity.Also applies to: 63-77
runagent-dart/lib/src/types/types.dart (2)
32-50: LGTM! Clean addition of persistent memory configuration fields.The new
userIdandpersistentMemoryfields are properly added as optional parameters, maintaining backward compatibility. The implementation is consistent with the existing field patterns in the class.
63-78: Factory method correctly forwards new parameters.The
createfactory properly accepts and passes through theuserIdandpersistentMemoryparameters, maintaining consistency with the constructor.runagent/utils/serializer.py (2)
61-64: Empty input handling is reasonable.Returning
Nonefor empty/whitespace input prevents JSON parse errors. The warning log aids debugging.
245-248: Verify intended behavior difference between deserialize methods.
deserialize_objectreturnsNonefor empty input (line 64), whiledeserialize_object_from_structuredraisesValueError(line 248). If this asymmetry is intentional (structured format requires valid input), consider adding a brief comment explaining the rationale.templates/agno/agno_persistent/agent.py (2)
146-163: Well-structured streaming implementation.The streaming handler properly yields session metadata first, streams content chunks, and confirms session completion. The structured output format with
typefield enables consumers to distinguish metadata from content.
40-45: No action needed. Agno'sdb.get_sessions()defaults to sorting bycreated_atin descending order (newest first), soexisting_sessions[0]correctly retrieves the latest session. This behavior is documented in Agno's Sessions API and confirmed in their Agent session examples.templates/agno/agno_persistent/runagent.config.json (2)
14-25: Entrypoints correctly reference agent functions.The two entrypoints properly map to
agent_print_responseandagent_print_response_streamfunctions inagent.py, matching the non-streaming and streaming patterns.
32-32:persistent_folderscorrectly configured.The
simifolder is properly listed, matching the SQLite database path"simi/agents.db"inagent.py.runagent-dart/lib/src/client/runagent_client.dart (4)
18-31: Clean addition of persistent memory fields to client.The
userIdandpersistentMemoryfields are properly declared with appropriate types and defaults. The private constructor correctly initializes these fields.
117-118: Configuration values properly forwarded.The
createfactory correctly extractsuserIdandpersistentMemoryfrom the config, with a sensible default offalseforpersistentMemorywhen not specified.
269-276: REST client call correctly includes new parameters.The
runAgentcall properly forwardsuserIdandpersistentMemoryto enable persistent memory on the server side.
375-382: WebSocket streaming call correctly includes new parameters.The
runStreamcall properly forwardsuserIdandpersistentMemory, maintaining parity with the REST path.examples/journalist_agent/dart_sdk/lib/main.dart (1)
8-8: Agent ID and log message update look goodThe new
agentIdand simplified log line are clear and consistent with the described config change. No functional issues from this diff.Also applies to: 14-14
runagent-rust/runagent/src/blocking.rs (1)
147-155: Blocking client accessors cleanly mirror async clientThe new
user_idandpersistent_memoryaccessors are straightforward delegations to the inner async client and follow the same pattern asagent_id,entrypoint_tag, andextra_params. This keeps the blocking API in sync with the async one without adding complexity.runagent/sdk/rest_client.py (1)
1507-1512: LGTM!The conditional logic correctly adds
user_idandpersistent_memoryto the request payload only when provided. This aligns with the cross-language API surface described in the PR.test/test_lightrag.py (2)
14-24: LGTM!The test properly clears old data before starting fresh. The hardcoded test directory path (
prova/test_rag_storage) makes it clear this is test data, and the logging is informative.
89-94: LGTM!Good practice to validate required environment variables before execution with a clear error message and usage instructions.
runagent/cli/commands/run_stream.py (2)
65-75: LGTM!CLI options are well-documented with clear help text that references the SDK implementation. The flag default for
--persistent-memoryis appropriate.
191-199: LGTM!The new parameters are correctly propagated to
RunAgentClient, maintaining backward compatibility while enabling persistent memory features for streaming agents.runagent-rust/runagent/src/client/rest_client.rs (1)
187-218: LGTM!The implementation correctly mirrors the Python SDK pattern for adding persistent storage parameters. The use of
Option<&str>foruser_idis idiomatic Rust, and the conditional insertion logic usingas_object_mut()is appropriate.runagent/sdk/sdk.py (2)
345-351: LGTM!The validation correctly enforces that
user_idmust be provided whenpersistent_memory=True. This is essential for proper data isolation in multi-tenant scenarios and prevents potential data leakage.Note: The static analysis hint about the long message string is a minor style preference and doesn't affect functionality.
354-384: LGTM!The enhanced error handling for local agents is a valuable improvement. It provides actionable diagnostic information by checking deployment status, source existence, and agent state, which significantly improves developer experience when debugging local agent issues.
test_scripts/dart/test_lightrag/lib/main.dart (2)
35-54: LGTM!The
queryRagfunction correctly configures the RunAgent client with persistent memory parameters and provides a sensible default for the query mode.
56-85: LGTM!The main function has appropriate error handling for a CLI test script, with specific handling for
RunAgentErrorthat extracts and displays suggestions, and a fallback for unexpected errors. The exit codes are correct for error conditions.runagent/cli/commands/run.py (2)
67-77: LGTM!CLI options are well-documented and consistent with the streaming command implementation. The help text appropriately references the SDK for detailed documentation.
224-232: LGTM!The new parameters are correctly passed to
RunAgentClientwhile maintaining backward compatibility. The implementation is consistent with the streaming command.test_scripts/python/client_test_lightrag.py (1)
27-38: Ingestion error not propagated; consider handling exceptions.If
ingest_client.run()fails, the exception will propagate uncaught. If silent failure is intentional, wrap in try-except; otherwise, the current behavior is acceptable for a test script.runagent-rust/runagent/src/client/socket_client.rs (2)
100-113: Payload insertion logic is correct and defensive.The conditional insertion of
user_idandpersistent_memorymatches the Python SDK behavior. Theas_object_mut()pattern is safe since the JSON value is guaranteed to be an object from thejson!macro above.
76-77: Type difference betweenRunAgentClientConfigandrun_streamis intentional and properly handled.The method takes
persistent_memory: boolwhileRunAgentClientConfigusesOption<bool>. This is a deliberate design: the config allows callers to leave it unset (None), and the conversion to a concreteboolhappens at SocketClient initialization via.unwrap_or(false). Callers ofrun_streamdo not need to unwrap—the adapter layer handles this transparently.runagent/sdk/socket_client.py (4)
61-61: Signature extended correctly with new parameters.The async method now accepts
user_idandpersistent_memorywith sensible defaults. The parameter order (afterentrypoint_tag, before**input_kwargs) ensures backward compatibility.
95-99: Payload augmentation is correct.The conditional insertion of
user_id(when not None) andpersistent_memory(when truthy) matches the expected server contract and aligns with the Rust implementation.
159-159: Sync method signature mirrors async correctly.Parameter additions are consistent between
run_streamandrun_stream_async, maintaining API symmetry.
197-201: Sync path payload logic duplicates async path.The logic is identical to lines 95-99. This duplication is acceptable given the different async/sync implementations, but if this pattern expands, consider extracting a helper to build the common request payload.
runagent/client/client.py (5)
35-37: Persistent storage settings stored correctly.The new instance variables
user_idandpersistent_memoryare properly initialized and documented.
89-94: Persistent storage parameters correctly forwarded to REST client.The
user_idandpersistent_memoryvalues are properly passed through torest_client.run_agent().
112-115: Direct dict handling added for response payload.The new branch correctly handles cases where
data_fieldis a dict that should be treated as the actual response. The ordering of checks (afterresult_dataand before fallback) is appropriate.
127-137: Fallback deserialization with broad exception catching is acceptable here.While static analysis flags broad
Exceptioncatches (BLE001), this is a deliberate graceful degradation pattern. The fallback chain (structured → direct → raw) ensures robustness against various response formats. Logging at debug level is appropriate.
159-174: Streaming path correctly updated with persistent storage parameters.The
run_streammethod properly forwardsuser_idandpersistent_memorytosocket_client.run_stream(), maintaining consistency with the non-streaming path.examples/agno_persistent/agent.py (5)
12-12: Module-level database singleton is appropriate for this example.The single
SqliteDbinstance at module level provides shared session storage. The comment about automatic path mapping (rad→/persistent/rad) is helpful for understanding serverless behavior.
87-89: Empty string fallback for missing prompt may cause unexpected agent behavior.When both
promptandkwargs['message']are missing,promptbecomes an empty string. Consider raising an error or using a more explicit default:if prompt is None: prompt = kwargs.get('message') if prompt is None: raise ValueError("Either 'prompt' or 'message' keyword argument is required")Alternatively, if empty prompts are valid for your use case, this is acceptable.
97-123: Response extraction handles multiple formats robustly.The cascading checks for
.content,.messages,.text, and fallback tostr()provide good compatibility with different response object types from the agent.
153-158: Streaming implementation with metadata yields is well-structured.The pattern of yielding
session_infofirst, then content chunks, thensession_endprovides clear stream semantics for clients. Thehasattrcheck handles different chunk types gracefully.
40-45: The code's assumption is correct—SqliteDb.get_sessions()returns sessions sorted bycreated_atin descending order (newest first), soexisting_sessions[0]reliably retrieves the latest session. No changes needed.examples/lightrag_persistent/agent.py (2)
1-11: LGTM!Imports and module setup are appropriate for a LightRAG example.
13-26: LGTM!The RAG instance initialization is clean. Storage and pipeline status are properly initialized before returning.
runagent-rust/runagent/src/client/runagent_client.rs (7)
26-30: LGTM!Field design is appropriate:
user_idis optional whilepersistent_memorydefaults tofalse, maintaining backward compatibility. The comments referencing Python SDK parity are helpful.
98-102: LGTM!Config fields are correctly typed as
Optionto support the builder pattern while allowing defaults.
177-189: LGTM!Builder methods follow the established pattern in this file and are idiomatic Rust.
316-318: LGTM!Config values are correctly consumed with
unwrap_or(false)providing a sensible default forpersistent_memory.
547-557: LGTM!Streaming path correctly mirrors the REST path, passing the same parameters for consistent behavior.
589-598: LGTM!Getter methods return appropriate types and match the blocking wrapper signatures shown in
blocking.rs.
395-405: Code looks good—as_deref()is the correct idiomatic choice for convertingOption<String>toOption<&str>, and all parameters match theRestClient::run_agentsignature.
| lightrag_agent/ | ||
| ├── agent.py # Main agent implementation | ||
| ├── requirements.txt # Python dependencies | ||
| ├── runagent.config.json # RunAgent configuration | ||
| ├── test_sdk.py # SDK test script | ||
| └── README.md # This file |
There was a problem hiding this comment.
Tighten naming and path consistency in the docs
A few small inconsistencies that may confuse users trying to follow the example:
- The tree shows a folder
lightrag_agent/, while the actual example path in the repo isexamples/lightrag_persistent/. Consider aligning the name or explicitly stating this is a logical project layout. - “Persistent Storage” mentions
rad/rag_storage/, while the response examples use"working_dir": "rad/rag_storage"vs"working_dir": "rag_storage". It would help to clarify whetherworking_diris expected to be a full path (rad/rag_storage) or a relative folder name (rag_storage) and keep it consistent across examples.
These are documentation-only tweaks but will make the README easier to follow.
Also applies to: 107-109, 121-128, 139-147
| @@ -1,4 +1,5 @@ | |||
| ag2 | |||
| autogen==0.10.1 | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for ag2 imports in the examples/trip_planner directory
echo "=== Searching for ag2 imports ==="
rg -n "import ag2|from ag2" examples/trip_planner/ || echo "No ag2 imports found"
# Search for autogen imports in the examples/trip_planner directory
echo -e "\n=== Searching for autogen imports ==="
rg -n "import autogen|from autogen" examples/trip_planner/ || echo "No autogen imports found"
# Check full requirements.txt context
echo -e "\n=== Full requirements.txt content ==="
cat -n examples/trip_planner/agent/requirements.txt
# Check if autogen==0.10.1 exists on PyPI
echo -e "\n=== Checking autogen version on PyPI ==="
curl -s https://pypi.org/pypi/autogen/json | jq '.releases | keys | sort' | grep -A2 -B2 "0.10.1" || echo "Checking specific version..."
curl -s https://pypi.org/pypi/autogen/0.10.1/json 2>/dev/null | jq '.info | {version, requires_python}' || echo "Version 0.10.1 may not exist"Repository: runagent-dev/runagent
Length of output: 641
Remove ag2[openai] and reconcile autogen dependency specification.
The codebase has been correctly migrated to use autogen imports (confirmed in trip_agent.py), but requirements.txt contains an inconsistency: line 5 still references ag2[openai] instead of autogen[openai]. Additionally, line 4 explicitly pins openai, while line 5 pulls the same package indirectly via ag2[openai], creating redundant dependencies.
Change line 5 from ag2[openai] to autogen[openai] to match the actual package being used, or remove the extra dependency if autogen==0.10.1 already satisfies the openai requirement through its own dependencies.
🤖 Prompt for AI Agents
In examples/trip_planner/agent/requirements.txt around lines 1-5, replace the
outdated ag2[openai] entry (line 5) to match the code's autogen usage: either
change ag2[openai] to autogen[openai] or remove the ag2[openai] line entirely if
autogen==0.10.1 already brings in openai; also remove the explicit openai pin on
line 4 if you choose autogen[openai] to avoid redundant pins, ensuring the
requirements reflect only the actual package names and avoid duplicate openai
installs.
| "template_source": { | ||
| "repo_url": "https://github.com/runagent-dev/runagent.git", | ||
| "author": "runagent-cli", | ||
| "path": "/home/azureuser/runagent/examples/trip_planner/agent" | ||
| }, |
There was a problem hiding this comment.
Remove absolute path from template_source configuration.
Line 11 contains an absolute path /home/azureuser/runagent/examples/trip_planner/agent that is environment-specific and will not work across different machines or CI/CD environments. This should be either a relative path or use environment variables.
Apply this diff to use a relative path:
"template_source": {
"repo_url": "https://github.com/runagent-dev/runagent.git",
"author": "runagent-cli",
- "path": "/home/azureuser/runagent/examples/trip_planner/agent"
+ "path": "examples/trip_planner/agent"
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "template_source": { | |
| "repo_url": "https://github.com/runagent-dev/runagent.git", | |
| "author": "runagent-cli", | |
| "path": "/home/azureuser/runagent/examples/trip_planner/agent" | |
| }, | |
| "template_source": { | |
| "repo_url": "https://github.com/runagent-dev/runagent.git", | |
| "author": "runagent-cli", | |
| "path": "examples/trip_planner/agent" | |
| }, |
🤖 Prompt for AI Agents
In examples/trip_planner/agent/runagent.config.json around lines 8 to 12, the
template_source.path currently uses an absolute, environment-specific path
(/home/azureuser/runagent/examples/trip_planner/agent); change it to a portable
location by replacing the absolute path with a relative path (e.g.,
"../examples/trip_planner/agent" relative to the repo root) or reference an
environment variable (e.g., "${TEMPLATE_PATH}") and update any docs or startup
scripts to set that variable.
| # Single SQLite DB for all agents/sessions | ||
| # Note: The backend automatically maps "rad" folder to /persistent/rad | ||
| # So we can use relative path "rad/agents.db" and it will persist across VM restarts | ||
| db = SqliteDb(db_file="simi/agents.db") |
There was a problem hiding this comment.
Stale comment: mentions "rad" folder but code uses "simi".
The comment at lines 10-11 references "rad" folder mapping, but the actual path is "simi/agents.db". Update the comment to reflect the actual folder name or correct the path.
# Single SQLite DB for all agents/sessions
-# Note: The backend automatically maps "rad" folder to /persistent/rad
-# So we can use relative path "rad/agents.db" and it will persist across VM restarts
+# Note: The backend automatically maps "simi" folder to /persistent/simi
+# So we can use relative path "simi/agents.db" and it will persist across VM restarts
db = SqliteDb(db_file="simi/agents.db")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Single SQLite DB for all agents/sessions | |
| # Note: The backend automatically maps "rad" folder to /persistent/rad | |
| # So we can use relative path "rad/agents.db" and it will persist across VM restarts | |
| db = SqliteDb(db_file="simi/agents.db") | |
| # Single SQLite DB for all agents/sessions | |
| # Note: The backend automatically maps "simi" folder to /persistent/simi | |
| # So we can use relative path "simi/agents.db" and it will persist across VM restarts | |
| db = SqliteDb(db_file="simi/agents.db") |
🤖 Prompt for AI Agents
In templates/agno/agno_persistent/agent.py around lines 9 to 12, the comment
refers to a "rad" folder mapping while the code instantiates the DB with
"simi/agents.db"; update the comment to match the actual directory name (simi)
or change the db_file to "rad/agents.db" so comment and code are consistent.
Make a single-source change: either edit the comment to mention the "simi"
folder mapping and persistence, or update the db_file argument to use
"rad/agents.db" if "rad" is the intended persistent path.
| { | ||
| "roots": [ | ||
| "test_lightrag" | ||
| ], | ||
| "packages": [ | ||
| { | ||
| "name": "test_lightrag", | ||
| "version": "0.1.0", | ||
| "dependencies": [ | ||
| "runagent" | ||
| ], | ||
| "devDependencies": [] | ||
| }, | ||
| { | ||
| "name": "runagent", | ||
| "version": "0.1.41", | ||
| "dependencies": [ | ||
| "http", | ||
| "web_socket_channel" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "web_socket_channel", | ||
| "version": "2.4.5", | ||
| "dependencies": [ | ||
| "async", | ||
| "crypto", | ||
| "stream_channel", | ||
| "web" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "http", | ||
| "version": "1.6.0", | ||
| "dependencies": [ | ||
| "async", | ||
| "http_parser", | ||
| "meta", | ||
| "web" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "web", | ||
| "version": "0.5.1", | ||
| "dependencies": [] | ||
| }, | ||
| { | ||
| "name": "stream_channel", | ||
| "version": "2.1.4", | ||
| "dependencies": [ | ||
| "async" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "crypto", | ||
| "version": "3.0.7", | ||
| "dependencies": [ | ||
| "typed_data" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "async", | ||
| "version": "2.13.0", | ||
| "dependencies": [ | ||
| "collection", | ||
| "meta" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "meta", | ||
| "version": "1.17.0", | ||
| "dependencies": [] | ||
| }, | ||
| { | ||
| "name": "http_parser", | ||
| "version": "4.1.2", | ||
| "dependencies": [ | ||
| "collection", | ||
| "source_span", | ||
| "string_scanner", | ||
| "typed_data" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "typed_data", | ||
| "version": "1.4.0", | ||
| "dependencies": [ | ||
| "collection" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "collection", | ||
| "version": "1.19.1", | ||
| "dependencies": [] | ||
| }, | ||
| { | ||
| "name": "string_scanner", | ||
| "version": "1.4.1", | ||
| "dependencies": [ | ||
| "source_span" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "source_span", | ||
| "version": "1.10.1", | ||
| "dependencies": [ | ||
| "collection", | ||
| "path", | ||
| "term_glyph" | ||
| ] | ||
| }, | ||
| { | ||
| "name": "term_glyph", | ||
| "version": "1.2.2", | ||
| "dependencies": [] | ||
| }, | ||
| { | ||
| "name": "path", | ||
| "version": "1.9.1", | ||
| "dependencies": [] | ||
| } | ||
| ], | ||
| "configVersion": 1 | ||
| } No newline at end of file |
There was a problem hiding this comment.
Generated file should not be committed to version control.
Files in .dart_tool/ are auto-generated by Dart's tooling (via dart pub get, etc.) and should not be committed to the repository. These files are:
- Regenerated automatically on each developer's machine
- Prone to merge conflicts and diff noise
- Not meant for version control
Add .dart_tool/ to .gitignore if it isn't already present, and remove this file from the PR. Developers will regenerate it automatically when they run dart pub get.
🤖 Prompt for AI Agents
In test_scripts/dart/test_lightrag/.dart_tool/package_graph.json lines 1-124:
this is a generated file that should not be committed; remove it from the PR and
ensure .dart_tool/ is ignored. Delete the file from version control (e.g.,
remove it from the commit or run git rm --cached) and add or confirm an entry
for .dart_tool/ in the repository .gitignore so generated Dart tooling files are
not tracked going forward.
| dependencies: | ||
| runagent: | ||
| path: /home/azureuser/runagent/runagent-dart | ||
|
|
There was a problem hiding this comment.
Avoid hardcoded absolute path for local runagent dependency
Using /home/azureuser/runagent/runagent-dart ties this test setup to a single machine and will fail on other dev/CI environments. Please switch to a repo‑relative path (e.g., ../runagent-dart or similar, depending on your layout).
dependencies:
runagent:
- path: /home/azureuser/runagent/runagent-dart
+ path: ../runagent-dart # adjust to the correct relative path in this repo📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| dependencies: | |
| runagent: | |
| path: /home/azureuser/runagent/runagent-dart | |
| dependencies: | |
| runagent: | |
| path: ../runagent-dart # adjust to the correct relative path in this repo |
🤖 Prompt for AI Agents
In test_scripts/dart/test_lightrag/pubspec.yaml around lines 8 to 11, the
dependency path for runagent is an absolute machine-specific path
(/home/azureuser/runagent/runagent-dart); change it to a repo-relative path (for
example ../runagent-dart or ../runagent/runagent-dart depending on the
repository layout) so the test can run on other dev/CI machines, update the path
accordingly in pubspec.yaml, and verify the referenced directory exists relative
to this test package and adjust CI job workspace paths if necessary.
| # Create client with persistent storage settings | ||
| # user_id and persistent_memory are set at client level for persistent storage | ||
| ra = RunAgentClient( | ||
| agent_id="c778c025-4c9f-4466-886e-14845efe664b", | ||
| entrypoint_tag="agno_print_response", | ||
| local=False, | ||
| user_id="prova", # User ID for persistent storage (VM-level) | ||
| persistent_memory=True # Enable persistent storage | ||
| ) |
There was a problem hiding this comment.
Align new_session usage with the explanatory comment
The active test block is labeled:
# First message - creating a new session
but the call is:
result = ra.run(
...,
session_id="f927c786-87c1-45c4-a201-aaa1711b8f53",
new_session=False
)If this is truly the first message of a new session, you’d typically either:
- Set
new_session=Trueand let the agent create a freshsession_id, or - Keep
new_session=Falsebut adjust the comment to reflect that you’re resuming an existing session by ID.
Clarifying this will make the example less confusing for anyone copying it as a reference.
Also applies to: 49-56, 58-60
🤖 Prompt for AI Agents
In test_scripts/python/client_test_agno_persistent.py around lines 39-47 (and
similarly for blocks at 49-56 and 58-60), the comment states "First message -
creating a new session" while the call passes session_id and new_session=False;
either update the code to actually create a new session by setting
new_session=True and omitting a fixed session_id (or generate a fresh one) or
keep new_session=False and change the comment to indicate this is resuming an
existing session by ID; make the same consistent change in the other two blocks
so comments and parameters align.
| [dependencies] | ||
| # RunAgent Rust SDK from local path | ||
| runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" } | ||
|
|
||
| # Required dependencies | ||
| tokio = { version = "1.0", features = ["full"] } | ||
| serde_json = "1.0" | ||
| anyhow = "1.0" | ||
| futures = "0.3" |
There was a problem hiding this comment.
Avoid absolute path for local runagent dependency.
Using /home/azureuser/... makes this test crate non-portable outside your machine (including CI). Prefer a relative path from this manifest to runagent-rust/runagent.
For example, from test_scripts/rust/test_lightrag to runagent-rust/runagent:
-runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" }
+runagent = { path = "../../../runagent-rust/runagent" }Adjust the relative path if the directory layout differs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [dependencies] | |
| # RunAgent Rust SDK from local path | |
| runagent = { path = "/home/azureuser/runagent/runagent-rust/runagent" } | |
| # Required dependencies | |
| tokio = { version = "1.0", features = ["full"] } | |
| serde_json = "1.0" | |
| anyhow = "1.0" | |
| futures = "0.3" | |
| [dependencies] | |
| # RunAgent Rust SDK from local path | |
| runagent = { path = "../../../runagent-rust/runagent" } | |
| # Required dependencies | |
| tokio = { version = "1.0", features = ["full"] } | |
| serde_json = "1.0" | |
| anyhow = "1.0" | |
| futures = "0.3" |
🤖 Prompt for AI Agents
In test_scripts/rust/test_lightrag/Cargo.toml lines 6-14, the runagent
dependency uses an absolute path (/home/azureuser/...), making the crate
non-portable; replace that absolute path with a relative path from
test_scripts/rust/test_lightrag to the runagent-rust/runagent directory (e.g.
adjust to something like ../../runagent-rust/runagent depending on your repo
layout), update the path entry in Cargo.toml, and verify by running cargo
metadata or cargo build to ensure Cargo resolves the local dependency correctly.
| #[tokio::main] | ||
| async fn main() -> runagent::RunAgentResult<()> { | ||
| // Ingest client (persistent memory enabled) | ||
| let ingest_client = RunAgentClient::new(RunAgentClientConfig { | ||
| agent_id: AGENT_ID.to_string(), | ||
| entrypoint_tag: "ingest_text".to_string(), | ||
| local: Some(LOCAL_MODE), | ||
| host: None, | ||
| port: None, | ||
| api_key: None, | ||
| base_url: None, | ||
| extra_params: None, | ||
| enable_registry: None, | ||
| user_id: Some(USER_ID.to_string()), | ||
| persistent_memory: Some(true), | ||
| }) | ||
| .await?; | ||
|
|
||
| // Query client (same user_id + persistent_memory) | ||
| let query_client = RunAgentClient::new(RunAgentClientConfig { | ||
| agent_id: AGENT_ID.to_string(), | ||
| entrypoint_tag: "query_rag".to_string(), | ||
| local: Some(LOCAL_MODE), | ||
| host: None, | ||
| port: None, | ||
| api_key: None, | ||
| base_url: None, | ||
| extra_params: None, | ||
| enable_registry: None, | ||
| user_id: Some(USER_ID.to_string()), | ||
| persistent_memory: Some(true), | ||
| }) | ||
| .await?; | ||
|
|
||
| // Example query (same as Python test) | ||
| let question = "population prediction"; | ||
| println!("============================================================"); | ||
| println!("STEP: Query RAG"); | ||
| println!("============================================================"); | ||
|
|
||
| let result = query_client | ||
| .run(&[ | ||
| ("query", json!(question)), | ||
| // mode is optional; default is handled server-side but we match Python example | ||
| ("mode", json!("hybrid")), | ||
| ]) | ||
| .await?; | ||
|
|
||
| println!("Result: {}", result); | ||
| Ok(()) |
There was a problem hiding this comment.
Clarify or remove unused ingest_client to match the intended LightRAG flow.
You construct an “Ingest client (persistent memory enabled)” but never use ingest_client afterward; only query_client.run(...) is called. This both produces an unused-variable warning and likely diverges from the Python LightRAG test flow that actually performs an ingest step.
Consider either:
- Wiring in an explicit ingest step, e.g. calling
ingest_client.run(&[("text", json!(...))])before the query, or - If ingest is intentionally done elsewhere, remove the unused client (and its comment) to avoid confusion:
- // Ingest client (persistent memory enabled)
- let ingest_client = RunAgentClient::new(RunAgentClientConfig {
- agent_id: AGENT_ID.to_string(),
- entrypoint_tag: "ingest_text".to_string(),
- local: Some(LOCAL_MODE),
- host: None,
- port: None,
- api_key: None,
- base_url: None,
- extra_params: None,
- enable_registry: None,
- user_id: Some(USER_ID.to_string()),
- persistent_memory: Some(true),
- })
- .await?;
-
- // Query client (same user_id + persistent_memory)
+ // Query client (same user_id + persistent_memory)The persistent memory configuration on query_client itself looks correct.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #[tokio::main] | |
| async fn main() -> runagent::RunAgentResult<()> { | |
| // Ingest client (persistent memory enabled) | |
| let ingest_client = RunAgentClient::new(RunAgentClientConfig { | |
| agent_id: AGENT_ID.to_string(), | |
| entrypoint_tag: "ingest_text".to_string(), | |
| local: Some(LOCAL_MODE), | |
| host: None, | |
| port: None, | |
| api_key: None, | |
| base_url: None, | |
| extra_params: None, | |
| enable_registry: None, | |
| user_id: Some(USER_ID.to_string()), | |
| persistent_memory: Some(true), | |
| }) | |
| .await?; | |
| // Query client (same user_id + persistent_memory) | |
| let query_client = RunAgentClient::new(RunAgentClientConfig { | |
| agent_id: AGENT_ID.to_string(), | |
| entrypoint_tag: "query_rag".to_string(), | |
| local: Some(LOCAL_MODE), | |
| host: None, | |
| port: None, | |
| api_key: None, | |
| base_url: None, | |
| extra_params: None, | |
| enable_registry: None, | |
| user_id: Some(USER_ID.to_string()), | |
| persistent_memory: Some(true), | |
| }) | |
| .await?; | |
| // Example query (same as Python test) | |
| let question = "population prediction"; | |
| println!("============================================================"); | |
| println!("STEP: Query RAG"); | |
| println!("============================================================"); | |
| let result = query_client | |
| .run(&[ | |
| ("query", json!(question)), | |
| // mode is optional; default is handled server-side but we match Python example | |
| ("mode", json!("hybrid")), | |
| ]) | |
| .await?; | |
| println!("Result: {}", result); | |
| Ok(()) | |
| #[tokio::main] | |
| async fn main() -> runagent::RunAgentResult<()> { | |
| // Query client (same user_id + persistent_memory) | |
| let query_client = RunAgentClient::new(RunAgentClientConfig { | |
| agent_id: AGENT_ID.to_string(), | |
| entrypoint_tag: "query_rag".to_string(), | |
| local: Some(LOCAL_MODE), | |
| host: None, | |
| port: None, | |
| api_key: None, | |
| base_url: None, | |
| extra_params: None, | |
| enable_registry: None, | |
| user_id: Some(USER_ID.to_string()), | |
| persistent_memory: Some(true), | |
| }) | |
| .await?; | |
| // Example query (same as Python test) | |
| let question = "population prediction"; | |
| println!("============================================================"); | |
| println!("STEP: Query RAG"); | |
| println!("============================================================"); | |
| let result = query_client | |
| .run(&[ | |
| ("query", json!(question)), | |
| // mode is optional; default is handled server-side but we match Python example | |
| ("mode", json!("hybrid")), | |
| ]) | |
| .await?; | |
| println!("Result: {}", result); | |
| Ok(()) | |
| } |
Add Persistent Memory Support Across All SDKs
🎯 Overview
This PR introduces Persistent Memory support across all RunAgent SDKs (Python, Dart, and Rust), enabling agents to maintain context and state across executions. This revolutionary feature breaks the traditional stateless serverless limitation, allowing agents to remember user preferences, conversation history, and workflow state.
✨ Features Added
Persistent Memory System
user_id: User identifier for memory isolation and multi-tenant supportpersistent_memory: Boolean flag to enable persistent storage across agent executions📦 Changes by SDK
Python SDK (
runagent)CLI Updates
--user-idoption torunagent runcommand--persistent-memoryflag torunagent runcommand--user-idoption torunagent run-streamcommand--persistent-memoryflag torunagent run-streamcommandClient Updates
RunAgentClientnow acceptsuser_idandpersistent_memoryparametersExample:
runagent run \ --id agent-id \ --tag entrypoint \ --user-id user123 \ --persistent-memory \ --query="Hello"Dart SDK (
runagent-dart)Configuration Updates
userIdfield toRunAgentClientConfigpersistentMemoryfield toRunAgentClientConfigRunAgentClientto store and forward these parametersRestClient.runAgent()to includeuserIdandpersistentMemoryin request payloadSocketClient.runStream()to includeuserIdandpersistentMemoryin WebSocket messagesExample:
Rust SDK (
runagent-rust)Configuration Updates
user_id: Option<String>toRunAgentClientConfigpersistent_memory: Option<bool>toRunAgentClientConfig.with_user_id()and.with_persistent_memory()RunAgentClientstruct to store these valuesRestClient::run_agent()to accept and forwarduser_idandpersistent_memorySocketClient::run_stream()to accept and forwarduser_idandpersistent_memoryuser_id()andpersistent_memory()toRunAgentClientExample:
🧪 Test Scripts
Rust Test (
test_scripts/rust/test_lightrag)user_idandpersistent_memoryusageDart Test (
test_scripts/dart/test_lightrag)userIdandpersistentMemoryusageingestFromFile()andqueryRag()functions📚 Documentation Updates
Main README (
README.md)Rust SDK README (
runagent-rust/runagent/README.md)user_idandpersistent_memoryto configuration overview table.with_user_id()and.with_persistent_memory()to API Reference🔄 Version Updates
0.1.42→0.1.430.1.41→0.1.42🎯 Use Cases Enabled
This feature enables:
🔒 Security & Isolation
user_idhas isolated memory space✅ Testing
📋 Checklist
🚀 Ready for Publishing
pub.dev(v0.1.43)crates.io(v0.1.42)Breaking Changes: None - All new parameters are optional and backward compatible.
Migration Guide: No migration needed. Existing code continues to work. To enable persistent memory, simply add
user_idandpersistent_memoryparameters to your client configuration.Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.