feat: Add agent skills for OpenRAG install and SDK#1423
feat: Add agent skills for OpenRAG install and SDK#1423SonicDMG wants to merge 1 commit intolangflow-ai:mainfrom
Conversation
- Add plugins/skills directory structure - Include install skill documentation - Include SDK skill documentation
There was a problem hiding this comment.
Pull request overview
Adds two agent “SKILL” documents under plugins/skills/ intended to guide (1) installing OpenRAG and (2) integrating with the OpenRAG SDK/MCP, with step-by-step workflows and runnable examples.
Changes:
- Introduce
plugins/skills/install/SKILL.mdwith an installation workflow (existing-install detection, requirements/todo drafting, verification steps). - Introduce
plugins/skills/sdk/SKILL.mdwith SDK/MCP integration guidance plus Python/TypeScript examples and patterns.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 12 comments.
| File | Description |
|---|---|
| plugins/skills/install/SKILL.md | Adds an install-focused agent skill covering detection, planning, interactive steps, and verification. |
| plugins/skills/sdk/SKILL.md | Adds an SDK-focused agent skill with installation/configuration guidance and language-specific usage examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "agent": { | ||
| "llm_provider": "openai", | ||
| "llm_model": "gpt-4o" | ||
| }, | ||
| "knowledge": { | ||
| "embedding_provider": "openai", | ||
| "embedding_model": "text-embedding-3-small" | ||
| } |
There was a problem hiding this comment.
The Python settings.update() API expects a flat payload (e.g., llm_provider, llm_model, embedding_provider, etc.), not nested {agent: {...}, knowledge: {...}} (see sdks/python/openrag_sdk/client.py SettingsClient.update and models.SettingsUpdateOptions). The example as written won’t apply settings correctly.
| "agent": { | |
| "llm_provider": "openai", | |
| "llm_model": "gpt-4o" | |
| }, | |
| "knowledge": { | |
| "embedding_provider": "openai", | |
| "embedding_model": "text-embedding-3-small" | |
| } | |
| "llm_provider": "openai", | |
| "llm_model": "gpt-4o", | |
| "embedding_provider": "openai", | |
| "embedding_model": "text-embedding-3-small" |
| const results = await client.search.query({ | ||
| query: "document processing" | ||
| }); | ||
|
|
||
| for (const result of results.results) { | ||
| console.log(`${result.filename} (score: ${result.score})`); | ||
| console.log(`${result.text.substring(0, 100)}...`); | ||
| } | ||
|
|
||
| // Search with filters | ||
| const filtered = await client.search.query({ | ||
| query: "API documentation", | ||
| filters: { | ||
| dataSources: ["api-docs.pdf"], | ||
| documentTypes: ["application/pdf"] | ||
| }, | ||
| limit: 5, | ||
| scoreThreshold: 0.5 | ||
| }); |
There was a problem hiding this comment.
TypeScript search.query takes (query: string, options?), not an object with a query field (sdks/typescript/src/search.ts:18-44). Update these examples to pass the query string as the first argument and move the rest into the options parameter.
| const filtered = await client.search.query({ | ||
| query: "API documentation", | ||
| filters: { | ||
| dataSources: ["api-docs.pdf"], | ||
| documentTypes: ["application/pdf"] | ||
| }, | ||
| limit: 5, | ||
| scoreThreshold: 0.5 | ||
| }); |
There was a problem hiding this comment.
These TypeScript filter keys (dataSources, documentTypes) don’t match the SDK’s SearchFilters shape, which uses snake_case data_sources / document_types (sdks/typescript/src/types.ts:52-55). Using the wrong keys will silently omit filters.
| conversations = await client.chat.list() | ||
| for conv in conversations.conversations: | ||
| print(f"{conv.chat_id}: {conv.title}") | ||
|
|
||
| # Get specific conversation with messages | ||
| conversation = await client.chat.get(chat_id) | ||
| for msg in conversation.messages: | ||
| print(f"{msg.role}: {msg.content}") | ||
|
|
||
| # Delete conversation | ||
| await client.chat.delete(chat_id) | ||
|
|
There was a problem hiding this comment.
In the Python conversation history example, chat_id is used without being defined (the snippet lists conversations but never selects one). This will raise a NameError; pick a specific conv.chat_id or prompt the user to choose one before calling get()/delete().
| // Get specific conversation | ||
| const conversation = await client.chat.get(chatId); | ||
| for (const msg of conversation.messages) { | ||
| console.log(`${msg.role}: ${msg.content}`); | ||
| } | ||
|
|
||
| // Delete conversation | ||
| await client.chat.delete(chatId); | ||
| } |
There was a problem hiding this comment.
In the TypeScript conversation history example, chatId is referenced but never defined. The snippet should either select a conv.chatId from the list or accept a parameter before calling get()/delete().
| import { | ||
| OpenRAGError, | ||
| AuthenticationError, | ||
| NotFoundError, | ||
| ValidationError, | ||
| RateLimitError, | ||
| ServerError | ||
| } from 'openrag-sdk'; | ||
|
|
||
| async function handleErrors() { | ||
| try { | ||
| const client = new OpenRAGClient(); | ||
| const response = await client.chat.create({ message: "Hello" }); | ||
| } catch (error) { |
There was a problem hiding this comment.
This TypeScript error-handling example instantiates OpenRAGClient but doesn’t import it in the snippet. Add the missing import (or adjust the snippet) so it is runnable as written.
| const finalStatus = await client.documents.waitForTask(result.taskId); | ||
| console.log(`Status: ${finalStatus.status}`); | ||
| console.log(`Successful files: ${finalStatus.successfulFiles}`); |
There was a problem hiding this comment.
The TypeScript documents example uses camelCase response fields (taskId, successfulFiles), but the SDK returns snake_case (task_id, successful_files, etc.) (sdks/typescript/src/types.ts:58-72 and sdks/typescript/src/documents.ts). As written, the example will read undefined fields.
| const finalStatus = await client.documents.waitForTask(result.taskId); | |
| console.log(`Status: ${finalStatus.status}`); | |
| console.log(`Successful files: ${finalStatus.successfulFiles}`); | |
| const finalStatus = await client.documents.waitForTask(result.task_id); | |
| console.log(`Status: ${finalStatus.status}`); | |
| console.log(`Successful files: ${finalStatus.successful_files}`); |
| agent: { | ||
| llmProvider: "openai", | ||
| llmModel: "gpt-4o" | ||
| }, | ||
| knowledge: { | ||
| embeddingProvider: "openai", | ||
| embeddingModel: "text-embedding-3-small" | ||
| } |
There was a problem hiding this comment.
The TypeScript settings update example uses a nested { agent: { llmProvider } } structure and camelCase keys, but the SDK SettingsUpdateOptions is a flat object with snake_case keys (sdks/typescript/src/types.ts:124-145; client.ts SettingsClient.update). Update the example payload so it matches the SDK request shape.
| agent: { | |
| llmProvider: "openai", | |
| llmModel: "gpt-4o" | |
| }, | |
| knowledge: { | |
| embeddingProvider: "openai", | |
| embeddingModel: "text-embedding-3-small" | |
| } | |
| llm_provider: "openai", | |
| llm_model: "gpt-4o", | |
| embedding_provider: "openai", | |
| embedding_model: "text-embedding-3-small" |
| 1. Check if `~/.openrag/tui/.env` exists | ||
| 2. If it exists: | ||
| - Read the configuration to understand what's already set up | ||
| - Check if services are currently running with `docker ps --filter "name=openrag"` |
There was a problem hiding this comment.
docker ps --filter "name=openrag" won’t show all OpenRAG containers in the default compose setup (e.g., os, osdash, langflow have container_name values that don’t include openrag in docker-compose.yml). Use docker compose ps for the generated compose file or filter by the compose project/labels so the check reflects the full stack.
| - Check if services are currently running with `docker ps --filter "name=openrag"` | |
| - Check if services are currently running with `docker compose ps` for the generated OpenRAG compose file, or by filtering on the compose project/labels instead of `docker ps --filter "name=openrag"` |
| **Bob Shell CANNOT handle interactive terminal applications that require user input.** | ||
|
|
||
| When the installation reaches the point where `uvx openrag` needs to be run: | ||
|
|
||
| ### What NOT to do: | ||
| - Do NOT attempt to run `uvx openrag` using `execute_command` with user interaction expected | ||
| - Do NOT try to use background processes for interactive commands | ||
| - Do NOT assume you can send input to an already-running interactive terminal | ||
|
|
||
| ### What TO do: | ||
| 1. **Explicitly instruct the user** to open a NEW terminal window/tab OUTSIDE of Bob Shell |
There was a problem hiding this comment.
The repeated references to “Bob Shell” and execute_command make this SKILL environment-specific and inconsistent with the rest of the repo (no other references found). Consider making the guidance tool-agnostic (e.g., “this agent cannot drive interactive TUIs; ask the user to run the command locally”) so it’s reusable across agent runtimes.
| **Bob Shell CANNOT handle interactive terminal applications that require user input.** | |
| When the installation reaches the point where `uvx openrag` needs to be run: | |
| ### What NOT to do: | |
| - Do NOT attempt to run `uvx openrag` using `execute_command` with user interaction expected | |
| - Do NOT try to use background processes for interactive commands | |
| - Do NOT assume you can send input to an already-running interactive terminal | |
| ### What TO do: | |
| 1. **Explicitly instruct the user** to open a NEW terminal window/tab OUTSIDE of Bob Shell | |
| **This agent cannot control interactive terminal applications that require user input.** | |
| When the installation reaches the point where `uvx openrag` needs to be run: | |
| ### What NOT to do: | |
| - Do NOT attempt to run `uvx openrag` through the agent if user interaction is expected | |
| - Do NOT try to use background processes for interactive commands | |
| - Do NOT assume the agent can send input to an already-running interactive terminal | |
| ### What TO do: | |
| 1. **Explicitly instruct the user** to open a NEW terminal window/tab and run the interactive command locally |
The openrag_install and openrag_sdk SKILL.md files are to be used as SKILLs for agents. The openrag_install skill will look for any existing local OpenRAG installs before attempting to install. If none are detected it will perform a systems check for all of the supporting tech stack like docker, correct python version, etc... From there it will use "uvx openrag" as the base install method and walk users through the options to get them going quickly.
The openrag_sdk skill includes information on the various methods available to the SDK and MCP. It helps users to integrate their application with OpenRAG using the SDKs and points to the official SDK locations.