Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ jobs:
echo " [typecheck] packages/$pkg"
(cd packages/$pkg && bun run typecheck) || exit 1
done
- name: Typecheck plugins
run: |
for plugin in agent-workbench-hermes; do
echo " [typecheck] plugins/$plugin"
(cd plugins/$plugin && bun run typecheck) || exit 1
done
- name: Typecheck apps
run: |
for app in server tui cli mobile-web dashboard; do
Expand Down
29 changes: 28 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions docs/27_PROJECT_ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 27 — Project Roadmap

Status: Phase 27 complete — Phase 29 (model experimentation & eval) in progress
Status: Phase 29 complete — Phase 30 (enterprise readiness) next
Document type: Roadmap for Phases 19–30
Supersedes: incremental updates in docs/04_IMPLEMENTATION_PHASE_CHECKLIST.md

Expand All @@ -21,8 +21,8 @@ Phase 25 ✅ complete ███████████████████
Phase 26 ✅ complete ██████████████████████ plugin system & extensibility
Phase 27 ✅ complete ██████████████████████ remote access & collaboration
Phase 28 ⏸️ ░░░░░░░░░░░░░░░░░░░░ ⏸️ desktop application (deferred)
Phase 29 ▌ ░░░░░░░░░░░░░░░░░░░░ model experimentation & eval
Phase 30 ░░░░░░░░░░░░░░░░░░░░░░░░░ enterprise readiness & compliance
Phase 29 ✅ complete ██████████████████████ model experimentation & eval
Phase 30 ░░░░░░░░░░░░░░░░░░░░ enterprise readiness & compliance
```

### Timeline
Expand Down Expand Up @@ -284,7 +284,7 @@ These bridges connect agent-workbench with existing developer tooling:
[ ] GDPR: right to access, right to delete endpoints
[ ] Supply chain: SBOM generation, dependency vulnerability scanning
[ ] FIPS 140-2 compliance for cryptographic operations
[ ] Hermes Agent bridge auto-discovers provider config from ~/.hermes/
[x] Hermes Agent bridge auto-discovers provider config from ~/.hermes/
[ ] OpenCode bridge syncs provider registry bidirectionally
```

Expand Down Expand Up @@ -360,5 +360,5 @@ Dependencies: Phase N

---

*Last updated: 2026-07-03 (Phase 29 in progress — prompt library, playground, ModelComparer committed)*
*Next review: After Phase 29 completion*
*Last updated: 2026-07-03 (Phase 29 complete, Phase 30 started — Hermes bridge)*
*Next review: After Phase 30 completion*
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"workspaces": [
"apps/*",
"packages/*",
"tests"
"tests",
"plugins/*"
],
"scripts": {
"phase": "echo Phase 1 workspace scaffold only",
Expand Down
26 changes: 26 additions & 0 deletions plugins/agent-workbench-hermes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@agent-workbench/hermes-bridge",
"version": "0.0.0",
"private": true,
"type": "module",
"description": "Hermes Agent Bridge — auto-discovers Hermes providers and maps them to agent-workbench",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@agent-workbench/plugin-sdk": "*"
},
"devDependencies": {
"@types/bun": "^1.3.14",
"@types/node": "^26.1.0"
}
}
18 changes: 10 additions & 8 deletions plugins/agent-workbench-hermes/src/copilot-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class CopilotAdapter {
async call(
messages: PluginModelMessage[],
tools?: PluginToolDefinition[],
signal?: AbortSignal,
signal?: AbortSignal | null,
): Promise<PluginModelResponse> {
const body = this.buildBody(messages, tools, false);
const headers = this.buildHeaders();
Expand All @@ -50,7 +50,7 @@ export class CopilotAdapter {
method: "POST",
headers,
body: JSON.stringify(body),
signal,
signal: signal ?? null,
});

if (!response.ok) {
Expand All @@ -70,19 +70,21 @@ export class CopilotAdapter {

return {
content,
usage: usage
...(usage
? {
inputTokens: (usage.prompt_tokens as number) ?? 0,
outputTokens: (usage.completion_tokens as number) ?? 0,
usage: {
inputTokens: (usage.prompt_tokens as number) ?? 0,
outputTokens: (usage.completion_tokens as number) ?? 0,
},
}
: undefined,
: {}),
};
}

async *stream(
messages: PluginModelMessage[],
tools?: PluginToolDefinition[],
signal?: AbortSignal,
signal?: AbortSignal | null,
): AsyncGenerator<PluginStreamChunk> {
const body = this.buildBody(messages, tools, true);
const headers = this.buildHeaders();
Expand All @@ -91,7 +93,7 @@ export class CopilotAdapter {
method: "POST",
headers,
body: JSON.stringify(body),
signal,
signal: signal ?? null,
});

if (!response.ok) {
Expand Down
10 changes: 5 additions & 5 deletions plugins/agent-workbench-hermes/src/hermes-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export interface HermesProviderEntry {
/** Model name (e.g. "deepseek-v4-flash", "kimi-k2.7-code"). */
readonly model: string;
/** Base URL from credentials (if available). */
readonly baseUrl?: string;
readonly baseUrl?: string | undefined;
/** API key from credentials. */
readonly apiKey?: string;
readonly apiKey?: string | undefined;
/** Whether this is the primary (default) provider. */
readonly isPrimary: boolean;
}
Expand Down Expand Up @@ -135,8 +135,8 @@ function parseConfig(raw: string, auth: AuthFile | null): HermesConfig {
// Look backwards for the default model
for (let j = i - 1; j >= 0 && j > i - 10; j--) {
const prev = lines[j]?.trim();
if (prev.startsWith("default:")) {
const model = prev.slice("default:".length).trim();
if (prev?.startsWith("default:")) {
const model = prev!.slice("default:".length).trim();
if (model) {
addEntry(entries, provider, model, true, auth);
}
Expand Down Expand Up @@ -169,7 +169,7 @@ function addEntry(
entries.push({
provider,
model,
baseUrl: cred?.base_url,
...(cred?.base_url ? { baseUrl: cred.base_url } : {}),
apiKey: resolveApiKey(cred),
isPrimary,
});
Expand Down
38 changes: 22 additions & 16 deletions plugins/agent-workbench-hermes/src/openai-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class OpenAIAdapter {
async call(
messages: PluginModelMessage[],
_tools?: PluginToolDefinition[],
signal?: AbortSignal,
signal?: AbortSignal | null,
): Promise<PluginModelResponse> {
const body = this.buildBody(messages, _tools, false);

Expand All @@ -51,7 +51,7 @@ export class OpenAIAdapter {
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify(body),
signal,
signal: signal ?? null,
});

if (!response.ok) {
Expand All @@ -76,27 +76,33 @@ export class OpenAIAdapter {

return {
content,
toolCalls: toolCallsRaw?.map((tc) => ({
id: tc.id as string,
name: (tc.function as Record<string, unknown>)?.name as string,
arguments: JSON.parse(
((tc.function as Record<string, unknown>)?.arguments as string) ??
"{}",
) as Record<string, unknown>,
})),
usage: usage
...(toolCallsRaw
? {
toolCalls: toolCallsRaw.map((tc) => ({
id: tc.id as string,
name: (tc.function as Record<string, unknown>)?.name as string,
arguments: JSON.parse(
((tc.function as Record<string, unknown>)
?.arguments as string) ?? "{}",
) as Record<string, unknown>,
})),
}
: {}),
...(usage
? {
inputTokens: (usage.prompt_tokens as number) ?? 0,
outputTokens: (usage.completion_tokens as number) ?? 0,
usage: {
inputTokens: (usage.prompt_tokens as number) ?? 0,
outputTokens: (usage.completion_tokens as number) ?? 0,
},
}
: undefined,
: {}),
};
}

async *stream(
messages: PluginModelMessage[],
_tools?: PluginToolDefinition[],
signal?: AbortSignal,
signal?: AbortSignal | null,
): AsyncGenerator<PluginStreamChunk> {
const body = this.buildBody(messages, _tools, true);

Expand All @@ -107,7 +113,7 @@ export class OpenAIAdapter {
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify(body),
signal,
signal: signal ?? null,
});

if (!response.ok) {
Expand Down
12 changes: 12 additions & 0 deletions plugins/agent-workbench-hermes/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"types": ["bun"]
},
"include": ["src/**/*.ts"]
}
4 changes: 4 additions & 0 deletions scripts/build-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ for pkg in events sdk shell permissions cache planner collab eval; do
(cd "$ROOT/packages/$pkg" && bun run build 2>&1) || exit 1
done

# Plugins
echo " [build] plugins/agent-workbench-hermes"
(cd "$ROOT/plugins/agent-workbench-hermes" && bun run build 2>&1) || exit 1

# Level 2: depends on cache, diff, protocol, shell, storage
echo " [build] packages/tools"
(cd "$ROOT/packages/tools" && bun run build 2>&1) || exit 1
Expand Down
Loading