Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
66f2f32
feat: add pluggable prompt renderer provider pattern with model-aware…
airtonix Dec 29, 2025
161f84d
test(renderers): add comprehensive unit tests and README documentation
airtonix Dec 29, 2025
acf7289
feat(config): support provider-specific model renderer selection with…
airtonix Dec 29, 2025
479e6c4
fix(tests): update renderer tests to use factory pattern and fix imports
airtonix Dec 29, 2025
e5b611b
fix(renderers): correct null-check ordering and JSDoc parameters in M…
airtonix Dec 29, 2025
af0db0c
refactor(config): make getModelFormat synchronous and update JSDoc
airtonix Dec 29, 2025
02c3df3
feat(config): add basePaths field to bunfig schema
airtonix Dec 29, 2025
21a7525
fix(docs): update README examples to match renderer implementation an…
airtonix Dec 29, 2025
794b395
fix(lint): resolve regex spaces linting error
airtonix Dec 29, 2025
7a382e0
fix(lint): resolve @typescript-eslint/no-explicit-any warnings
airtonix Dec 29, 2025
8ad60a0
fix(lint): suppress no-console warnings in mock file
airtonix Dec 29, 2025
12c4fdc
fix(lint): suppress no-console warnings in logger
airtonix Dec 29, 2025
cc881b8
fix(renderers): handle nested objects and arrays in array items
airtonix Dec 29, 2025
7d5d47d
fix(config): check for defined modelId and providerId before construc…
airtonix Dec 29, 2025
3f1746c
refactor(index): remove redundant optional chaining after null check
airtonix Dec 29, 2025
4396b48
fix(renderers): make content field optional and add default rootElement
airtonix Dec 29, 2025
0a97071
fix(services): clean up empty session objects after untracking messages
airtonix Dec 29, 2025
176990a
docs(agents): document NEVER USE ANY principle
airtonix Dec 30, 2025
d32dd13
docs(readme): update format examples to match implementation
airtonix Dec 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .mise/tasks/setup
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ echo ""
echo "🍜 Setting up project"
echo ""

hk install
# Only run hk install if not in a git worktree
if ! git worktree list | grep -q "$(pwd)"; then
hk install
fi

bun install

echo ""
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- **Methods/properties**: camelCase
- **Status strings**: use union types (e.g., `'pending' | 'running' | 'completed' | 'failed' | 'cancelled'`)
- **Explicit types**: prefer explicit type annotations over inference
- **NEVER USE ANY**: avoid `any` type at all costs
- **Return types**: optional (not required but recommended for public methods)

### Error Handling
Expand Down
224 changes: 214 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,103 @@ skill_find "testing -performance"
- Natural query syntax with negation and quoted phrases
- Skill ranking by relevance (name matches weighted higher)
- Silent message insertion (noReply pattern)
- **Pluggable prompt rendering** with model-aware format selection (XML, JSON, Markdown)

## Prompt Renderer Configuration

The plugin supports **multiple formats for prompt injection**, allowing you to optimize results for different LLM models and use cases.

> See the [Configuration](#configuration) section for complete configuration details, including bunfig setup and global/project-level overrides.

### Supported Formats

Choose the format that works best for your LLM:

| Format | Best For | Characteristics |
| ----------------- | ---------------------- | ---------------------------------------------------------------------- |
| **XML** (default) | Claude models | Human-readable, structured, XML-optimized for Claude |
| **JSON** | GPT and strict parsers | Machine-readable, strict JSON structure, strong parsing support |
| **Markdown** | All models | Readable prose, heading-based structure, easy to read in conversations |

### Configuration Syntax

Set your preferences in `.opencode-skillful.json`:

```json
{
"promptRenderer": "xml",
"modelRenderers": {
"claude-3-5-sonnet": "xml",
"gpt-4": "json",
"gpt-4-turbo": "json"
}
}
```

**How It Works:**

1. Every tool execution checks the current active LLM model
2. If `modelRenderers[modelID]` is configured, that format is used
3. Otherwise, the global `promptRenderer` default is used
4. Results are rendered in the selected format and injected into the prompt

### Format Output Examples

#### XML Format (Claude Optimized)

```xml
<Skill>
<name>git-commits</name>
<description>Guidelines for writing effective git commit messages</description>
<toolName>writing_git_commits</toolName>
</Skill>
```

**Advantages:**

- Matches Claude's native instruction format
- Clear tag-based structure
- Excellent readability for complex nested data

#### JSON Format (GPT Optimized)

```json
{
"name": "git-commits",
"description": "Guidelines for writing effective git commit messages",
"toolName": "writing_git_commits"
}
```

**Advantages:**

- Strong parsing support across LLMs
- Strict, validated structure
- Familiar format for language models trained on JSON data

#### Markdown Format (Human Readable)

```markdown
# Skill

### name

- **name**: _git-commits_

### description

- **description**: _Guidelines for writing effective git commit messages_

### toolName

- **toolName**: _writing_git_commits_
```

**Advantages:**

- Most readable in conversations
- Natural language-friendly
- Works well for exploratory workflows

## Skill Discovery Paths

Expand Down Expand Up @@ -354,26 +451,133 @@ Non-zero exit codes indicate script failures. Always check STDERR and the exit c

## Configuration

The plugin reads configuration from the OpenCode config file (`~/.config/opencode/config.json`):
The plugin loads configuration from **bunfig**, supporting both project-local and global configuration files:

### Configuration Files

Configuration is loaded in this priority order (highest priority last):

1. **Global config** (standard platform locations):
- Linux/macOS: `~/.config/opencode-skillful/config.json`
- Windows: `%APPDATA%/opencode-skillful/config.json`

2. **Project config** (in your project root):
- `.opencode-skillful.json`

Later configuration files override earlier ones. Use project-local `.opencode-skillful.json` to override global settings for specific projects.

### Configuration Options

#### Plugin Installation

First, register the plugin in your OpenCode config (`~/.config/opencode/config.json`):

```json
{
"plugins": ["@zenobius/opencode-skillful"],
"skillful": {
"debug": false,
"basePaths": ["~/.config/opencode/skills", ".opencode/skills"]
}
"plugins": ["@zenobius/opencode-skillful"]
}
```

### Configuration Options
#### Skill Discovery Configuration

Create `.opencode-skillful.json` in your project root or global config directory:

```json
{
"debug": false,
"basePaths": ["~/.config/opencode/skills", ".opencode/skills"],
"promptRenderer": "xml",
"modelRenderers": {}
}
```

**Configuration Fields:**

- **debug** (boolean, default: `false`): Enable debug output showing skill discovery stats
- When enabled, `skill_find` includes discovered, parsed, rejected, and duplicate counts
- Useful for diagnosing skill loading issues
- When enabled, `skill_find` responses include discovered, parsed, rejected, and error counts
- Useful for diagnosing skill loading and parsing issues

- **basePaths** (array, default: standard locations): Custom skill search directories
- Paths are searched in order; later paths override earlier ones for duplicate skill names
- Paths are searched in priority order; later paths override earlier ones for duplicate skill names
- Default: `[~/.config/opencode/skills, .opencode/skills]`
- Use project-local `.opencode/skills/` for project-specific skills
- Platform-aware paths: automatically resolves to XDG, macOS, or Windows standard locations

- **promptRenderer** (string, default: `'xml'`): Default format for prompt injection
- Options: `'xml'` | `'json'` | `'md'`
- XML (default): Claude-optimized, human-readable structured format
- JSON: GPT-optimized, strict JSON formatting for strong parsing models
- Markdown: Human-readable format with headings and nested lists
- Used when no model-specific renderer is configured

- **modelRenderers** (object, default: `{}`): Per-model format overrides
- Maps model IDs to preferred formats
- Overrides global `promptRenderer` for specific models
- Example: `{ "gpt-4": "json", "claude-3-5-sonnet": "xml" }`

### How Renderer Selection Works

When any tool executes (`skill_find`, `skill_use`, `skill_resource`):

1. The plugin queries the OpenCode session to determine the active LLM model
2. Builds a list of model candidates to check, from most to least specific:
- Full model ID (e.g., `"anthropic-claude-3-5-sonnet"`)
- Generic model pattern (e.g., `"claude-3-5-sonnet"`)
3. Checks if any candidate exists in `modelRenderers` configuration
- First match wins (most specific takes precedence)
- If found, uses that format
4. If no match in `modelRenderers`, falls back to `promptRenderer` default
5. Renders the results in the selected format and injects into the prompt

**Example**: If your config has `"claude-3-5-sonnet": "xml"` and the active model is `"anthropic-claude-3-5-sonnet"`, the plugin will:

- Try matching `"anthropic-claude-3-5-sonnet"` (no match)
- Try matching `"claude-3-5-sonnet"` (match found! Use XML)
- Return `"xml"` format

This allows different models to receive results in their preferred format without needing to specify every model variant. Configure the generic model name once and it works for all provider-prefixed variations.

### Example Configurations

#### Global Configuration for Multi-Model Setup

`~/.config/opencode-skillful/config.json`:

```json
{
"debug": false,
"promptRenderer": "xml",
"modelRenderers": {
"claude-3-5-sonnet": "xml",
"claude-3-opus": "xml",
"gpt-4": "json",
"gpt-4-turbo": "json",
"llama-2-70b": "md"
}
}
```

#### Project-Specific Override

`.opencode-skillful.json` (project root):

```json
{
"debug": true,
"basePaths": ["~/.config/opencode/skills", ".opencode/skills", "./vendor/skills"],
"promptRenderer": "xml",
"modelRenderers": {
"gpt-4": "json"
}
}
```

This project-local config:

- Enables debug output for troubleshooting
- Adds a custom vendor skills directory
- Uses JSON format specifically for GPT-4 when it's the active model
- Falls back to XML for all other models

## Architecture

Expand Down
23 changes: 23 additions & 0 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"name": "@zenobius/opencode-skillful",
"dependencies": {
"@opencode-ai/plugin": "1.0.85",
"bunfig": "^0.15.6",
"env-paths": "^3.0.0",
"gray-matter": "^4.0.3",
"mime": "^4.1.0",
Expand Down Expand Up @@ -179,6 +180,10 @@

"@rollup/rollup-win32-x64-msvc": ["@rollup/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="],

"@stacksjs/clapp": ["@stacksjs/[email protected]", "", { "dependencies": { "mri": "^1.2.0", "wrap-ansi": "^9.0.0" }, "bin": { "clapp": "dist/bin/cli.js", "@stacksjs/clapp": "dist/bin/cli.js" } }, "sha512-dSqnbeZjXnQLLvVxC5NU7D9Vpjxc6cC9Bo2ZwaqjgruK7pbVoFCI0goc9Mtf/lfSTbTx6Uvv/mbY7+cOW/j3Og=="],

"@stacksjs/clarity": ["@stacksjs/[email protected]", "", { "bin": { "clarity": "dist/bin/cli.js" } }, "sha512-QN21fT/9dovcuFTkni9LFHDzBpiBZ4Q//0a3vFJsckPiblNIu1RhwwePkkTK4j6Xu2DtVYGR60/9Scdrp6wRfw=="],

"@types/bun": ["@types/[email protected]", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="],

"@types/chai": ["@types/[email protected]", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
Expand Down Expand Up @@ -233,6 +238,8 @@

"ajv": ["[email protected]", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],

"ansi-regex": ["[email protected]", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],

"ansi-styles": ["[email protected]", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],

"argparse": ["[email protected]", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
Expand All @@ -247,6 +254,8 @@

"bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="],

"bunfig": ["[email protected]", "", { "dependencies": { "@stacksjs/clapp": "^0.2.0", "@stacksjs/clarity": "^0.3.24" }, "bin": { "bunfig": "bin/cli.js" } }, "sha512-7ynPmrn1dN5F+0DtUVY0Vo2MZOOnSdb6hpQePwABEYIJ+d/rSb3vaOVUs3MFxwxWuaVc1FEStVJG6+kCgbLuyg=="],

"cac": ["[email protected]", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],

"callsites": ["[email protected]", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
Expand All @@ -271,6 +280,8 @@

"deep-is": ["[email protected]", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],

"emoji-regex": ["[email protected]", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],

"env-paths": ["[email protected]", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],

"es-module-lexer": ["[email protected]", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
Expand Down Expand Up @@ -333,6 +344,8 @@

"fsevents": ["[email protected]", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],

"get-east-asian-width": ["[email protected]", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],

"glob-parent": ["[email protected]", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],

"glob-to-regex.js": ["[email protected]", "", { "peerDependencies": { "tslib": "2" } }, "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ=="],
Expand Down Expand Up @@ -397,6 +410,8 @@

"minimatch": ["[email protected]", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],

"mri": ["[email protected]", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],

"ms": ["[email protected]", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],

"nanoid": ["[email protected]", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
Expand Down Expand Up @@ -465,6 +480,10 @@

"std-env": ["[email protected]", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],

"string-width": ["[email protected]", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],

"strip-ansi": ["[email protected]", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],

"strip-bom-string": ["[email protected]", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="],

"strip-json-comments": ["[email protected]", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
Expand Down Expand Up @@ -523,6 +542,8 @@

"word-wrap": ["[email protected]", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],

"wrap-ansi": ["[email protected]", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],

"yocto-queue": ["[email protected]", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],

"zod": ["[email protected]", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
Expand Down Expand Up @@ -555,6 +576,8 @@

"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/[email protected]", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA=="],

"wrap-ansi/ansi-styles": ["[email protected]", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],

"@eslint/eslintrc/js-yaml/argparse": ["[email protected]", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],

"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["[email protected]", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
Expand Down
37 changes: 37 additions & 0 deletions bunfig.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Bunfig Configuration - Plugin Settings Schema
*
* WHY: Bunfig provides typed configuration loading with validation.
* It allows us to:
* - Define a schema for all plugin settings (type-safe)
* - Load from multiple sources (.opencode-skillful.json, ~/.config/opencode-skillful/config.json)
* - Merge with sensible defaults
* - Support model-aware prompt renderer selection
*/

export default {
debug: false,
basePaths: [] as string[],
promptRenderer: 'xml' as const,

/**
* Model-specific renderer overrides
*
* WHY: Different LLM models have different preferences and strengths:
* - Claude models: trained on XML, prefer structured formats
* - GPT models: strong JSON parsing, prefer JSON
* - Other models: may benefit from markdown readability
*
* Structure: Record<modelID, format>
* - modelID: The model identifier from OpenCode (e.g., 'claude-3-5-sonnet')
* - format: Preferred format for that model ('json' | 'xml' | 'md')
*
* Example:
* modelRenderers: {
* 'claude-3-5-sonnet': 'xml',
* 'gpt-4': 'json',
* 'llama-2': 'md',
* }
*/
modelRenderers: {} as Record<string, 'json' | 'xml' | 'md'>,
};
Loading
Loading