@alexanderzzlatkov/skilleval 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/config.d.ts +63 -0
- package/dist/config.js +42 -0
- package/dist/context-builder.d.ts +5 -0
- package/dist/context-builder.js +121 -0
- package/dist/evaluator.d.ts +4 -0
- package/dist/evaluator.js +239 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +113 -0
- package/dist/parser.d.ts +2 -0
- package/dist/parser.js +152 -0
- package/dist/providers.d.ts +4 -0
- package/dist/providers.js +33 -0
- package/dist/reporter.d.ts +5 -0
- package/dist/reporter.js +80 -0
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +53 -0
- package/dist/test-generator.d.ts +3 -0
- package/dist/test-generator.js +109 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 skilleval contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# skilleval
|
|
2
|
+
|
|
3
|
+
Evaluate how well AI models understand and respond to [Agent Skills](https://agentskills.io/home) (SKILL.md files).
|
|
4
|
+
|
|
5
|
+
Skill authors write a SKILL.md and have zero idea whether it works on any model besides the one they tested with. `skilleval` fixes that - it simulates how agents like [OpenClaw](https://openclaw.ai/) and Claude Code inject skills into prompts, following the [OpenSkills](https://github.com/numman-ali/openskills) specification, then tests whether various LLM models correctly trigger and follow the skill's instructions.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
You need an [OpenRouter](https://openrouter.ai) account. Create a free API key at [openrouter.ai/keys](https://openrouter.ai/keys).
|
|
10
|
+
|
|
11
|
+
OpenRouter is used for test prompt generation and evaluation judging, and as the default provider for testing models. Even if you use a different provider (Anthropic, OpenAI, Google) for the models being tested, an OpenRouter key is still required for the generator and judge unless you supply custom prompts via `--prompts`.
|
|
12
|
+
|
|
13
|
+
**Free model limitations:** OpenRouter's free models (those ending in `:free`) are subject to upstream rate limits and may be temporarily unavailable. If you encounter rate limit errors, you can:
|
|
14
|
+
- Wait and retry - free model availability fluctuates
|
|
15
|
+
- Use paid models instead (remove the `:free` suffix, e.g. `meta-llama/llama-3.3-70b-instruct`)
|
|
16
|
+
- Provide your own test prompts with `--prompts` to skip the generator model entirely
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Set your OpenRouter API key
|
|
22
|
+
export OPENROUTER_API_KEY=sk-or-...
|
|
23
|
+
|
|
24
|
+
# Evaluate a local skill
|
|
25
|
+
npx skilleval ./my-skill/SKILL.md
|
|
26
|
+
|
|
27
|
+
# Evaluate a skill from a GitHub repo (like skills.sh)
|
|
28
|
+
npx skilleval owner/repo
|
|
29
|
+
|
|
30
|
+
# Evaluate a specific skill within a repo
|
|
31
|
+
npx skilleval owner/repo --skill skill-name
|
|
32
|
+
|
|
33
|
+
# Evaluate from a GitHub URL
|
|
34
|
+
npx skilleval https://github.com/user/repo/blob/main/skills/my-skill/SKILL.md
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How It Works
|
|
38
|
+
|
|
39
|
+
`skilleval` follows the [OpenSkills](https://github.com/numman-ali/openskills) specification - a universal skills format based on Anthropic's SKILL.md system. It's compatible with skills built for agents like Claude Code, [OpenClaw](https://openclaw.ai/), and any agent that uses the SKILL.md format. It simulates how these agents inject skills into system prompts using `<available_skills>` XML blocks - the same format used in production. This means the evaluation reflects real-world skill behavior, not synthetic benchmarks.
|
|
40
|
+
|
|
41
|
+
1. **Parse** - Reads the SKILL.md, extracts name, description, and instructions.
|
|
42
|
+
2. **Build context** - The model is presented as a helpful AI agent with access to multiple skills. The system prompt uses `<available_skills>` XML injection where your skill is mixed in with 3 fake distractor skills (e.g. "git-commit-helper", "api-documentation", "test-generator"). This tests whether the model can identify the right skill from a realistic list rather than in isolation.
|
|
43
|
+
3. **Generate test prompts** - A generator model creates 5 positive prompts (should trigger) and 5 negative prompts (should not).
|
|
44
|
+
4. **Run trigger tests** - Sends each prompt to each target model with the skill-injected system prompt.
|
|
45
|
+
5. **Evaluate** - A judge model assesses trigger accuracy and, for correctly triggered prompts, runs a compliance test against the full skill instructions. If the skill references tools (e.g. `WebFetch`, `BraveSearch`, `Read`, `Write`, `Edit`, `Bash`, `Grep`, `Glob`), `skilleval` automatically provides mock tool definitions so the model can make real structured tool calls instead of fabricating results in text. The judge evaluates whether the model called the right tools with the right parameters, not the quality of the mock results.
|
|
46
|
+
6. **Report** - Prints a compatibility matrix to the terminal.
|
|
47
|
+
|
|
48
|
+
See [AGENTS.md](./AGENTS.md) for detailed pipeline internals.
|
|
49
|
+
|
|
50
|
+
## Output
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
skilleval v0.1.0
|
|
54
|
+
Skill: pdf-processing
|
|
55
|
+
Description: Extract text and tables from PDF files
|
|
56
|
+
Provider: openrouter
|
|
57
|
+
Models: 5
|
|
58
|
+
|
|
59
|
+
┌───────────────────────────────────────────┬──────────────┬────────────────┬─────────┐
|
|
60
|
+
│ Model │ Trigger │ Compliance │ Overall │
|
|
61
|
+
├───────────────────────────────────────────┼──────────────┼────────────────┼─────────┤
|
|
62
|
+
│ qwen/qwen3-235b-a22b:free │ 10/10 │ 5/5 (92) │ 98% │
|
|
63
|
+
│ meta-llama/llama-3.3-70b-instruct:free │ 9/10 │ 4/5 (85) │ 82% │
|
|
64
|
+
│ deepseek/deepseek-r1:free │ 9/10 │ 4/5 (80) │ 81% │
|
|
65
|
+
│ google/gemma-3-27b-it:free │ 8/10 │ 3/5 (70) │ 72% │
|
|
66
|
+
│ mistralai/mistral-small-3.1-24b:free │ 7/10 │ 3/5 (65) │ 66% │
|
|
67
|
+
└───────────────────────────────────────────┴──────────────┴────────────────┴─────────┘
|
|
68
|
+
|
|
69
|
+
Best model: qwen/qwen3-235b-a22b:free (98%)
|
|
70
|
+
Worst model: mistralai/mistral-small-3.1-24b:free (66%)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
skilleval <skill> [options]
|
|
77
|
+
|
|
78
|
+
Arguments:
|
|
79
|
+
skill Path, URL, or GitHub shorthand (owner/repo)
|
|
80
|
+
|
|
81
|
+
Options:
|
|
82
|
+
-p, --provider <provider> Provider: openrouter, anthropic, openai, google (default: openrouter)
|
|
83
|
+
-m, --models <models> Comma-separated model IDs
|
|
84
|
+
-s, --skill <name> Skill name within the repo (looks for skills/<name>/SKILL.md)
|
|
85
|
+
-k, --key <key> API key (or use provider-specific env var)
|
|
86
|
+
--generator-model <model> Model for test prompt generation (comma-separated for fallbacks)
|
|
87
|
+
--judge-model <model> Model for evaluation judging (comma-separated for fallbacks)
|
|
88
|
+
--json Output results as JSON
|
|
89
|
+
--verbose Show detailed per-prompt results
|
|
90
|
+
-n, --count <number> Number of positive+negative test prompts (default: 5, so 5+5=10 total)
|
|
91
|
+
--prompts <path> Path to JSON file with custom test prompts
|
|
92
|
+
-V, --version Output the version number
|
|
93
|
+
-h, --help Display help
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Model Roles
|
|
97
|
+
|
|
98
|
+
`skilleval` uses three types of models, each with a different role in the pipeline:
|
|
99
|
+
|
|
100
|
+
| Role | Flag | Default | Description |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| **Test models** | `-m, --models` | 5 free OpenRouter models | The models being evaluated. These receive the skill-injected prompt and are scored on how well they trigger and follow the skill. |
|
|
103
|
+
| **Generator models** | `--generator-model` | 3 free OpenRouter models (with fallback) | Generate test prompts (positive + negative) from the skill definition. Count configurable via `-n`. You can provide comma-separated model IDs for fallback. |
|
|
104
|
+
| **Judge models** | `--judge-model` | 3 free OpenRouter models (with fallback) | Evaluate each test model's response - did it correctly trigger the skill? Did it follow instructions? You can provide comma-separated model IDs for fallback. |
|
|
105
|
+
|
|
106
|
+
The generator and judge models always run through OpenRouter (even if you set a different `--provider`). Only the test models use your specified provider.
|
|
107
|
+
|
|
108
|
+
### Providers
|
|
109
|
+
|
|
110
|
+
All providers use the [Vercel AI SDK](https://ai-sdk.dev) under the hood.
|
|
111
|
+
|
|
112
|
+
| Provider | Flag | Env Var | Notes |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| OpenRouter | `--provider openrouter` | `OPENROUTER_API_KEY` | Default. Access 300+ models including free ones. |
|
|
115
|
+
| Anthropic | `--provider anthropic` | `ANTHROPIC_API_KEY` | Direct API access to Claude models. |
|
|
116
|
+
| OpenAI | `--provider openai` | `OPENAI_API_KEY` | Direct API access to GPT models. |
|
|
117
|
+
| Google | `--provider google` | `GOOGLE_GENERATIVE_AI_API_KEY` | Direct API access to Gemini models. |
|
|
118
|
+
|
|
119
|
+
### Examples
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# Test against default free OpenRouter models
|
|
123
|
+
npx skilleval ./SKILL.md
|
|
124
|
+
|
|
125
|
+
# Test against specific models via OpenRouter
|
|
126
|
+
npx skilleval ./SKILL.md --models "anthropic/claude-sonnet-4-20250514,openai/gpt-4o"
|
|
127
|
+
|
|
128
|
+
# Test directly against Anthropic
|
|
129
|
+
npx skilleval ./SKILL.md --provider anthropic --model claude-sonnet-4-20250514
|
|
130
|
+
|
|
131
|
+
# Use a smarter judge model
|
|
132
|
+
npx skilleval ./SKILL.md --judge-model "qwen/qwen3-235b-a22b:free"
|
|
133
|
+
|
|
134
|
+
# Provide your own test prompts
|
|
135
|
+
npx skilleval ./SKILL.md --prompts ./my-test-prompts.json
|
|
136
|
+
|
|
137
|
+
# Machine-readable output
|
|
138
|
+
npx skilleval ./SKILL.md --json
|
|
139
|
+
|
|
140
|
+
# Quick test with fewer prompts (1 positive + 1 negative)
|
|
141
|
+
npx skilleval ./SKILL.md -n 1
|
|
142
|
+
|
|
143
|
+
# Detailed per-prompt breakdown
|
|
144
|
+
npx skilleval ./SKILL.md --verbose
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Custom Test Prompts
|
|
148
|
+
|
|
149
|
+
Create a JSON file with your own test prompts:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
[
|
|
153
|
+
{"text": "Help me extract text from this PDF", "type": "positive"},
|
|
154
|
+
{"text": "Merge these two PDF files together", "type": "positive"},
|
|
155
|
+
{"text": "Convert this PDF to Word", "type": "positive"},
|
|
156
|
+
{"text": "Fill out this PDF form", "type": "positive"},
|
|
157
|
+
{"text": "Extract tables from the PDF report", "type": "positive"},
|
|
158
|
+
{"text": "What's the weather today?", "type": "negative"},
|
|
159
|
+
{"text": "Write me a Python script", "type": "negative"},
|
|
160
|
+
{"text": "Help me debug this CSS", "type": "negative"},
|
|
161
|
+
{"text": "Create a git commit message", "type": "negative"},
|
|
162
|
+
{"text": "Summarize this article for me", "type": "negative"}
|
|
163
|
+
]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Scoring
|
|
167
|
+
|
|
168
|
+
Each model is scored on two dimensions:
|
|
169
|
+
|
|
170
|
+
- **Trigger accuracy** (50% of overall): Did the model correctly identify when to use the skill (positive prompts) and when to ignore it (negative prompts)?
|
|
171
|
+
- **Compliance** (50% of overall): For positive prompts where the skill was triggered, did the model follow the skill's instructions? Split into pass/fail (30%) and quality score 0-100 (20%).
|
|
172
|
+
|
|
173
|
+
Exit code is `0` if all models score >= 50%, `1` otherwise - useful for CI.
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
git clone https://github.com/zlatkov/skilleval.git
|
|
179
|
+
cd skilleval
|
|
180
|
+
npm install
|
|
181
|
+
npm run dev -- ./path/to/SKILL.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { LanguageModel } from 'ai';
|
|
2
|
+
export declare const PROVIDER_NAMES: readonly ["openrouter", "anthropic", "openai", "google"];
|
|
3
|
+
export type ProviderName = (typeof PROVIDER_NAMES)[number];
|
|
4
|
+
export declare const PROVIDER_ENV_VARS: Record<ProviderName, string>;
|
|
5
|
+
export interface SkillDefinition {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
body: string;
|
|
9
|
+
rawContent: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TestPrompt {
|
|
12
|
+
text: string;
|
|
13
|
+
type: 'positive' | 'negative';
|
|
14
|
+
}
|
|
15
|
+
export interface TestResult {
|
|
16
|
+
modelId: string;
|
|
17
|
+
prompt: TestPrompt;
|
|
18
|
+
response: string;
|
|
19
|
+
latencyMs: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface TriggerEval {
|
|
23
|
+
triggered: boolean;
|
|
24
|
+
correct: boolean;
|
|
25
|
+
reason: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ComplianceEval {
|
|
28
|
+
compliant: boolean;
|
|
29
|
+
score: number;
|
|
30
|
+
reason: string;
|
|
31
|
+
}
|
|
32
|
+
export interface EvalResult {
|
|
33
|
+
modelId: string;
|
|
34
|
+
prompt: TestPrompt;
|
|
35
|
+
response: string;
|
|
36
|
+
trigger: TriggerEval;
|
|
37
|
+
compliance?: ComplianceEval;
|
|
38
|
+
}
|
|
39
|
+
export interface EvalReport {
|
|
40
|
+
modelId: string;
|
|
41
|
+
triggerScore: {
|
|
42
|
+
correct: number;
|
|
43
|
+
total: number;
|
|
44
|
+
};
|
|
45
|
+
complianceScore: {
|
|
46
|
+
correct: number;
|
|
47
|
+
total: number;
|
|
48
|
+
avgScore: number;
|
|
49
|
+
};
|
|
50
|
+
overall: number;
|
|
51
|
+
}
|
|
52
|
+
export declare const DEFAULT_FREE_MODELS: string[];
|
|
53
|
+
export declare const DEFAULT_GENERATOR_MODELS: string[];
|
|
54
|
+
export declare const DEFAULT_JUDGE_MODELS: string[];
|
|
55
|
+
export declare const REQUEST_TIMEOUT_MS = 30000;
|
|
56
|
+
export declare const DUMMY_SKILLS: {
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
}[];
|
|
60
|
+
export interface ModelWithId {
|
|
61
|
+
model: LanguageModel;
|
|
62
|
+
modelId: string;
|
|
63
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// --- Provider Types ---
|
|
2
|
+
export const PROVIDER_NAMES = ['openrouter', 'anthropic', 'openai', 'google'];
|
|
3
|
+
export const PROVIDER_ENV_VARS = {
|
|
4
|
+
openrouter: 'OPENROUTER_API_KEY',
|
|
5
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
6
|
+
openai: 'OPENAI_API_KEY',
|
|
7
|
+
google: 'GOOGLE_GENERATIVE_AI_API_KEY',
|
|
8
|
+
};
|
|
9
|
+
// --- Constants ---
|
|
10
|
+
export const DEFAULT_FREE_MODELS = [
|
|
11
|
+
'meta-llama/llama-3.3-70b-instruct:free',
|
|
12
|
+
'mistralai/mistral-small-3.1-24b-instruct:free',
|
|
13
|
+
'google/gemma-3-27b-it:free',
|
|
14
|
+
'qwen/qwen3-coder:free',
|
|
15
|
+
'nousresearch/hermes-3-llama-3.1-405b:free',
|
|
16
|
+
];
|
|
17
|
+
export const DEFAULT_GENERATOR_MODELS = [
|
|
18
|
+
'meta-llama/llama-3.3-70b-instruct:free',
|
|
19
|
+
'google/gemma-3-27b-it:free',
|
|
20
|
+
'mistralai/mistral-small-3.1-24b-instruct:free',
|
|
21
|
+
];
|
|
22
|
+
export const DEFAULT_JUDGE_MODELS = [
|
|
23
|
+
'meta-llama/llama-3.3-70b-instruct:free',
|
|
24
|
+
'google/gemma-3-27b-it:free',
|
|
25
|
+
'mistralai/mistral-small-3.1-24b-instruct:free',
|
|
26
|
+
];
|
|
27
|
+
export const REQUEST_TIMEOUT_MS = 30_000;
|
|
28
|
+
export const DUMMY_SKILLS = [
|
|
29
|
+
{
|
|
30
|
+
name: 'git-commit-helper',
|
|
31
|
+
description: 'Helps create well-formatted git commits with conventional commit messages.',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'api-documentation',
|
|
35
|
+
description: 'Generates API documentation from code comments and type definitions.',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'test-generator',
|
|
39
|
+
description: 'Creates unit tests for functions and classes based on their signatures and behavior.',
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CoreTool } from 'ai';
|
|
2
|
+
import { type SkillDefinition } from './config.js';
|
|
3
|
+
export declare function buildTriggerSystemPrompt(skill: SkillDefinition): string;
|
|
4
|
+
export declare function buildMockTools(): Record<string, CoreTool>;
|
|
5
|
+
export declare function buildComplianceSystemPrompt(skill: SkillDefinition): string;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { tool } from 'ai';
|
|
3
|
+
import { DUMMY_SKILLS } from './config.js';
|
|
4
|
+
// Tools provided to the model during compliance testing, matching what real agent hosts offer
|
|
5
|
+
const KNOWN_TOOLS = {
|
|
6
|
+
WebFetch: {
|
|
7
|
+
description: 'Fetch content from a URL',
|
|
8
|
+
parameters: z.object({ url: z.string().describe('The URL to fetch') }),
|
|
9
|
+
},
|
|
10
|
+
WebSearch: {
|
|
11
|
+
description: 'Search the web for information',
|
|
12
|
+
parameters: z.object({ query: z.string().describe('The search query') }),
|
|
13
|
+
},
|
|
14
|
+
BraveSearch: {
|
|
15
|
+
description: 'Search the web using Brave Search',
|
|
16
|
+
parameters: z.object({ query: z.string().describe('The search query') }),
|
|
17
|
+
},
|
|
18
|
+
Read: {
|
|
19
|
+
description: 'Read a file from the filesystem',
|
|
20
|
+
parameters: z.object({ file_path: z.string().describe('The file path to read') }),
|
|
21
|
+
},
|
|
22
|
+
Write: {
|
|
23
|
+
description: 'Write content to a file',
|
|
24
|
+
parameters: z.object({
|
|
25
|
+
file_path: z.string().describe('The file path to write'),
|
|
26
|
+
content: z.string().describe('The content to write'),
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
Edit: {
|
|
30
|
+
description: 'Edit a file by replacing text',
|
|
31
|
+
parameters: z.object({
|
|
32
|
+
file_path: z.string().describe('The file path to edit'),
|
|
33
|
+
old_string: z.string().describe('The text to replace'),
|
|
34
|
+
new_string: z.string().describe('The replacement text'),
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
Bash: {
|
|
38
|
+
description: 'Execute a shell command',
|
|
39
|
+
parameters: z.object({ command: z.string().describe('The command to execute') }),
|
|
40
|
+
},
|
|
41
|
+
Grep: {
|
|
42
|
+
description: 'Search file contents using regex',
|
|
43
|
+
parameters: z.object({
|
|
44
|
+
pattern: z.string().describe('The regex pattern to search for'),
|
|
45
|
+
path: z.string().optional().describe('The directory to search in'),
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
Glob: {
|
|
49
|
+
description: 'Find files matching a pattern',
|
|
50
|
+
parameters: z.object({ pattern: z.string().describe('The glob pattern') }),
|
|
51
|
+
},
|
|
52
|
+
NotebookEdit: {
|
|
53
|
+
description: 'Edit a Jupyter notebook cell',
|
|
54
|
+
parameters: z.object({
|
|
55
|
+
notebook: z.string().describe('The notebook file path'),
|
|
56
|
+
cell: z.number().describe('The cell index'),
|
|
57
|
+
new_source: z.string().describe('The new cell content'),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
code_interpreter: {
|
|
61
|
+
description: 'Execute Python code in a sandbox',
|
|
62
|
+
parameters: z.object({ code: z.string().describe('The Python code to execute') }),
|
|
63
|
+
},
|
|
64
|
+
browser: {
|
|
65
|
+
description: 'Browse a web page',
|
|
66
|
+
parameters: z.object({ url: z.string().describe('The URL to browse') }),
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const BASE_SYSTEM_PROMPT = `You are a helpful AI agent. You have access to various skills that can help you complete tasks. When a user's request matches a skill's description, you should use that skill by following its instructions.
|
|
70
|
+
|
|
71
|
+
When you determine a skill is relevant to the user's request:
|
|
72
|
+
1. Announce that you are using the skill
|
|
73
|
+
2. Follow the skill's instructions carefully
|
|
74
|
+
|
|
75
|
+
When no skill matches the user's request, respond normally without mentioning any skills.`;
|
|
76
|
+
function buildSkillXml(name, description, location) {
|
|
77
|
+
const loc = location ?? `skills/${name}/SKILL.md`;
|
|
78
|
+
return `<skill>
|
|
79
|
+
<name>${name}</name>
|
|
80
|
+
<description>${description}</description>
|
|
81
|
+
<location>${loc}</location>
|
|
82
|
+
</skill>`;
|
|
83
|
+
}
|
|
84
|
+
export function buildTriggerSystemPrompt(skill) {
|
|
85
|
+
const allSkills = [
|
|
86
|
+
buildSkillXml(DUMMY_SKILLS[0].name, DUMMY_SKILLS[0].description),
|
|
87
|
+
buildSkillXml(DUMMY_SKILLS[1].name, DUMMY_SKILLS[1].description),
|
|
88
|
+
buildSkillXml(skill.name, skill.description),
|
|
89
|
+
buildSkillXml(DUMMY_SKILLS[2].name, DUMMY_SKILLS[2].description),
|
|
90
|
+
];
|
|
91
|
+
return `${BASE_SYSTEM_PROMPT}
|
|
92
|
+
|
|
93
|
+
<available_skills>
|
|
94
|
+
${allSkills.join('\n')}
|
|
95
|
+
</available_skills>`;
|
|
96
|
+
}
|
|
97
|
+
export function buildMockTools() {
|
|
98
|
+
const tools = {};
|
|
99
|
+
for (const [name, def] of Object.entries(KNOWN_TOOLS)) {
|
|
100
|
+
tools[name] = tool({
|
|
101
|
+
description: def.description,
|
|
102
|
+
parameters: def.parameters,
|
|
103
|
+
execute: async () => `[Mock result from ${name}]`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return tools;
|
|
107
|
+
}
|
|
108
|
+
export function buildComplianceSystemPrompt(skill) {
|
|
109
|
+
return `${BASE_SYSTEM_PROMPT}
|
|
110
|
+
|
|
111
|
+
<available_skills>
|
|
112
|
+
<skill>
|
|
113
|
+
<name>${skill.name}</name>
|
|
114
|
+
<description>${skill.description}</description>
|
|
115
|
+
<instructions>
|
|
116
|
+
${skill.body}
|
|
117
|
+
</instructions>
|
|
118
|
+
</skill>
|
|
119
|
+
</available_skills>`;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=context-builder.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type LanguageModel } from 'ai';
|
|
2
|
+
import type { EvalReport, EvalResult, ModelWithId, SkillDefinition, TestResult } from './config.js';
|
|
3
|
+
export declare function evaluateResults(skill: SkillDefinition, testResults: TestResult[], judgeModels: LanguageModel[], models: ModelWithId[], verbose: boolean): Promise<EvalResult[]>;
|
|
4
|
+
export declare function computeReport(evalResults: EvalResult[], modelIds: string[]): EvalReport[];
|