@paperclipai/hermes-paperclip-adapter 0.3.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 +228 -0
- package/dist/cli/format-event.d.ts +14 -0
- package/dist/cli/format-event.d.ts.map +1 -0
- package/dist/cli/format-event.js +52 -0
- package/dist/cli/format-event.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +14 -0
- package/dist/index.test.js.map +1 -0
- package/dist/server/command-resolution.test.d.ts +2 -0
- package/dist/server/command-resolution.test.d.ts.map +1 -0
- package/dist/server/command-resolution.test.js +37 -0
- package/dist/server/command-resolution.test.js.map +1 -0
- package/dist/server/detect-model.d.ts +77 -0
- package/dist/server/detect-model.d.ts.map +1 -0
- package/dist/server/detect-model.js +158 -0
- package/dist/server/detect-model.js.map +1 -0
- package/dist/server/detect-model.test.d.ts +2 -0
- package/dist/server/detect-model.test.d.ts.map +1 -0
- package/dist/server/detect-model.test.js +166 -0
- package/dist/server/detect-model.test.js.map +1 -0
- package/dist/server/execute.d.ts +23 -0
- package/dist/server/execute.d.ts.map +1 -0
- package/dist/server/execute.js +482 -0
- package/dist/server/execute.js.map +1 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +43 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/skills.d.ts +8 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +177 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/test.d.ts +9 -0
- package/dist/server/test.d.ts.map +1 -0
- package/dist/server/test.js +341 -0
- package/dist/server/test.js.map +1 -0
- package/dist/shared/constants.d.ts +47 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +91 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/ui/build-config.d.ts +17 -0
- package/dist/ui/build-config.d.ts.map +1 -0
- package/dist/ui/build-config.js +69 -0
- package/dist/ui/build-config.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/parse-stdout.d.ts +25 -0
- package/dist/ui/parse-stdout.d.ts.map +1 -0
- package/dist/ui/parse-stdout.js +237 -0
- package/dist/ui/parse-stdout.js.map +1 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nous Research
|
|
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,228 @@
|
|
|
1
|
+
# Paperclip Adapter for Hermes Agent
|
|
2
|
+
|
|
3
|
+
A [Paperclip](https://paperclip.ing) adapter that lets you run [Hermes Agent](https://github.com/NousResearch/hermes-agent) as a managed employee in a Paperclip company.
|
|
4
|
+
|
|
5
|
+
Hermes Agent is a full-featured AI agent by [Nous Research](https://nousresearch.com) with 30+ native tools, persistent memory, session persistence, 80+ skills, MCP support, and multi-provider model access.
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
This adapter provides:
|
|
10
|
+
|
|
11
|
+
- **8 inference providers** — Anthropic, OpenRouter, OpenAI, Nous, OpenAI Codex, ZAI, Kimi Coding, MiniMax
|
|
12
|
+
- **Skills integration** — Scans both Paperclip-managed and Hermes-native skills (`~/.hermes/skills/`), with sync/list/resolve APIs
|
|
13
|
+
- **Structured transcript parsing** — Raw Hermes stdout is parsed into typed `TranscriptEntry` objects so Paperclip renders proper tool cards with status icons and expand/collapse
|
|
14
|
+
- **Rich post-processing** — Converts Hermes ASCII banners, setext headings, and `+--+` table borders into clean GFM markdown
|
|
15
|
+
- **Comment-driven wakes** — Agents wake to respond to issue comments, not just task assignments
|
|
16
|
+
- **Auto model detection** — Reads `~/.hermes/config.yaml` to pre-populate the UI with the user's configured model
|
|
17
|
+
- **Session codec** — Structured validation and migration of session state across heartbeats
|
|
18
|
+
- **Benign stderr reclassification** — MCP init messages and structured logs are reclassified so they don't appear as errors in the UI
|
|
19
|
+
- **Session source tagging** — Sessions are tagged as `tool` source so they don't clutter the user's interactive history
|
|
20
|
+
- **Filesystem checkpoints** — Optional `--checkpoints` for rollback safety
|
|
21
|
+
- **Thinking effort control** — Passes `--reasoning-effort` for thinking/reasoning models
|
|
22
|
+
|
|
23
|
+
### Hermes Agent Capabilities
|
|
24
|
+
|
|
25
|
+
| Feature | Claude Code | Codex | Hermes Agent |
|
|
26
|
+
|---------|------------|-------|-------------|
|
|
27
|
+
| Persistent memory | ❌ | ❌ | ✅ Remembers across sessions |
|
|
28
|
+
| Native tools | ~5 | ~5 | 30+ (terminal, file, web, browser, vision, git, etc.) |
|
|
29
|
+
| Skills system | ❌ | ❌ | ✅ 80+ loadable skills |
|
|
30
|
+
| Session search | ❌ | ❌ | ✅ FTS5 search over past conversations |
|
|
31
|
+
| Sub-agent delegation | ❌ | ❌ | ✅ Parallel sub-tasks |
|
|
32
|
+
| Context compression | ❌ | ❌ | ✅ Auto-compresses long conversations |
|
|
33
|
+
| MCP client | ❌ | ❌ | ✅ Connect to any MCP server |
|
|
34
|
+
| Multi-provider | Anthropic only | OpenAI only | ✅ 8 providers out of the box |
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install @paperclipai/hermes-paperclip-adapter
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
- [Hermes Agent](https://github.com/NousResearch/hermes-agent) installed (`pip install hermes-agent`)
|
|
45
|
+
- Python 3.10+
|
|
46
|
+
- At least one LLM API key (Anthropic, OpenRouter, or OpenAI)
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### 1. Register the adapter in your Paperclip server
|
|
51
|
+
|
|
52
|
+
Add to your Paperclip server's adapter registry (`server/src/adapters/registry.ts`):
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import * as hermesLocal from "@paperclipai/hermes-paperclip-adapter";
|
|
56
|
+
import {
|
|
57
|
+
execute,
|
|
58
|
+
testEnvironment,
|
|
59
|
+
detectModel,
|
|
60
|
+
listSkills,
|
|
61
|
+
syncSkills,
|
|
62
|
+
sessionCodec,
|
|
63
|
+
} from "@paperclipai/hermes-paperclip-adapter/server";
|
|
64
|
+
|
|
65
|
+
registry.set("hermes_local", {
|
|
66
|
+
...hermesLocal,
|
|
67
|
+
execute,
|
|
68
|
+
testEnvironment,
|
|
69
|
+
detectModel,
|
|
70
|
+
listSkills,
|
|
71
|
+
syncSkills,
|
|
72
|
+
sessionCodec,
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Create a Hermes agent in Paperclip
|
|
77
|
+
|
|
78
|
+
In the Paperclip UI or via API, create an agent with adapter type `hermes_local`:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"name": "Hermes Engineer",
|
|
83
|
+
"adapterType": "hermes_local",
|
|
84
|
+
"adapterConfig": {
|
|
85
|
+
"model": "anthropic/claude-sonnet-4",
|
|
86
|
+
"maxIterations": 50,
|
|
87
|
+
"timeoutSec": 300,
|
|
88
|
+
"persistSession": true,
|
|
89
|
+
"enabledToolsets": ["terminal", "file", "web"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Assign work
|
|
95
|
+
|
|
96
|
+
Create issues in Paperclip and assign them to your Hermes agent. On each heartbeat, Hermes will:
|
|
97
|
+
|
|
98
|
+
1. Receive the task instructions
|
|
99
|
+
2. Use its full tool suite to complete the work
|
|
100
|
+
3. Report results back to Paperclip
|
|
101
|
+
4. Persist session state for continuity
|
|
102
|
+
|
|
103
|
+
## Configuration Reference
|
|
104
|
+
|
|
105
|
+
### Core
|
|
106
|
+
|
|
107
|
+
| Field | Type | Default | Description |
|
|
108
|
+
|-------|------|---------|-------------|
|
|
109
|
+
| `model` | string | `anthropic/claude-sonnet-4` | Model in `provider/model` format |
|
|
110
|
+
| `provider` | string | *(auto-detected)* | API provider: `auto`, `openrouter`, `nous`, `openai-codex`, `zai`, `kimi-coding`, `minimax`, `minimax-cn` |
|
|
111
|
+
| `timeoutSec` | number | `300` | Execution timeout in seconds |
|
|
112
|
+
| `graceSec` | number | `10` | Grace period before SIGKILL |
|
|
113
|
+
|
|
114
|
+
### Tools
|
|
115
|
+
|
|
116
|
+
| Field | Type | Default | Description |
|
|
117
|
+
|-------|------|---------|-------------|
|
|
118
|
+
| `toolsets` | string | *(all)* | Comma-separated toolsets to enable (e.g. `"terminal,file,web"`) |
|
|
119
|
+
|
|
120
|
+
Available toolsets: `terminal`, `file`, `web`, `browser`, `code_execution`, `vision`, `mcp`, `creative`, `productivity`
|
|
121
|
+
|
|
122
|
+
### Session & Workspace
|
|
123
|
+
|
|
124
|
+
| Field | Type | Default | Description |
|
|
125
|
+
|-------|------|---------|-------------|
|
|
126
|
+
| `persistSession` | boolean | `true` | Resume sessions across heartbeats |
|
|
127
|
+
| `worktreeMode` | boolean | `false` | Git worktree isolation |
|
|
128
|
+
| `checkpoints` | boolean | `false` | Enable filesystem checkpoints for rollback |
|
|
129
|
+
|
|
130
|
+
### Advanced
|
|
131
|
+
|
|
132
|
+
| Field | Type | Default | Description |
|
|
133
|
+
|-------|------|---------|-------------|
|
|
134
|
+
| `hermesCommand` | string | `hermes` | Custom CLI binary path |
|
|
135
|
+
| `verbose` | boolean | `false` | Enable verbose output |
|
|
136
|
+
| `quiet` | boolean | `true` | Quiet mode (clean output, no banner/spinner) |
|
|
137
|
+
| `extraArgs` | string[] | `[]` | Additional CLI arguments |
|
|
138
|
+
| `env` | object | `{}` | Extra environment variables |
|
|
139
|
+
| `promptTemplate` | string | *(built-in)* | Custom prompt template |
|
|
140
|
+
| `paperclipApiUrl` | string | `http://127.0.0.1:3100/api` | Paperclip API base URL |
|
|
141
|
+
|
|
142
|
+
### Prompt Template Variables
|
|
143
|
+
|
|
144
|
+
Use `{{variable}}` syntax in `promptTemplate`:
|
|
145
|
+
|
|
146
|
+
| Variable | Description |
|
|
147
|
+
|----------|-------------|
|
|
148
|
+
| `{{agentId}}` | Paperclip agent ID |
|
|
149
|
+
| `{{agentName}}` | Agent display name |
|
|
150
|
+
| `{{companyId}}` | Company ID |
|
|
151
|
+
| `{{companyName}}` | Company name |
|
|
152
|
+
| `{{runId}}` | Current heartbeat run ID |
|
|
153
|
+
| `{{taskId}}` | Assigned task/issue ID |
|
|
154
|
+
| `{{taskTitle}}` | Task title |
|
|
155
|
+
| `{{taskBody}}` | Task instructions |
|
|
156
|
+
| `{{projectName}}` | Project name |
|
|
157
|
+
| `{{paperclipApiUrl}}` | Paperclip API base URL |
|
|
158
|
+
| `{{commentId}}` | Comment ID (when woken by a comment) |
|
|
159
|
+
| `{{wakeReason}}` | Reason this run was triggered |
|
|
160
|
+
|
|
161
|
+
Conditional sections:
|
|
162
|
+
|
|
163
|
+
- `{{#taskId}}...{{/taskId}}` — included only when a task is assigned
|
|
164
|
+
- `{{#noTask}}...{{/noTask}}` — included only when no task (heartbeat check)
|
|
165
|
+
- `{{#commentId}}...{{/commentId}}` — included only when woken by a comment
|
|
166
|
+
|
|
167
|
+
## Architecture
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
Paperclip Hermes Agent
|
|
171
|
+
┌──────────────────┐ ┌──────────────────┐
|
|
172
|
+
│ Heartbeat │ │ │
|
|
173
|
+
│ Scheduler │───execute()──▶│ hermes chat -q │
|
|
174
|
+
│ │ │ │
|
|
175
|
+
│ Issue System │ │ 30+ Tools │
|
|
176
|
+
│ Comment Wakes │◀──results─────│ Memory System │
|
|
177
|
+
│ │ │ Session DB │
|
|
178
|
+
│ Cost Tracking │ │ Skills │
|
|
179
|
+
│ │ │ MCP Client │
|
|
180
|
+
│ Skill Sync │◀──snapshot────│ ~/.hermes/skills│
|
|
181
|
+
│ Org Chart │ │ │
|
|
182
|
+
└──────────────────┘ └──────────────────┘
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The adapter spawns Hermes Agent's CLI in single-query mode (`-q`). Hermes
|
|
186
|
+
processes the task using its full tool suite, then exits. The adapter:
|
|
187
|
+
|
|
188
|
+
1. **Captures** stdout/stderr and parses token usage, session IDs, and cost
|
|
189
|
+
2. **Parses** raw output into structured `TranscriptEntry` objects (tool cards with status icons)
|
|
190
|
+
3. **Post-processes** Hermes ASCII formatting (banners, setext headings, table borders) into clean GFM markdown
|
|
191
|
+
4. **Reclassifies** benign stderr (MCP init, structured logs) so they don't show as errors
|
|
192
|
+
5. **Tags** sessions as `tool` source to keep them separate from interactive usage
|
|
193
|
+
6. **Reports** results back to Paperclip with cost, usage, and session state
|
|
194
|
+
|
|
195
|
+
Session persistence works via Hermes's `--resume` flag — each run picks
|
|
196
|
+
up where the last one left off, maintaining conversation context,
|
|
197
|
+
memories, and tool state across heartbeats. The `sessionCodec` validates
|
|
198
|
+
and migrates session state between runs.
|
|
199
|
+
|
|
200
|
+
### Skills Integration
|
|
201
|
+
|
|
202
|
+
The adapter scans two skill sources and merges them:
|
|
203
|
+
|
|
204
|
+
- **Paperclip-managed skills** — bundled with the adapter, togglable from the UI
|
|
205
|
+
- **Hermes-native skills** — from `~/.hermes/skills/`, read-only, always loaded
|
|
206
|
+
|
|
207
|
+
The `listSkills` / `syncSkills` APIs expose a unified snapshot so the
|
|
208
|
+
Paperclip UI can display both managed and native skills in one view.
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
git clone https://github.com/paperclipai/hermes-paperclip-adapter
|
|
214
|
+
cd hermes-paperclip-adapter
|
|
215
|
+
npm install
|
|
216
|
+
npm run build
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
MIT — see [LICENSE](LICENSE)
|
|
222
|
+
|
|
223
|
+
## Links
|
|
224
|
+
|
|
225
|
+
- [Hermes Agent](https://github.com/NousResearch/hermes-agent) — The AI agent this adapter runs
|
|
226
|
+
- [Paperclip](https://github.com/paperclipai/paperclip) — The orchestration platform
|
|
227
|
+
- [Nous Research](https://nousresearch.com) — The team behind Hermes
|
|
228
|
+
- [Paperclip Docs](https://paperclip.ing/docs) — Paperclip documentation
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output formatting for Hermes Agent adapter.
|
|
3
|
+
*
|
|
4
|
+
* Pretty-prints Hermes output lines in the terminal when running
|
|
5
|
+
* Paperclip's CLI tools.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Format a Hermes Agent stdout event for terminal display.
|
|
9
|
+
*
|
|
10
|
+
* @param raw Raw stdout line from Hermes
|
|
11
|
+
* @param debug If true, show extra metadata with color coding
|
|
12
|
+
*/
|
|
13
|
+
export declare function printHermesStreamEvent(raw: string, debug: boolean): void;
|
|
14
|
+
//# sourceMappingURL=format-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.d.ts","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CA6CxE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output formatting for Hermes Agent adapter.
|
|
3
|
+
*
|
|
4
|
+
* Pretty-prints Hermes output lines in the terminal when running
|
|
5
|
+
* Paperclip's CLI tools.
|
|
6
|
+
*/
|
|
7
|
+
import pc from "picocolors";
|
|
8
|
+
/**
|
|
9
|
+
* Format a Hermes Agent stdout event for terminal display.
|
|
10
|
+
*
|
|
11
|
+
* @param raw Raw stdout line from Hermes
|
|
12
|
+
* @param debug If true, show extra metadata with color coding
|
|
13
|
+
*/
|
|
14
|
+
export function printHermesStreamEvent(raw, debug) {
|
|
15
|
+
const line = raw.trim();
|
|
16
|
+
if (!line)
|
|
17
|
+
return;
|
|
18
|
+
if (!debug) {
|
|
19
|
+
console.log(line);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Adapter log lines
|
|
23
|
+
if (line.startsWith("[hermes]")) {
|
|
24
|
+
console.log(pc.blue(line));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Tool output (┊ prefix)
|
|
28
|
+
if (line.startsWith("┊")) {
|
|
29
|
+
console.log(pc.cyan(line));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Thinking
|
|
33
|
+
if (line.includes("💭") || line.startsWith("<thinking>")) {
|
|
34
|
+
console.log(pc.dim(line));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Errors
|
|
38
|
+
if (line.startsWith("Error:") ||
|
|
39
|
+
line.startsWith("ERROR:") ||
|
|
40
|
+
line.startsWith("Traceback")) {
|
|
41
|
+
console.log(pc.red(line));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Session info
|
|
45
|
+
if (/session/i.test(line) && /id|saved|resumed/i.test(line)) {
|
|
46
|
+
console.log(pc.green(line));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Default: gray in debug mode
|
|
50
|
+
console.log(pc.gray(line));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=format-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-event.js","sourceRoot":"","sources":["../../src/cli/format-event.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,KAAc;IAChE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,CAAC,IAAI;QAAE,OAAO;IAElB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO;IACT,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,yBAAyB;IACzB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,WAAW;IACX,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,SAAS;IACT,IACE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAC5B,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,eAAe;IACf,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,8BAA8B;IAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermes Agent adapter for Paperclip.
|
|
3
|
+
*
|
|
4
|
+
* Runs Hermes Agent (https://github.com/NousResearch/hermes-agent)
|
|
5
|
+
* as a managed employee in a Paperclip company. Hermes Agent is a
|
|
6
|
+
* full-featured AI agent with 30+ native tools, persistent memory,
|
|
7
|
+
* skills, session persistence, and MCP support.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import type { ServerAdapterModule } from "@paperclipai/adapter-utils";
|
|
12
|
+
export declare const type = "hermes_local";
|
|
13
|
+
export declare const label = "Hermes Agent";
|
|
14
|
+
/**
|
|
15
|
+
* Models available through Hermes Agent.
|
|
16
|
+
*
|
|
17
|
+
* Hermes supports any model via any provider. The Paperclip UI should
|
|
18
|
+
* prefer detectModel() plus manual entry over curated placeholder models,
|
|
19
|
+
* since Hermes availability depends on the user's local configuration.
|
|
20
|
+
*/
|
|
21
|
+
export declare const models: {
|
|
22
|
+
id: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}[];
|
|
25
|
+
/**
|
|
26
|
+
* Documentation shown in the Paperclip UI when configuring a Hermes agent.
|
|
27
|
+
*/
|
|
28
|
+
export declare const agentConfigurationDoc = "# Hermes Agent Configuration\n\nHermes Agent is a full-featured AI agent by Nous Research with 30+ native\ntools, persistent memory, session persistence, skills, and MCP support.\n\n## Prerequisites\n\n- Python 3.10+ installed\n- Hermes Agent installed: `pip install hermes-agent`\n- At least one LLM API key configured in ~/.hermes/.env\n\n## Core Configuration\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| model | string | (Hermes configured default) | Optional explicit model in provider/model format. Leave blank to use Hermes's configured default model. |\n| provider | string | (auto) | API provider: auto, openrouter, nous, openai-codex, zai, kimi-coding, minimax, minimax-cn. Usually not needed \u2014 Hermes auto-detects from model name. |\n| timeoutSec | number | 300 | Execution timeout in seconds |\n| graceSec | number | 10 | Grace period after SIGTERM before SIGKILL |\n\n## Tool Configuration\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| toolsets | string | (all) | Comma-separated toolsets to enable (e.g. \"terminal,file,web\") |\n\n## Session & Workspace\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| persistSession | boolean | true | Resume sessions across heartbeats |\n| worktreeMode | boolean | false | Use git worktree for isolated changes |\n| checkpoints | boolean | false | Enable filesystem checkpoints |\n\n## Advanced\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| hermesCommand | string | hermes | Path to hermes CLI binary |\n| verbose | boolean | false | Enable verbose output |\n| extraArgs | string[] | [] | Additional CLI arguments |\n| env | object | {} | Extra environment variables |\n| promptTemplate | string | (default) | Custom prompt template with {{variable}} placeholders |\n\n## Available Template Variables\n\n- `{{agentId}}` \u2014 Paperclip agent ID\n- `{{agentName}}` \u2014 Agent display name\n- `{{companyId}}` \u2014 Paperclip company ID\n- `{{companyName}}` \u2014 Company display name\n- `{{runId}}` \u2014 Current heartbeat run ID\n- `{{taskId}}` \u2014 Current task/issue ID (if assigned)\n- `{{taskTitle}}` \u2014 Task title (if assigned)\n- `{{taskBody}}` \u2014 Task description (if assigned)\n- `{{projectName}}` \u2014 Project name (if scoped to a project)\n";
|
|
29
|
+
/**
|
|
30
|
+
* External adapter plugin entrypoint expected by Paperclip's adapter manager.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createServerAdapter(): ServerAdapterModule;
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAYtE,eAAO,MAAM,IAAI,iBAAe,CAAC;AACjC,eAAO,MAAM,KAAK,iBAAgB,CAAC;AAEnC;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAO,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,qBAAqB,81EAuDjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,mBAAmB,CAgBzD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermes Agent adapter for Paperclip.
|
|
3
|
+
*
|
|
4
|
+
* Runs Hermes Agent (https://github.com/NousResearch/hermes-agent)
|
|
5
|
+
* as a managed employee in a Paperclip company. Hermes Agent is a
|
|
6
|
+
* full-featured AI agent with 30+ native tools, persistent memory,
|
|
7
|
+
* skills, session persistence, and MCP support.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import { ADAPTER_TYPE, ADAPTER_LABEL } from "./shared/constants.js";
|
|
12
|
+
import { execute, testEnvironment, sessionCodec, listSkills, syncSkills, detectModel, } from "./server/index.js";
|
|
13
|
+
export const type = ADAPTER_TYPE;
|
|
14
|
+
export const label = ADAPTER_LABEL;
|
|
15
|
+
/**
|
|
16
|
+
* Models available through Hermes Agent.
|
|
17
|
+
*
|
|
18
|
+
* Hermes supports any model via any provider. The Paperclip UI should
|
|
19
|
+
* prefer detectModel() plus manual entry over curated placeholder models,
|
|
20
|
+
* since Hermes availability depends on the user's local configuration.
|
|
21
|
+
*/
|
|
22
|
+
export const models = [];
|
|
23
|
+
/**
|
|
24
|
+
* Documentation shown in the Paperclip UI when configuring a Hermes agent.
|
|
25
|
+
*/
|
|
26
|
+
export const agentConfigurationDoc = `# Hermes Agent Configuration
|
|
27
|
+
|
|
28
|
+
Hermes Agent is a full-featured AI agent by Nous Research with 30+ native
|
|
29
|
+
tools, persistent memory, session persistence, skills, and MCP support.
|
|
30
|
+
|
|
31
|
+
## Prerequisites
|
|
32
|
+
|
|
33
|
+
- Python 3.10+ installed
|
|
34
|
+
- Hermes Agent installed: \`pip install hermes-agent\`
|
|
35
|
+
- At least one LLM API key configured in ~/.hermes/.env
|
|
36
|
+
|
|
37
|
+
## Core Configuration
|
|
38
|
+
|
|
39
|
+
| Field | Type | Default | Description |
|
|
40
|
+
|-------|------|---------|-------------|
|
|
41
|
+
| model | string | (Hermes configured default) | Optional explicit model in provider/model format. Leave blank to use Hermes's configured default model. |
|
|
42
|
+
| provider | string | (auto) | API provider: auto, openrouter, nous, openai-codex, zai, kimi-coding, minimax, minimax-cn. Usually not needed — Hermes auto-detects from model name. |
|
|
43
|
+
| timeoutSec | number | 300 | Execution timeout in seconds |
|
|
44
|
+
| graceSec | number | 10 | Grace period after SIGTERM before SIGKILL |
|
|
45
|
+
|
|
46
|
+
## Tool Configuration
|
|
47
|
+
|
|
48
|
+
| Field | Type | Default | Description |
|
|
49
|
+
|-------|------|---------|-------------|
|
|
50
|
+
| toolsets | string | (all) | Comma-separated toolsets to enable (e.g. "terminal,file,web") |
|
|
51
|
+
|
|
52
|
+
## Session & Workspace
|
|
53
|
+
|
|
54
|
+
| Field | Type | Default | Description |
|
|
55
|
+
|-------|------|---------|-------------|
|
|
56
|
+
| persistSession | boolean | true | Resume sessions across heartbeats |
|
|
57
|
+
| worktreeMode | boolean | false | Use git worktree for isolated changes |
|
|
58
|
+
| checkpoints | boolean | false | Enable filesystem checkpoints |
|
|
59
|
+
|
|
60
|
+
## Advanced
|
|
61
|
+
|
|
62
|
+
| Field | Type | Default | Description |
|
|
63
|
+
|-------|------|---------|-------------|
|
|
64
|
+
| hermesCommand | string | hermes | Path to hermes CLI binary |
|
|
65
|
+
| verbose | boolean | false | Enable verbose output |
|
|
66
|
+
| extraArgs | string[] | [] | Additional CLI arguments |
|
|
67
|
+
| env | object | {} | Extra environment variables |
|
|
68
|
+
| promptTemplate | string | (default) | Custom prompt template with {{variable}} placeholders |
|
|
69
|
+
|
|
70
|
+
## Available Template Variables
|
|
71
|
+
|
|
72
|
+
- \`{{agentId}}\` — Paperclip agent ID
|
|
73
|
+
- \`{{agentName}}\` — Agent display name
|
|
74
|
+
- \`{{companyId}}\` — Paperclip company ID
|
|
75
|
+
- \`{{companyName}}\` — Company display name
|
|
76
|
+
- \`{{runId}}\` — Current heartbeat run ID
|
|
77
|
+
- \`{{taskId}}\` — Current task/issue ID (if assigned)
|
|
78
|
+
- \`{{taskTitle}}\` — Task title (if assigned)
|
|
79
|
+
- \`{{taskBody}}\` — Task description (if assigned)
|
|
80
|
+
- \`{{projectName}}\` — Project name (if scoped to a project)
|
|
81
|
+
`;
|
|
82
|
+
/**
|
|
83
|
+
* External adapter plugin entrypoint expected by Paperclip's adapter manager.
|
|
84
|
+
*/
|
|
85
|
+
export function createServerAdapter() {
|
|
86
|
+
return {
|
|
87
|
+
type,
|
|
88
|
+
execute,
|
|
89
|
+
testEnvironment,
|
|
90
|
+
sessionCodec,
|
|
91
|
+
listSkills,
|
|
92
|
+
syncSkills,
|
|
93
|
+
models,
|
|
94
|
+
supportsLocalAgentJwt: true,
|
|
95
|
+
supportsInstructionsBundle: true,
|
|
96
|
+
instructionsPathKey: "instructionsFilePath",
|
|
97
|
+
requiresMaterializedRuntimeSkills: false,
|
|
98
|
+
agentConfigurationDoc,
|
|
99
|
+
detectModel,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EACL,OAAO,EACP,eAAe,EACf,YAAY,EACZ,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAC;AACjC,MAAM,CAAC,MAAM,KAAK,GAAG,aAAa,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAoC,EAAE,CAAC;AAE1D;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDpC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,IAAI;QACJ,OAAO;QACP,eAAe;QACf,YAAY;QACZ,UAAU;QACV,UAAU;QACV,MAAM;QACN,qBAAqB,EAAE,IAAI;QAC3B,0BAA0B,EAAE,IAAI;QAChC,mBAAmB,EAAE,sBAAsB;QAC3C,iCAAiC,EAAE,KAAK;QACxC,qBAAqB;QACrB,WAAW;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { createServerAdapter } from "./index.js";
|
|
3
|
+
test("root package export exposes Paperclip external adapter entrypoint", () => {
|
|
4
|
+
const adapter = createServerAdapter();
|
|
5
|
+
expect(adapter.type).toBe("hermes_local");
|
|
6
|
+
expect(typeof adapter.execute).toBe("function");
|
|
7
|
+
expect(typeof adapter.testEnvironment).toBe("function");
|
|
8
|
+
expect(typeof adapter.sessionCodec?.deserialize).toBe("function");
|
|
9
|
+
expect(adapter.supportsLocalAgentJwt).toBe(true);
|
|
10
|
+
expect(adapter.supportsInstructionsBundle).toBe(true);
|
|
11
|
+
expect(adapter.instructionsPathKey).toBe("instructionsFilePath");
|
|
12
|
+
expect(typeof adapter.detectModel).toBe("function");
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,IAAI,CAAC,mEAAmE,EAAE,GAAG,EAAE;IAC7E,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IAEtC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,MAAM,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,CAAC,OAAO,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClE,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACjE,MAAM,CAAC,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-resolution.test.d.ts","sourceRoot":"","sources":["../../src/server/command-resolution.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { expect, test } from "vitest";
|
|
5
|
+
import { HERMES_CLI } from "../shared/constants.js";
|
|
6
|
+
import { resolveHermesCommand } from "./execute.js";
|
|
7
|
+
import { testEnvironment } from "./test.js";
|
|
8
|
+
test("resolveHermesCommand prefers hermesCommand over command", () => {
|
|
9
|
+
expect(resolveHermesCommand({ hermesCommand: "hermes_maximus", command: "hermes_backup" }))
|
|
10
|
+
.toBe("hermes_maximus");
|
|
11
|
+
});
|
|
12
|
+
test("resolveHermesCommand falls back to command before default hermes binary", () => {
|
|
13
|
+
expect(resolveHermesCommand({ command: "hermes_maximus" })).toBe("hermes_maximus");
|
|
14
|
+
expect(resolveHermesCommand({})).toBe(HERMES_CLI);
|
|
15
|
+
});
|
|
16
|
+
test("testEnvironment accepts config.command when hermesCommand is absent", async () => {
|
|
17
|
+
const tempDir = await mkdtemp(path.join(os.tmpdir(), "hermes-command-resolution-"));
|
|
18
|
+
const cliPath = path.join(tempDir, "fake-hermes");
|
|
19
|
+
try {
|
|
20
|
+
await writeFile(cliPath, "#!/bin/sh\necho fake-hermes 1.2.3\n", "utf8");
|
|
21
|
+
await chmod(cliPath, 0o755);
|
|
22
|
+
const result = await testEnvironment({
|
|
23
|
+
companyId: "company-test",
|
|
24
|
+
adapterType: "hermes_local",
|
|
25
|
+
config: {
|
|
26
|
+
command: cliPath,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
expect(result.status).not.toBe("fail");
|
|
30
|
+
expect(result.checks.some((check) => check.code === "hermes_cli_not_found")).toBe(false);
|
|
31
|
+
expect(result.checks.some((check) => check.code === "hermes_version" && check.message.includes("fake-hermes 1.2.3"))).toBe(true);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=command-resolution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-resolution.test.js","sourceRoot":"","sources":["../../src/server/command-resolution.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,CAAC,oBAAoB,CAAC,EAAE,aAAa,EAAE,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;SACxF,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yEAAyE,EAAE,GAAG,EAAE;IACnF,MAAM,CAAC,oBAAoB,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnF,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;IACrF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAC;IACpF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,SAAS,CACb,OAAO,EACP,qCAAqC,EACrC,MAAM,CACP,CAAC;QACF,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE5B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;YACnC,SAAS,EAAE,cAAc;YACzB,WAAW,EAAE,cAAc;YAC3B,MAAM,EAAE;gBACN,OAAO,EAAE,OAAO;aACjB;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CACvB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAC1F,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect the current model and provider from the user's Hermes config.
|
|
3
|
+
*
|
|
4
|
+
* Reads ~/.hermes/config.yaml and extracts the default model,
|
|
5
|
+
* provider, base_url, api_key presence, and api_mode settings.
|
|
6
|
+
*
|
|
7
|
+
* Also provides provider resolution logic that merges explicit config,
|
|
8
|
+
* Hermes config detection, and model-name prefix inference.
|
|
9
|
+
*/
|
|
10
|
+
export interface DetectedModel {
|
|
11
|
+
/** Model name from config (e.g. "gpt-5.4", "anthropic/claude-sonnet-4") */
|
|
12
|
+
model: string;
|
|
13
|
+
/** Provider name from config (e.g. "copilot", "zai"). May be empty. */
|
|
14
|
+
provider: string;
|
|
15
|
+
/** Base URL override from config (e.g. "https://api.githubcopilot.com"). May be empty. */
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
/** Whether Hermes config includes a non-empty API key. */
|
|
18
|
+
hasApiKey: boolean;
|
|
19
|
+
/** API mode from config (e.g. "chat_completions", "codex_responses"). May be empty. */
|
|
20
|
+
apiMode: string;
|
|
21
|
+
/** Where the detection came from */
|
|
22
|
+
source: "config";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read the Hermes config file and extract the default model config.
|
|
26
|
+
*/
|
|
27
|
+
export declare function detectModel(configPath?: string): Promise<DetectedModel | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Parse model.default, model.provider, model.base_url, model.api_key, and model.api_mode
|
|
30
|
+
* from raw YAML content. Uses simple regex parsing to avoid a YAML dependency.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseModelFromConfig(content: string): DetectedModel | null;
|
|
33
|
+
/**
|
|
34
|
+
* Infer a provider from the model name using prefix-based hints.
|
|
35
|
+
*
|
|
36
|
+
* For example:
|
|
37
|
+
* "gpt-5.4" → "copilot"
|
|
38
|
+
* "claude-sonnet-4" → "anthropic"
|
|
39
|
+
* "glm-5-turbo" → "zai"
|
|
40
|
+
*
|
|
41
|
+
* Returns undefined if no hint matches (caller should fall back to "auto").
|
|
42
|
+
*/
|
|
43
|
+
export declare function inferProviderFromModel(model: string): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the correct provider for a model, using a priority chain:
|
|
46
|
+
*
|
|
47
|
+
* 1. Explicit provider from adapterConfig (highest priority — user override)
|
|
48
|
+
* 2. Provider from Hermes config file — ONLY if the config model matches
|
|
49
|
+
* the requested model (otherwise the config provider is for a different model)
|
|
50
|
+
* 3. If Hermes config matches the requested model but uses runtime settings that
|
|
51
|
+
* the adapter cannot represent directly, return "auto" and let Hermes resolve it itself
|
|
52
|
+
* 4. Provider inferred from model name prefix
|
|
53
|
+
* 5. "auto" (let Hermes figure it out — lowest priority)
|
|
54
|
+
*
|
|
55
|
+
* Always returns a valid provider string.
|
|
56
|
+
* The `resolvedFrom` field indicates which source was used, useful for logging.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveProvider(options: {
|
|
59
|
+
/** Explicit provider from adapterConfig (user override) */
|
|
60
|
+
explicitProvider?: string | null;
|
|
61
|
+
/** Provider detected from Hermes config file */
|
|
62
|
+
detectedProvider?: string;
|
|
63
|
+
/** Model name from Hermes config file (to check consistency) */
|
|
64
|
+
detectedModel?: string;
|
|
65
|
+
/** Base URL detected from Hermes config file */
|
|
66
|
+
detectedBaseUrl?: string;
|
|
67
|
+
/** Whether Hermes config includes a non-empty API key */
|
|
68
|
+
detectedHasApiKey?: boolean;
|
|
69
|
+
/** API mode detected from Hermes config file */
|
|
70
|
+
detectedApiMode?: string;
|
|
71
|
+
/** Model name to infer from if no explicit/detected provider */
|
|
72
|
+
model?: string;
|
|
73
|
+
}): {
|
|
74
|
+
provider: string;
|
|
75
|
+
resolvedFrom: string;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=detect-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-model.d.ts","sourceRoot":"","sources":["../../src/server/detect-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,MAAM,EAAE,QAAQ,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAW/B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA2C1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAaxE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAiE7C"}
|