From a1ad227185210fdb19b1f8139ed3439adeb008e5 Mon Sep 17 00:00:00 2001 From: mich-elle-luna Date: Tue, 11 Aug 2026 14:15:01 -0700 Subject: [PATCH 1/4] Add Context Engine (Redis Iris) agent type to the AI agent builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a fourth agent type, "Context Engine Agent", whose memory is fully managed by the Redis Iris Context Engine instead of raw Redis. Each turn the agent searches long-term memory, loads recent session/working memory, calls the LLM with that context, and writes both turns back — long-term facts are promoted automatically by the managed service. - Python template uses the redis-agent-memory SDK (AgentMemory) - JavaScript template uses the agent-memory-client SDK (MemoryAPIClient) - Wires the type into agent-builder.js (CONFIG, icon, default name, chip), the agent-builder.html initial chips, and the agent-builder _index.md SDK calls verified against the published packages: the Python signatures were bound against the redis-agent-memory 0.2.1 wheel source and the JS calls against the agent-memory-client 0.3.1 type definitions. Co-Authored-By: Claude Opus 4.8 (1M context) --- content/develop/ai/agent-builder/_index.md | 3 +- layouts/shortcodes/agent-builder.html | 1 + .../agent-templates/javascript/iris_agent.js | 167 +++++++++++++++++ .../code/agent-templates/python/iris_agent.py | 173 ++++++++++++++++++ static/js/agent-builder.js | 14 +- 5 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 static/code/agent-templates/javascript/iris_agent.js create mode 100644 static/code/agent-templates/python/iris_agent.py diff --git a/content/develop/ai/agent-builder/_index.md b/content/develop/ai/agent-builder/_index.md index 3239c2fa03..69f6072b78 100644 --- a/content/develop/ai/agent-builder/_index.md +++ b/content/develop/ai/agent-builder/_index.md @@ -30,11 +30,12 @@ Redis powers these capabilities with fast, reliable data storage and retrieval t ## What you can build -Choose from three types of intelligent agents: +Choose from four types of intelligent agents: - **Recommendation engines**: Personalized product and content recommendations - **Conversational assistants**: Chatbots with memory and context awareness - **Knowledge assistants**: RAG agents that ingest documents, answer questions with citations, and use semantic caching +- **Context engine agents**: Conversational agents backed by the managed [Redis Iris Context Engine]({{< relref "/develop/ai/context-engine/agent-memory" >}}) — session and long-term memory with no vector index to build The agent builder will generate complete, working code examples for your chosen agent type. diff --git a/layouts/shortcodes/agent-builder.html b/layouts/shortcodes/agent-builder.html index 0fd72ee6c6..8e4629f12a 100644 --- a/layouts/shortcodes/agent-builder.html +++ b/layouts/shortcodes/agent-builder.html @@ -25,6 +25,7 @@

Build Your AI Agent🛍️ Recommendation Engine + diff --git a/static/code/agent-templates/javascript/iris_agent.js b/static/code/agent-templates/javascript/iris_agent.js new file mode 100644 index 0000000000..eb74f8660f --- /dev/null +++ b/static/code/agent-templates/javascript/iris_agent.js @@ -0,0 +1,167 @@ +/* + * Redis Context Engine Agent (Redis Iris — Agent Memory) + * + * A conversational agent whose memory is fully managed by the Redis Iris + * Context Engine. Instead of building your own vector index, embeddings, and + * session store, the agent calls the managed Agent Memory service through the + * official agent-memory-client: + * + * Features: + * - Working memory: the running conversation is stored per session + * - Long-term memory: the service extracts and promotes important facts; + * the agent searches them semantically each turn + * - Cross-session recall: relevant facts follow the user across conversations + * - No embeddings, vector index, or Redis schema to manage + * + * Each turn the agent: + * 1. Searches long-term memory for facts relevant to the new message + * 2. Loads working memory for short-term conversational context + * 3. Calls the LLM with that memory injected into the system prompt + * 4. Writes the user and assistant messages back to working memory + * (long-term facts are extracted and promoted automatically) + * + * To run this code: + * Install dependencies: + * npm install agent-memory-client openai dotenv + * + * Set environment variables (Agent Memory — from the Redis Cloud console): + * AGENT_MEMORY_URL=your_agent_memory_base_url + * AGENT_MEMORY_API_KEY=your_agent_memory_api_key + * AGENT_MEMORY_NAMESPACE=my-app (optional - groups memories) + * + * Set environment variables (LLM): + * LLM_API_KEY=your_api_key_here + * LLM_API_BASE_URL=your_base_url (optional - default: ${CONFIG.models[formData.llmModel].baseUrl}) + * LLM_MODEL=your_model (optional - default: ${CONFIG.models[formData.llmModel].defaultModel}) + * + * Note: this template uses the OpenAI SDK with a configurable base URL, so you + * can point it at any OpenAI-compatible chat provider. Agent memory is handled + * entirely by the managed Agent Memory service — see + * https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/ + * + * Run: + * node iris_agent.js + */ + +'use strict'; + +require('dotenv').config(); +const { MemoryAPIClient } = require('agent-memory-client'); +const OpenAI = require('openai'); +const readline = require('readline'); +const crypto = require('crypto'); + +// How many long-term memories to inject as relevant background each turn. +const MAX_LONG_TERM_RESULTS = 5; + +class ${AgentClassName} { + constructor(sessionId) { + // Managed Agent Memory client. The service owns the vector index, + // embeddings, and storage — this client just talks to its REST API. + this.memory = new MemoryAPIClient({ + baseUrl: process.env.AGENT_MEMORY_URL, + apiKey: process.env.AGENT_MEMORY_API_KEY, + defaultNamespace: process.env.AGENT_MEMORY_NAMESPACE || 'default', + }); + + // Chat LLM. Uses the OpenAI SDK with a configurable base URL so any + // OpenAI-compatible provider works. + this.llm = new OpenAI({ + apiKey: process.env.LLM_API_KEY, + baseURL: process.env.LLM_API_BASE_URL || '${CONFIG.models[formData.llmModel].baseUrl}', + }); + this.model = process.env.LLM_MODEL || '${CONFIG.models[formData.llmModel].defaultModel}'; + + // A session groups one conversation's working memory. Long-term memory + // is shared across all of a user's sessions. + this.sessionId = sessionId || `session-${crypto.randomBytes(6).toString('hex')}`; + } + + // Semantic search over long-term memory for facts relevant to the query. + async relevantMemories(query) { + try { + const results = await this.memory.searchLongTermMemory({ text: query }); + const memories = results.memories || results || []; + return memories.slice(0, MAX_LONG_TERM_RESULTS).map(m => m.text || String(m)); + } catch (err) { + console.error(`[memory] long-term search unavailable: ${err.message}`); + return []; + } + } + + // Load working memory (recent messages) for short-term context. + async recentTurns() { + try { + const working = await this.memory.getOrCreateWorkingMemory(this.sessionId); + const messages = (working && working.messages) || []; + return messages.map(m => ({ + role: String(m.role).toLowerCase().endsWith('assistant') ? 'assistant' : 'user', + content: m.content, + })); + } catch (err) { + console.error(`[memory] working memory unavailable: ${err.message}`); + return []; + } + } + + async ask(userInput) { + // 1. Pull relevant long-term facts and 2. recent conversation. + const facts = await this.relevantMemories(userInput); + const recent = await this.recentTurns(); + + const systemPrompt = + 'You are a helpful assistant with persistent memory. ' + + 'Use the following remembered facts about the user when relevant. ' + + 'If nothing is relevant, answer normally.\n\n' + + (facts.length + ? 'Relevant memories:\n' + facts.map(f => `- ${f}`).join('\n') + : 'Relevant memories: (none yet)'); + + const messages = [ + { role: 'system', content: systemPrompt }, + ...recent, + { role: 'user', content: userInput }, + ]; + + // 3. Call the LLM. + const response = await this.llm.chat.completions.create({ model: this.model, messages }); + const answer = response.choices[0].message.content; + + // 4. Append both turns to working memory. The service promotes durable + // facts to long-term memory automatically. + await this.memory.putWorkingMemory(this.sessionId, { + messages: [ + ...recent, + { role: 'user', content: userInput }, + { role: 'assistant', content: answer }, + ], + }); + + return answer; + } +} + +async function main() { + const agent = new ${AgentClassName}(); + console.log('Redis Context Engine Agent — type "exit" to quit.'); + console.log(`Session: ${agent.sessionId}\n`); + + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const prompt = () => new Promise(resolve => rl.question('You: ', resolve)); + + for (;;) { + const userInput = (await prompt()).trim(); + if (!userInput || ['exit', 'quit'].includes(userInput.toLowerCase())) break; + console.log(`Agent: ${await agent.ask(userInput)}\n`); + } + rl.close(); +} + +if (require.main === module) { + main().catch(err => { + console.error('Fatal error:', err); + process.exit(1); + }); +} + +module.exports = ${AgentClassName}; diff --git a/static/code/agent-templates/python/iris_agent.py b/static/code/agent-templates/python/iris_agent.py new file mode 100644 index 0000000000..a68da63674 --- /dev/null +++ b/static/code/agent-templates/python/iris_agent.py @@ -0,0 +1,173 @@ +''' +Redis Context Engine Agent (Redis Iris — Agent Memory) + +A conversational agent whose memory is fully managed by the Redis Iris +Context Engine. Instead of building your own vector index, embeddings, and +session store, the agent calls the managed Agent Memory service: + +Features: +- Session memory: every user and assistant turn is stored as a session event +- Long-term memory: the service automatically promotes important facts from + session events; the agent searches them semantically each turn +- Cross-session recall: relevant facts follow the user across conversations +- No embeddings, vector index, or Redis schema to manage — the service does it + +Each turn the agent: + 1. Searches long-term memory for facts relevant to the new message + 2. Loads recent session events for short-term conversational context + 3. Calls the LLM with that memory injected into the system prompt + 4. Writes the user and assistant messages back as session events + (long-term facts are extracted and promoted automatically) + +To run this code: + Install dependencies: + pip install redis-agent-memory openai + + Set environment variables (Agent Memory — from the Redis Cloud console): + export AGENT_MEMORY_URL=your_agent_memory_base_url + export STORE_ID=your_store_id + export AGENT_MEMORY_API_KEY=your_agent_memory_api_key + + Set environment variables (LLM): + export LLM_API_KEY=your_api_key_here + export LLM_API_BASE_URL=your_${formData.llmModel.toLowerCase()}_api_base_url + (optional - default: ${CONFIG.models[formData.llmModel].baseUrl}) + export LLM_MODEL=your_${formData.llmModel.toLowerCase()}_model + (optional - default: ${CONFIG.models[formData.llmModel].defaultModel}) + + Note: this template uses the OpenAI SDK with a configurable base URL, so you + can point it at any OpenAI-compatible chat provider. Agent memory is handled + entirely by the managed Agent Memory service — see + https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/ + + To create an Agent Memory service and get the values above, follow the + Redis Cloud Agent Memory quickstart in the documentation. +''' + +import os +import uuid +from datetime import datetime, timezone + +import openai +from redis_agent_memory import AgentMemory, models + +# How many recent session events to load for short-term context each turn. +MAX_SESSION_EVENTS = 12 +# How many long-term memories to inject as relevant background each turn. +MAX_LONG_TERM_RESULTS = 5 + + +class ${AgentClassName}: + def __init__(self, session_id=None, actor_id='user'): + # Managed Agent Memory client. The service owns the vector index, + # embeddings, and storage — this client just talks to its REST API. + self.memory = AgentMemory( + os.environ['AGENT_MEMORY_URL'], + store_id=os.environ['STORE_ID'], + api_key=os.environ['AGENT_MEMORY_API_KEY'], + ) + + # Chat LLM. Uses the OpenAI SDK with a configurable base URL so any + # OpenAI-compatible provider works. + self.llm = openai.OpenAI( + api_key=os.environ['LLM_API_KEY'], + base_url=os.getenv('LLM_API_BASE_URL', '${CONFIG.models[formData.llmModel].baseUrl}'), + ) + self.model = os.getenv('LLM_MODEL', '${CONFIG.models[formData.llmModel].defaultModel}') + + # A session groups the events of one conversation. Reuse the same + # session_id to continue a conversation; long-term memory is shared + # across all of a user's sessions. + self.session_id = session_id or f'session-{uuid.uuid4().hex[:12]}' + self.actor_id = actor_id + + def _relevant_memories(self, query): + '''Semantic search over long-term memory for facts relevant to the query.''' + try: + results = self.memory.search_long_term_memory(request={'text': query}) + except Exception as e: + print(f'[memory] long-term search unavailable: {e}') + return [] + + # Matching records come back in `.items`; each record exposes its `.text`. + items = getattr(results, 'items', []) or [] + return [item.text for item in items[:MAX_LONG_TERM_RESULTS]] + + def _recent_turns(self): + '''Load recent session events for short-term conversational context.''' + try: + session = self.memory.get_session_memory(session_id=self.session_id) + except Exception: + return [] + + events = getattr(session, 'events', []) or [] + turns = [] + for event in events[-MAX_SESSION_EVENTS:]: + role = getattr(event, 'role', 'USER') + content = getattr(event, 'content', []) or [] + # Content parts are Content model objects (or dicts); read either. + text = ' '.join( + getattr(part, 'text', None) or (part.get('text', '') if isinstance(part, dict) else '') + for part in content + ) + turns.append({ + 'role': 'assistant' if str(role).upper().endswith('ASSISTANT') else 'user', + 'content': text, + }) + return turns + + def _record(self, role, text): + '''Persist one turn as a session event. Long-term promotion is automatic.''' + self.memory.add_session_event( + actor_id=self.actor_id, + role=role, + content=[{'text': text}], + created_at=datetime.now(timezone.utc), + session_id=self.session_id, + ) + + def ask(self, user_input): + # 1. Pull relevant long-term facts and 2. recent conversation. + facts = self._relevant_memories(user_input) + recent = self._recent_turns() + + system_prompt = ( + 'You are a helpful assistant with persistent memory. ' + 'Use the following remembered facts about the user when relevant. ' + 'If nothing is relevant, answer normally.\n\n' + + ('Relevant memories:\n' + '\n'.join(f'- {f}' for f in facts) + if facts else 'Relevant memories: (none yet)') + ) + + messages = [{'role': 'system', 'content': system_prompt}] + messages.extend(recent) + messages.append({'role': 'user', 'content': user_input}) + + # 3. Call the LLM. + response = self.llm.chat.completions.create(model=self.model, messages=messages) + answer = response.choices[0].message.content + + # 4. Write both turns back to session memory. + self._record(models.MessageRole.USER, user_input) + self._record(models.MessageRole.ASSISTANT, answer) + + return answer + + +def main(): + agent = ${AgentClassName}() + print('Redis Context Engine Agent — type "exit" to quit.') + print(f'Session: {agent.session_id}\n') + while True: + try: + user_input = input('You: ').strip() + except (EOFError, KeyboardInterrupt): + print() + break + if not user_input or user_input.lower() in ('exit', 'quit'): + break + print(f'Agent: {agent.ask(user_input)}\n') + + +if __name__ == '__main__': + main() diff --git a/static/js/agent-builder.js b/static/js/agent-builder.js index 36a326c341..02fe127f68 100644 --- a/static/js/agent-builder.js +++ b/static/js/agent-builder.js @@ -26,6 +26,12 @@ description: "A RAG agent that ingests documents, uses Redis-native hybrid retrieval (text pre-filter + vector search), semantic caching, and session memory to answer questions with citations.", features: ["Document ingestion with chunking", "Hybrid vector + full-text search", "Semantic caching", "Citations"], keywords: ["rag", "knowledge", "documents", "search", "retrieval", "qa", "question answering", "citations", "hybrid"] + }, + iris: { + name: "Context Engine Agent", + description: "A conversational agent whose memory is fully managed by the Redis Iris Context Engine. It stores session events and semantically searches long-term memory through the managed Agent Memory service — no vector index or embeddings to build.", + features: ["Managed Agent Memory service", "Session (short-term) memory", "Semantic long-term memory search", "Cross-session recall"], + keywords: ["iris", "context engine", "context", "agent memory", "memory", "managed", "persistent", "long-term"] } }, languages: { @@ -293,7 +299,7 @@ switch (conversationState.step) { case 'agent-type': { - const agentIcons = { recommendation: '🛍️', conversational: '💬', rag: '🔍' }; + const agentIcons = { recommendation: '🛍️', conversational: '💬', rag: '🔍', iris: '🧠' }; suggestions = Object.entries(CONFIG.agentTypes).map(([key, config]) => ({ value: key, label: config.name, @@ -400,7 +406,8 @@ const defaultNames = { recommendation: 'RecommendationEngine', conversational: 'ConversationalAgent', - rag: 'KnowledgeAssistant' + rag: 'KnowledgeAssistant', + iris: 'ContextEngineAgent' }; conversationState.selections.agentName = defaultNames[selectedType] || 'RedisAgent'; @@ -418,7 +425,8 @@ addMessage("I didn't understand that. Please choose one of the agent types:", 'bot', [ { value: 'recommendation', label: '🛍️ Recommendation Engine' }, { value: 'conversational', label: '💬 Conversational Assistant' }, - { value: 'rag', label: '🔍 Knowledge Assistant' } + { value: 'rag', label: '🔍 Knowledge Assistant' }, + { value: 'iris', label: '🧠 Context Engine Agent' } ]); } } From d51ede0661b6f037b64c483ac0563780ad8375be Mon Sep 17 00:00:00 2001 From: mich-elle-luna Date: Tue, 11 Aug 2026 14:21:59 -0700 Subject: [PATCH 2/4] Note the managed Context Engine memory option on the agent concepts page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the Redis Iris Context Engine (managed Agent Memory) as an alternative to building agent memory yourself with Redis data structures, in the Agent memory section and the Next steps links — consistent with the new Context Engine agent type in the agent builder. Co-Authored-By: Claude Opus 4.8 (1M context) --- content/develop/ai/agent-builder/agent-concepts.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/develop/ai/agent-builder/agent-concepts.md b/content/develop/ai/agent-builder/agent-concepts.md index 408c54b497..0d0ee83e41 100644 --- a/content/develop/ai/agent-builder/agent-concepts.md +++ b/content/develop/ai/agent-builder/agent-concepts.md @@ -79,6 +79,7 @@ Redis is the **ideal foundation** for AI agents because it excels at the three t - **Short-term**: Conversation context and session state - **Long-term**: User preferences and learned patterns - Flexible data structures (Hashes, Lists, Streams, JSON) for different memory types +- **Managed option**: The [Redis Iris Context Engine]({{< relref "/develop/ai/context-engine/agent-memory" >}}) provides short-term (session) and long-term memory as a managed service — with semantic long-term search — so you don't have to build the vector index and storage yourself - [Explore Redis data structures →](/develop/data-types/) ## Types of agents you can build @@ -365,6 +366,7 @@ Ready to build your AI agent with Redis? - [Redis quick start guide]({{< relref "/develop/get-started" >}}) for setting up Redis **Learn more:** +- [Redis Iris Context Engine — Agent Memory]({{< relref "/develop/ai/context-engine/agent-memory" >}}) for managed session and long-term agent memory - [Redis Vector Search documentation]({{< relref "develop/ai/search-and-query/vectors" >}}) - [RedisVL Python library]({{< relref "develop/clients/redis-vl" >}}) for vector operations and AI workflows - [Redis data structures guide](/develop/data-types/) From d083092549c8e5d2fa1b52e4552bc54fa96b1899 Mon Sep 17 00:00:00 2001 From: mich-elle-luna Date: Wed, 12 Aug 2026 09:43:03 -0700 Subject: [PATCH 3/4] Target Iris Cloud's store-scoped Agent Memory API; fix chip layout Addresses the Cursor Bugbot review and dwdougherty's layout note on the Context Engine agent PR. Templates (Bugbot): - JS (was High): it used agent-memory-client, which talks to the non-store-scoped Agent Memory Server working-memory endpoints, so it could never run against Iris Cloud (no STORE_ID). Rewritten to call the store-scoped Agent Memory REST API directly via fetch (POST session-memory/events, GET session-memory/{sessionId}, POST long-term-memory/search), matching the Python template. This also removes the working-memory PUT that dropped server-managed context/data on every write. - Both templates now fold the compacted session `summary` into the LLM context, so once the service summarizes older turns they still reach the model. - Endpoints and field names verified against the repo's OpenAPI spec. Chip layout (dwdougherty): .suggestion-chips now uses a two-column grid (grid grid-cols-2) instead of flex-wrap, collapsing to one column under 768px. Co-Authored-By: Claude Opus 4.8 (1M context) --- assets/css/index.css | 4 +- .../agent-templates/javascript/iris_agent.js | 125 +++++++++++------- .../code/agent-templates/python/iris_agent.py | 20 ++- 3 files changed, 96 insertions(+), 53 deletions(-) diff --git a/assets/css/index.css b/assets/css/index.css index 7cd6a3db8a..74e4768b98 100644 --- a/assets/css/index.css +++ b/assets/css/index.css @@ -1297,7 +1297,7 @@ a[href*="#no-click"], img[src*="#no-click"] { } .suggestion-chips { - @apply flex flex-wrap gap-2 mt-3; + @apply grid grid-cols-2 gap-2 mt-3; } .suggestion-chip { @@ -1368,7 +1368,7 @@ a[href*="#no-click"], img[src*="#no-click"] { } .suggestion-chips { - @apply flex-col space-y-2; + @apply grid-cols-1; } .suggestion-chip { diff --git a/static/code/agent-templates/javascript/iris_agent.js b/static/code/agent-templates/javascript/iris_agent.js index eb74f8660f..19e5f5cb08 100644 --- a/static/code/agent-templates/javascript/iris_agent.js +++ b/static/code/agent-templates/javascript/iris_agent.js @@ -2,32 +2,34 @@ * Redis Context Engine Agent (Redis Iris — Agent Memory) * * A conversational agent whose memory is fully managed by the Redis Iris - * Context Engine. Instead of building your own vector index, embeddings, and - * session store, the agent calls the managed Agent Memory service through the - * official agent-memory-client: + * Context Engine on Redis Cloud. Instead of building your own vector index, + * embeddings, and session store, the agent calls the managed, store-scoped + * Agent Memory REST API directly: * * Features: - * - Working memory: the running conversation is stored per session + * - Session memory: every user and assistant turn is stored as a session event * - Long-term memory: the service extracts and promotes important facts; * the agent searches them semantically each turn - * - Cross-session recall: relevant facts follow the user across conversations + * - Session summaries: older turns are compacted into a summary the agent + * folds back into context, so long conversations don't lose their history * - No embeddings, vector index, or Redis schema to manage * * Each turn the agent: * 1. Searches long-term memory for facts relevant to the new message - * 2. Loads working memory for short-term conversational context + * 2. Loads the session (recent events + compacted summary) for short-term context * 3. Calls the LLM with that memory injected into the system prompt - * 4. Writes the user and assistant messages back to working memory + * 4. Writes the user and assistant messages back as session events * (long-term facts are extracted and promoted automatically) * * To run this code: * Install dependencies: - * npm install agent-memory-client openai dotenv + * npm install openai dotenv + * (Node.js 18+ is required for the built-in fetch used to call the API.) * * Set environment variables (Agent Memory — from the Redis Cloud console): * AGENT_MEMORY_URL=your_agent_memory_base_url + * STORE_ID=your_store_id * AGENT_MEMORY_API_KEY=your_agent_memory_api_key - * AGENT_MEMORY_NAMESPACE=my-app (optional - groups memories) * * Set environment variables (LLM): * LLM_API_KEY=your_api_key_here @@ -39,6 +41,9 @@ * entirely by the managed Agent Memory service — see * https://redis.io/docs/latest/develop/ai/context-engine/agent-memory/ * + * To create an Agent Memory service and get the values above, follow the + * Redis Cloud Agent Memory quickstart in the documentation. + * * Run: * node iris_agent.js */ @@ -46,23 +51,23 @@ 'use strict'; require('dotenv').config(); -const { MemoryAPIClient } = require('agent-memory-client'); const OpenAI = require('openai'); const readline = require('readline'); const crypto = require('crypto'); // How many long-term memories to inject as relevant background each turn. const MAX_LONG_TERM_RESULTS = 5; +// How many recent session events to load for short-term context each turn. +const MAX_SESSION_EVENTS = 12; class ${AgentClassName} { - constructor(sessionId) { - // Managed Agent Memory client. The service owns the vector index, - // embeddings, and storage — this client just talks to its REST API. - this.memory = new MemoryAPIClient({ - baseUrl: process.env.AGENT_MEMORY_URL, - apiKey: process.env.AGENT_MEMORY_API_KEY, - defaultNamespace: process.env.AGENT_MEMORY_NAMESPACE || 'default', - }); + constructor(sessionId, actorId = 'user') { + // Managed Agent Memory service (Redis Cloud). The service owns the + // vector index, embeddings, and storage; we call its store-scoped + // REST API directly with fetch. + this.baseUrl = (process.env.AGENT_MEMORY_URL || '').replace(/\/$/, ''); + this.storeId = process.env.STORE_ID; + this.apiKey = process.env.AGENT_MEMORY_API_KEY; // Chat LLM. Uses the OpenAI SDK with a configurable base URL so any // OpenAI-compatible provider works. @@ -72,54 +77,90 @@ class ${AgentClassName} { }); this.model = process.env.LLM_MODEL || '${CONFIG.models[formData.llmModel].defaultModel}'; - // A session groups one conversation's working memory. Long-term memory - // is shared across all of a user's sessions. + // A session groups the events of one conversation. Long-term memory is + // shared across all of a user's sessions. this.sessionId = sessionId || `session-${crypto.randomBytes(6).toString('hex')}`; + this.actorId = actorId; + } + + // Call the store-scoped Agent Memory API. Returns parsed JSON, or null on + // 404 (e.g. a session that doesn't exist yet). + async memoryRequest(method, path, body) { + const res = await fetch(`${this.baseUrl}/v1/stores/${this.storeId}${path}`, { + method, + headers: { + Authorization: `Bearer ${this.apiKey}`, + 'Content-Type': 'application/json', + }, + body: body ? JSON.stringify(body) : undefined, + }); + if (res.status === 404) return null; + if (!res.ok) { + throw new Error(`Agent Memory ${method} ${path} -> ${res.status}: ${await res.text()}`); + } + return res.json(); } // Semantic search over long-term memory for facts relevant to the query. async relevantMemories(query) { try { - const results = await this.memory.searchLongTermMemory({ text: query }); - const memories = results.memories || results || []; - return memories.slice(0, MAX_LONG_TERM_RESULTS).map(m => m.text || String(m)); + const results = await this.memoryRequest('POST', '/long-term-memory/search', { text: query }); + const items = (results && results.items) || []; + return items.slice(0, MAX_LONG_TERM_RESULTS).map(item => item.text); } catch (err) { console.error(`[memory] long-term search unavailable: ${err.message}`); return []; } } - // Load working memory (recent messages) for short-term context. - async recentTurns() { + // Load the session: recent events for short-term context, plus the + // compacted summary of older turns the service has already summarized. + async loadSession() { try { - const working = await this.memory.getOrCreateWorkingMemory(this.sessionId); - const messages = (working && working.messages) || []; - return messages.map(m => ({ - role: String(m.role).toLowerCase().endsWith('assistant') ? 'assistant' : 'user', - content: m.content, + const session = await this.memoryRequest('GET', `/session-memory/${this.sessionId}`); + if (!session) return { turns: [], summary: '' }; + const events = (session.events || []).slice(-MAX_SESSION_EVENTS); + const turns = events.map(event => ({ + role: String(event.role).toUpperCase() === 'ASSISTANT' ? 'assistant' : 'user', + content: (event.content || []).map(part => part.text || '').join(' '), })); + return { turns, summary: (session.summary && session.summary.text) || '' }; } catch (err) { - console.error(`[memory] working memory unavailable: ${err.message}`); - return []; + console.error(`[memory] session load unavailable: ${err.message}`); + return { turns: [], summary: '' }; } } + // Persist one turn as a session event. Long-term promotion is automatic. + async recordEvent(role, text) { + await this.memoryRequest('POST', '/session-memory/events', { + sessionId: this.sessionId, + actorId: this.actorId, + role, + content: [{ text }], + createdAt: new Date().toISOString(), + }); + } + async ask(userInput) { - // 1. Pull relevant long-term facts and 2. recent conversation. + // 1. Relevant long-term facts and 2. this session's recent turns + summary. const facts = await this.relevantMemories(userInput); - const recent = await this.recentTurns(); + const { turns, summary } = await this.loadSession(); - const systemPrompt = + let systemPrompt = 'You are a helpful assistant with persistent memory. ' + 'Use the following remembered facts about the user when relevant. ' + 'If nothing is relevant, answer normally.\n\n' + (facts.length ? 'Relevant memories:\n' + facts.map(f => `- ${f}`).join('\n') : 'Relevant memories: (none yet)'); + if (summary) { + systemPrompt += `\n\nSummary of earlier conversation:\n${summary}`; + } const messages = [ { role: 'system', content: systemPrompt }, - ...recent, + ...turns, { role: 'user', content: userInput }, ]; @@ -127,15 +168,9 @@ class ${AgentClassName} { const response = await this.llm.chat.completions.create({ model: this.model, messages }); const answer = response.choices[0].message.content; - // 4. Append both turns to working memory. The service promotes durable - // facts to long-term memory automatically. - await this.memory.putWorkingMemory(this.sessionId, { - messages: [ - ...recent, - { role: 'user', content: userInput }, - { role: 'assistant', content: answer }, - ], - }); + // 4. Write both turns back as session events. + await this.recordEvent('USER', userInput); + await this.recordEvent('ASSISTANT', answer); return answer; } diff --git a/static/code/agent-templates/python/iris_agent.py b/static/code/agent-templates/python/iris_agent.py index a68da63674..940a92c9b8 100644 --- a/static/code/agent-templates/python/iris_agent.py +++ b/static/code/agent-templates/python/iris_agent.py @@ -93,12 +93,13 @@ def _relevant_memories(self, query): items = getattr(results, 'items', []) or [] return [item.text for item in items[:MAX_LONG_TERM_RESULTS]] - def _recent_turns(self): - '''Load recent session events for short-term conversational context.''' + def _load_session(self): + '''Load the session: recent events for short-term context, plus the + compacted summary of older turns the service has already summarized.''' try: session = self.memory.get_session_memory(session_id=self.session_id) except Exception: - return [] + return [], '' events = getattr(session, 'events', []) or [] turns = [] @@ -114,7 +115,12 @@ def _recent_turns(self): 'role': 'assistant' if str(role).upper().endswith('ASSISTANT') else 'user', 'content': text, }) - return turns + + # After summarization, older events are dropped from `events` and the + # compacted history is returned separately in `summary`. + summary_obj = getattr(session, 'summary', None) + summary = getattr(summary_obj, 'text', '') if summary_obj else '' + return turns, summary def _record(self, role, text): '''Persist one turn as a session event. Long-term promotion is automatic.''' @@ -127,9 +133,9 @@ def _record(self, role, text): ) def ask(self, user_input): - # 1. Pull relevant long-term facts and 2. recent conversation. + # 1. Pull relevant long-term facts and 2. this session's recent turns + summary. facts = self._relevant_memories(user_input) - recent = self._recent_turns() + recent, summary = self._load_session() system_prompt = ( 'You are a helpful assistant with persistent memory. ' @@ -138,6 +144,8 @@ def ask(self, user_input): + ('Relevant memories:\n' + '\n'.join(f'- {f}' for f in facts) if facts else 'Relevant memories: (none yet)') ) + if summary: + system_prompt += f'\n\nSummary of earlier conversation:\n{summary}' messages = [{'role': 'system', 'content': system_prompt}] messages.extend(recent) From 0c0e4527d92eabd616bfd48ba56350bafa8bab89 Mon Sep 17 00:00:00 2001 From: mich-elle-luna Date: Wed, 12 Aug 2026 13:23:58 -0700 Subject: [PATCH 4/4] Rename the agent type and narrow its routing keywords MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two refinements to the new agent type from the review round: - Rename "Context Engine Agent" to "Redis Iris Conversational Assistant". The template only uses the Agent Memory service, so the old name overclaimed the whole Context Engine. The new name states the function (conversational assistant) and keeps the brand, without implying the other Iris services. Updated across agent-builder.js, the initial chips, the agent-builder landing page, and both template headers/banners. Internal key stays `iris`. - Narrow the routing keywords to the distinctive terms "iris", "context engine", "agent memory" (Bugbot finding). The previous generic terms (context, memory, persistent, managed, long-term) hijacked the longest-match selector, so "persistent chatbot" and "rag with long-term memory" resolved to this type instead of Conversational / Knowledge Assistant. Deliberately did not add "conversational"/"assistant" as keywords — they would collide with the Conversational type; the chip routes by key regardless. Co-Authored-By: Claude Opus 4.8 (1M context) --- content/develop/ai/agent-builder/_index.md | 2 +- layouts/shortcodes/agent-builder.html | 2 +- static/code/agent-templates/javascript/iris_agent.js | 4 ++-- static/code/agent-templates/python/iris_agent.py | 4 ++-- static/js/agent-builder.js | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/content/develop/ai/agent-builder/_index.md b/content/develop/ai/agent-builder/_index.md index 69f6072b78..62ba5826fe 100644 --- a/content/develop/ai/agent-builder/_index.md +++ b/content/develop/ai/agent-builder/_index.md @@ -35,7 +35,7 @@ Choose from four types of intelligent agents: - **Recommendation engines**: Personalized product and content recommendations - **Conversational assistants**: Chatbots with memory and context awareness - **Knowledge assistants**: RAG agents that ingest documents, answer questions with citations, and use semantic caching -- **Context engine agents**: Conversational agents backed by the managed [Redis Iris Context Engine]({{< relref "/develop/ai/context-engine/agent-memory" >}}) — session and long-term memory with no vector index to build +- **Redis Iris conversational assistants**: Conversational agents backed by managed [Redis Iris Agent Memory]({{< relref "/develop/ai/context-engine/agent-memory" >}}) — session and long-term memory with no vector index to build The agent builder will generate complete, working code examples for your chosen agent type. diff --git a/layouts/shortcodes/agent-builder.html b/layouts/shortcodes/agent-builder.html index 8e4629f12a..3518699339 100644 --- a/layouts/shortcodes/agent-builder.html +++ b/layouts/shortcodes/agent-builder.html @@ -25,7 +25,7 @@

Build Your AI Agent🛍️ Recommendation Engine - + diff --git a/static/code/agent-templates/javascript/iris_agent.js b/static/code/agent-templates/javascript/iris_agent.js index 19e5f5cb08..69ffa9c23b 100644 --- a/static/code/agent-templates/javascript/iris_agent.js +++ b/static/code/agent-templates/javascript/iris_agent.js @@ -1,5 +1,5 @@ /* - * Redis Context Engine Agent (Redis Iris — Agent Memory) + * Redis Iris Conversational Assistant (Agent Memory) * * A conversational agent whose memory is fully managed by the Redis Iris * Context Engine on Redis Cloud. Instead of building your own vector index, @@ -178,7 +178,7 @@ class ${AgentClassName} { async function main() { const agent = new ${AgentClassName}(); - console.log('Redis Context Engine Agent — type "exit" to quit.'); + console.log('Redis Iris Conversational Assistant — type "exit" to quit.'); console.log(`Session: ${agent.sessionId}\n`); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); diff --git a/static/code/agent-templates/python/iris_agent.py b/static/code/agent-templates/python/iris_agent.py index 940a92c9b8..93034323c6 100644 --- a/static/code/agent-templates/python/iris_agent.py +++ b/static/code/agent-templates/python/iris_agent.py @@ -1,5 +1,5 @@ ''' -Redis Context Engine Agent (Redis Iris — Agent Memory) +Redis Iris Conversational Assistant (Agent Memory) A conversational agent whose memory is fully managed by the Redis Iris Context Engine. Instead of building your own vector index, embeddings, and @@ -164,7 +164,7 @@ def ask(self, user_input): def main(): agent = ${AgentClassName}() - print('Redis Context Engine Agent — type "exit" to quit.') + print('Redis Iris Conversational Assistant — type "exit" to quit.') print(f'Session: {agent.session_id}\n') while True: try: diff --git a/static/js/agent-builder.js b/static/js/agent-builder.js index 02fe127f68..4676ab40ab 100644 --- a/static/js/agent-builder.js +++ b/static/js/agent-builder.js @@ -28,10 +28,10 @@ keywords: ["rag", "knowledge", "documents", "search", "retrieval", "qa", "question answering", "citations", "hybrid"] }, iris: { - name: "Context Engine Agent", - description: "A conversational agent whose memory is fully managed by the Redis Iris Context Engine. It stores session events and semantically searches long-term memory through the managed Agent Memory service — no vector index or embeddings to build.", + name: "Redis Iris Conversational Assistant", + description: "A conversational assistant whose memory is managed by Redis Iris Agent Memory. It stores session events and semantically searches long-term memory through the managed service — no vector index or embeddings to build.", features: ["Managed Agent Memory service", "Session (short-term) memory", "Semantic long-term memory search", "Cross-session recall"], - keywords: ["iris", "context engine", "context", "agent memory", "memory", "managed", "persistent", "long-term"] + keywords: ["iris", "context engine", "agent memory"] } }, languages: { @@ -407,7 +407,7 @@ recommendation: 'RecommendationEngine', conversational: 'ConversationalAgent', rag: 'KnowledgeAssistant', - iris: 'ContextEngineAgent' + iris: 'IrisConversationalAssistant' }; conversationState.selections.agentName = defaultNames[selectedType] || 'RedisAgent'; @@ -426,7 +426,7 @@ { value: 'recommendation', label: '🛍️ Recommendation Engine' }, { value: 'conversational', label: '💬 Conversational Assistant' }, { value: 'rag', label: '🔍 Knowledge Assistant' }, - { value: 'iris', label: '🧠 Context Engine Agent' } + { value: 'iris', label: '🧠 Redis Iris Conversational Assistant' } ]); } }