You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Build agents that dynamically discover and load skills from the workspace at query time. Instead of hardcoding all capabilities, the agent receives a lightweight skill catalog, decides which skill is relevant, and requests the full skill content from the client - keeping the initial context small and enabling an open-ended set of behaviors.
18
+
Build agents that dynamically discover and load skills from the workspace at query time. The agent receives a lightweight skill catalog, decides which skill is relevant, and requests the full content from the client. This keeps the initial context small and supports an open-ended set of behaviors without hardcoding capabilities.
19
19
20
20
Reference implementation in [this GitHub repository](https://github.com/OpenBB-finance/agents-for-openbb/tree/main/41-vanilla-agent-dynamic-skill).
21
21
@@ -33,14 +33,14 @@ Agent being able to select the right skill:
33
33
34
34
## Architecture
35
35
36
-
Dynamic skill loading follows a two-step handshake between the agent and the OpenBB workspace:
36
+
Dynamic skill loading follows a two-step exchange between the agent and the OpenBB workspace:
37
37
38
-
1. The workspace sends the request with a `skills_catalog` — a lightweight list of available skills (slug + description).
38
+
1. The workspace sends the request with a `skills_catalog`, a lightweight list of available skills (slug + description).
39
39
2. The agent decides if a skill is relevant and emits a `copilotFunctionCall` event for `get_skill_content` with the chosen slug.
40
40
3. The workspace loads the full skill content and sends it back as a tool result containing the skill's markdown instructions.
41
41
4. The agent incorporates those instructions into its system prompt and answers the user.
42
42
43
-
This keeps the initial payload small and lets the agent pull in detailed instructions only when needed.
43
+
Only the catalog is sent up front, so detailed instructions are pulled in only when needed.
44
44
45
45
`agents.json` configuration:
46
46
@@ -66,9 +66,9 @@ return JSONResponse(content={
66
66
67
67
The workspace sends a `skills_catalog` array with each request. Each entry contains:
68
68
69
-
-**`slug`** — unique identifier for the skill (e.g. `"financial-analysis"`)
70
-
-**`description`** — short description of what the skill does
71
-
-**`updatedAt`** — timestamp of last update
69
+
-**`slug`**: unique identifier for the skill (e.g. `"financial-analysis"`)
70
+
-**`description`**: short description of what the skill does
71
+
-**`updatedAt`**: timestamp of last update
72
72
73
73
```json
74
74
{
@@ -93,19 +93,21 @@ The workspace sends a `skills_catalog` array with each request. Each entry conta
93
93
94
94
### OpenBB AI SDK
95
95
96
-
-`QueryRequest`: Base request model — `SkillQueryRequest` extends it with `skills_catalog` and `selected_skills` fields
97
-
-`message_chunk(text)`: Streams response content back to the user
98
-
-`FunctionCallSSE` / `FunctionCallSSEData`: Emits a `copilotFunctionCall` event to request skill content from the workspace
99
-
- Skill content arrives as a tool message with `function: "get_skill_content"`
96
+
The SDK provides the building blocks for skill-aware agents:
97
+
98
+
-**`QueryRequest`** is the base request model. `SkillQueryRequest` extends it with `skills_catalog` and `selected_skills` fields.
99
+
-**`message_chunk(text)`** streams response content back to the user.
100
+
-**`FunctionCallSSE`** / **`FunctionCallSSEData`** emit a `copilotFunctionCall` event to request skill content from the workspace.
101
+
- Skill content arrives as a tool message with `function: "get_skill_content"`.
100
102
101
103
## Core logic
102
104
103
105
### Request model
104
106
105
107
The request model extends `QueryRequest` with two skill-specific fields:
106
108
107
-
-**`skills_catalog`** — the menu of available skills (slug + description). The LLM sees this to decide which skill to request.
108
-
-**`selected_skills`** — the full skill content, already loaded. Present when the client pre-loaded a skill (e.g. user typed `/skill-name`) or after the LLM requested one and the client fetched it.
109
+
-`skills_catalog` carries the list of available skills (slug + description) so the LLM can decide which skill to request.
110
+
-`selected_skills` holds the full skill content when it has already been loaded, either because the client pre-loaded it (e.g. user typed `/skill-name`) or because the LLM requested one and the client fetched it.
109
111
110
112
```python
111
113
from typing import Literal
@@ -133,7 +135,7 @@ class SkillQueryRequest(QueryRequest):
133
135
134
136
### Extracting the active skill
135
137
136
-
The `_get_active_skill` helper checks whether a skill has already been loaded — either via `selected_skills` (client pre-loaded) or from the last tool message (LLM requested it, client fetched it):
138
+
The `_get_active_skill` helper checks whether a skill has already been loaded, either via `selected_skills` (client pre-loaded) or from the last tool message (LLM requested it, client fetched it):
The endpoint builds a system prompt that adapts based on whether a skill is active, constructs the OpenAI function definition inline when skill loading is allowed, and streams the response:
167
+
The endpoint builds a system prompt that changes depending on skill state, constructs the OpenAI function definition inline when skill loading is allowed, and streams the response:
166
168
167
169
```python
168
170
@app.post("/v1/query")
@@ -381,5 +383,5 @@ Rules for skill loading:
381
383
-**One skill per request** — the agent loads at most one skill per turn to keep the flow simple and predictable.
382
384
-**Lightweight catalog** — only slugs and descriptions are sent initially, keeping the prompt small even with many skills available.
383
385
-**Client-side loading** — the workspace (not the agent) resolves and loads skill content, so the agent never needs filesystem or network access to skills.
384
-
-**Extends `QueryRequest`** — `SkillQueryRequest` subclasses `QueryRequest` from `openbb_ai`, adding only the two skill fields. This means the agent gets typed message handling for free.
386
+
-**Extends `QueryRequest`** — `SkillQueryRequest` subclasses `QueryRequest` from `openbb_ai`, adding only the two skill fields. The agent gets typed message handling for free.
385
387
-**Graceful fallback** — if no skill is relevant, the agent answers directly without loading one.
0 commit comments