Skip to main content

atlas-agent-engine

Guide for extending Atlas Agent Engine templates and generated apps. Use this before editing templates/hello-world-agent, templates/insurance-agent, templates/chatbot-client, or any generated project with agent.yaml, agent_engine_sdk_langgraph, agent_engine_runner_shared, @app.tool, memory, guardrails, human review, or Atlas Agent Engine API streaming. Covers project layouts, template-specific files, tools, graph flow, memory, HITL, guardrails, testing, and deployment.

Informations de source

Dépôt
mongodb/agent-engine-examples
Dernière activité de la source
8 octobre 2026 à 05:04
Langue détectée de SKILL.md
anglais
Étoiles
3
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
atlas-agent-engine
description
Guide for extending Atlas Agent Engine templates and generated apps. Use this before editing templates/hello-world-agent, templates/insurance-agent, templates/chatbot-client, or any generated project with agent.yaml, agent_engine_sdk_langgraph, agent_engine_runner_shared, @app.tool, memory, guardrails, human review, or Atlas Agent Engine API streaming. Covers project layouts, template-specific files, tools, graph flow, memory, HITL, guardrails, testing, and deployment.
# Atlas Agent Engine Agent Template Guide Use this skill when building from, maintaining, or extending an Atlas Agent Engine sample template or a project generated from one. For setup and quickstart, still read the template's `README.md` first. ## Start Here Identify which template you are editing before changing files: | Template | Type | What it demonstrates | Main files | |---|---|---|---| | `templates/hello-world-agent/` | Python Agent Engine agent | Minimal LangGraph assistant, date tool, optional profile memory, provider selection | `src/hello_world_agent/main.py`, `llm.py`, `tools.py`, `system_message.py`, `state.py` | | `templates/insurance-agent/` | Python Agent Engine agent | Quotes, policies, claims, MongoDB storage, memory, guardrails, human review | `src/insurance_agent/main.py`, `policy_store.py` | | `templates/chatbot-client/` | Next.js client app | Chat UI that streams to an existing Atlas Agent Engine workspace | `app/api/chat/route.ts`, `app/page.tsx`, `components/chat/*` | The `agents/` directory contains fuller reference apps. Use those as examples, but keep `templates/` clean, scaffold-friendly, and small enough for `agentengine create`. ## Common Rules - Preserve the template's current layout. Do not invent `graph.py`, `prompts.py`, `store.py`, or one-file-per-tool modules unless the template already uses that pattern or the user explicitly asks for a refactor. - Keep generated apps standalone. A copied template should work from its own root with its own `agent.yaml`, `pyproject.toml` or `package.json`, environment example, and README. - Keep secrets in `.env` or `.env.local`; never commit filled secret files. `env.example` and `.env.example` should contain names and safe sample values only. - Let `agent.yaml` own app identity, entrypoint, and runtime feature flags. Provider and model selection belongs in the app's own LLM module, not `agent.yaml`. Do not move feature flags into `.env`. Keep `agent.yaml` portable: local-development-only settings (service ports, the local-vs-remote MongoDB toggle) belong in `dev.yaml` next to it. - Never edit `.agentengine/`; it is generated by the `agentengine` CLI and can be overwritten. - Use existing helper surfaces from the SDK: `app.llm(...)`, `app.get_tools()`, `app.get_tool_schemas()`, `app.checkpointer()`, `app.memory`, and `app.validate_llm_response(...)`. - Keep template code easy to read. Avoid chains of tiny single-use helpers unless they create a real boundary. ## Runtime Model `agentengine dev up` starts the local platform processes needed by a Python agent: ```text User message -> Orchestration Engine (OE) -> Agent Sandbox runs the LangGraph graph -> LLM decides whether to call tools -> Tool Sandbox runs @app.tool(is_local=False) tools -> Agent Sandbox runs @app.tool(is_local=True) tools -> app.validate_llm_response(...) applies guardrails when enabled -> OE records native LangGraph interrupts and resumes them by interrupt ID ``` The local Playground UI is exposed on the port configured in `dev.yaml` under `services.playground.port`, currently `3000` in the Python templates. ## Project Layouts ### Generated Python Agent The Python templates are intended to be copied into a new standalone project: ```text my-agent/ ├── agent.yaml ├── dev.yaml ├── env.example ├── pyproject.toml ├── pyrightconfig.json ├── README.md ├── .agents/skills/atlas-agent-engine/SKILL.md ├── .claude/skills/atlas-agent-engine/SKILL.md └── src/ └── my_agent/ ├── __init__.py ├── main.py └── ... ``` Run `agentengine dev up`, `agentengine init`, `agentengine build`, and `agentengine deploy` from the generated app root. ### This Examples Monorepo The examples repository root is a uv workspace and has a root `agent.yaml` with an `agents:` list. That monorepo shape is for maintaining examples; it is not required for a generated app. Templates are intentionally outside the root uv workspace. Validate them directly under `templates/`, not as root workspace members. ## Template File Map | Goal | Hello World | Insurance | Chatbot Client | |---|---|---|---| | App metadata and feature flags | `agent.yaml` | `agent.yaml` | `.env.example`, `README.md` | | LLM provider selection | `src/hello_world_agent/llm.py` | `src/insurance_agent/llm.py` | Existing deployed workspace, not local LLM code | | Persona and workflow rules | `src/hello_world_agent/system_message.py` | `SYSTEM_PROMPT` in `src/insurance_agent/main.py` | UI copy and request handling | | Tool registration | `src/hello_world_agent/tools.py` via `register(app)` | `@app.tool(...)` functions in `src/insurance_agent/main.py` | Not applicable | | Graph assembly | `build_agent()` in `main.py` | `build_agent()` in `main.py` | Not applicable | | State shape | `src/hello_world_agent/state.py` | `AgentState` in `main.py` | React component state | | App data storage | Optional memory only | `src/insurance_agent/policy_store.py` | Browser/client state only | | Platform API integration | SDK runtime | SDK runtime | `app/api/chat/route.ts` | ## `agent.yaml` For Python agents, `entrypoint` is a Python import path to the SDK `App` object. In the current src-layout templates, do not prefix the path with `src.`: ```yaml name: hello-world-agent entrypoint: hello_world_agent.main:app framework: langgraph features: durable_workflow: true memory: false guardrails: false ``` Rules: - `name` should be a lowercase app slug with hyphens. - `entrypoint` must point to the module and variable that expose `app`. - Provider and model are not part of `agent.yaml`. New CLI scaffolds contain one provider import, a direct constructor and `MODEL` in the LLM module. When changing providers, update the client and model; keep the shared `LLM_API_KEY` lookup. - Generated clients contain one supported provider or Azure recipe; manual setup contains a builder stub. Keep credentials in `.env` or project secrets and preserve send-time authentication injection so traces cannot serialize keys. - `features.memory: true` requires `VOYAGE_API_KEY`. - `features.guardrails: true` requires a guardrails service endpoint such as `GUARDRAILS_SERVER_URL` in templates that expose that setting. - `features.durable_workflow: true` lets the platform preserve and resume workflow state across runtime restarts. - Keep provider support accurate per template. `hello-world-agent` and `insurance-agent` both support Anthropic, Gemini, OpenAI, and xAI. - Keep `agent.yaml` portable across environments. Local-development-only settings (service ports, the local-vs-remote MongoDB toggle) live in `dev.yaml`, not `agent.yaml`. ## `dev.yaml` `dev.yaml` sits next to `agent.yaml` and holds settings that only apply when you run the agent locally with `agentengine dev up`: host port overrides for the local stack and whether to use a local MongoDB Atlas container or an external cluster. It is never read by build or deploy, so it has no effect on a platform deploy even if committed. The file is optional — omit it (or any field) to get the defaults: a local Atlas container on port 27017 and Docker-assigned host ports. ```yaml services: playground: port: 3000 # Pinned so the browser UI has a stable URL. # mongodb: # local: false # Use an external cluster; set MONGODB_URI in .env. ``` Valid service names: `oe`, `aer`, `tool`, `playground`, `memory-server`, `grpc`, `mongodb`. Every service takes a `port`; `mongodb` also takes `local` (set `local: false` plus `MONGODB_URI` in `.env` to use an external cluster). Consult the installed SDK documentation for the full schema. ## Python Dependencies Preserve each template's current dependency style unless the change truly requires a new package. Use `uv add <package>` inside a generated app when adding dependencies. In this repo's templates, edit `pyproject.toml` carefully and keep the agent-engine SDK packages pinned to an exact published version. ## Tools Use the existing tool registration style for the template. Hello World: ```python from datetime import datetime from zoneinfo import ZoneInfo def register(app: App) -> None: @app.tool(is_local=False) def get_current_date(timezone_name: str = "UTC") -> str: """Return today's date in ISO 8601 format for an IANA timezone.""" timezone = ZoneInfo(timezone_name) return json.dumps({"date": datetime.now(timezone).date().isoformat()}) ``` Insurance: ```python @app.tool(is_local=False) def lookup_policy(policy_number: str) -> str: """Look up an insurance policy by policy number.""" policy = policy_store.get_policy(policy_number) if policy: return json.dumps(policy, indent=2) return json.dumps({"error": f"No policy found: {policy_number}"}) ``` Rules: - Every tool must have a clear docstring because the LLM uses it to decide when to call the tool. - Return a string, normally `json.dumps(...)`, so the LLM receives structured content. - Use `app.get_current_user_id()` to scope user data. Never hardcode user IDs. - After adding or changing a tool, update the system prompt so the LLM knows when and how to use it. - Use `redact_fields=[...]` for sensitive tool arguments that should not appear in logs. - Prefer `is_local=False` for deterministic app tools, database reads/writes, and external APIs that should run in the isolated Tool Sandbox. - Use `is_local=True` when a tool must run in the Agent Sandbox process, especially human review suspension or runtime-local side effects. ## Human Review For durable LangGraph agents, place the review tool in the agent sandbox and call `interrupt()` with replay-stable payload content. Include a response schema when the Playground or API client should render and validate structured reviewer input: ```yaml sandboxes: agent: tools: - human_review tool: tools: [] ``` ```python import json from langgraph.types import interrupt REVIEW_RESPONSE_SCHEMA = { "type": "object", "required": ["decision"], "properties": { "decision": {"type": "string", "enum": ["approved", "denied"]}, "reviewer_notes": {"type": "string"}, }, "additionalProperties": False, } @app.tool() def human_review(claim_id: str, reason: str) -> str: """Request human review before resolving a claim.""" answer = interrupt( { "action": "review_claim", "task_id": f"REVIEW-{claim_id}", "claim_id": claim_id, "reason": reason, "response_schema": REVIEW_RESPONSE_SCHEMA, } ) if not isinstance(answer, dict): raise TypeError("human review resume value must be an object") return json.dumps(answer) ``` Build interrupt identity and payload fields from stable workflow inputs. Random IDs, timestamps, and fresh external reads inside the payload can change during replay. Continue a structured interrupt through the same session using the interrupt ID reported in `suspend_context.interrupts[].id`: ```json { "session_id": "existing-session-id", "resume_map": { "interrupt-id": { "decision": "approved", "reviewer_notes": "Verified supporting documents." } } } ``` For the insurance template, keep the prompt's post-review contract intact: after either an approved or denied review returns, call `resolve_claim` with the decision and reviewer notes, then notify the customer. ## Memory Memory is optional and scoped by `user_id`. Enable it with `features.memory: true` in `agent.yaml`. Memory return shapes differ by SDK revision: some return plain values (`build_context` a `str`, writes a `bool` or an id), others return typed results (`ContextResponse.formatted_context`, `Create*Result.acknowledged`). Whether a read accepts `visibility=` varies separately from the return shape, so check both against the revision your agent resolves — see [migrate-app-memory](../migrate-app-memory/SKILL.md) for the matrix. The snippets below read results defensively, which is what the examples in this repo do and what works on either surface. Note that a typed wrapper is truthy even when it carries no context, so unwrap before testing for content. Semantic memory: ```python user_id = app.get_current_user_id() result = app.memory.save_semantic( text="Customer prefers comprehensive coverage", label=f"{user_id}_coverage_preference", source="insurance_agent", metadata={"type": "customer_info", "info_key": "coverage_preference"}, user_id=user_id, ) if getattr(result, "acknowledged", result): ... # the write landed context = app.memory.build_context(query="coverage preference", user_id=user_id) memory_text = getattr(context, "formatted_context", context) memory_text = memory_text if isinstance(memory_text, str) else "" ``` Episodic memory: ```python episode = app.memory.save_episode( title="Policy created for customer", content="Customer purchased comprehensive auto policy.", summary="Policy created with comprehensive coverage.", participants=["Customer", "Agent"], user_id=user_id, ) if getattr(episode, "acknowledged", bool(episode)): episode_id = getattr(episode, "id", episode) ``` Taxonomic memory is used by the insurance template for domain knowledge like insurance terms and coverage options. When memory is disabled, tools should fail gracefully and explain that memory is not enabled. Enable memory with `features.memory: true` and `VOYAGE_API_KEY`. ## Guardrails `app.validate_llm_response(response)` is the application hook. The SDK treats it as active only when guardrails are enabled/configured. For templates with guardrail support: - Set `features.guardrails: true` in `agent.yaml`. - Set the matching guardrails endpoint in `.env`. - Keep validation close to the LLM response in the graph node, before returning the message to the user. ## Graph Changes Both Python templates use LangGraph and a `ToolNode` loop: ```python builder = StateGraph(AgentState) builder.add_node("agent", agent_node) builder.add_node("tools", ToolNode(tools)) builder.add_edge(START, "agent") builder.add_conditional_edges("agent", should_continue, {"tools": "tools", "end": END}) builder.add_edge("tools", "agent") graph = builder.compile(checkpointer=app.checkpointer()) ``` Rules: - Keep state JSON-serializable: strings, numbers, booleans, lists, dicts, datetimes, and LangChain message objects. - Do not put database clients, file handles, closures, thread objects, or other runtime resources in graph state. - Use `add_messages` for message history. - Keep the user-facing response rule explicit when tool results are not visible to the user. ## Chatbot Client Template `templates/chatbot-client` is not a Python agent and should not import `agent_engine_sdk_langgraph`. When editing it: - Use `pnpm`, not uv. - Preserve the Next.js/Vercel AI SDK streaming shape in `app/api/chat/route.ts`. - Keep workspace/API values in `.env.local`, copied from `.env.example`. - Preserve any existing Next.js version warning in the template: inspect local Next docs under `node_modules/next/dist/docs/` before changing framework APIs. ## Validation For Python template changes in this repo:
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub