@kylebrodeur/pi-model-router 0.1.2
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/CHANGELOG.md +42 -0
- package/CONTRIBUTING.md +310 -0
- package/LEARNINGS.md +181 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +111 -0
- package/README.md +195 -0
- package/TESTING.md +374 -0
- package/docs/ARCHITECTURE.md +54 -0
- package/docs/UPSTREAM_ISSUE_scoped_models.md +94 -0
- package/extensions/commands.ts +1068 -0
- package/extensions/config.ts +415 -0
- package/extensions/constants.ts +1 -0
- package/extensions/index.ts +583 -0
- package/extensions/ollama-sync.ts +254 -0
- package/extensions/provider.ts +558 -0
- package/extensions/rate-limit.ts +317 -0
- package/extensions/routing.ts +418 -0
- package/extensions/scope-shim.ts +213 -0
- package/extensions/state.ts +49 -0
- package/extensions/types.ts +148 -0
- package/extensions/ui.ts +130 -0
- package/model-router.agent-bus.json +15 -0
- package/model-router.essential.json +31 -0
- package/model-router.example.json +70 -0
- package/model-router.ledger.json +15 -0
- package/package.json +64 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Ollama auto-sync feature
|
|
12
|
+
- Rate-limit fallback with transparent HTTP error handling (402, 429, 503, 529)
|
|
13
|
+
- Feature toggles in config (`features` object)
|
|
14
|
+
- Scope shim for syncing router profiles to Pi enabled models
|
|
15
|
+
- Progressive enhancement (auto-detect qmd-ledger and agent-bus)
|
|
16
|
+
- Progressive config files (`model-router.ledger.json`, `model-router.agent-bus.json`, `model-router.essential.json`)
|
|
17
|
+
- GitHub issue templates and pull request template
|
|
18
|
+
- Code of Conduct
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Updated minimum Pi SDK version from 0.68.0 to 0.70.2
|
|
22
|
+
- Merged `README_FORK.md` into canonical `README.md`
|
|
23
|
+
- Replaced `@sinclair/typebox` peer dependency with `typebox`
|
|
24
|
+
|
|
25
|
+
## [0.1.1] - 2025-04-22
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- Config merge bug where `features`, `ollamaSync`, and `rateLimitFallback` were dropped during global/project merge
|
|
29
|
+
|
|
30
|
+
## [0.1.0] - 2025-04-21
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- Initial fork from `yeliu84/pi-model-router`
|
|
34
|
+
- Feature toggles system
|
|
35
|
+
- Ollama sync module
|
|
36
|
+
- Rate-limit fallback module
|
|
37
|
+
- Scope shim module
|
|
38
|
+
- Progressive enhancement with plugin detection
|
|
39
|
+
|
|
40
|
+
[Unreleased]: https://github.com/kylebrodeur/pi-model-router/compare/v0.1.1...HEAD
|
|
41
|
+
[0.1.1]: https://github.com/kylebrodeur/pi-model-router/compare/v0.1.0...v0.1.1
|
|
42
|
+
[0.1.0]: https://github.com/kylebrodeur/pi-model-router/releases/tag/v0.1.0
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Contributing to Upstream (pi-model-router)
|
|
2
|
+
|
|
3
|
+
This fork is designed for eventual upstream contribution. Here's how to structure and deliver your changes.
|
|
4
|
+
|
|
5
|
+
## Fork Strategy
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
yeliu84/pi-model-router (upstream)
|
|
9
|
+
│
|
|
10
|
+
└── your-github/pi-model-router-fork (this repo)
|
|
11
|
+
│
|
|
12
|
+
├── branch: main (tracks upstream)
|
|
13
|
+
├── branch: feature/ollama-sync
|
|
14
|
+
├── branch: feature/rate-limit-fallback
|
|
15
|
+
└── branch: feature/feature-toggles
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Recommended Commit Structure
|
|
19
|
+
|
|
20
|
+
Separate your work into **independent PRs** for maximum merge probability:
|
|
21
|
+
|
|
22
|
+
### PR 1: Feature Toggle Framework
|
|
23
|
+
**Commit message:** `feat: add feature toggle system for modular extensions`
|
|
24
|
+
|
|
25
|
+
**Files touched:**
|
|
26
|
+
- `extensions/types.ts` — add `FeatureToggles`, `OllamaSyncConfig`, `RateLimitFallbackConfig`
|
|
27
|
+
- `extensions/config.ts` — add feature fields to `mergeConfig()` and `normalizeConfig()`
|
|
28
|
+
|
|
29
|
+
**Rationale:**
|
|
30
|
+
- Minimal surface area
|
|
31
|
+
- No behavior changes to existing code
|
|
32
|
+
- Enables future features
|
|
33
|
+
- Easy to review and merge
|
|
34
|
+
|
|
35
|
+
### PR 2: Ollama Auto-Sync Feature
|
|
36
|
+
**Commit message:** `feat: add ollama-sync for auto-registering local models`
|
|
37
|
+
|
|
38
|
+
**Files touched:**
|
|
39
|
+
- `extensions/ollama-sync.ts` — new file
|
|
40
|
+
- `extensions/index.ts` — conditionally initialize from toggles
|
|
41
|
+
|
|
42
|
+
**Rationale:**
|
|
43
|
+
- Self-contained module
|
|
44
|
+
- Uses existing patterns (pi.exec, config merge)
|
|
45
|
+
- Useful to upstream community (many Pi users use Ollama)
|
|
46
|
+
|
|
47
|
+
### PR 3: Rate Limit Fallback
|
|
48
|
+
**Commit message:** `feat: add rate-limit fallback with manual restore`
|
|
49
|
+
|
|
50
|
+
**Files touched:**
|
|
51
|
+
- `extensions/rate-limit.ts` — new file
|
|
52
|
+
- `extensions/index.ts` — conditionally initialize from toggles
|
|
53
|
+
|
|
54
|
+
**Rationale:**
|
|
55
|
+
- Solves real production pain (API rate limits)
|
|
56
|
+
- Manual fallback is safe (no auto-magic)
|
|
57
|
+
- Composable with any routing profile
|
|
58
|
+
|
|
59
|
+
## Upstream Compatibility Rules
|
|
60
|
+
|
|
61
|
+
### ✅ Do
|
|
62
|
+
|
|
63
|
+
1. **Extend existing types** rather than replacing
|
|
64
|
+
```typescript
|
|
65
|
+
// ✅ Good
|
|
66
|
+
export interface RouterConfig {
|
|
67
|
+
// ... existing fields ...
|
|
68
|
+
features?: FeatureToggles;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ❌ Bad
|
|
72
|
+
export interface RouterConfigWithToggles { } // Separate type
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
2. **Use existing patterns** from upstream code
|
|
76
|
+
- Session persistence via `pi.appendEntry('router-state', ...)`
|
|
77
|
+
- Config merge: global → project (already in `loadRouterConfig()`)
|
|
78
|
+
- Commands via `pi.registerCommand()`
|
|
79
|
+
- State restoration in `session_start`
|
|
80
|
+
|
|
81
|
+
3. **Make features opt-out** (enabled by default)
|
|
82
|
+
```typescript
|
|
83
|
+
const isEnabled =
|
|
84
|
+
!currentConfig.features ||
|
|
85
|
+
currentConfig.features.myFeature !== false;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
4. **Co-locate feature commands** under `/router-*` namespace
|
|
89
|
+
- `/router-ollama-sync` not `/ollama-sync`
|
|
90
|
+
- `/router-fallback` not `/fallback`
|
|
91
|
+
|
|
92
|
+
5. **Follow style guide**
|
|
93
|
+
- Single quotes for strings
|
|
94
|
+
- Trailing commas in objects/arrays
|
|
95
|
+
- Same naming conventions (kebab-case files, camelCase identifiers)
|
|
96
|
+
|
|
97
|
+
### ❌ Don't
|
|
98
|
+
|
|
99
|
+
1. **Don't modify upstream internals** without justification
|
|
100
|
+
- Don't change `provider.ts` routing logic
|
|
101
|
+
- Don't change `routing.ts` tier decisions
|
|
102
|
+
- Don't modify UI rendering unless adding new elements
|
|
103
|
+
|
|
104
|
+
2. **Don't introduce breaking config changes**
|
|
105
|
+
- Keep `model-router.json` backward compatible
|
|
106
|
+
- New fields must be optional
|
|
107
|
+
|
|
108
|
+
3. **Don't add new dependencies**
|
|
109
|
+
- Use built-in `node:*` modules
|
|
110
|
+
- If upstream uses a package, you can use it
|
|
111
|
+
|
|
112
|
+
4. **Don't auto-switch models without explicit user action**
|
|
113
|
+
- Manual fallback only (user must type `/router-fallback`)
|
|
114
|
+
- Optional auto-fallback behind config flag (disabled by default)
|
|
115
|
+
|
|
116
|
+
5. **Don't modify the `RouterPersistedState` structure**
|
|
117
|
+
- Use separate session entries for feature state
|
|
118
|
+
- Or nest inside state object without changing required fields
|
|
119
|
+
|
|
120
|
+
## PR Preparation Checklist
|
|
121
|
+
|
|
122
|
+
For each PR:
|
|
123
|
+
|
|
124
|
+
- [ ] All TypeScript compiles with `npx tsc --noEmit`
|
|
125
|
+
- [ ] No lint errors (`npm run lint` if available)
|
|
126
|
+
- [ ] Upstream tests pass (`npm test` if available)
|
|
127
|
+
- [ ] New code follows file header comment pattern
|
|
128
|
+
- [ ] README.md updated with new feature docs
|
|
129
|
+
- [ ] Example config in `model-router.example.json` updated
|
|
130
|
+
- [ ] CHANGELOG.md entry (if upstream uses one)
|
|
131
|
+
|
|
132
|
+
## Commit Message Format
|
|
133
|
+
|
|
134
|
+
Follow upstream conventions:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
feat: add ollama-sync for auto-registering local models
|
|
138
|
+
|
|
139
|
+
- Detect new Ollama models on session start/reload
|
|
140
|
+
- Infer capabilities (vision, reasoning, context window)
|
|
141
|
+
- Update models.json with sensible defaults
|
|
142
|
+
- Toggle via features.ollamaSync in config
|
|
143
|
+
|
|
144
|
+
Refs: #upstream-issue-if-any
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
feat: add rate-limit fallback to local Ollama models
|
|
149
|
+
|
|
150
|
+
- Monitor after_provider_response for HTTP 429/503
|
|
151
|
+
- Manual fallback command: /router-fallback
|
|
152
|
+
- Restore command: /router-restore
|
|
153
|
+
- Configurable via features.rateLimitFallback
|
|
154
|
+
|
|
155
|
+
Refs: #upstream-issue-if-any
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
feat: add feature toggle system for modular extension
|
|
160
|
+
|
|
161
|
+
- features config key for enabling/disabling features
|
|
162
|
+
- ollamaSync and rateLimitFallback as first features
|
|
163
|
+
- Per-turn routing preserved as default behavior
|
|
164
|
+
- Project-level override support
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Testing for Upstream PRs
|
|
168
|
+
|
|
169
|
+
Before submitting each PR:
|
|
170
|
+
|
|
171
|
+
1. **Clean checkout of upstream `main` branch**
|
|
172
|
+
```bash
|
|
173
|
+
git remote add upstream https://github.com/yeliu84/pi-model-router.git
|
|
174
|
+
git fetch upstream
|
|
175
|
+
git checkout -b my-feature upstream/main
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
2. **Cherry-pick only your feature commits**
|
|
179
|
+
```bash
|
|
180
|
+
git cherry-pick <commit-hash-from-fork>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
3. **Ensure no other fork changes leak in**
|
|
184
|
+
```bash
|
|
185
|
+
git diff upstream/main --name-only
|
|
186
|
+
# Should only show files relevant to this PR
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
4. **Test against upstream's vanilla config**
|
|
190
|
+
```bash
|
|
191
|
+
mv ~/.pi/agent/model-router.json ~/.pi/agent/model-router.json.bak
|
|
192
|
+
|
|
193
|
+
# Test with upstream defaults only
|
|
194
|
+
# Ensure no runtime errors when features are absent
|
|
195
|
+
|
|
196
|
+
mv ~/.pi/agent/model-router.json.bak ~/.pi/agent/model-router.json
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Handling Merge Conflicts
|
|
200
|
+
|
|
201
|
+
If upstream changes while your PR is open:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# Fetch latest
|
|
205
|
+
git fetch upstream
|
|
206
|
+
|
|
207
|
+
# Rebase your branch
|
|
208
|
+
git rebase upstream/main
|
|
209
|
+
|
|
210
|
+
# Resolve conflicts (usually in config.ts and index.ts)
|
|
211
|
+
# - Always preserve upstream defaults
|
|
212
|
+
# - Add your features as additions
|
|
213
|
+
git add .
|
|
214
|
+
git rebase --continue
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Common conflict points:
|
|
218
|
+
- **`config.ts` `normalizeConfig()`** — add your feature fields at the end
|
|
219
|
+
- **`index.ts` imports** — add new feature imports in alphabetical order
|
|
220
|
+
- **`index.ts` `actions` object** — add `syncFeatures` last
|
|
221
|
+
- **`types.ts`** — add new interfaces at the bottom
|
|
222
|
+
|
|
223
|
+
## Conversation with Upstream
|
|
224
|
+
|
|
225
|
+
### What to say in your PR description
|
|
226
|
+
|
|
227
|
+
```markdown
|
|
228
|
+
## Summary
|
|
229
|
+
Adds [feature name] to pi-model-router. This feature [1-sentence problem it solves].
|
|
230
|
+
|
|
231
|
+
## Configuration
|
|
232
|
+
Users can enable it in their `model-router.json`:
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"features": {
|
|
236
|
+
"[featureName]": true
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## How it works
|
|
242
|
+
[2-3 sentence description]
|
|
243
|
+
|
|
244
|
+
## Backward Compatibility
|
|
245
|
+
- Disabled by default (opt-out after feature framework PR)
|
|
246
|
+
- No changes to existing routing behavior
|
|
247
|
+
- Existing configs work without modification
|
|
248
|
+
|
|
249
|
+
## Testing
|
|
250
|
+
- [ ] Tested with Pi 0.67+
|
|
251
|
+
- [ ] Tested with Ollama [if applicable]
|
|
252
|
+
- [ ] Regression tested upstream routing
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### What NOT to say
|
|
256
|
+
- Don't pitch it as "our fork adds X"
|
|
257
|
+
- Don't mention other features in the same PR description
|
|
258
|
+
- Don't change scope mid-PR (no "later I'll also add Y")
|
|
259
|
+
|
|
260
|
+
## If Upstream Declines
|
|
261
|
+
|
|
262
|
+
Your options:
|
|
263
|
+
|
|
264
|
+
1. **Maintain fork** — Keep this repo, publish as separate npm package
|
|
265
|
+
2. **Plugin architecture** — Request upstream add an extension hook API
|
|
266
|
+
3. **Separate extension** — Extract to `.pi/extensions/some-name.ts` as standalone
|
|
267
|
+
|
|
268
|
+
## Quick Reference: Files by PR
|
|
269
|
+
|
|
270
|
+
### PR 1: Feature Toggles (minimal)
|
|
271
|
+
| File | Change |
|
|
272
|
+
|------|--------|
|
|
273
|
+
| `extensions/types.ts` | +FeatureToggles, +OllamaSyncConfig, +RateLimitFallbackConfig, add fields to RouterConfig |
|
|
274
|
+
| `extensions/config.ts` | preserve feature fields in mergeConfig/normalizeConfig |
|
|
275
|
+
|
|
276
|
+
### PR 2: Ollama Sync
|
|
277
|
+
| File | Change |
|
|
278
|
+
|------|--------|
|
|
279
|
+
| `extensions/ollama-sync.ts` | New file |
|
|
280
|
+
| `extensions/index.ts` | Import + conditional init |
|
|
281
|
+
|
|
282
|
+
### PR 3: Rate Limit Fallback
|
|
283
|
+
| File | Change |
|
|
284
|
+
|------|--------|
|
|
285
|
+
| `extensions/rate-limit.ts` | New file |
|
|
286
|
+
| `extensions/index.ts` | Import + conditional init |
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Release Plan (for your fork)
|
|
291
|
+
|
|
292
|
+
Before upstream PRs merge, your fork can be used as:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Install from local folder
|
|
296
|
+
pi install ~/projects/pi-model-router-forked
|
|
297
|
+
|
|
298
|
+
# Or register manually
|
|
299
|
+
cp -r ~/projects/pi-model-router-forked/extensions ~/pi/extensions/model-router
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Once upstream merges, switch back:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Update upstream package
|
|
306
|
+
npm install -g @yeliu84/pi-model-router
|
|
307
|
+
|
|
308
|
+
# Remove local override
|
|
309
|
+
rm -rf ~/.pi/agent/extensions/pi-model-router
|
|
310
|
+
```
|
package/LEARNINGS.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Pi Model Router: Extension Development Learnings
|
|
2
|
+
|
|
3
|
+
This document captures key insights from developing the `pi-model-router` extension, focusing on architectural patterns, type safety, and best practices for future Pi extensions and AI tool integrations.
|
|
4
|
+
|
|
5
|
+
## 🎯 Extension Architecture
|
|
6
|
+
|
|
7
|
+
### 1. Provider-First Design Pattern
|
|
8
|
+
The extension registers itself as a **custom provider** rather than a simple script. The `router` provider exposes "virtual models" (e.g., `router/auto`, `router/cheap`) that remain stable while underlying concrete models change transparently.
|
|
9
|
+
|
|
10
|
+
* **When to use**: For any extension that needs to provide its own model selection logic, caching, or request routing.
|
|
11
|
+
* **Key benefit**: The UI and commands can target `router/auto` consistently, while the backend can swap underlying models based on configuration, load, or context.
|
|
12
|
+
|
|
13
|
+
### 2. Modularity by Concern
|
|
14
|
+
The extension strictly separates responsibilities into dedicated modules:
|
|
15
|
+
|
|
16
|
+
* `extensions/types.ts`: All interfaces (e.g., `RouterConfig`, `RoutingRule`)
|
|
17
|
+
* `extensions/config.ts`: Loading, normalization, merging, validation
|
|
18
|
+
* `extensions/routing.ts`: Core decision logic (heuristics, classifier, rules)
|
|
19
|
+
* `extensions/provider.ts`: Provider registration, stream delegation
|
|
20
|
+
* `extensions/state.ts`: Session-persisted state management
|
|
21
|
+
* `extensions/ui.ts`: Status line and widget rendering
|
|
22
|
+
* `extensions/commands.ts`: CLI command registrations and completions
|
|
23
|
+
* `extensions/feature-module.ts`: Feature-specific modules (e.g., `ollama-sync.ts`, `rate-limit.ts`)
|
|
24
|
+
|
|
25
|
+
* **When to use**: For any extension with complex logic that will benefit from maintainability and testing benefits.
|
|
26
|
+
* **Key benefit**: Each module can be unit tested in isolation. Changes to one concern (e.g., updating heuristics) don't risk breaking unrelated logic (e.g., command registration).
|
|
27
|
+
|
|
28
|
+
### 3. State Management via Session Entries
|
|
29
|
+
Router state is persisted using `pi.appendEntry('router-state', state)`, which creates custom session entries. This ensures state is **branch-safe**, meaning if a user creates a new conversation branch, the router can either share or isolate state as needed.
|
|
30
|
+
|
|
31
|
+
* **When to use**: For any extension that needs to maintain state across agent restarts or conversation branches.
|
|
32
|
+
* **Key benefit**: State survives session reloads and is automatically cleaned up when branches are deleted.
|
|
33
|
+
|
|
34
|
+
## 🛡️ Type Safety & Code Quality
|
|
35
|
+
|
|
36
|
+
### 1. Zero-`any` Policy
|
|
37
|
+
The extension enforces a strict policy: **Never use the `any` type**. When `any` was encountered, it was replaced with `unknown` or more specific types (e.g., `RoutedTierConfig`, `RouterTier`).
|
|
38
|
+
|
|
39
|
+
* **When to use**: For any project where long-term maintainability and robustness are priorities.
|
|
40
|
+
* **Key benefit**: Prevents runtime errors from invalid data structures. The compiler catches mismatches before deployment.
|
|
41
|
+
|
|
42
|
+
### 2. Arrow Functions Only
|
|
43
|
+
All functions are defined as arrow functions (`const myFunc = () => ...`) instead of function statements. This ensures consistent lexical scoping.
|
|
44
|
+
|
|
45
|
+
* **When to use**: For consistency across modern TypeScript projects.
|
|
46
|
+
* **Key benefit**: Eliminates unexpected `this` binding issues.
|
|
47
|
+
|
|
48
|
+
### 3. Prettier-First Development
|
|
49
|
+
The extension was formatted with Prettier (`npx prettier --write extensions/*.ts`). This enforced consistency before any deeper logic work.
|
|
50
|
+
|
|
51
|
+
* **When to use**: For any multi-author project or open-source contribution.
|
|
52
|
+
* **Key benefit**: Saves time on code reviews and prevents "style wars" in PR discussions.
|
|
53
|
+
|
|
54
|
+
## 🧭 Routing Decision Logic
|
|
55
|
+
|
|
56
|
+
### 1. Tiered Decision System
|
|
57
|
+
The router uses a tiered (`high`, `medium`, `low`) decision system, ordered by complexity and cost. A priority-based flow:
|
|
58
|
+
1. **Budget Check** (downgrade if exceeded)
|
|
59
|
+
2. **Context Trigger** (upgrade if large)
|
|
60
|
+
3. **Manual Pin** (user override)
|
|
61
|
+
4. **Custom Rules** (keyword matching)
|
|
62
|
+
5. **LLM Classifier** (optional)
|
|
63
|
+
6. **Heuristics** (fallback)
|
|
64
|
+
7. **Phase Bias** (stickiness)
|
|
65
|
+
|
|
66
|
+
* **When to use**: For any AI agent that needs to balance cost vs. performance dynamically.
|
|
67
|
+
* **Key insight**: Tiering allows fine-grained control over cost vs. quality trade-offs.
|
|
68
|
+
|
|
69
|
+
### 2. Fallback Sequence Design
|
|
70
|
+
The fallback mechanism uses a user-configurable sequence of models: `fallbackSequence: ["anthropic/claude-3-haiku", "ollama/*"]`. This is more robust than hardcoding.
|
|
71
|
+
|
|
72
|
+
* **When to use**: For any extension with high-stakes reliability requirements.
|
|
73
|
+
* **Key benefit**: Prevents catastrophic failures when a primary model is unavailable.
|
|
74
|
+
|
|
75
|
+
### 3. Graceful Error Handling
|
|
76
|
+
The extension transparently handles errors. For "out of credits" (`402`) or "rate limit" (`429`), it automatically switches to a fallback model and emits a custom session entry (`router-fallback`) for headless tooling to detect.
|
|
77
|
+
|
|
78
|
+
* **When to use**: For any extension exposed to external API services.
|
|
79
|
+
* **Key insight**: Never mask API errors; provide enough detail (status codes) in UI notifications for users to diagnose.
|
|
80
|
+
|
|
81
|
+
## 🔌 Pi Integration Patterns
|
|
82
|
+
|
|
83
|
+
### 1. Feature Toggles via Config
|
|
84
|
+
A `features` object in `model-router.json` allows enabling/disabling features at runtime:
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"features": {
|
|
88
|
+
"ollamaSync": true,
|
|
89
|
+
"respectPiScope": false,
|
|
90
|
+
"rateLimitFallback": true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
* **When to use**: For any extension with optional functionality.
|
|
96
|
+
* **Key benefit**: Allows backward compatibility while testing new features.
|
|
97
|
+
|
|
98
|
+
### 2. Config Merging Strategy
|
|
99
|
+
The extension supports both global and project-level config:
|
|
100
|
+
- Global: `~/.pi/agent/model-router.json`
|
|
101
|
+
- Project: `.pi/model-router.json`
|
|
102
|
+
|
|
103
|
+
The project config **overrides** the global config, enabling granular overrides per repository.
|
|
104
|
+
|
|
105
|
+
* **When to use**: For any extension where users want both global defaults and per-project overrides.
|
|
106
|
+
* **Key insight**: A clear merge hierarchy avoids confusion about where settings live.
|
|
107
|
+
|
|
108
|
+
### 3. Command Registration
|
|
109
|
+
Commands are registered under `/router` with subcommands (`/router status`, `/router profile`, etc.). This namespace keeps the command list clean and avoids conflicts.
|
|
110
|
+
|
|
111
|
+
* **When to use**: For any extension with multiple commands.
|
|
112
|
+
* **Key benefit**: Users can discover commands via autocompletion.
|
|
113
|
+
|
|
114
|
+
## 📊 Pi Extension Best Practices (Learnings Summary)
|
|
115
|
+
|
|
116
|
+
### For Future Pi Extensions
|
|
117
|
+
|
|
118
|
+
1. **Provider Registration**
|
|
119
|
+
- Always register a custom provider if your extension needs to provide its own models or routing logic.
|
|
120
|
+
- Keep the provider name stable while underlying models change.
|
|
121
|
+
|
|
122
|
+
2. **State Management**
|
|
123
|
+
- Use `pi.appendEntry('router-state', state)` for session-persisted state.
|
|
124
|
+
- Use a `type` field (e.g., `customType: 'router-state'`) to serialize/deserialize custom state.
|
|
125
|
+
|
|
126
|
+
3. **Type Safety**
|
|
127
|
+
- Never use `any`. Replace with `unknown` or specific interfaces.
|
|
128
|
+
- Enforce TypeScript strict mode.
|
|
129
|
+
- Format code with Prettier.
|
|
130
|
+
|
|
131
|
+
4. **Configuration**
|
|
132
|
+
- Support global (`~/.pi/agent/`) and project (`.pi/`) config.
|
|
133
|
+
- Use feature flags (`features: {...}`) to enable/disable optional behavior.
|
|
134
|
+
|
|
135
|
+
5. **Command Design**
|
|
136
|
+
- Prefix all commands with a single top-level namespace (e.g., `/router *`).
|
|
137
|
+
- Use autocompletion (`getArgumentCompletions`) to guide users.
|
|
138
|
+
|
|
139
|
+
6. **Error Handling**
|
|
140
|
+
- Never mask API errors. Provide details (status codes) in UI notifications.
|
|
141
|
+
- For critical failures, emit custom session entries so headless tooling can react.
|
|
142
|
+
|
|
143
|
+
### For AI Tools and LLM Systems
|
|
144
|
+
|
|
145
|
+
1. **Fallback Strategy**
|
|
146
|
+
- Always implement a fallback sequence. Never leave the user hanging on a single point of failure.
|
|
147
|
+
|
|
148
|
+
2. **Cost vs. Quality Trade-off**
|
|
149
|
+
- Tiering (`high`, `medium`, `low`) is a powerful abstraction for managing cost vs. quality.
|
|
150
|
+
- Let users define their own tiers based on their wallet and performance needs.
|
|
151
|
+
|
|
152
|
+
3. **Context Awareness**
|
|
153
|
+
- Be aware of context size limits. Many models have smaller context windows than their advertised maximum.
|
|
154
|
+
- Implement context truncation and auto-oversight to prevent failures.
|
|
155
|
+
|
|
156
|
+
4. **User Transparency**
|
|
157
|
+
- Inform users when switching models or tiers.
|
|
158
|
+
- Provide history or logs so users can audit decisions.
|
|
159
|
+
|
|
160
|
+
5. **Testing and Documentation**
|
|
161
|
+
- Create a `TESTING.md` for step-by-step user validation.
|
|
162
|
+
- Create a `QUICKSTART.md` for users to get running in 5 minutes.
|
|
163
|
+
- Document all feature flags and their trade-offs.
|
|
164
|
+
|
|
165
|
+
## 🚀 Next Steps for pi-model-router
|
|
166
|
+
|
|
167
|
+
1. **NPM Publishing**
|
|
168
|
+
- Bump version in `package.json` (e.g., `v0.1.2`).
|
|
169
|
+
- Run `npm publish --access public`.
|
|
170
|
+
- Tag release on GitHub (`git tag v0.1.2`).
|
|
171
|
+
|
|
172
|
+
2. **Documentation Enhancements**
|
|
173
|
+
- Consider adding a "Thinking Guide" for users to choose thinking levels (`off`, `minimal`, `medium`, `high`, `xhigh`) based on task type.
|
|
174
|
+
- Add a "Tier Selection" guide, explaining when to use `high` vs. `medium` vs. `low`.
|
|
175
|
+
|
|
176
|
+
3. **Future Feature Ideas**
|
|
177
|
+
- Per-profile Ollama models (different models per router profile).
|
|
178
|
+
- Rate limit dashboard (`/router rate-limit show` with history graph).
|
|
179
|
+
- Config UI wizard (`/router config setup` interactive).
|
|
180
|
+
|
|
181
|
+
This document serves as a knowledge base for the project, capturing lessons learned and recommendations for future development. It can be used to onboard new contributors or to inform the architecture of similar extensions.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ye Liu
|
|
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/QUICKSTART.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Quick Start — Use the Fork TODAY
|
|
2
|
+
|
|
3
|
+
## 1. Install Extension
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pi install npm:@kylebrodeur/pi-model-router
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 2. Initialize Config
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/router init
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This scaffolds a default configuration at `~/.pi/agent/model-router.json`.
|
|
16
|
+
|
|
17
|
+
## 3. Use in Pi
|
|
18
|
+
|
|
19
|
+
In Pi, run:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
/reload
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You should see in console:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
[router] Feature sync complete - ollama: true rate-limit: true
|
|
29
|
+
[router] ollama-sync: enabled
|
|
30
|
+
[router] rate-limit-fallback: enabled
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 4. Verify Features
|
|
34
|
+
|
|
35
|
+
### Auto-Sync Test
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# In another terminal
|
|
39
|
+
ollama pull llama3.2:3b
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
# In Pi
|
|
44
|
+
/router ollama-sync
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Expected: `Added: llama3.2:3b`
|
|
48
|
+
|
|
49
|
+
### Fallback Test
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
# In Pi — switch to a cloud model first
|
|
53
|
+
/model anthropic/claude-sonnet-4
|
|
54
|
+
|
|
55
|
+
# Then trigger fallback
|
|
56
|
+
/router fallback
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Expected: switches to best available model matching your `fallbackSequence` (e.g., an Ollama model)
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
# Restore
|
|
63
|
+
/router restore
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 5. New Commands
|
|
67
|
+
|
|
68
|
+
| Command | What it does |
|
|
69
|
+
| --------------------- | ------------------------------------------ |
|
|
70
|
+
| `/router ollama-sync` | Manually sync Ollama models |
|
|
71
|
+
| `/router fallback` | Switch to fallback model sequence (manual) |
|
|
72
|
+
| `/router restore` | Restore original cloud model |
|
|
73
|
+
| `/router init` | Scaffold default config file |
|
|
74
|
+
| `/router scope apply` | Sync router profiles to Pi enabled models |
|
|
75
|
+
| `/router scope reset` | Clear router profiles from Pi enabled list |
|
|
76
|
+
| `/router scope show` | Show current Pi scoped models settings |
|
|
77
|
+
|
|
78
|
+
All existing `/router *` commands still work unchanged.
|
|
79
|
+
|
|
80
|
+
## 6. Daily Workflow
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Pull new Ollama model
|
|
84
|
+
ollama pull qwen3.5:7b
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
# In Pi — auto-sync triggers on session start
|
|
89
|
+
/new
|
|
90
|
+
# → [Router] Added 1 model(s): qwen3.5:7b
|
|
91
|
+
# → Run /reload to see: qwen3.5:7b
|
|
92
|
+
|
|
93
|
+
/reload
|
|
94
|
+
# → Model now available in /model
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Troubleshooting
|
|
98
|
+
|
|
99
|
+
**"Ollama not available"**
|
|
100
|
+
→ Check `ollama list` works in terminal
|
|
101
|
+
|
|
102
|
+
**Models not in registry**
|
|
103
|
+
→ `/reload` — extension reload refreshes model registry
|
|
104
|
+
|
|
105
|
+
**TypeScript errors**
|
|
106
|
+
→ Requires Pi 0.67+ for rate-limit fallback (uses `after_provider_response` event)
|
|
107
|
+
→ Ollama sync works with current Pi version
|
|
108
|
+
|
|
109
|
+
**Config not applying**
|
|
110
|
+
→ Verify `~/.pi/agent/model-router.json` exists
|
|
111
|
+
→ Check with `cat ~/.pi/agent/model-router.json`
|