@compyle/unagent 1.0.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 +547 -0
- package/dist/agents/agent-as-tool.d.ts +4 -0
- package/dist/agents/agent-as-tool.d.ts.map +1 -0
- package/dist/agents/agent-as-tool.js +105 -0
- package/dist/agents/agent-as-tool.js.map +1 -0
- package/dist/agents/define-agent.d.ts +101 -0
- package/dist/agents/define-agent.d.ts.map +1 -0
- package/dist/agents/define-agent.js +866 -0
- package/dist/agents/define-agent.js.map +1 -0
- package/dist/agents/index.d.ts +3 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +3 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/bridge/node-bridge.d.ts +2 -0
- package/dist/bridge/node-bridge.d.ts.map +1 -0
- package/dist/bridge/node-bridge.js +772 -0
- package/dist/bridge/node-bridge.js.map +1 -0
- package/dist/client/base-client.d.ts +86 -0
- package/dist/client/base-client.d.ts.map +1 -0
- package/dist/client/base-client.js +254 -0
- package/dist/client/base-client.js.map +1 -0
- package/dist/client/claude.d.ts +66 -0
- package/dist/client/claude.d.ts.map +1 -0
- package/dist/client/claude.js +846 -0
- package/dist/client/claude.js.map +1 -0
- package/dist/client/codex/codex-client.d.ts +78 -0
- package/dist/client/codex/codex-client.d.ts.map +1 -0
- package/dist/client/codex/codex-client.js +906 -0
- package/dist/client/codex/codex-client.js.map +1 -0
- package/dist/client/codex/codex-home.d.ts +6 -0
- package/dist/client/codex/codex-home.d.ts.map +1 -0
- package/dist/client/codex/codex-home.js +26 -0
- package/dist/client/codex/codex-home.js.map +1 -0
- package/dist/client/codex/config/config-loader.d.ts +8 -0
- package/dist/client/codex/config/config-loader.d.ts.map +1 -0
- package/dist/client/codex/config/config-loader.js +137 -0
- package/dist/client/codex/config/config-loader.js.map +1 -0
- package/dist/client/codex/config/config-types.d.ts +43 -0
- package/dist/client/codex/config/config-types.d.ts.map +1 -0
- package/dist/client/codex/config/config-types.js +2 -0
- package/dist/client/codex/config/config-types.js.map +1 -0
- package/dist/client/codex/config/config-writer.d.ts +24 -0
- package/dist/client/codex/config/config-writer.d.ts.map +1 -0
- package/dist/client/codex/config/config-writer.js +353 -0
- package/dist/client/codex/config/config-writer.js.map +1 -0
- package/dist/client/codex/config/index.d.ts +7 -0
- package/dist/client/codex/config/index.d.ts.map +1 -0
- package/dist/client/codex/config/index.js +6 -0
- package/dist/client/codex/config/index.js.map +1 -0
- package/dist/client/codex/config/mcp-config-generator.d.ts +7 -0
- package/dist/client/codex/config/mcp-config-generator.d.ts.map +1 -0
- package/dist/client/codex/config/mcp-config-generator.js +140 -0
- package/dist/client/codex/config/mcp-config-generator.js.map +1 -0
- package/dist/client/codex/config/tools-config-writer.d.ts +2 -0
- package/dist/client/codex/config/tools-config-writer.d.ts.map +1 -0
- package/dist/client/codex/config/tools-config-writer.js +21 -0
- package/dist/client/codex/config/tools-config-writer.js.map +1 -0
- package/dist/client/codex/index.d.ts +4 -0
- package/dist/client/codex/index.d.ts.map +1 -0
- package/dist/client/codex/index.js +3 -0
- package/dist/client/codex/index.js.map +1 -0
- package/dist/client/config-utils.d.ts +4 -0
- package/dist/client/config-utils.d.ts.map +1 -0
- package/dist/client/config-utils.js +32 -0
- package/dist/client/config-utils.js.map +1 -0
- package/dist/client/extra-headers.d.ts +12 -0
- package/dist/client/extra-headers.d.ts.map +1 -0
- package/dist/client/extra-headers.js +102 -0
- package/dist/client/extra-headers.js.map +1 -0
- package/dist/client/field-mappings.d.ts +3 -0
- package/dist/client/field-mappings.d.ts.map +1 -0
- package/dist/client/field-mappings.js +40 -0
- package/dist/client/field-mappings.js.map +1 -0
- package/dist/client/transformers/content-utils.d.ts +34 -0
- package/dist/client/transformers/content-utils.d.ts.map +1 -0
- package/dist/client/transformers/content-utils.js +237 -0
- package/dist/client/transformers/content-utils.js.map +1 -0
- package/dist/events/event-bus.d.ts +19 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +134 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/events/event-types.d.ts +53 -0
- package/dist/events/event-types.d.ts.map +1 -0
- package/dist/events/event-types.js +6 -0
- package/dist/events/event-types.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +4 -0
- package/dist/events/index.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/messages/index.d.ts +3 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +3 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/message-types.d.ts +60 -0
- package/dist/messages/message-types.d.ts.map +1 -0
- package/dist/messages/message-types.js +6 -0
- package/dist/messages/message-types.js.map +1 -0
- package/dist/messages/message-utils.d.ts +51 -0
- package/dist/messages/message-utils.d.ts.map +1 -0
- package/dist/messages/message-utils.js +343 -0
- package/dist/messages/message-utils.js.map +1 -0
- package/dist/tools/define-tool.d.ts +6 -0
- package/dist/tools/define-tool.d.ts.map +1 -0
- package/dist/tools/define-tool.js +83 -0
- package/dist/tools/define-tool.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mcp-stdio-proxy.d.ts +2 -0
- package/dist/tools/mcp-stdio-proxy.d.ts.map +1 -0
- package/dist/tools/mcp-stdio-proxy.js +31 -0
- package/dist/tools/mcp-stdio-proxy.js.map +1 -0
- package/dist/tools/tool-call-context.d.ts +8 -0
- package/dist/tools/tool-call-context.d.ts.map +1 -0
- package/dist/tools/tool-call-context.js +44 -0
- package/dist/tools/tool-call-context.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +14 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +47 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/tool-result-converter.d.ts +3 -0
- package/dist/tools/tool-result-converter.d.ts.map +1 -0
- package/dist/tools/tool-result-converter.js +38 -0
- package/dist/tools/tool-result-converter.js.map +1 -0
- package/dist/tools/tool-service-manager.d.ts +12 -0
- package/dist/tools/tool-service-manager.d.ts.map +1 -0
- package/dist/tools/tool-service-manager.js +118 -0
- package/dist/tools/tool-service-manager.js.map +1 -0
- package/dist/tools/tool-stdio-mcp-service.d.ts +29 -0
- package/dist/tools/tool-stdio-mcp-service.d.ts.map +1 -0
- package/dist/tools/tool-stdio-mcp-service.js +185 -0
- package/dist/tools/tool-stdio-mcp-service.js.map +1 -0
- package/dist/tools/tool-types.d.ts +29 -0
- package/dist/tools/tool-types.d.ts.map +1 -0
- package/dist/tools/tool-types.js +2 -0
- package/dist/tools/tool-types.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { extractCustomTools } from "../tools/define-tool.js";
|
|
3
|
+
import { attachToolServiceOwner } from "../tools/tool-service-manager.js";
|
|
4
|
+
import { normalizeExtraHeaders, resolveEnvHeaders, mergeHeaderRecords, serializeAnthropicHeaders, applyCodexExtraHeaders, } from "../client/extra-headers.js";
|
|
5
|
+
export class Agent {
|
|
6
|
+
constructor(definition) {
|
|
7
|
+
if (!definition || typeof definition !== "object") {
|
|
8
|
+
throw new Error("Agent definition must be a valid object");
|
|
9
|
+
}
|
|
10
|
+
if (!definition.client || typeof definition.client !== "string") {
|
|
11
|
+
throw new Error("Agent client must be a non-empty string");
|
|
12
|
+
}
|
|
13
|
+
Object.assign(this, definition);
|
|
14
|
+
const state = getAgentState(this);
|
|
15
|
+
state.config = buildAgentClientConfig(definition);
|
|
16
|
+
}
|
|
17
|
+
get definition() {
|
|
18
|
+
return { ...this };
|
|
19
|
+
}
|
|
20
|
+
get config() {
|
|
21
|
+
const state = getAgentState(this);
|
|
22
|
+
if (!state.config) {
|
|
23
|
+
state.config = buildAgentClientConfig(this);
|
|
24
|
+
}
|
|
25
|
+
return { ...state.config };
|
|
26
|
+
}
|
|
27
|
+
async run(params) {
|
|
28
|
+
const client = await requireAgentClient(this);
|
|
29
|
+
return client.run(normalizeRunParams(params));
|
|
30
|
+
}
|
|
31
|
+
async runStream(params) {
|
|
32
|
+
const client = await requireAgentClient(this);
|
|
33
|
+
return client.runStream(normalizeRunParams(params));
|
|
34
|
+
}
|
|
35
|
+
async resume(params) {
|
|
36
|
+
const client = await requireAgentClient(this);
|
|
37
|
+
return client.resume(params);
|
|
38
|
+
}
|
|
39
|
+
abort() {
|
|
40
|
+
const state = getAgentState(this);
|
|
41
|
+
if (state.client) {
|
|
42
|
+
state.client.abort();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (state.clientPromise) {
|
|
46
|
+
state.clientPromise.then((client) => client.abort()).catch(() => { });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
cleanup() {
|
|
50
|
+
const state = getAgentState(this);
|
|
51
|
+
const client = state.client;
|
|
52
|
+
if (client && typeof client.cleanup === "function") {
|
|
53
|
+
client.cleanup?.();
|
|
54
|
+
}
|
|
55
|
+
state.client = undefined;
|
|
56
|
+
state.clientPromise = undefined;
|
|
57
|
+
}
|
|
58
|
+
async getSessionDir() {
|
|
59
|
+
const client = await requireAgentClient(this);
|
|
60
|
+
if (typeof client.getSessionDir === "function") {
|
|
61
|
+
return client.getSessionDir();
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Client type '${this.client}' does not support getSessionDir`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const agentState = new WeakMap();
|
|
67
|
+
export function defineAgent(definition) {
|
|
68
|
+
const agentDefinition = buildAgentDefinition(definition);
|
|
69
|
+
return new Agent(agentDefinition);
|
|
70
|
+
}
|
|
71
|
+
export function resolveAgentDefinition(agent) {
|
|
72
|
+
if (isAgentInstance(agent)) {
|
|
73
|
+
return agent.definition;
|
|
74
|
+
}
|
|
75
|
+
return agent;
|
|
76
|
+
}
|
|
77
|
+
export function buildAgentClientConfig(agent) {
|
|
78
|
+
const definition = resolveAgentDefinition(agent);
|
|
79
|
+
const config = {};
|
|
80
|
+
if (isRecord(definition.otherConfig) && Object.keys(definition.otherConfig).length > 0) {
|
|
81
|
+
Object.assign(config, definition.otherConfig);
|
|
82
|
+
}
|
|
83
|
+
const systemPrompt = resolveString(definition.systemPrompt) ?? resolveString(definition.prompt);
|
|
84
|
+
const otherConfigPrompt = resolveString(isRecord(definition.otherConfig) ? definition.otherConfig.developer_instructions : undefined);
|
|
85
|
+
const existingPrompt = resolveString(config.systemPrompt);
|
|
86
|
+
if (systemPrompt) {
|
|
87
|
+
config.systemPrompt = systemPrompt;
|
|
88
|
+
}
|
|
89
|
+
else if (!existingPrompt && otherConfigPrompt) {
|
|
90
|
+
config.systemPrompt = otherConfigPrompt;
|
|
91
|
+
}
|
|
92
|
+
if (resolveString(definition.model)) {
|
|
93
|
+
config.model = definition.model;
|
|
94
|
+
}
|
|
95
|
+
if (resolveString(definition.apiKey)) {
|
|
96
|
+
config.apiKey = definition.apiKey;
|
|
97
|
+
}
|
|
98
|
+
if (resolveString(definition.baseURL)) {
|
|
99
|
+
config.baseURL = definition.baseURL;
|
|
100
|
+
}
|
|
101
|
+
if (definition.env && Object.keys(definition.env).length > 0) {
|
|
102
|
+
config.env = { ...definition.env };
|
|
103
|
+
}
|
|
104
|
+
const homeDir = resolveString(definition.homeDir);
|
|
105
|
+
if (homeDir && (definition.client === "codex" || definition.client === "claude")) {
|
|
106
|
+
const envRecord = isRecord(config.env)
|
|
107
|
+
? { ...config.env }
|
|
108
|
+
: {};
|
|
109
|
+
if (definition.client === "codex") {
|
|
110
|
+
envRecord.CODEX_HOME = homeDir;
|
|
111
|
+
}
|
|
112
|
+
else if (definition.client === "claude") {
|
|
113
|
+
envRecord.CLAUDE_CONFIG_DIR = homeDir;
|
|
114
|
+
}
|
|
115
|
+
config.env = envRecord;
|
|
116
|
+
}
|
|
117
|
+
const extraHeaders = normalizeExtraHeaders(definition.extraHeaders);
|
|
118
|
+
if (extraHeaders) {
|
|
119
|
+
if (definition.client === "claude") {
|
|
120
|
+
const envRecord = isRecord(config.env)
|
|
121
|
+
? config.env
|
|
122
|
+
: {};
|
|
123
|
+
const resolvedEnvHeaders = resolveEnvHeaders(extraHeaders.envHeaders, envRecord);
|
|
124
|
+
const mergedHeaders = mergeHeaderRecords(extraHeaders.headers, resolvedEnvHeaders);
|
|
125
|
+
const customHeaderValue = serializeAnthropicHeaders(mergedHeaders);
|
|
126
|
+
if (customHeaderValue) {
|
|
127
|
+
envRecord.ANTHROPIC_CUSTOM_HEADERS = customHeaderValue;
|
|
128
|
+
config.env = envRecord;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (definition.client === "codex") {
|
|
132
|
+
const existingConfig = isRecord(config.config)
|
|
133
|
+
? config.config
|
|
134
|
+
: {};
|
|
135
|
+
const updatedConfig = applyCodexExtraHeaders(existingConfig, extraHeaders);
|
|
136
|
+
if (Object.keys(updatedConfig).length > 0) {
|
|
137
|
+
config.config = updatedConfig;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const customTools = Array.isArray(definition.customTools) ? definition.customTools : [];
|
|
142
|
+
if (customTools.length > 0) {
|
|
143
|
+
config.tools = customTools;
|
|
144
|
+
}
|
|
145
|
+
const toolFilters = resolveToolFilters(definition);
|
|
146
|
+
const hasExplicitAllowList = hasExplicitAllowedTools(definition);
|
|
147
|
+
const fallbackTools = normalizeStringArray(definition.tools) ?? [];
|
|
148
|
+
const allowedTools = hasExplicitAllowList ? toolFilters.allowedTools : fallbackTools;
|
|
149
|
+
if (allowedTools.length > 0) {
|
|
150
|
+
config.allowedTools = allowedTools;
|
|
151
|
+
}
|
|
152
|
+
if (toolFilters.disallowedTools.length > 0) {
|
|
153
|
+
config.disallowedTools = toolFilters.disallowedTools;
|
|
154
|
+
}
|
|
155
|
+
const mcpServers = definition.client === "codex"
|
|
156
|
+
? extractCodexMcpServerRecord(definition.mcpServers, toolFilters)
|
|
157
|
+
: extractMcpServerRecord(definition.mcpServers);
|
|
158
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
159
|
+
config.mcpServers = mcpServers;
|
|
160
|
+
}
|
|
161
|
+
if (definition.permissionMode) {
|
|
162
|
+
config.permissionMode = definition.permissionMode;
|
|
163
|
+
}
|
|
164
|
+
if (definition.hooks && Object.keys(definition.hooks).length > 0) {
|
|
165
|
+
config.hooks = definition.hooks;
|
|
166
|
+
}
|
|
167
|
+
if (Array.isArray(definition.settingSources) && definition.settingSources.length > 0) {
|
|
168
|
+
config.settingSources = definition.settingSources;
|
|
169
|
+
}
|
|
170
|
+
if (Array.isArray(definition.addDirs) && definition.addDirs.length > 0) {
|
|
171
|
+
config.addDirs = definition.addDirs;
|
|
172
|
+
}
|
|
173
|
+
if (resolveString(definition.cwd)) {
|
|
174
|
+
config.cwd = definition.cwd;
|
|
175
|
+
}
|
|
176
|
+
if (resolveString(definition.skillDir)) {
|
|
177
|
+
config.skillDir = definition.skillDir;
|
|
178
|
+
}
|
|
179
|
+
const homeDirHashIgnore = normalizeHashIgnoreList(definition.homeDirHashIgnore ??
|
|
180
|
+
definition.home_dir_hash_ignore);
|
|
181
|
+
if (homeDirHashIgnore.length > 0) {
|
|
182
|
+
config.homeDirHashIgnore = homeDirHashIgnore;
|
|
183
|
+
}
|
|
184
|
+
if (isRecord(agent)) {
|
|
185
|
+
attachToolServiceOwner(config, agent);
|
|
186
|
+
}
|
|
187
|
+
const codexHomeKey = createCodexHomeKey(definition);
|
|
188
|
+
if (codexHomeKey) {
|
|
189
|
+
const envRecord = isRecord(config.env) ? config.env : undefined;
|
|
190
|
+
const envCodexHome = resolveString(envRecord?.CODEX_HOME);
|
|
191
|
+
const existingCodexHomeKey = resolveString(config.codexHomeKey);
|
|
192
|
+
if (!envCodexHome && !existingCodexHomeKey) {
|
|
193
|
+
config.codexHomeKey = codexHomeKey;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return config;
|
|
197
|
+
}
|
|
198
|
+
function buildAgentDefinition(definition) {
|
|
199
|
+
const description = definition.description;
|
|
200
|
+
const systemPrompt = resolveSystemPrompt(definition);
|
|
201
|
+
const client = definition.client;
|
|
202
|
+
if (!client || typeof client !== "string") {
|
|
203
|
+
throw new Error("Agent client must be a non-empty string");
|
|
204
|
+
}
|
|
205
|
+
const validClients = ["claude", "codex", "other"];
|
|
206
|
+
if (!validClients.includes(client)) {
|
|
207
|
+
throw new Error(`Invalid client value: "${client}". Must be one of: ${validClients.join(", ")}`);
|
|
208
|
+
}
|
|
209
|
+
if (description !== undefined && (typeof description !== "string" || !description)) {
|
|
210
|
+
throw new Error("Agent description must be a non-empty string");
|
|
211
|
+
}
|
|
212
|
+
if (systemPrompt !== undefined && (typeof systemPrompt !== "string" || !systemPrompt)) {
|
|
213
|
+
throw new Error("Agent systemPrompt must be a non-empty string");
|
|
214
|
+
}
|
|
215
|
+
if (definition.apiKey !== undefined && typeof definition.apiKey !== "string") {
|
|
216
|
+
throw new Error("Agent apiKey must be a string");
|
|
217
|
+
}
|
|
218
|
+
if (definition.baseURL !== undefined && typeof definition.baseURL !== "string") {
|
|
219
|
+
throw new Error("Agent baseURL must be a string");
|
|
220
|
+
}
|
|
221
|
+
if (definition.skillDir !== undefined && typeof definition.skillDir !== "string") {
|
|
222
|
+
throw new Error("Agent skillDir must be a string");
|
|
223
|
+
}
|
|
224
|
+
if (definition.skillDir !== undefined && typeof definition.skillDir === "string" && !definition.skillDir) {
|
|
225
|
+
throw new Error("Agent skillDir must be a non-empty string");
|
|
226
|
+
}
|
|
227
|
+
if (definition.homeDir !== undefined && typeof definition.homeDir !== "string") {
|
|
228
|
+
throw new Error("Agent homeDir must be a string");
|
|
229
|
+
}
|
|
230
|
+
if (definition.homeDir !== undefined && typeof definition.homeDir === "string" && !definition.homeDir) {
|
|
231
|
+
throw new Error("Agent homeDir must be a non-empty string");
|
|
232
|
+
}
|
|
233
|
+
const extraHeaders = normalizeExtraHeaders(definition.extraHeaders);
|
|
234
|
+
if (definition.extraHeaders !== undefined && !extraHeaders) {
|
|
235
|
+
throw new Error("Agent extraHeaders must be a record of string headers or { headers, envHeaders }");
|
|
236
|
+
}
|
|
237
|
+
if (definition.homeDirHashIgnore !== undefined &&
|
|
238
|
+
!Array.isArray(definition.homeDirHashIgnore) &&
|
|
239
|
+
typeof definition.homeDirHashIgnore !== "string") {
|
|
240
|
+
throw new Error("Agent homeDirHashIgnore must be a string or list of strings");
|
|
241
|
+
}
|
|
242
|
+
if (definition.home_dir_hash_ignore !== undefined &&
|
|
243
|
+
!Array.isArray(definition.home_dir_hash_ignore) &&
|
|
244
|
+
typeof definition.home_dir_hash_ignore !== "string") {
|
|
245
|
+
throw new Error("Agent home_dir_hash_ignore must be a string or list of strings");
|
|
246
|
+
}
|
|
247
|
+
const toolFilters = resolveToolFilters(definition);
|
|
248
|
+
const allowedTools = toolFilters.allowedTools;
|
|
249
|
+
const disallowedTools = toolFilters.disallowedTools;
|
|
250
|
+
const customTools = extractCustomTools(definition.tools);
|
|
251
|
+
const toolNames = mergeUniqueStrings([
|
|
252
|
+
...allowedTools,
|
|
253
|
+
...customTools.map((tool) => tool.name),
|
|
254
|
+
]);
|
|
255
|
+
const normalizedMcpServers = normalizeAgentMcpServers(definition.mcpServers);
|
|
256
|
+
const addDirs = normalizeStringList(definition.addDirs);
|
|
257
|
+
const homeDirHashIgnore = mergeUniqueStrings([
|
|
258
|
+
...normalizeHashIgnoreList(definition.homeDirHashIgnore),
|
|
259
|
+
...normalizeHashIgnoreList(definition.home_dir_hash_ignore),
|
|
260
|
+
]);
|
|
261
|
+
const otherConfig = buildOtherConfig({
|
|
262
|
+
client,
|
|
263
|
+
model: definition.model,
|
|
264
|
+
systemPrompt,
|
|
265
|
+
mcpServers: definition.mcpServers,
|
|
266
|
+
addDirs,
|
|
267
|
+
allowedTools,
|
|
268
|
+
disallowedTools,
|
|
269
|
+
skillDir: definition.skillDir,
|
|
270
|
+
customConfig: definition.otherConfig,
|
|
271
|
+
});
|
|
272
|
+
const agent = {
|
|
273
|
+
client,
|
|
274
|
+
};
|
|
275
|
+
if (description !== undefined) {
|
|
276
|
+
agent.description = description;
|
|
277
|
+
}
|
|
278
|
+
if (systemPrompt !== undefined) {
|
|
279
|
+
agent.prompt = systemPrompt;
|
|
280
|
+
agent.systemPrompt = systemPrompt;
|
|
281
|
+
}
|
|
282
|
+
if (toolNames.length > 0) {
|
|
283
|
+
agent.tools = toolNames;
|
|
284
|
+
}
|
|
285
|
+
if (allowedTools.length > 0) {
|
|
286
|
+
agent.allowedTools = allowedTools;
|
|
287
|
+
}
|
|
288
|
+
if (disallowedTools.length > 0) {
|
|
289
|
+
agent.disallowedTools = disallowedTools;
|
|
290
|
+
}
|
|
291
|
+
if (definition.model) {
|
|
292
|
+
agent.model = definition.model;
|
|
293
|
+
}
|
|
294
|
+
if (definition.apiKey) {
|
|
295
|
+
agent.apiKey = definition.apiKey;
|
|
296
|
+
}
|
|
297
|
+
if (definition.baseURL) {
|
|
298
|
+
agent.baseURL = definition.baseURL;
|
|
299
|
+
}
|
|
300
|
+
if (normalizedMcpServers && normalizedMcpServers.length > 0) {
|
|
301
|
+
agent.mcpServers = normalizedMcpServers;
|
|
302
|
+
}
|
|
303
|
+
const permissionMode = definition.permissionMode;
|
|
304
|
+
if (permissionMode) {
|
|
305
|
+
agent.permissionMode = permissionMode;
|
|
306
|
+
}
|
|
307
|
+
if (definition.hooks) {
|
|
308
|
+
agent.hooks = definition.hooks;
|
|
309
|
+
}
|
|
310
|
+
const settingSources = normalizeStringList(definition.settingSources);
|
|
311
|
+
if (settingSources.length > 0) {
|
|
312
|
+
agent.settingSources = settingSources;
|
|
313
|
+
}
|
|
314
|
+
if (definition.env && Object.keys(definition.env).length > 0) {
|
|
315
|
+
agent.env = { ...definition.env };
|
|
316
|
+
}
|
|
317
|
+
if (addDirs.length > 0) {
|
|
318
|
+
agent.addDirs = addDirs;
|
|
319
|
+
}
|
|
320
|
+
if (definition.cwd) {
|
|
321
|
+
agent.cwd = definition.cwd;
|
|
322
|
+
}
|
|
323
|
+
if (definition.homeDir) {
|
|
324
|
+
agent.homeDir = definition.homeDir;
|
|
325
|
+
}
|
|
326
|
+
if (definition.skillDir) {
|
|
327
|
+
agent.skillDir = definition.skillDir;
|
|
328
|
+
}
|
|
329
|
+
if (homeDirHashIgnore.length > 0) {
|
|
330
|
+
agent.homeDirHashIgnore = homeDirHashIgnore;
|
|
331
|
+
}
|
|
332
|
+
if (extraHeaders) {
|
|
333
|
+
agent.extraHeaders = extraHeaders;
|
|
334
|
+
}
|
|
335
|
+
if (customTools.length > 0) {
|
|
336
|
+
agent.customTools = customTools;
|
|
337
|
+
}
|
|
338
|
+
if (otherConfig && Object.keys(otherConfig).length > 0) {
|
|
339
|
+
agent.otherConfig = otherConfig;
|
|
340
|
+
}
|
|
341
|
+
return agent;
|
|
342
|
+
}
|
|
343
|
+
function resolveSystemPrompt(definition) {
|
|
344
|
+
return definition.systemPrompt;
|
|
345
|
+
}
|
|
346
|
+
function createCodexHomeKey(definition) {
|
|
347
|
+
if (definition.client !== "codex") {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
const hashSource = buildCodexHomeHashSource(definition);
|
|
351
|
+
const homeDirHashIgnore = normalizeHashIgnoreList(definition.homeDirHashIgnore ??
|
|
352
|
+
definition.home_dir_hash_ignore);
|
|
353
|
+
const filteredHashSource = applyHashIgnoreToRecord(hashSource, homeDirHashIgnore);
|
|
354
|
+
const serialized = logCodexHomeHashSource(filteredHashSource);
|
|
355
|
+
return createHash("sha256").update(serialized).digest("hex");
|
|
356
|
+
}
|
|
357
|
+
function buildCodexHomeHashSource(definition) {
|
|
358
|
+
const mcpServers = stripCustomToolsMcpServers(definition.mcpServers);
|
|
359
|
+
const otherConfig = stripCustomToolsMcpFromOtherConfig(definition.otherConfig);
|
|
360
|
+
return {
|
|
361
|
+
client: definition.client,
|
|
362
|
+
description: definition.description,
|
|
363
|
+
systemPrompt: resolveString(definition.systemPrompt) ?? resolveString(definition.prompt),
|
|
364
|
+
tools: definition.tools,
|
|
365
|
+
allowedTools: definition.allowedTools,
|
|
366
|
+
disallowedTools: definition.disallowedTools,
|
|
367
|
+
model: definition.model,
|
|
368
|
+
baseURL: definition.baseURL,
|
|
369
|
+
mcpServers,
|
|
370
|
+
permissionMode: definition.permissionMode,
|
|
371
|
+
settingSources: definition.settingSources,
|
|
372
|
+
addDirs: definition.addDirs,
|
|
373
|
+
cwd: definition.cwd,
|
|
374
|
+
homeDir: definition.homeDir,
|
|
375
|
+
skillDir: definition.skillDir,
|
|
376
|
+
extraHeaders: definition.extraHeaders,
|
|
377
|
+
otherConfig,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const HASH_EXCLUDED_KEYS = new Set([
|
|
381
|
+
"resume",
|
|
382
|
+
"resumesessionid",
|
|
383
|
+
"resume_session_id",
|
|
384
|
+
"sessionid",
|
|
385
|
+
"session_id",
|
|
386
|
+
"threadid",
|
|
387
|
+
"thread_id",
|
|
388
|
+
]);
|
|
389
|
+
const CUSTOM_TOOLS_MCP_NAME = "custom-tools";
|
|
390
|
+
function shouldExcludeHashKey(key) {
|
|
391
|
+
return HASH_EXCLUDED_KEYS.has(key.toLowerCase());
|
|
392
|
+
}
|
|
393
|
+
function isCustomToolsMcpName(name) {
|
|
394
|
+
return name.toLowerCase() === CUSTOM_TOOLS_MCP_NAME;
|
|
395
|
+
}
|
|
396
|
+
function stripCustomToolsMcpServers(input) {
|
|
397
|
+
if (!input) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
let removed = false;
|
|
401
|
+
const filtered = [];
|
|
402
|
+
for (const entry of input) {
|
|
403
|
+
if (typeof entry === "string") {
|
|
404
|
+
if (isCustomToolsMcpName(entry)) {
|
|
405
|
+
removed = true;
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
filtered.push(entry);
|
|
409
|
+
}
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (!isRecord(entry)) {
|
|
413
|
+
filtered.push(entry);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
let recordRemoved = false;
|
|
417
|
+
const nextRecord = {};
|
|
418
|
+
for (const [name, config] of Object.entries(entry)) {
|
|
419
|
+
if (isCustomToolsMcpName(name)) {
|
|
420
|
+
recordRemoved = true;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
nextRecord[name] = config;
|
|
424
|
+
}
|
|
425
|
+
if (Object.keys(nextRecord).length > 0) {
|
|
426
|
+
filtered.push(nextRecord);
|
|
427
|
+
}
|
|
428
|
+
if (recordRemoved) {
|
|
429
|
+
removed = true;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (!removed) {
|
|
433
|
+
return input;
|
|
434
|
+
}
|
|
435
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
436
|
+
}
|
|
437
|
+
function stripCustomToolsMcpFromRecord(input) {
|
|
438
|
+
let removed = false;
|
|
439
|
+
const nextRecord = {};
|
|
440
|
+
for (const [name, config] of Object.entries(input)) {
|
|
441
|
+
if (isCustomToolsMcpName(name)) {
|
|
442
|
+
removed = true;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
nextRecord[name] = config;
|
|
446
|
+
}
|
|
447
|
+
if (!removed) {
|
|
448
|
+
return input;
|
|
449
|
+
}
|
|
450
|
+
return Object.keys(nextRecord).length > 0 ? nextRecord : undefined;
|
|
451
|
+
}
|
|
452
|
+
function stripCustomToolsMcpFromOtherConfig(input) {
|
|
453
|
+
if (!input || Object.keys(input).length === 0) {
|
|
454
|
+
return input;
|
|
455
|
+
}
|
|
456
|
+
let updated = false;
|
|
457
|
+
const output = { ...input };
|
|
458
|
+
const updateKey = (key) => {
|
|
459
|
+
if (!(key in output)) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const value = output[key];
|
|
463
|
+
if (Array.isArray(value)) {
|
|
464
|
+
const filtered = stripCustomToolsMcpServers(value);
|
|
465
|
+
if (filtered !== value) {
|
|
466
|
+
updated = true;
|
|
467
|
+
}
|
|
468
|
+
if (!filtered || filtered.length === 0) {
|
|
469
|
+
delete output[key];
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
output[key] = filtered;
|
|
473
|
+
}
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (isRecord(value)) {
|
|
477
|
+
const filtered = stripCustomToolsMcpFromRecord(value);
|
|
478
|
+
if (filtered !== value) {
|
|
479
|
+
updated = true;
|
|
480
|
+
}
|
|
481
|
+
if (!filtered || Object.keys(filtered).length === 0) {
|
|
482
|
+
delete output[key];
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
output[key] = filtered;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
};
|
|
489
|
+
updateKey("mcpServers");
|
|
490
|
+
updateKey("mcp_servers");
|
|
491
|
+
return updated ? output : input;
|
|
492
|
+
}
|
|
493
|
+
function logCodexHomeHashSource(hashSource) {
|
|
494
|
+
const serialized = JSON.stringify(normalizeHashValue(hashSource));
|
|
495
|
+
return serialized;
|
|
496
|
+
}
|
|
497
|
+
function normalizeHashValue(value, seen = new WeakSet()) {
|
|
498
|
+
if (value === null) {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
502
|
+
return value;
|
|
503
|
+
}
|
|
504
|
+
if (typeof value === "bigint") {
|
|
505
|
+
return value.toString();
|
|
506
|
+
}
|
|
507
|
+
if (value instanceof Date) {
|
|
508
|
+
return value.toISOString();
|
|
509
|
+
}
|
|
510
|
+
if (Array.isArray(value)) {
|
|
511
|
+
return value.map((item) => {
|
|
512
|
+
const normalized = normalizeHashValue(item, seen);
|
|
513
|
+
return normalized === undefined ? null : normalized;
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
if (typeof value === "object") {
|
|
517
|
+
if (seen.has(value)) {
|
|
518
|
+
return "[Circular]";
|
|
519
|
+
}
|
|
520
|
+
seen.add(value);
|
|
521
|
+
const record = {};
|
|
522
|
+
for (const key of Object.keys(value).sort()) {
|
|
523
|
+
if (shouldExcludeHashKey(key)) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
const lowerKey = key.toLowerCase();
|
|
527
|
+
let nextValue = value[key];
|
|
528
|
+
if (lowerKey === "mcp_servers" || lowerKey === "mcpservers") {
|
|
529
|
+
if (Array.isArray(nextValue)) {
|
|
530
|
+
nextValue = stripCustomToolsMcpServers(nextValue);
|
|
531
|
+
}
|
|
532
|
+
else if (isRecord(nextValue)) {
|
|
533
|
+
nextValue = stripCustomToolsMcpFromRecord(nextValue);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const normalized = normalizeHashValue(nextValue, seen);
|
|
537
|
+
if (normalized !== undefined) {
|
|
538
|
+
record[key] = normalized;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
seen.delete(value);
|
|
542
|
+
return record;
|
|
543
|
+
}
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
function normalizeAgentMcpServers(input) {
|
|
547
|
+
if (!input) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
if (Array.isArray(input)) {
|
|
551
|
+
return input;
|
|
552
|
+
}
|
|
553
|
+
return [input];
|
|
554
|
+
}
|
|
555
|
+
function normalizeStringList(value) {
|
|
556
|
+
if (!value) {
|
|
557
|
+
return [];
|
|
558
|
+
}
|
|
559
|
+
if (Array.isArray(value)) {
|
|
560
|
+
return value.filter((item) => typeof item === "string" && item.length > 0);
|
|
561
|
+
}
|
|
562
|
+
if (typeof value === "string") {
|
|
563
|
+
return value.length > 0 ? [value] : [];
|
|
564
|
+
}
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
567
|
+
function normalizeHashIgnoreList(value) {
|
|
568
|
+
return normalizeStringList(value)
|
|
569
|
+
.map((item) => item.trim())
|
|
570
|
+
.filter((item) => item.length > 0);
|
|
571
|
+
}
|
|
572
|
+
function normalizeHashIgnoreKey(value) {
|
|
573
|
+
return value.replace(/_/g, "").toLowerCase();
|
|
574
|
+
}
|
|
575
|
+
function applyHashIgnoreToRecord(record, ignoreList) {
|
|
576
|
+
if (ignoreList.length === 0) {
|
|
577
|
+
return record;
|
|
578
|
+
}
|
|
579
|
+
const ignoreSet = new Set(ignoreList.map((item) => normalizeHashIgnoreKey(item)));
|
|
580
|
+
const filtered = {};
|
|
581
|
+
for (const [key, value] of Object.entries(record)) {
|
|
582
|
+
if (ignoreSet.has(normalizeHashIgnoreKey(key))) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
filtered[key] = value;
|
|
586
|
+
}
|
|
587
|
+
return filtered;
|
|
588
|
+
}
|
|
589
|
+
function mergeUniqueStrings(values) {
|
|
590
|
+
return Array.from(new Set(values));
|
|
591
|
+
}
|
|
592
|
+
function resolveToolFilters(input) {
|
|
593
|
+
const allowedTools = mergeUniqueStrings([
|
|
594
|
+
...normalizeStringList(input.allowedTools),
|
|
595
|
+
...normalizeStringList(input.allowed_tools),
|
|
596
|
+
]);
|
|
597
|
+
const disallowedTools = mergeUniqueStrings([
|
|
598
|
+
...normalizeStringList(input.disallowedTools),
|
|
599
|
+
...normalizeStringList(input.disallowed_tools),
|
|
600
|
+
]);
|
|
601
|
+
return { allowedTools, disallowedTools };
|
|
602
|
+
}
|
|
603
|
+
function hasExplicitAllowedTools(input) {
|
|
604
|
+
if (Array.isArray(input.allowedTools) || Array.isArray(input.allowed_tools)) {
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
if (typeof input.allowedTools === "string") {
|
|
608
|
+
return input.allowedTools.length > 0;
|
|
609
|
+
}
|
|
610
|
+
if (typeof input.allowed_tools === "string") {
|
|
611
|
+
return input.allowed_tools.length > 0;
|
|
612
|
+
}
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
function applyCodexToolFilters(mcpServers, toolFilters) {
|
|
616
|
+
if (!toolFilters) {
|
|
617
|
+
return mcpServers;
|
|
618
|
+
}
|
|
619
|
+
const enabledTools = toolFilters.allowedTools ?? [];
|
|
620
|
+
const disabledTools = toolFilters.disallowedTools ?? [];
|
|
621
|
+
if (enabledTools.length === 0 && disabledTools.length === 0) {
|
|
622
|
+
return mcpServers;
|
|
623
|
+
}
|
|
624
|
+
const updated = {};
|
|
625
|
+
for (const [name, config] of Object.entries(mcpServers)) {
|
|
626
|
+
const nextConfig = { ...config };
|
|
627
|
+
if (enabledTools.length > 0) {
|
|
628
|
+
const existingEnabledTools = normalizeStringArray(nextConfig.enabled_tools);
|
|
629
|
+
if (!existingEnabledTools || existingEnabledTools.length === 0) {
|
|
630
|
+
nextConfig.enabled_tools = [...enabledTools];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
if (disabledTools.length > 0) {
|
|
634
|
+
const existingDisabledTools = normalizeStringArray(nextConfig.disabled_tools);
|
|
635
|
+
if (!existingDisabledTools || existingDisabledTools.length === 0) {
|
|
636
|
+
nextConfig.disabled_tools = [...disabledTools];
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
updated[name] = nextConfig;
|
|
640
|
+
}
|
|
641
|
+
return updated;
|
|
642
|
+
}
|
|
643
|
+
function buildOtherConfig(input) {
|
|
644
|
+
const config = {};
|
|
645
|
+
if (input.customConfig && Object.keys(input.customConfig).length > 0) {
|
|
646
|
+
Object.assign(config, input.customConfig);
|
|
647
|
+
}
|
|
648
|
+
if (!input.customConfig || Object.keys(input.customConfig).length === 0) {
|
|
649
|
+
if (input.model) {
|
|
650
|
+
config.model = input.model;
|
|
651
|
+
}
|
|
652
|
+
if (input.systemPrompt) {
|
|
653
|
+
config.developer_instructions = input.systemPrompt;
|
|
654
|
+
}
|
|
655
|
+
const mcpServers = input.client === "codex"
|
|
656
|
+
? extractCodexMcpServerRecord(input.mcpServers, {
|
|
657
|
+
allowedTools: input.allowedTools ?? [],
|
|
658
|
+
disallowedTools: input.disallowedTools ?? [],
|
|
659
|
+
})
|
|
660
|
+
: extractMcpServerRecord(input.mcpServers);
|
|
661
|
+
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
662
|
+
config.mcp_servers = mcpServers;
|
|
663
|
+
}
|
|
664
|
+
if (input.addDirs && input.addDirs.length > 0) {
|
|
665
|
+
config.sandbox_workspace_write = {
|
|
666
|
+
writable_roots: [...input.addDirs],
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
if (input.skillDir && input.client === "codex") {
|
|
670
|
+
config.skills = {
|
|
671
|
+
config: [{ path: input.skillDir, enabled: true }],
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
if (Object.keys(config).length === 0) {
|
|
676
|
+
return undefined;
|
|
677
|
+
}
|
|
678
|
+
return config;
|
|
679
|
+
}
|
|
680
|
+
function extractMcpServerRecord(input) {
|
|
681
|
+
if (!input) {
|
|
682
|
+
return undefined;
|
|
683
|
+
}
|
|
684
|
+
if (!Array.isArray(input)) {
|
|
685
|
+
return input;
|
|
686
|
+
}
|
|
687
|
+
const merged = {};
|
|
688
|
+
for (const entry of input) {
|
|
689
|
+
if (typeof entry === "string") {
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
Object.assign(merged, entry);
|
|
693
|
+
}
|
|
694
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
695
|
+
}
|
|
696
|
+
function extractCodexMcpServerRecord(input, toolFilters) {
|
|
697
|
+
const record = extractMcpServerRecord(input);
|
|
698
|
+
if (!record) {
|
|
699
|
+
return undefined;
|
|
700
|
+
}
|
|
701
|
+
const converted = {};
|
|
702
|
+
for (const [name, config] of Object.entries(record)) {
|
|
703
|
+
converted[name] = toCodexMcpServerConfig(name, config);
|
|
704
|
+
}
|
|
705
|
+
if (Object.keys(converted).length === 0) {
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
return applyCodexToolFilters(converted, toolFilters);
|
|
709
|
+
}
|
|
710
|
+
function toCodexMcpServerConfig(name, config) {
|
|
711
|
+
if (!isRecord(config)) {
|
|
712
|
+
throw new Error(`MCP server "${name}" must be an object`);
|
|
713
|
+
}
|
|
714
|
+
const source = config;
|
|
715
|
+
const type = typeof source.type === "string" ? source.type : undefined;
|
|
716
|
+
if (type === "sdk" || "instance" in source) {
|
|
717
|
+
throw new Error(`MCP server "${name}" uses SDK transport which Codex does not support`);
|
|
718
|
+
}
|
|
719
|
+
const codexConfig = {};
|
|
720
|
+
if (typeof source.command === "string" && source.command.length > 0) {
|
|
721
|
+
codexConfig.command = source.command;
|
|
722
|
+
}
|
|
723
|
+
const args = normalizeStringArray(source.args);
|
|
724
|
+
if (args && args.length > 0) {
|
|
725
|
+
codexConfig.args = args;
|
|
726
|
+
}
|
|
727
|
+
const env = normalizeStringRecord(source.env);
|
|
728
|
+
if (env) {
|
|
729
|
+
codexConfig.env = env;
|
|
730
|
+
}
|
|
731
|
+
if (typeof source.url === "string" && source.url.length > 0) {
|
|
732
|
+
codexConfig.url = source.url;
|
|
733
|
+
}
|
|
734
|
+
const httpHeaders = normalizeStringRecord(source.http_headers)
|
|
735
|
+
?? normalizeStringRecord(source.headers);
|
|
736
|
+
if (httpHeaders) {
|
|
737
|
+
codexConfig.http_headers = httpHeaders;
|
|
738
|
+
}
|
|
739
|
+
const envHttpHeaders = normalizeStringRecord(source.env_http_headers);
|
|
740
|
+
if (envHttpHeaders) {
|
|
741
|
+
codexConfig.env_http_headers = envHttpHeaders;
|
|
742
|
+
}
|
|
743
|
+
if (typeof source.bearer_token_env_var === "string" && source.bearer_token_env_var.length > 0) {
|
|
744
|
+
codexConfig.bearer_token_env_var = source.bearer_token_env_var;
|
|
745
|
+
}
|
|
746
|
+
const envVars = normalizeStringArray(source.env_vars);
|
|
747
|
+
if (envVars && envVars.length > 0) {
|
|
748
|
+
codexConfig.env_vars = envVars;
|
|
749
|
+
}
|
|
750
|
+
if (typeof source.cwd === "string" && source.cwd.length > 0) {
|
|
751
|
+
codexConfig.cwd = source.cwd;
|
|
752
|
+
}
|
|
753
|
+
if (typeof source.persistent === "boolean") {
|
|
754
|
+
codexConfig.persistent = source.persistent;
|
|
755
|
+
}
|
|
756
|
+
if (typeof source.enabled === "boolean") {
|
|
757
|
+
codexConfig.enabled = source.enabled;
|
|
758
|
+
}
|
|
759
|
+
if (typeof source.startup_timeout_sec === "number") {
|
|
760
|
+
codexConfig.startup_timeout_sec = source.startup_timeout_sec;
|
|
761
|
+
}
|
|
762
|
+
if (typeof source.startup_timeout_ms === "number") {
|
|
763
|
+
codexConfig.startup_timeout_ms = source.startup_timeout_ms;
|
|
764
|
+
}
|
|
765
|
+
if (typeof source.tool_timeout_sec === "number") {
|
|
766
|
+
codexConfig.tool_timeout_sec = source.tool_timeout_sec;
|
|
767
|
+
}
|
|
768
|
+
const enabledTools = normalizeStringArray(source.enabled_tools);
|
|
769
|
+
if (enabledTools && enabledTools.length > 0) {
|
|
770
|
+
codexConfig.enabled_tools = enabledTools;
|
|
771
|
+
}
|
|
772
|
+
const disabledTools = normalizeStringArray(source.disabled_tools);
|
|
773
|
+
if (disabledTools && disabledTools.length > 0) {
|
|
774
|
+
codexConfig.disabled_tools = disabledTools;
|
|
775
|
+
}
|
|
776
|
+
if (!codexConfig.url && !codexConfig.command) {
|
|
777
|
+
throw new Error(`MCP server "${name}" must define a url or command for Codex`);
|
|
778
|
+
}
|
|
779
|
+
return codexConfig;
|
|
780
|
+
}
|
|
781
|
+
function getAgentState(agent) {
|
|
782
|
+
const existing = agentState.get(agent);
|
|
783
|
+
if (existing) {
|
|
784
|
+
return existing;
|
|
785
|
+
}
|
|
786
|
+
const state = {};
|
|
787
|
+
agentState.set(agent, state);
|
|
788
|
+
return state;
|
|
789
|
+
}
|
|
790
|
+
async function requireAgentClient(agent) {
|
|
791
|
+
const state = getAgentState(agent);
|
|
792
|
+
if (state.client) {
|
|
793
|
+
return state.client;
|
|
794
|
+
}
|
|
795
|
+
if (state.clientPromise) {
|
|
796
|
+
return state.clientPromise;
|
|
797
|
+
}
|
|
798
|
+
const config = state.config ?? buildAgentClientConfig(agent);
|
|
799
|
+
state.config = config;
|
|
800
|
+
const clientPromise = createAgentClient(agent.client, config);
|
|
801
|
+
state.clientPromise = clientPromise;
|
|
802
|
+
try {
|
|
803
|
+
const client = await clientPromise;
|
|
804
|
+
state.client = client;
|
|
805
|
+
return client;
|
|
806
|
+
}
|
|
807
|
+
finally {
|
|
808
|
+
if (state.clientPromise === clientPromise) {
|
|
809
|
+
state.clientPromise = undefined;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
async function createAgentClient(client, config) {
|
|
814
|
+
if (client === "claude") {
|
|
815
|
+
const { ClaudeClient } = await import("../client/claude.js");
|
|
816
|
+
return new ClaudeClient(config);
|
|
817
|
+
}
|
|
818
|
+
if (client === "codex") {
|
|
819
|
+
const { CodexClient } = await import("../client/codex/index.js");
|
|
820
|
+
return new CodexClient(config);
|
|
821
|
+
}
|
|
822
|
+
throw new Error('Agent client must be "claude" or "codex" to run');
|
|
823
|
+
}
|
|
824
|
+
function normalizeRunParams(params) {
|
|
825
|
+
if (typeof params === "string") {
|
|
826
|
+
return { query: params };
|
|
827
|
+
}
|
|
828
|
+
return params;
|
|
829
|
+
}
|
|
830
|
+
function isAgentInstance(value) {
|
|
831
|
+
if (!value || typeof value !== "object") {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
const candidate = value;
|
|
835
|
+
return (typeof candidate.run === "function" &&
|
|
836
|
+
typeof candidate.runStream === "function" &&
|
|
837
|
+
typeof candidate.resume === "function" &&
|
|
838
|
+
typeof candidate.client === "string" &&
|
|
839
|
+
"definition" in candidate);
|
|
840
|
+
}
|
|
841
|
+
function resolveString(value) {
|
|
842
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
843
|
+
}
|
|
844
|
+
function isRecord(value) {
|
|
845
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
846
|
+
}
|
|
847
|
+
function normalizeStringArray(value) {
|
|
848
|
+
if (!Array.isArray(value)) {
|
|
849
|
+
return undefined;
|
|
850
|
+
}
|
|
851
|
+
const filtered = value.filter((item) => typeof item === "string" && item.length > 0);
|
|
852
|
+
return filtered.length > 0 ? filtered : undefined;
|
|
853
|
+
}
|
|
854
|
+
function normalizeStringRecord(value) {
|
|
855
|
+
if (!isRecord(value)) {
|
|
856
|
+
return undefined;
|
|
857
|
+
}
|
|
858
|
+
const entries = Object.entries(value)
|
|
859
|
+
.filter(([, entryValue]) => typeof entryValue === "string" && entryValue.length > 0)
|
|
860
|
+
.map(([key, entryValue]) => [key, entryValue]);
|
|
861
|
+
if (entries.length === 0) {
|
|
862
|
+
return undefined;
|
|
863
|
+
}
|
|
864
|
+
return Object.fromEntries(entries);
|
|
865
|
+
}
|
|
866
|
+
//# sourceMappingURL=define-agent.js.map
|