A cognitive agent built on the Memory-Perception-Decision-Action (MPDA) architecture, wired through an MCP server (stdio transport) and the LLM Gateway V3.
HTTP (localhost:8101)
agent6.py ──────────────────────────────→ LLM Gateway V3
│ (Gemini / auto-route)
│
│ stdio (subprocess, JSON-RPC)
└──────────────────────────────────→ mcp_server.py
(spawned per run) (9 tools)
The Loop — each iteration executes four roles in fixed order:
| Role | File | LLM Call? | Responsibility |
|---|---|---|---|
| Memory | memory.py |
Only on remember() (write-time classification) |
Durable keyword-searchable store. read() is pure Python. |
| Perception | perception.py |
Yes — one call per iteration | Decomposes query into goals (iter 1). Updates done flags (iter 2+). Controls artifact attachment. |
| Decision | decision.py |
Yes — one call per iteration | Picks one action for the current open goal: tool call or answer. |
| Action | action.py |
No — pure dispatch | Executes MCP tool, stores large results as artifacts. |
Supporting stores:
state/memory.json— durable memory (persists across runs)state/artifacts/— content-addressable file store for large tool outputs
Typed contracts (schemas.py): Every boundary between roles is a Pydantic v2 model. MemoryItem, Observation, DecisionOutput, ActionResult, ToolCall, Goal, Artifact.
├── agent6.py # Orchestrator — the MPDA loop
├── schemas.py # Pydantic v2 contracts for all boundaries
├── memory.py # Memory layer (read/remember/record_outcome)
├── perception.py # Perception layer (goal decomposition + status)
├── decision.py # Decision layer (tool call or answer)
├── action.py # Action layer (pure MCP dispatch)
├── artifacts.py # Content-addressable artifact store
├── mcp_server.py # MCP server (9 tools, stdio transport)
├── prompts.py # Extracted prompts for evaluation
├── evaluate_prompt.py # Prompt evaluation against EAGv3 rubric
├── pyproject.toml # Dependencies (uv)
├── .env.example # Required environment variables
└── .gitignore
- Python 3.11+
uvpackage manager- LLM Gateway V3 running on
localhost:8101
# Clone and enter the project
cd W6
# Edit the .env file to update the tavily api key ,and llm gateway url
cp .env.example .env
# Install dependencies
uv sync
# Start LLM Gateway V3 in a separate terminal
cd ../llm_gatewayV3
uv run python main.py
# Keep running — agent connects to it over HTTPRemove-Item -Recurse -Force state/
Remove-Item -Recurse -Force sandbox/
New-Item -ItemType Directory stateuv run python agent6.pyQuery: Fetch https://en.wikipedia.org/wiki/Claude_Shannon and tell me his birth date, death date, and three key contributions to information theory. Answer: Claude Shannon's biographical details and contributions to information theory are as follows:
Birth Date: April 30, 1916
Death Date: February 24, 2001
Three Key Contributions to Information Theory:
1. Founding Information Theory: He authored the 1948 paper "A Mathematical Theory of Communication," which established the field of information theory and is considered a foundational blueprint for the digital era.
2. Introduction of the "Bit": He formally introduced the term "bit" as the fundamental unit of information.
3. Digital Circuit Foundations: Through his 1937 master's thesis, he demonstrated that Boolean algebra could be used to construct logical numerical relationships in electrical circuits, providing the theoretical basis for digital computing and digital circuits.
Query: Find 3 family-friendly things to do in Tokyo this weekend.
Check Saturday's weather forecast there and tell me which one
is most appropriate.
Answer: TSince Tokyo is currently in its "Tsuyu" (rainy season) in June, the weather this Saturday is likely to be warm (19–26°C/67–79°F), humid, and potentially rainy.
Given these conditions, here are three family-friendly activities in Tokyo and a recommendation: 1. Indoor Museum Hopping (e.g., Roppongi Art Triangle): Tokyo has world-class museums like the Mori Art Museum or the National Art Center. These are ideal for escaping the humidity and potential rain while keeping the family entertained.
2. Shopping and Entertainment Complexes: Large indoor complexes like Sunshine City in Ikebukuro offer aquariums, planetariums, and indoor theme parks (like Namjatown), providing a full day of activity regardless of the weather. 3. Hidden Jazz Bars or Cafes: For a more relaxed experience, exploring the atmospheric cafes or themed indoor venues in areas like Shinjuku or Shibuya allows you to enjoy the "Ghibli-esque" rainy aesthetic of the city from the comfort of a dry, cozy space.
Recommendation:
The most appropriate activity for this Saturday is visiting an indoor entertainment complex like Sunshine City. Because the rainy season in Tokyo is characterized by muggy, unpredictable showers, an indoor complex is the safest choice; it consolidates multiple family-friendly attractions (aquarium, shopping, dining, and games) in one location, ensuring your plans won't be disrupted by the weather.
Query
Run1: My mom's birthday is 15 May 2026. Remember that and give me
a calendar reminder for two weeks before and on the day.
Answer:
{
"ok": true,
"path": "moms_birthday.json",
"size_bytes": 126
} {
"ok": true,
"path": "reminder_2026_05_01.json",
"size_bytes": 80
} {
"ok": true,
"path": "reminder_2026_05_15.json",
"size_bytes": 80
}
Run 2: When is mom's birthday?
Answer: Mom's birthday is May 15, 2026.
Query: Search for 'Python asyncio best practices', read the top 3 results,
and give me a short numbered list of the advice they agree on.
Answer: Based on the provided documentation, here are the common best practices for Python asyncio:
1. Do Not Block the Event Loop: Avoid running long-running synchronous code (e.g.,time.sleep(), heavy CPU-bound tasks) directly in an async function, as this halts the event loop and causes lag. Use asyncio.sleep() for non-blocking delays.
2. Offload Blocking Operations: If you must use synchronous or blocking I/O code, offload it to a thread pool using loop.run_in_executor() to keep the event loop responsive.
3. Use Tasks for Concurrency: Instead of awaiting functions sequentially, use asyncio.create_task() or asyncio.gather() to schedule independent operations to run concurrently.
4. Maintain Task References: Always keep a reference to your tasks (e.g., by storing them in a collection or using Task Groups in Python 3.11+). If a task is not referenced, it may be garbage collected mid-execution.
5. Handle Cancellation Gracefully: When cancelling tasks, ensure you handle asyncio.CancelledError to perform necessary cleanup before the task terminates.
6. Use Async-Specific Synchronization: If you need to synchronize access to shared resources, use asyncio.Lock rather than threading.Lock to avoid blocking the event loop.
Run the prompt evaluation against the School of AI EAGv3 rubric:
uv run python evaluate_prompt.py