@smithers-orchestrator/agents 0.21.0 → 0.23.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/package.json +6 -5
- package/src/AmpAgent.js +26 -19
- package/src/AntigravityAgent.js +53 -18
- package/src/AntigravityAgentOptions.ts +45 -4
- package/src/BaseCliAgent/AgentGenerateOptions.ts +12 -0
- package/src/BaseCliAgent/BaseCliAgent.js +19 -1
- package/src/BaseCliAgent/runRpcCommandEffect.js +7 -3
- package/src/BaseCliAgent/taskContextEnv.js +31 -0
- package/src/BaseCliAgent/truncateToBytes.js +18 -1
- package/src/ClaudeCodeAgent.js +19 -1
- package/src/CodexAgent.js +15 -8
- package/src/ForgeAgent.js +26 -19
- package/src/HermesAgent.js +41 -0
- package/src/HermesAgentOptions.ts +41 -0
- package/src/VibeAgent.js +214 -0
- package/src/VibeAgentOptions.ts +11 -0
- package/src/agent-contract/createSmithersAgentContract.js +1 -0
- package/src/agent-contract/renderSmithersAgentPromptGuidance.js +4 -0
- package/src/capability-registry/AgentCapabilityRegistry.ts +1 -1
- package/src/cli-capabilities/CliAgentCapabilityAdapterId.ts +4 -1
- package/src/cli-capabilities/CliAgentCapabilityReportEntry.ts +2 -0
- package/src/cli-capabilities/getCliAgentCapabilityDoctorReport.js +48 -1
- package/src/cli-capabilities/getCliAgentCapabilityReport.js +24 -0
- package/src/cli-capabilities/index.js +5 -0
- package/src/cli-surface/CliAgentSurfaceTypes.ts +34 -0
- package/src/cli-surface/cliAgentSurfaceManifest.js +490 -0
- package/src/cli-surface/index.js +5 -0
- package/src/diagnostics/runDiagnostics.js +9 -1
- package/src/index.d.ts +715 -380
- package/src/index.js +27 -0
- package/src/mcp/McpServerConfig.ts +19 -0
- package/src/mcp/McpToolset.ts +17 -0
- package/src/mcp/createMcpToolset.js +94 -0
- package/src/sanitizeForOpenAI.js +20 -17
package/src/index.js
CHANGED
|
@@ -13,22 +13,39 @@
|
|
|
13
13
|
* @template [TOOLS=import("ai").ToolSet]
|
|
14
14
|
* @typedef {import("./OpenAIAgentOptions.ts").OpenAIAgentOptions<CALL_OPTIONS, TOOLS>} OpenAIAgentOptions
|
|
15
15
|
*/
|
|
16
|
+
/**
|
|
17
|
+
* @template [CALL_OPTIONS=never]
|
|
18
|
+
* @template [TOOLS=import("ai").ToolSet]
|
|
19
|
+
* @typedef {import("./HermesAgentOptions.ts").HermesAgentOptions<CALL_OPTIONS, TOOLS>} HermesAgentOptions
|
|
20
|
+
*/
|
|
16
21
|
/** @typedef {import("./PiAgentOptions.ts").PiAgentOptions} PiAgentOptions */
|
|
17
22
|
/** @typedef {import("./BaseCliAgent/PiExtensionUiRequest.ts").PiExtensionUiRequest} PiExtensionUiRequest */
|
|
18
23
|
/** @typedef {import("./BaseCliAgent/PiExtensionUiResponse.ts").PiExtensionUiResponse} PiExtensionUiResponse */
|
|
19
24
|
/** @typedef {import("./OpenCodeAgent.ts").OpenCodeAgentOptions} OpenCodeAgentOptions */
|
|
25
|
+
/** @typedef {import("./VibeAgentOptions.ts").VibeAgentOptions} VibeAgentOptions */
|
|
20
26
|
/** @typedef {import("./agent-contract/SmithersAgentContract.ts").SmithersAgentContract} SmithersAgentContract */
|
|
21
27
|
/** @typedef {import("./agent-contract/SmithersAgentContractTool.ts").SmithersAgentContractTool} SmithersAgentContractTool */
|
|
22
28
|
/** @typedef {import("./agent-contract/SmithersAgentToolCategory.ts").SmithersAgentToolCategory} SmithersAgentToolCategory */
|
|
23
29
|
/** @typedef {import("./agent-contract/SmithersListedTool.ts").SmithersListedTool} SmithersListedTool */
|
|
24
30
|
/** @typedef {import("./agent-contract/SmithersToolSurface.ts").SmithersToolSurface} SmithersToolSurface */
|
|
31
|
+
/** @typedef {import("./cli-capabilities/CliAgentCapabilityAdapterId.ts").CliAgentCapabilityAdapterId} CliAgentCapabilityAdapterId */
|
|
32
|
+
/** @typedef {import("./cli-capabilities/CliAgentCapabilityDoctorReport.ts").CliAgentCapabilityDoctorEntry} CliAgentCapabilityDoctorEntry */
|
|
33
|
+
/** @typedef {import("./cli-capabilities/CliAgentCapabilityDoctorReport.ts").CliAgentCapabilityDoctorReport} CliAgentCapabilityDoctorReport */
|
|
34
|
+
/** @typedef {import("./cli-capabilities/CliAgentCapabilityDoctorReport.ts").CliAgentCapabilityIssue} CliAgentCapabilityIssue */
|
|
35
|
+
/** @typedef {import("./cli-capabilities/CliAgentCapabilityReportEntry.ts").CliAgentCapabilityReportEntry} CliAgentCapabilityReportEntry */
|
|
36
|
+
/** @typedef {import("./cli-surface/CliAgentSurfaceTypes.ts").CliAgentSurfaceManifestEntry} CliAgentSurfaceManifestEntry */
|
|
37
|
+
/** @typedef {import("./cli-surface/CliAgentSurfaceTypes.ts").CliAgentSurfaceOptionMapping} CliAgentSurfaceOptionMapping */
|
|
38
|
+
/** @typedef {import("./cli-surface/CliAgentSurfaceTypes.ts").CliAgentSurfaceResumeContract} CliAgentSurfaceResumeContract */
|
|
39
|
+
/** @typedef {import("./cli-surface/CliAgentSurfaceTypes.ts").CliAgentUnsupportedFlag} CliAgentUnsupportedFlag */
|
|
25
40
|
// @smithers-type-exports-end
|
|
26
41
|
|
|
27
42
|
export { BaseCliAgent } from "./BaseCliAgent/index.js";
|
|
28
43
|
export { hashCapabilityRegistry } from "./capability-registry/index.js";
|
|
29
44
|
export { AnthropicAgent } from "./AnthropicAgent.js";
|
|
30
45
|
export { OpenAIAgent } from "./OpenAIAgent.js";
|
|
46
|
+
export { HermesAgent } from "./HermesAgent.js";
|
|
31
47
|
export { AmpAgent } from "./AmpAgent.js";
|
|
48
|
+
export { createAmpCapabilityRegistry } from "./AmpAgent.js";
|
|
32
49
|
export { AntigravityAgent, createAntigravityCapabilityRegistry } from "./AntigravityAgent.js";
|
|
33
50
|
export { ClaudeCodeAgent } from "./ClaudeCodeAgent.js";
|
|
34
51
|
export { CodexAgent } from "./CodexAgent.js";
|
|
@@ -36,7 +53,17 @@ export { GeminiAgent } from "./GeminiAgent.js";
|
|
|
36
53
|
export { PiAgent } from "./PiAgent.js";
|
|
37
54
|
export { KimiAgent } from "./KimiAgent.js";
|
|
38
55
|
export { ForgeAgent } from "./ForgeAgent.js";
|
|
56
|
+
export { createForgeCapabilityRegistry } from "./ForgeAgent.js";
|
|
39
57
|
export { OpenCodeAgent } from "./OpenCodeAgent.js";
|
|
58
|
+
export { VibeAgent, createVibeCapabilityRegistry } from "./VibeAgent.js";
|
|
59
|
+
export {
|
|
60
|
+
getCliAgentCapabilityReport,
|
|
61
|
+
getCliAgentCapabilityDoctorReport,
|
|
62
|
+
formatCliAgentCapabilityDoctorReport,
|
|
63
|
+
CLI_AGENT_SURFACE_MANIFEST,
|
|
64
|
+
getCliAgentSurfaceManifestEntry,
|
|
65
|
+
listCliAgentSurfaceManifests,
|
|
66
|
+
} from "./cli-capabilities/index.js";
|
|
40
67
|
export { createSmithersAgentContract } from "./agent-contract/createSmithersAgentContract.js";
|
|
41
68
|
export { renderSmithersAgentPromptGuidance } from "./agent-contract/renderSmithersAgentPromptGuidance.js";
|
|
42
69
|
export { zodToOpenAISchema } from "./zodToOpenAISchema.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How to launch an MCP server over stdio. Swap `command`/`args` to point at any
|
|
3
|
+
* MCP server (the demo fixture, GitHub's `@modelcontextprotocol/server-github`,
|
|
4
|
+
* Linear's MCP server, etc.) and its tools become agent-callable.
|
|
5
|
+
*/
|
|
6
|
+
export type McpServerConfig = {
|
|
7
|
+
/** Executable to spawn, e.g. `"bun"`, `"npx"`, `"node"`. */
|
|
8
|
+
command: string;
|
|
9
|
+
/** Arguments passed to the executable. */
|
|
10
|
+
args?: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Environment for the spawned process. When omitted, the MCP SDK passes a
|
|
13
|
+
* minimal safe environment. Include any secrets the server needs here
|
|
14
|
+
* (e.g. `GITHUB_PERSONAL_ACCESS_TOKEN`).
|
|
15
|
+
*/
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
/** Working directory for the spawned process. */
|
|
18
|
+
cwd?: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Tool } from "ai";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A live connection to an MCP server, with its tools projected as AI SDK tools.
|
|
5
|
+
*
|
|
6
|
+
* `tools` is shaped exactly like the record returned by `createOpenApiTools`, so it
|
|
7
|
+
* drops straight into an SDK agent's `tools`. The connection (and the spawned server
|
|
8
|
+
* process) stays open until `close()` is called.
|
|
9
|
+
*/
|
|
10
|
+
export type McpToolset = {
|
|
11
|
+
/** AI SDK tools keyed by (prefixed) MCP tool name. */
|
|
12
|
+
tools: Record<string, Tool>;
|
|
13
|
+
/** Names present in `tools`, after include/exclude/prefix are applied. */
|
|
14
|
+
toolNames: string[];
|
|
15
|
+
/** Disconnect the client and terminate the spawned server process. */
|
|
16
|
+
close: () => Promise<void>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
+
import { dynamicTool, jsonSchema } from "ai";
|
|
4
|
+
|
|
5
|
+
/** @typedef {import("./McpServerConfig.ts").McpServerConfig} McpServerConfig */
|
|
6
|
+
/** @typedef {import("./McpToolset.ts").McpToolset} McpToolset */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Options for shaping the generated toolset. Mirrors the curation knobs on
|
|
10
|
+
* `createOpenApiTools` so MCP and OpenAPI integrations feel the same.
|
|
11
|
+
*
|
|
12
|
+
* @typedef {object} McpToolsetOptions
|
|
13
|
+
* @property {string[]} [include] Only expose these MCP tool names.
|
|
14
|
+
* @property {string[]} [exclude] Drop these MCP tool names.
|
|
15
|
+
* @property {string} [namePrefix] Prefix applied to every tool name (e.g. `"github_"`).
|
|
16
|
+
* @property {string} [clientName] Identifies this client to the server.
|
|
17
|
+
* @property {string} [clientVersion] Client version reported to the server.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Connect to an MCP server and expose its tools as AI SDK tools an agent can call.
|
|
22
|
+
*
|
|
23
|
+
* This is the inbound half of MCP-as-integration: declare a server, get back a
|
|
24
|
+
* `Record<string, Tool>` to hand to an SDK agent's `tools`. Each generated tool
|
|
25
|
+
* proxies to the server via `tools/call` on demand, so the agent discovers and
|
|
26
|
+
* invokes them mid reasoning loop. The returned `close()` MUST be called to
|
|
27
|
+
* disconnect and terminate the spawned server process.
|
|
28
|
+
*
|
|
29
|
+
* @param {McpServerConfig} config
|
|
30
|
+
* @param {McpToolsetOptions} [options]
|
|
31
|
+
* @returns {Promise<McpToolset>}
|
|
32
|
+
*/
|
|
33
|
+
export async function createMcpToolset(config, options = {}) {
|
|
34
|
+
const transport = new StdioClientTransport({
|
|
35
|
+
command: config.command,
|
|
36
|
+
args: config.args ?? [],
|
|
37
|
+
...(config.env ? { env: config.env } : {}),
|
|
38
|
+
...(config.cwd ? { cwd: config.cwd } : {}),
|
|
39
|
+
stderr: "pipe",
|
|
40
|
+
});
|
|
41
|
+
const client = new Client({
|
|
42
|
+
name: options.clientName ?? "smithers-mcp-toolset",
|
|
43
|
+
version: options.clientVersion ?? "0.0.0",
|
|
44
|
+
});
|
|
45
|
+
await client.connect(transport);
|
|
46
|
+
|
|
47
|
+
const prefix = options.namePrefix ?? "";
|
|
48
|
+
const listed = await client.listTools();
|
|
49
|
+
/** @type {Record<string, import("ai").Tool>} */
|
|
50
|
+
const tools = {};
|
|
51
|
+
for (const mcpTool of listed.tools) {
|
|
52
|
+
if (options.include && !options.include.includes(mcpTool.name)) continue;
|
|
53
|
+
if (options.exclude && options.exclude.includes(mcpTool.name)) continue;
|
|
54
|
+
tools[`${prefix}${mcpTool.name}`] = dynamicTool({
|
|
55
|
+
description: mcpTool.description ?? mcpTool.name,
|
|
56
|
+
inputSchema: jsonSchema(/** @type {any} */ (mcpTool.inputSchema ?? { type: "object", properties: {} })),
|
|
57
|
+
execute: async (input) => callMcpTool(client, mcpTool.name, input),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
tools,
|
|
63
|
+
toolNames: Object.keys(tools),
|
|
64
|
+
close: () => client.close(),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Invoke one MCP tool and reduce its result to a value the model can read:
|
|
70
|
+
* structured content when the server returns it, otherwise the joined text.
|
|
71
|
+
*
|
|
72
|
+
* @param {Client} client
|
|
73
|
+
* @param {string} name
|
|
74
|
+
* @param {unknown} input
|
|
75
|
+
* @returns {Promise<unknown>}
|
|
76
|
+
*/
|
|
77
|
+
async function callMcpTool(client, name, input) {
|
|
78
|
+
const result = await client.callTool({
|
|
79
|
+
name,
|
|
80
|
+
arguments: /** @type {Record<string, unknown>} */ (input ?? {}),
|
|
81
|
+
});
|
|
82
|
+
const parts = Array.isArray(result.content) ? result.content : [];
|
|
83
|
+
let text = "";
|
|
84
|
+
for (const part of parts) {
|
|
85
|
+
const item = /** @type {{ type?: string; text?: string }} */ (part);
|
|
86
|
+
if (item.type === "text" && typeof item.text === "string") {
|
|
87
|
+
text += text ? `\n${item.text}` : item.text;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (result.isError) {
|
|
91
|
+
return { error: true, message: text || `MCP tool "${name}" failed`, status: "failed" };
|
|
92
|
+
}
|
|
93
|
+
return result.structuredContent ?? text;
|
|
94
|
+
}
|
package/src/sanitizeForOpenAI.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* OpenAI's `response_format` imposes constraints beyond standard JSON Schema:
|
|
5
5
|
*
|
|
6
6
|
* 1. Every object node **must** include `"type": "object"`.
|
|
7
|
-
* 2.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* 2. Structured output object nodes must set `additionalProperties: false`.
|
|
8
|
+
* 3. When `additionalProperties: false`, every key in `properties` must also
|
|
9
|
+
* appear in `required` (strict mode treats all listed properties as
|
|
10
|
+
* required; truly-optional fields should be modeled as nullable).
|
|
11
11
|
*
|
|
12
|
-
* Zod v4's `toJSONSchema()` can violate
|
|
13
|
-
*
|
|
12
|
+
* Zod v4's `toJSONSchema()` can violate these rules when loose/passthrough
|
|
13
|
+
* objects are used. Codex rejects those schemas unless they are strict.
|
|
14
14
|
*
|
|
15
15
|
* This function fixes these issues in-place so any agent (Codex, future
|
|
16
16
|
* OpenAI-backed agents, etc.) can safely use a JSON Schema for OpenAI.
|
|
@@ -19,20 +19,23 @@ export function sanitizeForOpenAI(node) {
|
|
|
19
19
|
if (node == null || typeof node !== "object")
|
|
20
20
|
return;
|
|
21
21
|
const obj = node;
|
|
22
|
-
// Rule 1
|
|
23
|
-
//
|
|
24
|
-
// passthrough objects, which OpenAI rejects.
|
|
22
|
+
// Rule 1: If a node has `additionalProperties`, it must also have
|
|
23
|
+
// `"type": "object"`. Zod can omit `type` on passthrough objects.
|
|
25
24
|
if ("additionalProperties" in obj && !("type" in obj)) {
|
|
26
25
|
obj.type = "object";
|
|
27
26
|
}
|
|
28
|
-
// Rule
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
// Rule 2: Codex/OpenAI structured outputs require strict object schemas.
|
|
28
|
+
if (obj.type === "object" && obj.additionalProperties !== false) {
|
|
29
|
+
obj.additionalProperties = false;
|
|
30
|
+
}
|
|
31
|
+
// Rule 3: With `additionalProperties: false`, OpenAI strict mode requires
|
|
32
|
+
// every key in `properties` to also appear in `required`. Zod omits
|
|
33
|
+
// optional fields from `required`, which strict mode rejects. List all
|
|
34
|
+
// property keys (truly-optional fields should be modeled as nullable).
|
|
35
|
+
if (obj.additionalProperties === false &&
|
|
36
|
+
obj.properties != null &&
|
|
37
|
+
typeof obj.properties === "object") {
|
|
38
|
+
obj.required = Object.keys(obj.properties);
|
|
36
39
|
}
|
|
37
40
|
// Recurse into all sub-schemas
|
|
38
41
|
for (const value of Object.values(obj)) {
|