diff --git a/haiku_rag_slim/haiku/rag/app.py b/haiku_rag_slim/haiku/rag/app.py index 45aa4220..0c69fa92 100644 --- a/haiku_rag_slim/haiku/rag/app.py +++ b/haiku_rag_slim/haiku/rag/app.py @@ -443,14 +443,12 @@ class HaikuRAGApp: # pragma: no cover async def ask( self, question: str, - cite: bool = False, filter: str | None = None, ): """Ask a question using the RAG system. Args: question: The question to ask - cite: Include citations in the answer filter: SQL WHERE clause to filter documents """ async with HaikuRAG( @@ -465,9 +463,8 @@ class HaikuRAGApp: # pragma: no cover self.console.print() self.console.print("[bold green]Answer:[/bold green]") self.console.print(Markdown(answer)) - if cite and citations: - for renderable in format_citations_rich(citations): - self.console.print(renderable) + for renderable in format_citations_rich(citations): + self.console.print(renderable) async def analyze( self, diff --git a/haiku_rag_slim/haiku/rag/cli.py b/haiku_rag_slim/haiku/rag/cli.py index 985404bf..64e62b38 100644 --- a/haiku_rag_slim/haiku/rag/cli.py +++ b/haiku_rag_slim/haiku/rag/cli.py @@ -369,11 +369,6 @@ def ask( # pragma: no cover "--db", help="Path to the LanceDB database file", ), - cite: bool = typer.Option( - False, - "--cite", - help="Include citations in the response", - ), filter: str | None = typer.Option( None, "--filter", @@ -385,7 +380,6 @@ def ask( # pragma: no cover asyncio.run( app.ask( question=question, - cite=cite, filter=filter, ) ) diff --git a/haiku_rag_slim/haiku/rag/client/__init__.py b/haiku_rag_slim/haiku/rag/client/__init__.py index 537c5e18..842fb486 100644 --- a/haiku_rag_slim/haiku/rag/client/__init__.py +++ b/haiku_rag_slim/haiku/rag/client/__init__.py @@ -368,12 +368,11 @@ class HaikuRAG: async def ask( self, question: str, - system_prompt: str | None = None, filter: str | None = None, ) -> "tuple[str, list[Citation]]": from haiku.rag.client.agents import ask - return await ask(self, question, system_prompt, filter) + return await ask(self, question, filter) async def research( self, diff --git a/haiku_rag_slim/haiku/rag/client/agents.py b/haiku_rag_slim/haiku/rag/client/agents.py index 87ebc145..0db7210c 100644 --- a/haiku_rag_slim/haiku/rag/client/agents.py +++ b/haiku_rag_slim/haiku/rag/client/agents.py @@ -9,24 +9,32 @@ if TYPE_CHECKING: async def ask( client: "HaikuRAG", question: str, - system_prompt: str | None = None, filter: str | None = None, ) -> "tuple[str, list[Citation]]": - """Ask a question using the configured QA agent. + """Ask a question against the knowledge base via the rag skill. Args: client: The HaikuRAG client. question: The question to ask. - system_prompt: Optional custom system prompt for the QA agent. filter: SQL WHERE clause to filter documents. Returns: Tuple of (answer text, list of resolved citations). """ - from haiku.rag.agents.qa import get_qa_agent + from haiku.rag.skills.rag import RAGState, create_skill + from haiku.rag.utils import get_model + from haiku.skills import run_skill - qa_agent = get_qa_agent(client, config=client._config, system_prompt=system_prompt) - return await qa_agent.answer(question, filter=filter) + skill = create_skill(db_path=client.store.db_path, config=client._config) + state = RAGState(document_filter=filter) + model = get_model(client._config.qa.model, client._config) + answer, _, _ = await run_skill(model, skill, question, state=state) + citations = [ + state.citation_index[cid] + for cid in state.citations + if cid in state.citation_index + ] + return answer, citations async def research( diff --git a/tests/cassettes/test_client/test_client_ask.yaml b/tests/cassettes/test_client/test_client_ask.yaml index 88bd1d25..5921feaf 100644 --- a/tests/cassettes/test_client/test_client_ask.yaml +++ b/tests/cassettes/test_client/test_client_ask.yaml @@ -48,7 +48,7 @@ interactions: connection: - keep-alive content-length: - - '2666' + - '5583' content-type: - application/json host: @@ -57,58 +57,100 @@ interactions: parsed_body: messages: - content: |- - You are a knowledgeable assistant that answers questions using a document knowledge base. + You are a focused execution agent. Complete the following task using the skills and instructions provided. - Process: - 1. Call search_documents with relevant keywords from the question - 2. Review the results ordered by relevance - 3. If needed, perform follow-up searches with different keywords (max 3 total) - 4. Provide a concise answer based strictly on the retrieved content + ## Task - The search tool returns results like: - [chunk_abc123] [rank 1 of 5] - Source: "Document Title" > Section > Subsection - Type: paragraph - Content: - The actual text content here... + What is Python? - [chunk_def456] [rank 2 of 5] - Source: "Another Document" - Type: table - Content: - | Column 1 | Column 2 | - ... + ## Skill instructions + + # RAG + + You are a RAG assistant with access to a document knowledge base. + Use your tools to search and answer questions. Never make up information — always use tools to get facts from the knowledge base. + + ## Tools + + ### search + Search the knowledge base using hybrid search (vector + full-text). Returns ranked results with context-expanded content. Each result includes: - - chunk_id in brackets and rank position (rank 1 = most relevant) - - Source: document title and section hierarchy (when available) - - Type: content type like paragraph, table, code, list_item (when available) + - `chunk_id` in brackets and rank position (rank 1 = most relevant) + - Source: document title and section hierarchy + - Type: content type (paragraph, table, code, list_item, picture) - Content: the actual text - In your response, include the chunk IDs you used in cited_chunks. + When a result's Type is `picture`, the corresponding figure may also be attached to the tool response as an image alongside the text. Use the image directly to answer questions about figures, diagrams, charts, screenshots. - Guidelines: - - Base answers strictly on retrieved content - do not use external knowledge + ### list_documents + List available documents in the knowledge base. Use when the user wants to browse what's available. + + ### get_document + Retrieve a document by ID, title, or URI. Partial matches work. Use when the user wants the full content of a specific document. + + ### cite + Register the chunk IDs that ground your answer. Call this BEFORE writing your final answer, with the `chunk_id` values from search results that support each claim. Every answer that uses search results must be backed by `cite`. + + Use chunk_ids exactly as they appear in the search response — copy the full UUID verbatim. Do not abbreviate, paraphrase, or reconstruct chunk_ids from memory; the tool matches them as opaque strings. + + ## How to answer questions + + 1. Call `search` with relevant keywords from the question + 2. Review the results — they are ordered by relevance (rank 1 = best match) + 3. If needed, search again with different keywords (you have a limited number of searches) + 4. Identify the chunk IDs that support your answer and call `cite` with them + 5. Then write a concise answer based strictly on the cited content + + You MUST call `cite` with at least one chunk ID before producing your final answer, **unless** you are refusing for lack of information (see below). Answers without citations are considered ungrounded. + + ## Guidelines + + - Base answers strictly on retrieved content — do not use external knowledge - Use the Source and Type metadata to understand context - If multiple results are relevant, synthesize them coherently - - If information is insufficient, say: "I cannot find enough information in the knowledge base to answer this question." - - Be concise and direct - avoid elaboration unless asked - - Results are ordered by relevance, with rank 1 being most relevant + - Be concise and direct — avoid elaboration unless asked + - If the search tool tells you the search limit is reached, stop searching and answer with what you have + - If the retrieved documents do not directly address the question, say: "I cannot find enough information in the knowledge base to answer this question." Do not guess or infer from tangentially related content. In this refusal case do **not** call `cite` — there is nothing to cite. + - Do NOT include chunk IDs or UUIDs in your answer text — your answer should read naturally. Use the `cite` tool separately to register citations. + + ## When the user mentions a specific document + + If the user says "search in [doc]", "find in [doc]", or "answer from [doc]": + - Use `get_document` or `list_documents` first to identify the document + - Then search for the topic + + ## When search returns irrelevant results + + If your first search returns results that clearly don't match the question: + - Try one more search with different keywords + - If still irrelevant, report that the knowledge base doesn't contain relevant information + + ## Guidelines + + - Follow the skill instructions carefully + - Stay focused on the specific task described above + - Provide a clear, complete result role: system - content: What is Python? role: user model: gpt-oss - reasoning_effort: low - stream: false + reasoning_effort: high + stream: true + stream_options: + include_usage: true + temperature: 0.3 tool_choice: auto tools: - function: description: |- - Search the knowledge base for relevant documents. + Search the knowledge base using hybrid search (vector + full-text). - Returns results with chunk IDs and rank positions. - Reference results by their chunk_id in cited_chunks. - name: search_documents + Returns ranked results with content and metadata. When picture + content is in the result set and the driving skill model is + vision-capable, picture bytes are attached as ``BinaryContent`` + parts so the model sees figures alongside text. + name: search parameters: additionalProperties: false properties: @@ -117,71 +159,141 @@ interactions: - type: integer - type: 'null' default: null + description: Maximum number of results. query: + description: The search query. type: string required: - query type: object type: function - function: - description: Answer to a search query with chunk references. - name: final_result + description: List all documents in the knowledge base. + name: list_documents + parameters: + additionalProperties: false + properties: {} + type: object + type: function + - function: + description: Retrieve a document by ID, title, or URI. + name: get_document parameters: additionalProperties: false properties: - answer: - description: The answer to the question - type: string - cited_chunks: - description: IDs of chunks used to form the answer - items: - type: string - type: array - confidence: - default: 1.0 - description: Confidence score for this answer (0-1) - maximum: 1.0 - minimum: 0.0 - type: number query: - description: The question that was answered + description: Document ID, title, or URI to look up. type: string required: - query - - answer + type: object + type: function + - function: + description: |- + Register chunk IDs as citations for your answer. + + Call this after searching, with the chunk_id values from search + results that support your answer. + name: cite + parameters: + additionalProperties: false + properties: + chunk_ids: + description: List of chunk_id values from search results. + items: + type: string + type: array + required: + - chunk_ids type: object type: function uri: http://localhost:11434/v1/chat/completions response: + body: + string: |+ + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114310,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"We"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114310,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" need"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114310,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" to"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114310,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" answer"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":":"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" \""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"What"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" is"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" Python"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"?\""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" We"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" must"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" use"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" the"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" knowledge"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" base"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" We"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" need"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" to"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" search"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" Let's"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" search"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" for"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" \""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"Python"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"\""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" or"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" \""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"Python"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" programming"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" language"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"\""},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" etc"},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","tool_calls":[{"id":"call_c33pjm3l","index":0,"type":"function","function":{"name":"search","arguments":"{\"query\":\"Python programming language\",\"limit\":5}"}}]},"finish_reason":"tool_calls"}]} + + data: {"id":"chatcmpl-381","object":"chat.completion.chunk","created":1779114311,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[],"usage":{"prompt_tokens":1077,"completion_tokens":65,"total_tokens":1142}} + + data: [DONE] + headers: - content-length: - - '506' content-type: - - application/json - parsed_body: - choices: - - finish_reason: tool_calls - index: 0 - message: - content: '' - reasoning: Need to search for "What is Python". - role: assistant - tool_calls: - - function: - arguments: '{"limit":5,"query":"What is Python?"}' - name: search_documents - id: call_qr5c35xf - index: 0 - type: function - created: 1769001440 - id: chatcmpl-499 - model: gpt-oss - object: chat.completion - system_fingerprint: fp_ollama - usage: - completion_tokens: 40 - prompt_tokens: 545 - total_tokens: 585 + - text/event-stream + transfer-encoding: + - chunked status: code: 200 message: OK @@ -194,7 +306,7 @@ interactions: connection: - keep-alive content-length: - - '85' + - '97' content-type: - application/json host: @@ -203,7 +315,7 @@ interactions: parsed_body: encoding_format: base64 input: - - What is Python? + - Python programming language model: qwen3-embedding:4b uri: http://localhost:11434/v1/embeddings response: @@ -214,14 +326,14 @@ interactions: - chunked parsed_body: data: - - embedding: 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 + - embedding: ixhxN5NT6ry3uFG89HP5PC1fzrmSAqU8gjt3PcdND73/jp08q3D0vAidrT3cata8QgwIulv60rws5Sg8vimlO2DIRDyBY9q8lKAPvS8I+7u+hhe8A367vJ0x7TzN/wM9imSCvYlaKj1QPJC8ou2GvVc/pLwbyVA9ODooPaJayruceBE9DUZAu6Cpzzoa9/68kQuru8+Plzq90Pq85kHMvG+tLrxgi/M7L6ehPKp+/zxSaQC8TMcyvX6QATsYLJ28vhSMu93wrry1D7A4o4dhu+CLZrtRmJ+82pUZPdSMWjyv8208QtKmu4L33rxBSwu9yzkMuxkjDLtIFpW8p3UuvNn2x7tXf927w6h/PG+jI70M4CU8FII+vOyp6rsruIs93Abfu8O93DusvDy8XQmKvKuPhrsKhMg8cMrivKBhlTz3JE+81jN1u2Uzp7vLdwc9jSqdPGblEz37XVE8scNjvLSpHTsnHXY7gKasO33wort1RSu6Y0gYPJiFoLvMkL+7C5cju0pMSrx53cO8Fn+wuikrE7t5LHu8sbnDvO2D37pzqlQ5taIPu+lAArxPl4A8p4PdO1IzyzoU4hO76RHQuuhxbzxkMTk88QYAPOAPhDqukUe8IZUnPVWx9jtXtZk4xv/+uyFi2zzCfU88+zkNvaMJYjxlQpu8TvAlvJllATzTFhG9m6F3PM6osDvPykC8M/AXvJj0jbyWna88NGjiu+np0Lw9npu8eba+u8LxHTvXKkc6t4uHO3HqQTo96C08XxXdO8wXN73huOq8nTybPIYDhbx/g367Z0LAO/C8lLzMDjC6OD8zPICQUTo/Q5U8aY3kOpYASzzisdo7+fDyO2mSILwoP2i8WsouvD+XH7yznUK8QWbEO1D6hrz5UGa8zuTzuxVWI73zOKg8UNUqvDBHTLyTGSE8m5HXu0LhCbzsyhG8aqZ4u8Y1zrpRZNY7Q18QPJjUwrvWWmY8QqzlO1ty/bpK1Qu8K/ebu12QET0m3V08IhLju9HTQrsTTkg8/V/wO8NzCzz3u/G7HKdYusIDm7zlSiS8NMTpuzaRmDyadQo9b4eqPD34NjyLFZ28dqc3PB6Tuzwu/mA8U4MYvJww/juncym8eh1suZ5c3Ly4/Z+8FFZMvbKAsTur3y48itCIvJMUT7xxKYQ7UZ+KPEcPmLwXpAU8Pb4SO90nprqY0J68v4zTPDj3rLvNnyA8geAmPBjmD7wfw8s8KeFrPKONkrvNvOG7o51Bu3AgBrwP4Ke8V42yu1JHNbykqSW8hbYyvO+FEbxeg687alhJPM9a5boLdsG8wjUJvGeJQLx+zRY9tKSkvEk+hLvsph67ci7WPA2jdLxcKsw8DvGuu6reB7zUoVO9+ug7vOSeDjwI1pe8Dt/nPJM0JbylFu8756efuwGwprxAV6Q7D/wEvHYUUTzIhbY6bRluPXKQFbqeRqA7ZzYtujVXlbvbig+9AHlkPOvqwzwy7Vw8OuZbu8o4+Dgsu4s8ShdgvOvpAjxFWy07Ox29O344+zzisV27Dx4hvAiymjxCUXu7KpU/vSY42jsinZE6RCK0vKKT5DyGds066RUsO/kMFLyjocO8ub9wvAYAFzyPEb+6BI4Kva5EmTvDdZ+7gU3TuvYwGzyEAu67y+EqPIj2IrzYOyG87/tiPBt3hDsBwsy8ptVQvXUGhruEnZq6d24KvEMqh7y5naw808IxvdSSzrwLhBe9jVwUvS7oDr29H0w8MMdpuJ+HkLwYAHe829e+vFWCoDyMZCW9knVwu2Rghjwn0WK8jpp9vC0l6DxDOrY8lEWvO5HAIjigD288XNOgu6lwRr2NDVw8MaY5vIhSvzxBYYw8B3ExvGvQLLwfHBe9p6AiuhxMPLxOx2+8nGrquqYh1jykPsY6VuzWvOjAKTxN1u68cfcTvLgiLDw1PaC7g4GEPK67E7x3+148zQAFvUxMoLziQsU8Ztv9O+qpEjxtBYe9ux3MPNz3uTwED1u8X3OtO+ww/zz7jZu8NAR/PFdLFrtvuEc8VYhEu19RRrz1GgA8+AiwO/IQezskhQi8d+mGPOzzuLzcL447ur3puZkWDDzoBeI7UJxuPCdAqrwnMuI8FZSdO/XNgzxEpv68w4CbvLu0zbs2jWS8vCwUvWrEAr0mORk8jiftuwSePzxlQvo8w0C7vPGHbLstDOe7sxV8PJeJVzyY/s883n/lPKEIgDxBfQg8RecmvfH8yrw4WzU7b6cIO7mydbxNuBM8w3nKuuATpzyGt7I7vk7qO80udD0GSo28+XCrOaUmWDzq1Oa7AWq1PO3IBz3HSvC7Wd6HPCIPO72Jleo80oYGvcTfpbyC3+i7DdQLvP7a9TvB6nw8lC6Fu0eytzxV1vo8OsCbOsdU3jwyrOS8kxmzvMaMpLxjGxI8NjETvfEMNr1mcyo9mS0ZPOAKbTzWAhq873WoO2+/l72o8xg8g+64PFOKszxvQ6G7/eynvG3BQ7vgywk8NQ2ovKF/qjzLoyG9KrXvvASgXrxldvG7Z2GZO8MvH7uHv1E7TPyJPOO7ibzW+VW51dOyPPuaSzxMtG68PgucPKE5MLoKIRC8MIXiO8Ho7DwOoI+86jyBvDYVzzl8HjU7m3T9O/wS0rtNXuS6aNETPK/HnDwa/7s7341cu24yjzyNn7U7dOkNvH7xxDxcOQU8RfCjvPr2BjwHNCE9TGYMvTBKzTu8JV+8HDCIvFNP1zsJfqS7SFO4vMdGabxboSW8DigCPeM1GryU9ik7pcLbOyUyarzsJ4m8XKmiPLCcBbvlWFa9m7GdPEH+2DwwuX69P8xevTv8vbx37qe8nJyHPL5M6LyPITw8idQIvdDdjjzsxKY7s4RPO5IDwTsox2Y6J7U5vK/cujyYTRu7BBZGO6dfgDdthMU7OMyeuxRCOLwrd1y88+nhvAedozzSEU68CbfQPKc5mLy7o9u8l2VMPJ7EGbyKUhc9rxfPPNAcrDyaQn06MB9RO98+Brz3dfK7ryevu3L+1bwOrZ25NmPVPPrhSLzq7Ry8iRyBvNfQ5LuI3dU7J8zaPL5cc7yDJF+8lpn7utNmIbx79S460XzgPL1AbTx4OVy7uC2uu4ZVGbwqdvw8PeZ8vLtD1Lx3NUI7kiiNPDT52Dsf4y29QwnnOzotKrsUrZw8wrnMPBcNBbx/EQ69TtZ7PJXVwboM5au8OTEsPCgWkbz0DWQ8azvSPI8WKLwbSes8vD6Tu6QR7Dzm6rM6CCQIu946p7ybZBU9XYZYvPdeuDwSAwk9ZQifvFrBBTmwTws8GqbvukwmaryV9Oo7W3rxvDHAArxyeUG9d/YePbke8LxFQTk8U3GSPFsPVrz75ju8nKjuuwdAl7x3gbU8O7rAO6vKnLzZJAs9KRoKvb1t9TqxGeO8qzZNvEddu7wVqLA8MrPkPJJGKb0U+TM75CyvPPrBD737EIW8kjVWvc6h9DsAaS68MJCEOoXIfbzRysI8oISoPH1w9bzvVzM7+kWXPDmeejq8GNE8PcjJO20qr7n7jaa8hxBpPLiJhLyX/Tc8EEA0vaPUHzx5q6w8iel9OztAvzy/QiA8UmsrvK0bibwstXA8NBUNvS4IMj3wBpY849MPPUmh+LwbX9Y8S0iQPA20L7yYBM67MyugPKtXozz7wxy958ypPAajrrymcuA7ucWxvNgVrDoLG8k6U881PS+mqLwvAEm8QryjuyDqYLwFI/e7BJ1UvBZCOTosigi8450BvIwUd7wGBi67a/F1PaNljbzQp5I8r00Muyp/qrtw6/O8iDbivLrCQr3lYvY795yAO+oPuzyiasq7MRxovPla7btY6Aq8gdN0PKoBzDztJTe9p/KOvIdVdzzs3g+7zVK3upJb5DvPOQm98+6NPSUhET2t4v66LQObO5a+lztZCJu7s5sROjRd5zyu2408dyAUPCLYqTsoTvs88yC0u5p6uTzyx52760rbPNjlED0gaWm8Ca2VvJX2qLu26x49YPL+u9ksvTxH/tu7+7RkPNNWoTxqOD0985qMvCHYhrwWxZg8eP/vOzmPaLy3Mpu8VIAFPSsMJjuwAx28HIhDO7vYKD2q+/q8nFYivbEUJT0BE6m6IkUBPT/mqrzvOA27ummqvAQSuDz6Y5a88Xi1vCeb/jxdzaO8mkgBvc+vSLxRaYS8uMw1vA9nyzt8Iui8Arm1vPhqF717cCm9vTUUva7HvTwviYw8SVQUvTE+b7yQ+RE9H1qFu0/ZczyunMK7APVgveG6njwV0b66ILDCvCOgszswSjs2v8xBPOkIqjs+nf47Z6CvvLBvxbud38w8tpeAPMS9drtpvEy6sp3hPHiP8zsewHE8N0nvPFDDQb1NNGC7WFS5PMsLubz88fa6X0R7u50w+7uJGDu7gO4cvc76Fj1QG3q8lrBhvHu+KL3RA6w8Fw5hO9nVDjx5d3s8axPIvCWphLzNyoO7APgUvXLHVbtYiso74sycPBJPgjqLy/I6StxCu0SauTwwYL06Z4ITvJb7VTzxFis9x7pJvMHxBDvJwkQ9qXjVuyNOG7sjvIs8t6j9O1zNAz3WG7e728wqPF/W6LxRUC88YIV7vRlBBL0zebe5YB05PMxKeztbjM88k/gEvVQ0y7tpV2G8Vd1yPKAxmzzEzs+6bjbLOcbThLvnXLE8kuuRvJJXR7yvYgc9MfShvOnTXbtIGv68pwUYPeAUtLqStZ+8a+mQuk79Aj34rFw8VGWlvLeZbzz9Emm8kBMCPX7L7jzIsGs8ceySvDuxeDxwsCm9gH0guw/pJLxyYs28z8RePDoWiLuLnkE8L2F+PMe6bj3WEYE8aaNGPKhwObyDisc8oTSePBPbGzu+ZLw6LOwQPV2URzz2BYO8GHqau4huK7wYZUE9NlaRuzLdDL21Mga7kXcVvB+WqLy115s8SgT8PHdVY7veUlu9UzQRPXYnFb3j57i7V61WuCQ2LLqjXK88m38RvBaGojyA74y8nNlIvJLHgTr/6V07oBoKvY3nRrwoUAC8o1Pjula8MT1ERQU9/ftivLsBnbpqSb88GBStu/ZUMD1ll9m84hDUu14NsbwicIy6Vg81PAo+GDwxcii8aHqHvB6CILsBIIw6zRB1vBowt7wilaK869VdPDIBvTxUQYu8tU2IOrLZkjtOLhU7YPw+vFESA7zCdlg8TGasvH+rAL1z/5e7Bso5PYrYgDsgkEw8MXAlPUj3XjxSkaa8eTj+u4V3zruivYm6T8mMvC9Ur7zu+7w8DhOgvEQIsjxX/I28b+ygPGnZi7wllng8P1bFugSEIzu04so8gucRvbjYFj2l4cE8LKBYu951z7wcaco89GoLPbzdajx1Yyk9QoHGurj+AT2IrwI67Ko7PShQlryWCHS8Eh4rvHvqPDp2vS+81qotvWRUxrz0JaY73zMUvBCQ8TtX8bg7YfVEPKLGhbwyodK7X8lXvJ6CAT2IWDm8CyFfO6Dipbtzkx88btQWO371kDzUVhS3wGMjvC7evryVddw8s5pyuzqbjLylwYy8LAjRu86mc7soDOC6ng++Oxyjyzywtou8zQjwvEmpPLzt9IU8zv0XvGHlkbyRdkM9H3dpOyw4eT2shXi5j3N9vD6JnrwsyTQ8ehMPPRNwFT0JcxU8HulaO4XYGzxe4m481E4iPQps0zs00SS9mmwSvXBSATzmZ7K7bOH1vKp/Zru6ojA77Q83uw0jIrtCPpm7SbKFPGzTn7zDzSq8s6Q9uz7bjbv93fq7ZYi/vPMB8jxoIHS8DRDKvP3aLbzxJTY76ObVPNPdsDy1iZK8vGKtO8itFjyZrOg8XkYOvQtGPLyHLfA8VE6vvHVbvLzESYq8b+O3Of5IAL3LyGc6DwYcPAx0YzwTIGo8SqJJOOdTXDtFlRA7asYdPH41g7yydcI8VIkbu+X0hDxtHjg7hRAsPKBEdLyimrw6fdeTvK/niLykpAy9jVGkuozp4zuqQPQ8yi1MvFTt7zx59NC8X4mnOoizjbypwBC8asxNvPYj5LuK7T28hPuzOyIYEjzEsM+7xBsrPQv0XT0zUB48f5gGvLTOJ7yKNHQ8SKebO8cDTbv9fog5b6IyN56LaLz6uMo8WeI0vQNJPTyng548LFZPu2PMfbu/Rzu6WrS3PKwnCTusSJO7MssiPMnvKD0hL3K7BX2gPGFJqjxy9/q8LN88PFau7Twe/+o8QX1UvbPqIj0UDHk8gjzcO5ul0bu6l3E8oB7KvFmGCr08fCQ8cKHFPL4QELnbrHo8w/xiPBKMejwsNY48NWDTvMi/AD2DVO47scSXPMkTKbtN2Eu8bXM3POvZjbuQSJk7vR4mvLyCuLuLNOo847jPOyLvBLqZ/lA8EAYbu/C6njvhW+E47pFVvW0iEb3HVsW7sBYTvNuUAb2QLCA8NBEKPDzUSDwpWdC8LJUmvdFHijsLTzi8dxHkuQVDF7yQJk881Q5WumCFhTwGq4C8AhVjO1yOJ7oXVxe9R2kJPQyei7wo0KI8yFtFvBU2XzxaReO8COUfu/3yybrEPK+8LESeO+I85TqItkw8vLKjO3s/9zuceBg9A3KiPIEmpzzhcu07XaKDvN/7RDxMPzA9VrMoPZeyxLxEDVg7x3yLPIoedTyvjTm6oFocPBJyLbyeJWE8SG5FvLKq+7zOETa9PYZ9O5KdFjzv2Vk8nL+7O9omJLxheRU9nvfzvIlWRjxtUyI8Mx72vBG4K72tFmC8s9ABvPeM7jpenYC8r6dlvM+KaDwZ5IO8Xg+HPEKNGzxi6aw8ixOlPHaewjzNg/m8KR35vMsjhrw48sm8MbyEO1npYrw3gwG9ydkKu7ocsjx4vYq8GIoivI1Vm7xrmR69q+PrPCJKL7yyuw69bduNO5Oh2jkfNhS88rrNu97mML1qQ4q7ZXydPFuHJTw0m+u8Q87UvPW067tCOvq7P3c0PPJ5przG3hE8AUO6vF/uNz3GF6y8HL4DvQqM/jwKFoY8WO/Nu/3WTryBety6Zl4APe6fSbwl+/C6OD/svOhPfrz/olS7uCa5PM5pTLzGvqo8KnEiPXAhazzvlqS8w+KVvI2jkDwnG327mhf/ux51LLyKsMY6LJ/gu1YqQz2D/wq8rEKludPiqjz3OxE9MkpMPKS6gzs8n7q8Dxp+PG09Cr1gG6o8x4ICPNJnTDryaoq7Uf4OPLmnuDxeNt45ZgCevEaZ0DyOSqY8p2UXPWYPBD1B61U8s0C+u5b0SzzZvwg8nXbAu0ygnLxeTGi8isevPKIaiTxzChq9vndYO6VfVT3Ae+o7dCS4vPnQxjyLhHc7c/AqPYlf7bucbme7IWqQPKlmijz5m7M8sPpHPbdw/DtFbg+9bVeIPCx2gbpE+KE894wuvOBgBzxbOjo9+UpMvHGGDzw2LcA8zgIZPX/CubrCiMc7LDtJukkFCD1PkjA8TlWRvFn5drwggYs7zyjZuwql3btXmIq6fg6PvAYPmToNI8o8ldqiPPlhCrwyDzg8zhZiO/gJsLzsjgO9a5uMO4WNFD2EUha9zvhkuwZmxTx7a9k8G/IZPQfAOrwdQ4u6+lmmvBadF7vhk/063kf0Oy4Grjs5dQQ8BHqTvMc5qjzS7rw87mvpuzMAMzwngPU5KeNHPEaicLxBg2S8fcCOvB+YhDxqm+Y8J3WXPDkKfjxgV+U7BfhkO6gNFLxR0vw8yoEfvA3iWDt5mIw8T/LZOlMkYbjMDK48qZENPRYEmrsRxoq7YNgDPZYdlTzCvSg8OwreuwW6GzxTvNC6LyFKugirLL1twwO95NStPCtdqrx2GtU8S2aYPP51H73TFTw8nFIyu7lrgLt7zCm8bSfWvENJmzy6tse7QX45Or/Q77zLL688J56lO0XbB712gsy7gufrvNx9xzxgYDy8mSS7PPo1IrtICWO9ZhFkvA9pT7ymDYu6W/LuO1pXWzyW+K87z8mpvGm/SzxUI6A887uFPH42XLyQniw8tY8Uvf0HszyyauW8H6SxPCNiALw1b566CNuYvG7rELk60U+7TpNGO5Ko3rmkAJ074iulPEC7Qbunhn27oByquts/fLzXPMO8nkVvvDIOiTw5AOy861lpvFlIRDwRzgA8XhXVvOiXrbwsSHi8d4RhPFI6Sb24Mew7J5n9uhlTproU04q7CT9/PDJnHb1HeDu6m9d6uvAQarwJnhI8pL/Pul7wZjz7SkY8LgXIuth6hDzk8xw8HyLNPE6HwTtbQM47y89rvADCYTwz4tA8j0mPO4EtgrtVFQQ7CtTqvDN3azzNNo+7XKAgvJpEijxdfqg8HDhkPNp83Dx3IZM8gMTWvGrUFz3Ke+i8SjOoPBQKvLxPuco4YGuqvGZPFTp3coa82/ChvNiTAr0dEbI8BXvqO4d8FTlj03S8O77ZPNvNkLv3DPK8gZ+3OqPogby+lM255KLjuw+DXzyFW/C7aECZPKXCoDxeCQ08LddzPC34SjswW7y817Oruz1OhTv6QL67rn6aPIbYqDuefCu9brGQO9wvVz1VYcs86HePPJ6kzDsR/Co82sdMPESxxDwU+0a8cyrTvKX/qztfWZu8albbuy909DuOcDY72rGsPEi3lzy2w5U85j5oPK1GDLzgQn+7oB4GPTwaljw0F2E8U2RJPFZIVbl2IZ68+MYwve3G2bsWtes8DELpPNXWDrzF7/s60maQPHiDST0k2Va8YeDcO4Lp/rwFnoC7HFmJPNUIeLyjCs48yqpCuxMWjrxFpcA8yVmyu+rXTDyKTSe9CAFBO6gsrjsCpRA86V0xOxykbjxBgOy7QAZRPFxr77yOOG+6gTuNPNToxTzF34E8iAwUvK5ISLt/vhs7yLD0vEEqJrsav2m8tsgRPb/Iv7yxAL683UXAO9r1hjsLxYu8vmTIvNACgLxJtxK8Cv+dO0RoLLx4u/i72WXqOhtl2zwqyoa9WmY3u/z4XDkGCD27lAGPvFfNgrzYa8y7bVBRO7ukADzLJrO44m8Ju8OxtjxPmI08u1xwPIewmbwNt408He5YvKuCWjwRtpa7R3TAu6OqvTsrfZq7HH9ZO5qprTxP7xA6/5HHOxK+tLoXB3y8riKEPEIrLjxMRBS9adf+vKP3gr1LcM88ikieu6nDNbx18cs7MZobvT7zHzuoxRI8x43yOztV1Dzoa4w7AP/9PEOJLzuVXOo7mAjxvJDagDyXdGc7/SelvDxjCD08GAC6RDZMPPcX8TxBNUM7LeEvvNAjFD1B2oG8wsBoO+VaELsR03y84yKTvPThXbooYQ07mTLFu7Ofhzy6+828viA+u3OMjTziQj482Ly/vGKw5jxfmbI8HzEDPADMqDmLRe48LXW0usVXZLzbV4g7BLqKPJ0OdryyP047Sd+kvDCrWzykQKk8mCYTvfoNKL3/Iji8p0/EuyVKUTxuRDe8zQ+2O6hSQjz/nGO7xQPBvLHzY7zmzw87WIUEvM9C2TtfEZO8PDBBPKyQjrhNB268Rew6u7M19jtfsTa8UCosPIbIyTy+HuE7hWaXO6A+GDwjFSs9+WbMPIkgVjwm8c28miz/O+IQEzyia4y87GW8O6b6sToiG7O8q82aPLFPgrzZQrc8cJTGvLu3x7yPPs463h7ku/bC8jwCtWe7rY2zO2Qxrro5TXm8i1YQvTlmfjzp9Hq81ndGvNeNgbzJ5No76tMNPE+5YDvYYBI94p62u5gtI7wptLi8MtYHvBRTvjqvV3e8l5AdvT9PDr27Spo7AEwtuwGA0rwnFVY8f3Q2vJVyNzzPrt+6m5ziu5E92DvvTmo6k32iun1bLL3/lUY7dTuhutQ6uTyjy9q7srRtvMNdJTtDLwg8ausRvEBKc7xALCk8a8WWvCMFuDzkP7I8jyFlPEekTbzkkDu8WwCavCwUXzzsblK88mZiup8t67v5L/k7GFKBPCYKyLyL5/C7KdBhPOnY3TsRJCg8G8yLvF3UVryv/qc8mdVHu4gbJrwWVHS8Mi1ovFHKJDoDkqw83o0uPHVv47waQeA8H698vHGd2ryXPI27FFuEPEfnUzyGLFq7MuSWPPiKuTu/+EC7bA4TPEAIErxGRTQ6NRKHujQWHz2U7Sg7quBgPOjCKTzWibA65i8NPS65krxLHQW79pzgPOk7VzxrNJ+87/eRu/lA9bssIIG8oJh8vMTIxrq2etG8jIV0vDv/o7xVSp47TGj/PCp5hDyGgt48Wu5Ju54wGT3zxxI9SjdQvO3VFz0cwtG8wlsZPGmEYLz2du08Q+jju4cdALss0DI9Jg7QuxbQkrwiQgQ8lK/PPAv2dDygCb47OlkVPb2NtDyHrUw8gmu7O1oXazyODVY84QiQPL8hhjwP9PK8d7/Ju3a6rrzwkYQ86sOHPP/03bqjo0c8wLWbPBH4wTy8opW8EnkaORWm+ry15Vu8Ma3APA58bjwmIBU5kuNUPBLCOTpc6Q487TlfPCPB3Dwhej4829j9O72k27wgRq+8rqtuvOF0Zjx2J668wrvhPGeTarxgXEg56YEjvKy7Kb0cIiK9ltPcO0xvLbje0js8ukl4O0fbJ7wbW8a8i2eNO4fLxzt5TMS8Ip1uPB9iCj2HJfc7u/jqPKhHjrsIM9G7LiyEPIFk0zy4+Lq730+DPBHrB7t7RMY8iDu2vCe57TvMVgY91wcJvFQtqjyOIZ47OgE1PdbkDj0Z2Zw89HzSuqrP/LwRbKC8qFUlPGxnibx4af686/M7OwIRTr1LDuq78RZZvJdxNjqrtWu7S/12vAoOrzz//vs7vUsAvbjE6DucJDa7BSD0O8uGiryOoiW8PZHcu/0KGDylYyY9fNaMPKdPV7yvIYG8oyQmvPk9ebxOlAy8QU3UPJjYEDwiTX+8kP4lvI72gjro74W8I1IwvNlYYrwIOMI7QMAaPcLmvzw/gj48skA1PVNbhbxRaY86UpYRPdUCrLyct1g8qzgTvVAiCD2kOKS8t5eBOhntSDw9UyG9S/30vJImRrwA43S8uiwcPaoAGb3AkbW8MNB8PJ7gUbxoAtg51/oLO0laHLzuZbY8TtQ5vVjpuDsPkuK8ibdpvNxKj7vLhCI8LZrPvJTROzoWZi+85kv/vATTOjzVgLo66buMPBjSgjzM3M+8WK8RPM3svrzpOUU84BF1PAHGL7yueHm7+XfNPBfgCrzu7A08nIsoPYrjnjxG1PO7ssP0u0qfAj1dWaa807MIPLCWBbvLhSe6vgaGu8CRiDyt4Ic8hNKoPFjhljuohYm8aESsPAT+Mb1eO4i8ihO8vEQqHLxTJCQ6awByO2JZEjwqg0G9C1aNvBMuvDugvgA97Fn0vNKkpLwC+B08WmGaPHFDq7ysHD877/COut0lEDzvPz48Wa3Hu6oeoLwKFXa8NoeHvGO69zvqcum8W7TAPM2mlzug4A88r+90PEN2KTx7ltC8JAJ7PMMujzy20DY7wl7/O7KUZTwpOYg8tMgjPbeomjxhgXw8RV/YPG1FEb1AvLu8fTpOu4GhabyrfQg8NgaLPPZbgLvnstO7poGou71eQDstXC07IJe8uXm+qrloo/e8nolmPBfqTLxeM/o7b3GCvKRVhrswuAW9wweQPKfqdzx/5R+61tvovDT8U7unEh69ZddRPN8H6Lpn2/s7rd1pvDNu37x0c049azjSPODWeTxsehe7wadEPL1w3TwtZQk9wkKTPPdyhzzn0SQ8VzSJvErl5Dv+5aO7GnV/vOTB2Tycx6O8RT7BOgPpCL1omts7Z79UvHU4bbv3Olc6TfbNO5JQLbpcnVa9LH8TOmZaPTwlD7q8lHr+uTO6A70DP6I8iTDpvN58Jj0msP67c/IPvfbp7ru5NBq93jHFPDQjmzs3R5U8U/mOu3ajXLmJG/W74EsVPXNA9bqk3QS8c80qvUGMQjwlRJw71y7WPJUUQLwi+u88Bbc0PNJA2Tvwr688NL8CvCtOpLv3/2i856QhO8GJ3rypgEq9h1uDvGrfqLz3zJs8TAnSO+/6hzxHMZm8ksAHvc6WjzuyoPo7mD5GvKkJgjy8ETE7j1xfvNtPFLzlsrc7ybNHvBjUeTxJySm8XUDHPE1YgbwLP507qku4O9z9DDyll3y9tNkGO82yxrsEEY+7L/7APAiUqrsNrY48tE/kOZpHWTt2wSu8+HtiPNP+FLwGSVA7y1AgPCefybwdvvE8uyoXvXVrfbzWREY7rfKavO4BUDxUQR08jU7aPPKfLrzLEGO8Ky6zvC8HPzmbn6W83UUjvf9DET3jv8w6E/+GPNqRljtUKwe8TJdQOjprlDzClRo6hKk3vK5oaTxR/EA8l3LbOxH+rrz8qOu7NEvjuuH5ZbyLeOy72uZDvDa8Vb2Hv4g87w9dPXToQj2vL1g8YWDHvPCjA70ypnY8wBf4OV3nT7vQGwa7u0nZurDN2rvDvWi8Ay9tvGb5bDyqP586b02uvJyMzTonH3O6UJyLvCcmeTv+cQk8XxqiO+8GOztHWe+63jgBvL6YkrwMl+28gOEfPE1MjTuhR287UGviPFnEEzzwxbC8m+8NvFNQATwOA2o7mK1WvB4ag7x6vlC8cNKPO0ebqrzJ/3C8le4APCPfCLwESCw8Jy0avDZK1TypcY284c3zu6aaIb0xdic8qOM3vGVusTxoae+7B8kNvbLdqDxvd4a8u/PwPDJ8prwAvtk82BKougmAi7yF9WU8UPJCPS8UAj3UuQY6rIxFvNVvpDvBc2k8rR0eveuaXzvq/we9Fc7wOvIB4bzEOZI8ohOoPG8VkryOSjg98OwFPQZQaDzBac48JV9vu+Y6mLsb4Qe7IX7EPOfIC72wAVY8TO2JPFrjI7r41Cs8uHnYuwQsmzsBowk8dpvXuWWlcLwiaQ664iMDvaerLTu/RTg85AUGPKuMw7t/LXM8zH8bvEkttTzKXbg8+l61uW1+57toACM9KYisO7igRL0mp3A79MH9Ow3eHzxHsiS9uXyfPCiHjLupg4o8zWoyO2BE07i0YrK8mfHaujQg07rKyp67hNuBvMbah7sQzW+8wCbJOwCyvDw8iba804USvDLM8rxBfyU8/62tOqB8H7yIQnC7jLRHvEurQjxXpD28qQ/5POnzOjzYHiK8eSRIO2FzYjv6P6i7s+WivPK4HTwzpNE8rHYjPRHjTTzB0ku7Jf9qO1DairwvWJO89MLxO9jv+zzllZA8GuEWvOZZSDz5/kC8rLG6PMDewzwigZq8m4chu9W9iTuljxA8tVJVvI9ok7wPjA88qpYUPDIUlLywl4+8EemEO4mdrbyQTzy9zbeGPL0vmLtpY5M8Z3ERPI5GtDxxe8s7n4cNvD/fz7tiZ668hVabPBE1x7zVr2A8aBPJOyWMG7xgiZc62E8dO6TdRTw+h0a8v8MBPKPsiruIQqK8Qy1OPPXX3br1rKw70hhhu9Dm9DyMNIw6OIgAPIaxKTz+rLg8eexQPKqlhTwLrSk8irLxO+vCMbydQpi50A0uPY3PzTsEHco8Qnjzuuqptztb3407P8beO6tgdruFgGM80kzkOw4bWjzdLg47ci/Lu7a+t7wv2CC8KQfCu95XUTx5XGw8rLYIvXLwjrtR+da7F1GhvBWhL7tJ0vY76qR7vGJEcjwinec70j62PKnMHzxr86e8x0MWPETWLrxYyTk8eFDTOw== index: 0 object: embedding model: qwen3-embedding:4b object: list usage: - prompt_tokens: 5 - total_tokens: 5 + prompt_tokens: 4 + total_tokens: 4 status: code: 200 message: OK @@ -234,7 +346,7 @@ interactions: connection: - keep-alive content-length: - - '3090' + - '6126' content-type: - application/json host: @@ -243,76 +355,117 @@ interactions: parsed_body: messages: - content: |- - You are a knowledgeable assistant that answers questions using a document knowledge base. + You are a focused execution agent. Complete the following task using the skills and instructions provided. - Process: - 1. Call search_documents with relevant keywords from the question - 2. Review the results ordered by relevance - 3. If needed, perform follow-up searches with different keywords (max 3 total) - 4. Provide a concise answer based strictly on the retrieved content + ## Task - The search tool returns results like: - [chunk_abc123] [rank 1 of 5] - Source: "Document Title" > Section > Subsection - Type: paragraph - Content: - The actual text content here... + What is Python? - [chunk_def456] [rank 2 of 5] - Source: "Another Document" - Type: table - Content: - | Column 1 | Column 2 | - ... + ## Skill instructions + + # RAG + + You are a RAG assistant with access to a document knowledge base. + Use your tools to search and answer questions. Never make up information — always use tools to get facts from the knowledge base. + + ## Tools + + ### search + Search the knowledge base using hybrid search (vector + full-text). Returns ranked results with context-expanded content. Each result includes: - - chunk_id in brackets and rank position (rank 1 = most relevant) - - Source: document title and section hierarchy (when available) - - Type: content type like paragraph, table, code, list_item (when available) + - `chunk_id` in brackets and rank position (rank 1 = most relevant) + - Source: document title and section hierarchy + - Type: content type (paragraph, table, code, list_item, picture) - Content: the actual text - In your response, include the chunk IDs you used in cited_chunks. + When a result's Type is `picture`, the corresponding figure may also be attached to the tool response as an image alongside the text. Use the image directly to answer questions about figures, diagrams, charts, screenshots. - Guidelines: - - Base answers strictly on retrieved content - do not use external knowledge + ### list_documents + List available documents in the knowledge base. Use when the user wants to browse what's available. + + ### get_document + Retrieve a document by ID, title, or URI. Partial matches work. Use when the user wants the full content of a specific document. + + ### cite + Register the chunk IDs that ground your answer. Call this BEFORE writing your final answer, with the `chunk_id` values from search results that support each claim. Every answer that uses search results must be backed by `cite`. + + Use chunk_ids exactly as they appear in the search response — copy the full UUID verbatim. Do not abbreviate, paraphrase, or reconstruct chunk_ids from memory; the tool matches them as opaque strings. + + ## How to answer questions + + 1. Call `search` with relevant keywords from the question + 2. Review the results — they are ordered by relevance (rank 1 = best match) + 3. If needed, search again with different keywords (you have a limited number of searches) + 4. Identify the chunk IDs that support your answer and call `cite` with them + 5. Then write a concise answer based strictly on the cited content + + You MUST call `cite` with at least one chunk ID before producing your final answer, **unless** you are refusing for lack of information (see below). Answers without citations are considered ungrounded. + + ## Guidelines + + - Base answers strictly on retrieved content — do not use external knowledge - Use the Source and Type metadata to understand context - If multiple results are relevant, synthesize them coherently - - If information is insufficient, say: "I cannot find enough information in the knowledge base to answer this question." - - Be concise and direct - avoid elaboration unless asked - - Results are ordered by relevance, with rank 1 being most relevant + - Be concise and direct — avoid elaboration unless asked + - If the search tool tells you the search limit is reached, stop searching and answer with what you have + - If the retrieved documents do not directly address the question, say: "I cannot find enough information in the knowledge base to answer this question." Do not guess or infer from tangentially related content. In this refusal case do **not** call `cite` — there is nothing to cite. + - Do NOT include chunk IDs or UUIDs in your answer text — your answer should read naturally. Use the `cite` tool separately to register citations. + + ## When the user mentions a specific document + + If the user says "search in [doc]", "find in [doc]", or "answer from [doc]": + - Use `get_document` or `list_documents` first to identify the document + - Then search for the topic + + ## When search returns irrelevant results + + If your first search returns results that clearly don't match the question: + - Try one more search with different keywords + - If still irrelevant, report that the knowledge base doesn't contain relevant information + + ## Guidelines + + - Follow the skill instructions carefully + - Stay focused on the specific task described above + - Provide a clear, complete result role: system - content: What is Python? role: user - - content: |- - - Need to search for "What is Python". - + - content: null + reasoning: 'We need to answer: "What is Python?" We must use the knowledge base. We need to search. Let''s search + for "Python" or "Python programming language" etc.' role: assistant tool_calls: - function: - arguments: '{"limit":5,"query":"What is Python?"}' - name: search_documents - id: call_qr5c35xf + arguments: '{"query":"Python programming language","limit":5}' + name: search + id: call_c33pjm3l type: function - content: |- - [36ec1231-b2f5-4295-bad7-9045e947d0a0] [rank 1 of 1] + [ae8a228f-c5f8-43bd-9dbd-582b2e5e27a5] [rank 1 of 1] Type: text Content: Python is a high-level programming language. role: tool - tool_call_id: call_qr5c35xf + tool_call_id: call_c33pjm3l model: gpt-oss - reasoning_effort: low - stream: false + reasoning_effort: high + stream: true + stream_options: + include_usage: true + temperature: 0.3 tool_choice: auto tools: - function: description: |- - Search the knowledge base for relevant documents. + Search the knowledge base using hybrid search (vector + full-text). - Returns results with chunk IDs and rank positions. - Reference results by their chunk_id in cited_chunks. - name: search_documents + Returns ranked results with content and metadata. When picture + content is in the result set and the driving skill model is + vision-capable, picture bytes are attached as ``BinaryContent`` + parts so the model sees figures alongside text. + name: search parameters: additionalProperties: false properties: @@ -321,64 +474,177 @@ interactions: - type: integer - type: 'null' default: null + description: Maximum number of results. query: + description: The search query. type: string required: - query type: object type: function - function: - description: Answer to a search query with chunk references. - name: final_result + description: List all documents in the knowledge base. + name: list_documents + parameters: + additionalProperties: false + properties: {} + type: object + type: function + - function: + description: Retrieve a document by ID, title, or URI. + name: get_document parameters: additionalProperties: false properties: - answer: - description: The answer to the question - type: string - cited_chunks: - description: IDs of chunks used to form the answer - items: - type: string - type: array - confidence: - default: 1.0 - description: Confidence score for this answer (0-1) - maximum: 1.0 - minimum: 0.0 - type: number query: - description: The question that was answered + description: Document ID, title, or URI to look up. type: string required: - query - - answer + type: object + type: function + - function: + description: |- + Register chunk IDs as citations for your answer. + + Call this after searching, with the chunk_id values from search + results that support your answer. + name: cite + parameters: + additionalProperties: false + properties: + chunk_ids: + description: List of chunk_id values from search results. + items: + type: string + type: array + required: + - chunk_ids type: object type: function uri: http://localhost:11434/v1/chat/completions response: + body: + string: |+ + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"We"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" have"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" a"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" result"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":":"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" chunk"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"_id"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" ae"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"8"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"a"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"228"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"f"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"-c"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"5"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"f"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"8"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"-"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"43"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"bd"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"-"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"9"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"db"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"d"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"-"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"582"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"b"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"2"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"e"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"5"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"e"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"27"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"a"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"5"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":","},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" content"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":":"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" \""},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"Python"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" is"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" a"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" high"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"-level"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" programming"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" language"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":".\""},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" That"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" is"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" enough"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" We"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" need"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" to"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114312,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" cite"},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114313,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114313,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"","tool_calls":[{"id":"call_xtrtxg84","index":0,"type":"function","function":{"name":"cite","arguments":"{\"chunk_ids\":[\"ae8a228f-c5f8-43bd-9dbd-582b2e5e27a5\"]}"}}]},"finish_reason":"tool_calls"}]} + + data: {"id":"chatcmpl-713","object":"chat.completion.chunk","created":1779114313,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[],"usage":{"prompt_tokens":1202,"completion_tokens":105,"total_tokens":1307}} + + data: [DONE] + headers: - content-length: - - '454' content-type: - - application/json - parsed_body: - choices: - - finish_reason: stop - index: 0 - message: - content: '{"answer":"Python is a high-level programming language.","cited_chunks":["36ec1231-b2f5-4295-bad7-9045e947d0a0"],"confidence":1.0,"query":"What - is Python?"}' - role: assistant - created: 1769001442 - id: chatcmpl-258 - model: gpt-oss - object: chat.completion - system_fingerprint: fp_ollama - usage: - completion_tokens: 61 - prompt_tokens: 649 - total_tokens: 710 + - text/event-stream + transfer-encoding: + - chunked status: code: 200 message: OK @@ -391,7 +657,7 @@ interactions: connection: - keep-alive content-length: - - '3422' + - '6573' content-type: - application/json host: @@ -400,85 +666,130 @@ interactions: parsed_body: messages: - content: |- - You are a knowledgeable assistant that answers questions using a document knowledge base. + You are a focused execution agent. Complete the following task using the skills and instructions provided. - Process: - 1. Call search_documents with relevant keywords from the question - 2. Review the results ordered by relevance - 3. If needed, perform follow-up searches with different keywords (max 3 total) - 4. Provide a concise answer based strictly on the retrieved content + ## Task - The search tool returns results like: - [chunk_abc123] [rank 1 of 5] - Source: "Document Title" > Section > Subsection - Type: paragraph - Content: - The actual text content here... + What is Python? - [chunk_def456] [rank 2 of 5] - Source: "Another Document" - Type: table - Content: - | Column 1 | Column 2 | - ... + ## Skill instructions + + # RAG + + You are a RAG assistant with access to a document knowledge base. + Use your tools to search and answer questions. Never make up information — always use tools to get facts from the knowledge base. + + ## Tools + + ### search + Search the knowledge base using hybrid search (vector + full-text). Returns ranked results with context-expanded content. Each result includes: - - chunk_id in brackets and rank position (rank 1 = most relevant) - - Source: document title and section hierarchy (when available) - - Type: content type like paragraph, table, code, list_item (when available) + - `chunk_id` in brackets and rank position (rank 1 = most relevant) + - Source: document title and section hierarchy + - Type: content type (paragraph, table, code, list_item, picture) - Content: the actual text - In your response, include the chunk IDs you used in cited_chunks. + When a result's Type is `picture`, the corresponding figure may also be attached to the tool response as an image alongside the text. Use the image directly to answer questions about figures, diagrams, charts, screenshots. - Guidelines: - - Base answers strictly on retrieved content - do not use external knowledge + ### list_documents + List available documents in the knowledge base. Use when the user wants to browse what's available. + + ### get_document + Retrieve a document by ID, title, or URI. Partial matches work. Use when the user wants the full content of a specific document. + + ### cite + Register the chunk IDs that ground your answer. Call this BEFORE writing your final answer, with the `chunk_id` values from search results that support each claim. Every answer that uses search results must be backed by `cite`. + + Use chunk_ids exactly as they appear in the search response — copy the full UUID verbatim. Do not abbreviate, paraphrase, or reconstruct chunk_ids from memory; the tool matches them as opaque strings. + + ## How to answer questions + + 1. Call `search` with relevant keywords from the question + 2. Review the results — they are ordered by relevance (rank 1 = best match) + 3. If needed, search again with different keywords (you have a limited number of searches) + 4. Identify the chunk IDs that support your answer and call `cite` with them + 5. Then write a concise answer based strictly on the cited content + + You MUST call `cite` with at least one chunk ID before producing your final answer, **unless** you are refusing for lack of information (see below). Answers without citations are considered ungrounded. + + ## Guidelines + + - Base answers strictly on retrieved content — do not use external knowledge - Use the Source and Type metadata to understand context - If multiple results are relevant, synthesize them coherently - - If information is insufficient, say: "I cannot find enough information in the knowledge base to answer this question." - - Be concise and direct - avoid elaboration unless asked - - Results are ordered by relevance, with rank 1 being most relevant + - Be concise and direct — avoid elaboration unless asked + - If the search tool tells you the search limit is reached, stop searching and answer with what you have + - If the retrieved documents do not directly address the question, say: "I cannot find enough information in the knowledge base to answer this question." Do not guess or infer from tangentially related content. In this refusal case do **not** call `cite` — there is nothing to cite. + - Do NOT include chunk IDs or UUIDs in your answer text — your answer should read naturally. Use the `cite` tool separately to register citations. + + ## When the user mentions a specific document + + If the user says "search in [doc]", "find in [doc]", or "answer from [doc]": + - Use `get_document` or `list_documents` first to identify the document + - Then search for the topic + + ## When search returns irrelevant results + + If your first search returns results that clearly don't match the question: + - Try one more search with different keywords + - If still irrelevant, report that the knowledge base doesn't contain relevant information + + ## Guidelines + + - Follow the skill instructions carefully + - Stay focused on the specific task described above + - Provide a clear, complete result role: system - content: What is Python? role: user - - content: |- - - Need to search for "What is Python". - + - content: null + reasoning: 'We need to answer: "What is Python?" We must use the knowledge base. We need to search. Let''s search + for "Python" or "Python programming language" etc.' role: assistant tool_calls: - function: - arguments: '{"limit":5,"query":"What is Python?"}' - name: search_documents - id: call_qr5c35xf + arguments: '{"query":"Python programming language","limit":5}' + name: search + id: call_c33pjm3l type: function - content: |- - [36ec1231-b2f5-4295-bad7-9045e947d0a0] [rank 1 of 1] + [ae8a228f-c5f8-43bd-9dbd-582b2e5e27a5] [rank 1 of 1] Type: text Content: Python is a high-level programming language. role: tool - tool_call_id: call_qr5c35xf - - content: '{"answer":"Python is a high-level programming language.","cited_chunks":["36ec1231-b2f5-4295-bad7-9045e947d0a0"],"confidence":1.0,"query":"What - is Python?"}' + tool_call_id: call_c33pjm3l + - content: null + reasoning: 'We have a result: chunk_id ae8a228f-c5f8-43bd-9dbd-582b2e5e27a5, content: "Python is a high-level programming + language." That is enough. We need to cite.' role: assistant - - content: |- - Validation feedback: - Please include your response in a tool call. - - Fix the errors and try again. - role: user + tool_calls: + - function: + arguments: '{"chunk_ids":["ae8a228f-c5f8-43bd-9dbd-582b2e5e27a5"]}' + name: cite + id: call_xtrtxg84 + type: function + - content: Registered 1 citation(s). + role: tool + tool_call_id: call_xtrtxg84 model: gpt-oss - reasoning_effort: low - stream: false + reasoning_effort: high + stream: true + stream_options: + include_usage: true + temperature: 0.3 tool_choice: auto tools: - function: description: |- - Search the knowledge base for relevant documents. + Search the knowledge base using hybrid search (vector + full-text). - Returns results with chunk IDs and rank positions. - Reference results by their chunk_id in cited_chunks. - name: search_documents + Returns ranked results with content and metadata. When picture + content is in the result set and the driving skill model is + vision-capable, picture bytes are attached as ``BinaryContent`` + parts so the model sees figures alongside text. + name: search parameters: additionalProperties: false properties: @@ -487,73 +798,89 @@ interactions: - type: integer - type: 'null' default: null + description: Maximum number of results. query: + description: The search query. type: string required: - query type: object type: function - function: - description: Answer to a search query with chunk references. - name: final_result + description: List all documents in the knowledge base. + name: list_documents + parameters: + additionalProperties: false + properties: {} + type: object + type: function + - function: + description: Retrieve a document by ID, title, or URI. + name: get_document parameters: additionalProperties: false properties: - answer: - description: The answer to the question - type: string - cited_chunks: - description: IDs of chunks used to form the answer - items: - type: string - type: array - confidence: - default: 1.0 - description: Confidence score for this answer (0-1) - maximum: 1.0 - minimum: 0.0 - type: number query: - description: The question that was answered + description: Document ID, title, or URI to look up. type: string required: - query - - answer + type: object + type: function + - function: + description: |- + Register chunk IDs as citations for your answer. + + Call this after searching, with the chunk_id values from search + results that support your answer. + name: cite + parameters: + additionalProperties: false + properties: + chunk_ids: + description: List of chunk_id values from search results. + items: + type: string + type: array + required: + - chunk_ids type: object type: function uri: http://localhost:11434/v1/chat/completions response: + body: + string: |+ + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"Python"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":" is"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":" a"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":" high"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"‑"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"level"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":" programming"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":" language"},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":"."},"finish_reason":null}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":"stop"}]} + + data: {"id":"chatcmpl-985","object":"chat.completion.chunk","created":1779114314,"model":"gpt-oss","system_fingerprint":"fp_ollama","choices":[],"usage":{"prompt_tokens":1324,"completion_tokens":13,"total_tokens":1337}} + + data: [DONE] + headers: - content-length: - - '616' content-type: - - application/json - parsed_body: - choices: - - finish_reason: tool_calls - index: 0 - message: - content: '' - reasoning: Must use final_result tool. - role: assistant - tool_calls: - - function: - arguments: '{"answer":"Python is a high-level programming language.","cited_chunks":["36ec1231-b2f5-4295-bad7-9045e947d0a0"],"confidence":1,"query":"What - is Python?"}' - name: final_result - id: call_cjmyxq28 - index: 0 - type: function - created: 1769001443 - id: chatcmpl-594 - model: gpt-oss - object: chat.completion - system_fingerprint: fp_ollama - usage: - completion_tokens: 78 - prompt_tokens: 731 - total_tokens: 809 + - text/event-stream + transfer-encoding: + - chunked status: code: 200 message: OK version: 1 +...