@hmharness/kernel 0.1.0 → 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/dist/mcp.d.ts +2 -0
- package/dist/mcp.js +7 -1
- package/dist/provider.d.ts +3 -0
- package/dist/provider.js +6 -5
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/dist/mcp.d.ts
CHANGED
|
@@ -5,11 +5,13 @@ export type McpServerConfig = {
|
|
|
5
5
|
args?: string[];
|
|
6
6
|
env?: Record<string, string>;
|
|
7
7
|
trusted?: boolean;
|
|
8
|
+
trustedTools?: string[];
|
|
8
9
|
} | {
|
|
9
10
|
type: 'http';
|
|
10
11
|
url: string;
|
|
11
12
|
headers?: Record<string, string>;
|
|
12
13
|
trusted?: boolean;
|
|
14
|
+
trustedTools?: string[];
|
|
13
15
|
};
|
|
14
16
|
export declare class McpClient {
|
|
15
17
|
readonly serverName: string;
|
package/dist/mcp.js
CHANGED
|
@@ -253,14 +253,20 @@ export async function mcpServerTools(serverName, config) {
|
|
|
253
253
|
await client.connect();
|
|
254
254
|
const remote = await client.listTools();
|
|
255
255
|
const trusted = 'trusted' in config && config.trusted === true;
|
|
256
|
+
// Exemption granularity: `trusted: true` exempts the WHOLE server (dangerous,
|
|
257
|
+
// meant for servers you own). `trustedTools: ['search', ...]` exempts only
|
|
258
|
+
// the named REMOTE tool names - read-only lookups stay frictionless while
|
|
259
|
+
// every mutating tool on the same server still hits the approval gate.
|
|
260
|
+
const trustedTools = 'trustedTools' in config && Array.isArray(config.trustedTools) ? config.trustedTools : [];
|
|
256
261
|
const tools = remote.map((t) => {
|
|
257
262
|
const localName = `mcp_${sanitizeToolName(serverName)}_${sanitizeToolName(t.name)}`.slice(0, 60);
|
|
258
263
|
const remoteName = t.name;
|
|
264
|
+
const exempt = trusted || trustedTools.includes(remoteName);
|
|
259
265
|
return {
|
|
260
266
|
name: localName,
|
|
261
267
|
description: `[mcp:${serverName}] ${t.description ?? t.name}`.slice(0, 400),
|
|
262
268
|
parameters: normalizeSchema(t.inputSchema),
|
|
263
|
-
needsApproval:
|
|
269
|
+
needsApproval: exempt ? undefined : () => true,
|
|
264
270
|
async execute(args) {
|
|
265
271
|
return client.callTool(remoteName, args);
|
|
266
272
|
},
|
package/dist/provider.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export interface ChatOptions {
|
|
|
21
21
|
onDelta?(kind: DeltaKind, chunk: string): void;
|
|
22
22
|
}
|
|
23
23
|
export declare function chat(cfg: ProviderConfig, messages: ChatMessage[], tools?: unknown[], opts?: ChatOptions): Promise<ChatResponse>;
|
|
24
|
+
/** Accept bases with any /vN suffix (v1 OpenAI convention, v4 zhipu coding
|
|
25
|
+
* plan: open.bigmodel.cn/api/coding/paas/v4) or none at all. */
|
|
26
|
+
export declare function endpoint(baseUrl: string): string;
|
|
24
27
|
/**
|
|
25
28
|
* Single multimodal call: text prompt + one image (data URL). Used by the
|
|
26
29
|
* see_image tool; deliberately separate from chat() so the streaming path
|
package/dist/provider.js
CHANGED
|
@@ -17,7 +17,7 @@ export async function chat(cfg, messages, tools, opts = {}) {
|
|
|
17
17
|
let lastError = '';
|
|
18
18
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
19
19
|
const ctrl = new AbortController();
|
|
20
|
-
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 120_000);
|
|
20
|
+
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? cfg.timeoutMs ?? 120_000);
|
|
21
21
|
try {
|
|
22
22
|
const res = await fetch(endpoint(cfg.baseUrl), {
|
|
23
23
|
method: 'POST',
|
|
@@ -162,10 +162,11 @@ async function consumeStream(res, onDelta) {
|
|
|
162
162
|
usage,
|
|
163
163
|
};
|
|
164
164
|
}
|
|
165
|
-
/** Accept bases
|
|
166
|
-
|
|
165
|
+
/** Accept bases with any /vN suffix (v1 OpenAI convention, v4 zhipu coding
|
|
166
|
+
* plan: open.bigmodel.cn/api/coding/paas/v4) or none at all. */
|
|
167
|
+
export function endpoint(baseUrl) {
|
|
167
168
|
const b = baseUrl.replace(/\/+$/, '');
|
|
168
|
-
return b
|
|
169
|
+
return /\/v\d+$/.test(b) ? `${b}/chat/completions` : `${b}/v1/chat/completions`;
|
|
169
170
|
}
|
|
170
171
|
/**
|
|
171
172
|
* Single multimodal call: text prompt + one image (data URL). Used by the
|
|
@@ -191,7 +192,7 @@ export async function chatVision(cfg, prompt, imageDataUrl, opts = {}) {
|
|
|
191
192
|
let vAuth = cfg.authHeader ?? 'bearer';
|
|
192
193
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
193
194
|
const ctrl = new AbortController();
|
|
194
|
-
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 120_000);
|
|
195
|
+
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? cfg.timeoutMs ?? 120_000);
|
|
195
196
|
try {
|
|
196
197
|
const vHeaders = vAuth === 'bearer'
|
|
197
198
|
? { 'Content-Type': 'application/json', Authorization: `Bearer ${cfg.apiKey}` }
|
package/dist/types.d.ts
CHANGED
|
@@ -60,6 +60,10 @@ export interface ProviderConfig {
|
|
|
60
60
|
* for freellmapi). Omit for standard Authorization: Bearer; on 401 the
|
|
61
61
|
* provider renegotiates with X-Api-Key automatically. */
|
|
62
62
|
authHeader?: string;
|
|
63
|
+
/** Per-request timeout override (ms). Slow reasoning models (free-tier
|
|
64
|
+
* tokenrouter took 84s on an evolve-sized prompt vs the 120s default)
|
|
65
|
+
* set e.g. 240000 on the evolve/bench routes. */
|
|
66
|
+
timeoutMs?: number;
|
|
63
67
|
}
|
|
64
68
|
/** User-level configuration (HMH_HOME/config.json). */
|
|
65
69
|
export interface HmhConfig {
|
package/dist/types.js
CHANGED
|
@@ -30,7 +30,7 @@ export function listProviders(cfg) {
|
|
|
30
30
|
export const PROVIDER_PRESETS = [
|
|
31
31
|
{ name: 'deepseek', baseUrl: 'https://api.deepseek.com/v1', envVar: 'DEEPSEEK_API_KEY', model: 'deepseek-chat' },
|
|
32
32
|
{ name: 'kimi', baseUrl: 'https://api.moonshot.cn/v1', envVar: 'MOONSHOT_API_KEY', model: 'kimi-latest' },
|
|
33
|
-
{ name: 'glm', baseUrl: 'https://open.bigmodel.cn/api/paas/v4', envVar: 'ZHIPU_API_KEY', model: 'glm-
|
|
33
|
+
{ name: 'glm', baseUrl: 'https://open.bigmodel.cn/api/coding/paas/v4', envVar: 'ZHIPU_API_KEY', model: 'glm-5.3' },
|
|
34
34
|
{ name: 'qwen', baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1', envVar: 'DASHSCOPE_API_KEY', model: 'qwen3-max' },
|
|
35
35
|
{ name: 'openai', baseUrl: 'https://api.openai.com/v1', envVar: 'OPENAI_API_KEY', model: 'gpt-5' },
|
|
36
36
|
{ name: 'siliconflow', baseUrl: 'https://api.siliconflow.cn/v1', envVar: 'SILICONFLOW_API_KEY', model: 'deepseek-ai/DeepSeek-V3.2-Exp' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hmharness/kernel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "hmharness kernel: tool registry, provider adapters, the agent loop, session log, config. Zero runtime dependencies (Node >=22 native fetch).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|