nolo-cli 0.1.22 → 0.1.26
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/README.md +25 -3
- package/agent-runtime/agentRecordConfig.ts +4 -0
- package/agent-runtime/hostAdapter.ts +2 -0
- package/agent-runtime/hybridRecordStore.ts +30 -9
- package/agent-runtime/index.ts +7 -0
- package/agent-runtime/localLoop.ts +14 -4
- package/agent-runtime/localToolPolicy.ts +22 -10
- package/agent-runtime/localWorkspaceTools.ts +140 -374
- package/agent-runtime/platformChatProvider.ts +3 -0
- package/agent-runtime/runtimeToolPolicy.ts +133 -0
- package/agent-runtime/types.ts +47 -0
- package/agentAliases.ts +1 -1
- package/agentCommandSupport.ts +77 -0
- package/agentInternalCommandEntries.ts +34 -0
- package/agentListCommands.ts +123 -0
- package/agentListHelpers.ts +187 -0
- package/agentMachineCommands.ts +402 -0
- package/agentRecordCommands.ts +141 -0
- package/agentRecordHelpers.ts +395 -0
- package/agentRunCommand.ts +75 -3
- package/agentRuntimeCommands.ts +7 -773
- package/ai/agent/_executeModel.ts +29 -3
- package/ai/agent/buildSystemPrompt.ts +17 -0
- package/ai/agent/cliChatClient.ts +38 -4
- package/ai/agent/cliExecutor.ts +304 -25
- package/ai/agent/createAgentSchema.ts +2 -2
- package/ai/agent/guidedCreation/assistant.ts +82 -0
- package/ai/agent/guidedCreation/capabilities.ts +84 -0
- package/ai/agent/guidedCreation/draft.ts +62 -0
- package/ai/agent/guidedCreation/types.ts +38 -0
- package/ai/agent/machineRunPermissions.ts +21 -3
- package/ai/agent/runtimeGuidance.ts +1 -1
- package/ai/agent/server/fetchPublicAgents.ts +6 -1
- package/ai/agent/streamAgentChatTurn.ts +593 -36
- package/ai/agent/web/useGuidedAgentCreation.ts +217 -0
- package/ai/ai.locale.ts +14 -2
- package/ai/chat/fetchUtils.native.ts +2 -0
- package/ai/chat/fetchUtils.ts +2 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +82 -1
- package/ai/chat/sendOpenAIResponseRequest.ts +65 -0
- package/ai/llm/getPricing.ts +14 -0
- package/ai/llm/kimi.ts +4 -1
- package/ai/llm/modelAvatar.ts +1 -0
- package/ai/llm/providers.ts +4 -1
- package/ai/llm/reasoningModels.ts +1 -0
- package/ai/taskRun/taskRunProtocol.ts +25 -10
- package/ai/token/modelUsageQuery.ts +17 -0
- package/ai/tools/agent/agentTools.ts +38 -0
- package/ai/tools/agent/prepareAgentDraftTool.ts +159 -0
- package/ai/tools/agent/startAgentDialogTool.ts +53 -0
- package/ai/tools/checkEnvTool.ts +52 -20
- package/ai/tools/convertMarxistsBookTool.ts +103 -0
- package/ai/tools/{execBashTool.ts → execShellTool.ts} +44 -161
- package/ai/tools/index.ts +24 -14
- package/ai/tools/marxistsOfflineBook.ts +253 -0
- package/ai/tools/modelUsageTools.ts +9 -2
- package/ai/tools/readTool.ts +31 -0
- package/ai/tools/toolApiClient.ts +35 -1
- package/ai/tools/toolNameAliases.ts +13 -0
- package/cliCommandAdapters.ts +28 -0
- package/cliCommandDispatch.ts +66 -0
- package/cliCommandFactories.ts +34 -0
- package/cliCommandTypes.ts +49 -0
- package/cliEnvHelpers.ts +44 -0
- package/client/agentRun.test.ts +330 -24
- package/client/agentRun.ts +117 -35
- package/client/hybridRecordStore.test.ts +42 -0
- package/client/hybridRecordStore.ts +11 -0
- package/client/localRuntimeAdapter.test.ts +191 -21
- package/client/localRuntimeAdapter.ts +99 -10
- package/client/localRuntimeDryRun.test.ts +5 -2
- package/client/taskRunPrompt.ts +1 -0
- package/commandRegistry.ts +11 -61
- package/connector-experimental/capabilities.ts +1 -0
- package/database/actions/common.ts +4 -3
- package/database/config.ts +19 -0
- package/database/server/coreDataProxy.ts +43 -26
- package/index.ts +54 -191
- package/internalCommandEntries.ts +12 -0
- package/machineCommands.ts +688 -64
- package/offlineMarxistsAgentCommand.ts +314 -0
- package/package.json +22 -2
- package/render/canvas/canvasEditContext.ts +127 -0
- package/render/canvas/canvasRuntime.ts +57 -0
- package/render/canvas/canvasSnapshotParser.ts +76 -0
- package/render/canvas/canvasTree.ts +308 -0
- package/render/canvas/types.ts +46 -0
- package/render/layout/deleteBehavior.ts +52 -0
- package/render/layout/mainLayoutSidebar.ts +17 -0
- package/render/layout/mainLayoutViewMode.ts +56 -0
- package/render/layout/topbarUtils.ts +87 -0
- package/render/layout/useDevReloadPending.ts +30 -0
- package/render/page/createPageAction.ts +183 -0
- package/render/page/docSlice.ts +468 -0
- package/render/page/server/createPage.ts +174 -0
- package/render/page/server/handleCreatePage.ts +91 -0
- package/render/page/server/index.ts +4 -0
- package/render/page/types.ts +17 -0
- package/render/page/useKeyboardSave.ts +48 -0
- package/render/styles/zIndex.ts +12 -0
- package/render/surf/WeatherIconStyles.ts +17 -0
- package/render/surf/color.ts +9 -0
- package/render/surf/config.ts +46 -0
- package/render/surf/screens/style.ts +1 -0
- package/render/surf/styles/ToggleButtonStyles.ts +8 -0
- package/render/surf/utils/groupedWeatherData.ts +32 -0
- package/render/surf/weatherUtils.ts +50 -0
- package/render/table/activityColumns.ts +6 -0
- package/render/table/createTableAction.ts +270 -0
- package/render/table/deleteTableAction.ts +129 -0
- package/render/table/fetchAndCacheTableRows.ts +174 -0
- package/render/table/tableSlice.ts +1106 -0
- package/render/table/tableView.ts +289 -0
- package/render/table/toolValueUtils.ts +363 -0
- package/render/table/types.ts +252 -0
- package/render/table/useCreateTable.ts +72 -0
- package/render/table/useTable.ts +61 -0
- package/render/table/utils/tableSerialization.ts +50 -0
- package/render/web/elements/artifactPreviewCode.ts +43 -0
- package/render/web/elements/artifactRuntimePreload.ts +52 -0
- package/render/web/elements/codeBlockAutoPreview.ts +10 -0
- package/render/web/elements/mermaidPreview.ts +21 -0
- package/render/web/ui/useInlineEdit.ts +135 -0
- package/runtimeDoctorCommands.ts +118 -0
- package/scriptCommandEntries.ts +71 -0
- package/systemInternalCommandEntries.ts +71 -0
- package/tableCommands.ts +42 -5
- package/workflowInternalCommandEntries.ts +11 -0
|
@@ -9,6 +9,7 @@ import { generateRequestBody } from "ai/llm/generateRequestBody";
|
|
|
9
9
|
import { getApiEndpoint } from "ai/llm/providers";
|
|
10
10
|
import { selectCurrentServer } from "app/settings/settingSlice";
|
|
11
11
|
import { selectCurrentToken } from "auth/authSlice";
|
|
12
|
+
import { applyChatCompletionsStreamMode } from "integrations/openai/chatCompletionStreamMode";
|
|
12
13
|
|
|
13
14
|
import { sendOpenAICompletionsRequest } from "../chat/sendOpenAICompletionsRequest";
|
|
14
15
|
import { performFetchRequest } from "../chat/fetchUtils";
|
|
@@ -73,13 +74,13 @@ export const _executeModel = async (
|
|
|
73
74
|
messages = [{ role: "user", content: args.content }];
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
const
|
|
77
|
+
const requestBody = generateRequestBody({
|
|
77
78
|
agentConfig: resolvedConfig,
|
|
78
79
|
messages,
|
|
79
80
|
userInput: content,
|
|
80
81
|
contexts: agentContexts,
|
|
81
82
|
});
|
|
82
|
-
bodyData
|
|
83
|
+
const bodyData = applyChatCompletionsStreamMode(requestBody, isStreaming);
|
|
83
84
|
|
|
84
85
|
if (isStreaming) {
|
|
85
86
|
await sendOpenAICompletionsRequest({
|
|
@@ -97,7 +98,32 @@ export const _executeModel = async (
|
|
|
97
98
|
currentServer: selectCurrentServer(state),
|
|
98
99
|
token: selectCurrentToken(state),
|
|
99
100
|
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
let message = `Model request failed with HTTP ${response.status}`;
|
|
103
|
+
try {
|
|
104
|
+
const errorBody = await response.json();
|
|
105
|
+
const upstreamMessage =
|
|
106
|
+
typeof errorBody?.error?.message === "string"
|
|
107
|
+
? errorBody.error.message
|
|
108
|
+
: typeof errorBody?.message === "string"
|
|
109
|
+
? errorBody.message
|
|
110
|
+
: "";
|
|
111
|
+
if (upstreamMessage.trim()) message = upstreamMessage.trim();
|
|
112
|
+
} catch {
|
|
113
|
+
// Keep the status-based message when the response body is not JSON.
|
|
114
|
+
}
|
|
115
|
+
throw new Error(message);
|
|
116
|
+
}
|
|
100
117
|
const result = await response.json();
|
|
118
|
+
const content = result?.choices?.[0]?.message?.content;
|
|
119
|
+
if (typeof content !== "string") {
|
|
120
|
+
const upstreamMessage =
|
|
121
|
+
typeof result?.error?.message === "string" ? result.error.message : "";
|
|
122
|
+
throw new Error(
|
|
123
|
+
upstreamMessage.trim() ||
|
|
124
|
+
"Model response missing choices[0].message.content"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
101
127
|
if (args.billingDialogKey && result?.usage) {
|
|
102
128
|
await updateTokensAction(
|
|
103
129
|
{
|
|
@@ -109,7 +135,7 @@ export const _executeModel = async (
|
|
|
109
135
|
thunkApi
|
|
110
136
|
);
|
|
111
137
|
}
|
|
112
|
-
return
|
|
138
|
+
return content;
|
|
113
139
|
}
|
|
114
140
|
} catch (error: any) {
|
|
115
141
|
console.error(`_executeModel failed`, error);
|
|
@@ -198,6 +198,8 @@ const CODE_EDITING_FIDELITY_INSTRUCTIONS = `--- 代码编辑真值规则 ---
|
|
|
198
198
|
当任务涉及 readFile / writeFile / applyEdit / applyLineEdits 等代码编辑工具时,必须遵守以下规则:
|
|
199
199
|
|
|
200
200
|
- 先读取目标文件的最新内容,再决定修改。
|
|
201
|
+
- 读取本地或代码仓库文件时,必须调用 readFile。不要用 read、readDoc、readPage 读取本地路径;这些工具用于知识库页面/文档 ID。
|
|
202
|
+
- 执行本地 shell/bash 命令时,必须调用 execShell。
|
|
201
203
|
- 如果用户提供了 URL、文档页或产品页,且你需要据此改代码,必须先抓取这些网页,再开始编辑。
|
|
202
204
|
- 如果用户已经提供可用 URL,就不要再搜索替代来源;只有这些 URL 无法满足任务时,才允许降级到搜索,并在最终回复中说明。
|
|
203
205
|
- 网页中直接出现的模型名、价格、上下文窗口、发布日期、能力描述、是否支持 function calling / vision 等字段,视为本次修改的权威来源。
|
|
@@ -219,6 +221,16 @@ const TABLE_SHARE_INSTRUCTIONS = `--- 表格创建与分享 ---
|
|
|
219
221
|
- 传入表的 dbKey,或 tenantId + tableId;
|
|
220
222
|
- 完成后直接返回 /share/... 链接。`;
|
|
221
223
|
|
|
224
|
+
const AGENT_CREATION_DRAFT_INSTRUCTIONS = `--- Agent 创建草稿流程 ---
|
|
225
|
+
当用户想创建、定制、配置自己的 Agent / AI 助手时,必须走草稿优先流程:
|
|
226
|
+
|
|
227
|
+
- 不要直接创建真实 Agent 记录,也不要声称已经创建完成。
|
|
228
|
+
- 先基于当前对话和用户刚说的话整理一个可预览草稿,调用 prepareAgentDraft。
|
|
229
|
+
- 草稿应尽量包含名称、用途简介、prompt 摘要、完整 prompt、能力、知识引用建议、公开状态和仍需确认的问题。
|
|
230
|
+
- 用户表达模糊时,也先给出合理的初版草稿;信息不足时每次只问一个关键问题。
|
|
231
|
+
- 对知识引用、公开状态、高风险工具能力,必须等待用户确认后再视为已选。
|
|
232
|
+
- 草稿足够完整后,引导用户点击“预览并创建”,进入 /create/agent 做最终确认。`;
|
|
233
|
+
|
|
222
234
|
// ============================================================================
|
|
223
235
|
// 无 prompt 时的澄清模式
|
|
224
236
|
// ============================================================================
|
|
@@ -453,6 +465,10 @@ export const buildSystemPromptContext = (options: {
|
|
|
453
465
|
? TABLE_SHARE_INSTRUCTIONS
|
|
454
466
|
: "";
|
|
455
467
|
|
|
468
|
+
const agentCreationDraftSection = agentTools.includes("prepareAgentDraft")
|
|
469
|
+
? AGENT_CREATION_DRAFT_INSTRUCTIONS
|
|
470
|
+
: "";
|
|
471
|
+
|
|
456
472
|
// 知识管理:有页面读写工具时注入通用知识管理说明
|
|
457
473
|
const knowledgeManagementSection = agentTools.some((t) =>
|
|
458
474
|
["createDoc", "updateDoc", "read", "readDoc", "readPage"].includes(t)
|
|
@@ -519,6 +535,7 @@ export const buildSystemPromptContext = (options: {
|
|
|
519
535
|
{ id: "web-access", owner: "platform", content: webAccessSection },
|
|
520
536
|
{ id: "local-file-organization", owner: "platform", content: localFileOrganizationSection },
|
|
521
537
|
{ id: "table-share", owner: "platform", content: tableShareSection },
|
|
538
|
+
{ id: "agent-creation-draft", owner: "platform", content: agentCreationDraftSection },
|
|
522
539
|
{ id: "menu-usage", owner: "platform", content: menuUsageSection },
|
|
523
540
|
{ id: "clarification-mode", owner: "platform", content: clarifyingSection },
|
|
524
541
|
{ id: "knowledge-management", owner: "platform", content: knowledgeManagementSection },
|
|
@@ -8,6 +8,15 @@ type CliChatAction = "start" | "turn" | "get" | "close";
|
|
|
8
8
|
type CliChatRequestBase = {
|
|
9
9
|
cliProvider?: CliProvider;
|
|
10
10
|
model?: string;
|
|
11
|
+
systemPrompt?: string;
|
|
12
|
+
reasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
13
|
+
temperature?: number;
|
|
14
|
+
topP?: number;
|
|
15
|
+
frequencyPenalty?: number;
|
|
16
|
+
presencePenalty?: number;
|
|
17
|
+
maxTokens?: number;
|
|
18
|
+
enableThinking?: boolean;
|
|
19
|
+
thinkingBudget?: number;
|
|
11
20
|
};
|
|
12
21
|
|
|
13
22
|
function getCliChatRequestConfig(thunkApi: any) {
|
|
@@ -41,10 +50,18 @@ export async function startCliChatSession(
|
|
|
41
50
|
) {
|
|
42
51
|
const response = await postCliChat(thunkApi, {
|
|
43
52
|
action: "start" satisfies CliChatAction,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
cliProvider: args.cliProvider,
|
|
54
|
+
model: args.model,
|
|
55
|
+
systemPrompt: args.systemPrompt,
|
|
56
|
+
reasoningEffort: args.reasoningEffort,
|
|
57
|
+
temperature: args.temperature,
|
|
58
|
+
topP: args.topP,
|
|
59
|
+
frequencyPenalty: args.frequencyPenalty,
|
|
60
|
+
presencePenalty: args.presencePenalty,
|
|
61
|
+
maxTokens: args.maxTokens,
|
|
62
|
+
enableThinking: args.enableThinking,
|
|
63
|
+
thinkingBudget: args.thinkingBudget,
|
|
64
|
+
});
|
|
48
65
|
return response.json();
|
|
49
66
|
}
|
|
50
67
|
|
|
@@ -108,11 +125,28 @@ export function createCliChatTurnStream(
|
|
|
108
125
|
sessionId: args.sessionId,
|
|
109
126
|
prompt: args.prompt,
|
|
110
127
|
model: args.model,
|
|
128
|
+
reasoningEffort: args.reasoningEffort,
|
|
129
|
+
temperature: args.temperature,
|
|
130
|
+
topP: args.topP,
|
|
131
|
+
frequencyPenalty: args.frequencyPenalty,
|
|
132
|
+
presencePenalty: args.presencePenalty,
|
|
133
|
+
maxTokens: args.maxTokens,
|
|
134
|
+
enableThinking: args.enableThinking,
|
|
135
|
+
thinkingBudget: args.thinkingBudget,
|
|
111
136
|
}
|
|
112
137
|
: {
|
|
113
138
|
prompt: args.prompt,
|
|
114
139
|
model: args.model,
|
|
115
140
|
cliProvider: args.cliProvider,
|
|
141
|
+
systemPrompt: args.systemPrompt,
|
|
142
|
+
reasoningEffort: args.reasoningEffort,
|
|
143
|
+
temperature: args.temperature,
|
|
144
|
+
topP: args.topP,
|
|
145
|
+
frequencyPenalty: args.frequencyPenalty,
|
|
146
|
+
presencePenalty: args.presencePenalty,
|
|
147
|
+
maxTokens: args.maxTokens,
|
|
148
|
+
enableThinking: args.enableThinking,
|
|
149
|
+
thinkingBudget: args.thinkingBudget,
|
|
116
150
|
},
|
|
117
151
|
signal,
|
|
118
152
|
);
|
package/ai/agent/cliExecutor.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI Executor - 通过命令行工具执行 AI 任务
|
|
3
3
|
*
|
|
4
|
-
* 设计为可扩展:当前支持 Copilot CLI、Gemini CLI、Codex CLI 与
|
|
4
|
+
* 设计为可扩展:当前支持 Copilot CLI、Gemini CLI、Codex CLI、Claude CLI 与 Antigravity CLI。
|
|
5
5
|
*
|
|
6
6
|
* 注意:
|
|
7
7
|
* - CLI provider 与普通 model 路由共享 prompt / model / 最近文本上下文这些能力面
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* const result = await executeCli("copilot", prompt, { model: "claude-haiku-4.5" });
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { exec, spawn } from "child_process";
|
|
16
|
+
import { exec, execSync, spawn } from "child_process";
|
|
17
17
|
import { randomUUID } from "node:crypto";
|
|
18
18
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
19
19
|
import { join } from "node:path";
|
|
@@ -23,7 +23,7 @@ import { buildCliPrompt } from "./cliPrompt";
|
|
|
23
23
|
// ── 类型定义 ──────────────────────────────────────────────────────────────────
|
|
24
24
|
|
|
25
25
|
/** 已支持的 CLI 工具。新增时在此联合类型追加,并在 EXECUTORS 里注册实现 */
|
|
26
|
-
export type CliProvider = "copilot" | "gemini" | "codex" | "claude";
|
|
26
|
+
export type CliProvider = "copilot" | "gemini" | "codex" | "claude" | "agy";
|
|
27
27
|
|
|
28
28
|
export interface CliExecuteOptions {
|
|
29
29
|
model?: string;
|
|
@@ -31,12 +31,22 @@ export interface CliExecuteOptions {
|
|
|
31
31
|
cwd?: string;
|
|
32
32
|
env?: Record<string, string | undefined>;
|
|
33
33
|
yolo?: boolean; // 允许所有工具,默认 true(后台任务常用)
|
|
34
|
+
systemPrompt?: string;
|
|
35
|
+
reasoningEffort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
36
|
+
temperature?: number;
|
|
37
|
+
topP?: number;
|
|
38
|
+
frequencyPenalty?: number;
|
|
39
|
+
presencePenalty?: number;
|
|
40
|
+
maxTokens?: number;
|
|
41
|
+
enableThinking?: boolean;
|
|
42
|
+
thinkingBudget?: number;
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
export interface CliExecuteResult {
|
|
37
46
|
text: string; // 解析后的纯文本回复
|
|
38
47
|
raw: string; // 原始 stdout
|
|
39
48
|
elapsed: number; // 耗时 ms
|
|
49
|
+
warnings?: string[];
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
type CliSessionMessage = {
|
|
@@ -63,16 +73,163 @@ export interface CliSessionTurnResult extends CliExecuteResult {
|
|
|
63
73
|
|
|
64
74
|
const cliSessions = new Map<string, CliSessionState>();
|
|
65
75
|
|
|
76
|
+
type ProxyEnv = {
|
|
77
|
+
HTTP_PROXY?: string;
|
|
78
|
+
HTTPS_PROXY?: string;
|
|
79
|
+
ALL_PROXY?: string;
|
|
80
|
+
NO_PROXY?: string;
|
|
81
|
+
http_proxy?: string;
|
|
82
|
+
https_proxy?: string;
|
|
83
|
+
all_proxy?: string;
|
|
84
|
+
no_proxy?: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
function readMacSystemProxyEnv(): ProxyEnv {
|
|
88
|
+
if (process.platform !== "darwin") return {};
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const raw = String(execSync("scutil --proxy", { encoding: "utf8" }) || "");
|
|
92
|
+
const values = new Map<string, string>();
|
|
93
|
+
for (const line of raw.split("\n")) {
|
|
94
|
+
const match = line.match(/^\s*([A-Za-z0-9_]+)\s*:\s*(.+?)\s*$/);
|
|
95
|
+
if (!match) continue;
|
|
96
|
+
values.set(match[1], match[2].replace(/^"|"$/g, ""));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const httpEnabled = values.get("HTTPEnable") === "1";
|
|
100
|
+
const httpsEnabled = values.get("HTTPSEnable") === "1";
|
|
101
|
+
const httpHost = values.get("HTTPProxy")?.trim();
|
|
102
|
+
const httpsHost = values.get("HTTPSProxy")?.trim();
|
|
103
|
+
const httpPort = values.get("HTTPPort")?.trim();
|
|
104
|
+
const httpsPort = values.get("HTTPSPort")?.trim();
|
|
105
|
+
const noProxy = values.get("ExceptionsList")?.trim();
|
|
106
|
+
|
|
107
|
+
const httpProxy = httpEnabled && httpHost && httpPort ? `http://${httpHost}:${httpPort}` : "";
|
|
108
|
+
const httpsProxy = httpsEnabled && httpsHost && httpsPort ? `http://${httpsHost}:${httpsPort}` : "";
|
|
109
|
+
const allProxy = httpsProxy || httpProxy;
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
...(httpProxy ? { HTTP_PROXY: httpProxy, http_proxy: httpProxy } : {}),
|
|
113
|
+
...(httpsProxy ? { HTTPS_PROXY: httpsProxy, https_proxy: httpsProxy } : {}),
|
|
114
|
+
...(allProxy ? { ALL_PROXY: allProxy, all_proxy: allProxy } : {}),
|
|
115
|
+
...(noProxy ? { NO_PROXY: noProxy, no_proxy: noProxy } : {}),
|
|
116
|
+
};
|
|
117
|
+
} catch {
|
|
118
|
+
return {};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normalizeProxyEnv(env: Record<string, string | undefined>): Record<string, string | undefined> {
|
|
123
|
+
const explicitHttp = env.HTTP_PROXY?.trim() || env.http_proxy?.trim() || "";
|
|
124
|
+
const explicitHttps = env.HTTPS_PROXY?.trim() || env.https_proxy?.trim() || "";
|
|
125
|
+
const explicitAll = env.ALL_PROXY?.trim() || env.all_proxy?.trim() || "";
|
|
126
|
+
const explicitNoProxy = env.NO_PROXY?.trim() || env.no_proxy?.trim() || "";
|
|
127
|
+
const fallback = explicitHttp || explicitHttps || explicitAll ? {} : readMacSystemProxyEnv();
|
|
128
|
+
|
|
129
|
+
const httpProxy = explicitHttp || fallback.HTTP_PROXY || fallback.http_proxy || "";
|
|
130
|
+
const httpsProxy = explicitHttps || fallback.HTTPS_PROXY || fallback.https_proxy || httpProxy;
|
|
131
|
+
const allProxy = explicitAll || fallback.ALL_PROXY || fallback.all_proxy || httpsProxy || httpProxy;
|
|
132
|
+
const noProxy = explicitNoProxy || fallback.NO_PROXY || fallback.no_proxy || "";
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...env,
|
|
136
|
+
...(httpProxy ? { HTTP_PROXY: httpProxy, http_proxy: httpProxy } : {}),
|
|
137
|
+
...(httpsProxy ? { HTTPS_PROXY: httpsProxy, https_proxy: httpsProxy } : {}),
|
|
138
|
+
...(allProxy ? { ALL_PROXY: allProxy, all_proxy: allProxy } : {}),
|
|
139
|
+
...(noProxy ? { NO_PROXY: noProxy, no_proxy: noProxy } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
66
143
|
function buildCliProcessEnv(extraEnv?: Record<string, string | undefined>) {
|
|
67
144
|
return Object.fromEntries(
|
|
68
|
-
Object.entries({
|
|
145
|
+
Object.entries(normalizeProxyEnv({
|
|
69
146
|
...process.env,
|
|
70
147
|
...extraEnv,
|
|
71
148
|
NO_COLOR: "1",
|
|
72
|
-
}).filter((entry): entry is [string, string] => typeof entry[1] === "string")
|
|
149
|
+
})).filter((entry): entry is [string, string] => typeof entry[1] === "string")
|
|
73
150
|
);
|
|
74
151
|
}
|
|
75
152
|
|
|
153
|
+
function getCliProviderLabel(provider: CliProvider): string {
|
|
154
|
+
switch (provider) {
|
|
155
|
+
case "claude":
|
|
156
|
+
return "Claude CLI";
|
|
157
|
+
case "codex":
|
|
158
|
+
return "Codex CLI";
|
|
159
|
+
case "copilot":
|
|
160
|
+
return "Copilot CLI";
|
|
161
|
+
case "agy":
|
|
162
|
+
return "Antigravity CLI";
|
|
163
|
+
case "gemini":
|
|
164
|
+
return "Gemini CLI";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function supportsNativeSystemPrompt(provider: CliProvider): boolean {
|
|
169
|
+
return provider === "claude";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function supportsModel(provider: CliProvider): boolean {
|
|
173
|
+
return provider !== "agy";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function supportsReasoningEffort(provider: CliProvider): boolean {
|
|
177
|
+
return provider === "claude" || provider === "copilot";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function collectCliCapabilityWarnings(
|
|
181
|
+
provider: CliProvider,
|
|
182
|
+
options: CliExecuteOptions
|
|
183
|
+
): string[] {
|
|
184
|
+
const warnings: string[] = [];
|
|
185
|
+
const label = getCliProviderLabel(provider);
|
|
186
|
+
|
|
187
|
+
if (options.reasoningEffort !== undefined && !supportsReasoningEffort(provider)) {
|
|
188
|
+
warnings.push(`${label} does not support reasoning_effort; ignored.`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (options.model !== undefined && !supportsModel(provider)) {
|
|
192
|
+
warnings.push(`${label} does not support model selection; ignored.`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const unsupportedFields: Array<[string, unknown]> = [
|
|
196
|
+
["temperature", options.temperature],
|
|
197
|
+
["top_p", options.topP],
|
|
198
|
+
["frequency_penalty", options.frequencyPenalty],
|
|
199
|
+
["presence_penalty", options.presencePenalty],
|
|
200
|
+
["max_tokens", options.maxTokens],
|
|
201
|
+
["enableThinking", options.enableThinking ? true : undefined],
|
|
202
|
+
["thinkingBudget", options.thinkingBudget],
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
for (const [field, value] of unsupportedFields) {
|
|
206
|
+
if (value !== undefined) {
|
|
207
|
+
warnings.push(`${label} does not support ${field}; ignored.`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return warnings;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function resolveCliExecution(
|
|
215
|
+
provider: CliProvider,
|
|
216
|
+
prompt: string,
|
|
217
|
+
options: CliExecuteOptions
|
|
218
|
+
): { prompt: string; options: CliExecuteOptions; warnings: string[] } {
|
|
219
|
+
const warnings = collectCliCapabilityWarnings(provider, options);
|
|
220
|
+
if (supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()) {
|
|
221
|
+
return { prompt, options, warnings };
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
prompt: buildCliPrompt(options.systemPrompt, prompt),
|
|
225
|
+
options: {
|
|
226
|
+
...options,
|
|
227
|
+
systemPrompt: undefined,
|
|
228
|
+
},
|
|
229
|
+
warnings,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
76
233
|
// ── 各 provider 实现 ─────────────────────────────────────────────────────────
|
|
77
234
|
|
|
78
235
|
/**
|
|
@@ -85,6 +242,7 @@ function executeCopilot(
|
|
|
85
242
|
): Promise<CliExecuteResult> {
|
|
86
243
|
const {
|
|
87
244
|
model,
|
|
245
|
+
reasoningEffort,
|
|
88
246
|
timeout = 120_000,
|
|
89
247
|
cwd = process.cwd(),
|
|
90
248
|
yolo = true,
|
|
@@ -101,6 +259,7 @@ function executeCopilot(
|
|
|
101
259
|
"--no-color",
|
|
102
260
|
];
|
|
103
261
|
if (model) args.push(`--model ${model}`);
|
|
262
|
+
if (reasoningEffort) args.push(`--reasoning-effort ${reasoningEffort}`);
|
|
104
263
|
if (yolo) args.push("--yolo");
|
|
105
264
|
|
|
106
265
|
const cmd = args.join(" ");
|
|
@@ -327,6 +486,8 @@ function executeClaude(
|
|
|
327
486
|
): Promise<CliExecuteResult> {
|
|
328
487
|
const {
|
|
329
488
|
model,
|
|
489
|
+
systemPrompt,
|
|
490
|
+
reasoningEffort,
|
|
330
491
|
timeout = 120_000,
|
|
331
492
|
cwd = process.cwd(),
|
|
332
493
|
yolo = true,
|
|
@@ -338,6 +499,14 @@ function executeClaude(
|
|
|
338
499
|
args.push("--model");
|
|
339
500
|
args.push(model);
|
|
340
501
|
}
|
|
502
|
+
if (systemPrompt?.trim()) {
|
|
503
|
+
args.push("--system-prompt");
|
|
504
|
+
args.push(systemPrompt.trim());
|
|
505
|
+
}
|
|
506
|
+
if (reasoningEffort) {
|
|
507
|
+
args.push("--effort");
|
|
508
|
+
args.push(reasoningEffort);
|
|
509
|
+
}
|
|
341
510
|
if (yolo) {
|
|
342
511
|
args.push("--permission-mode");
|
|
343
512
|
args.push("bypassPermissions");
|
|
@@ -389,6 +558,77 @@ function executeClaude(
|
|
|
389
558
|
});
|
|
390
559
|
}
|
|
391
560
|
|
|
561
|
+
function formatCliTimeout(timeoutMs: number) {
|
|
562
|
+
return `${Math.max(1, Math.ceil(timeoutMs / 1000))}s`;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function executeAgy(
|
|
566
|
+
prompt: string,
|
|
567
|
+
options: CliExecuteOptions
|
|
568
|
+
): Promise<CliExecuteResult> {
|
|
569
|
+
const {
|
|
570
|
+
timeout = 120_000,
|
|
571
|
+
cwd = process.cwd(),
|
|
572
|
+
yolo = true,
|
|
573
|
+
} = options;
|
|
574
|
+
|
|
575
|
+
return new Promise((resolve, reject) => {
|
|
576
|
+
const args = [
|
|
577
|
+
"--print",
|
|
578
|
+
prompt,
|
|
579
|
+
"--print-timeout",
|
|
580
|
+
formatCliTimeout(timeout),
|
|
581
|
+
];
|
|
582
|
+
if (yolo) {
|
|
583
|
+
args.push("--dangerously-skip-permissions");
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const start = Date.now();
|
|
587
|
+
const proc = spawn("agy", args, {
|
|
588
|
+
cwd,
|
|
589
|
+
env: buildCliProcessEnv(options.env),
|
|
590
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
591
|
+
});
|
|
592
|
+
let stdout = "";
|
|
593
|
+
let stderr = "";
|
|
594
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
595
|
+
|
|
596
|
+
if (timeout > 0) {
|
|
597
|
+
timer = setTimeout(() => {
|
|
598
|
+
proc.kill("SIGTERM");
|
|
599
|
+
reject(new Error(`Antigravity CLI timed out after ${timeout}ms`));
|
|
600
|
+
}, timeout + 1_000);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
proc.stdout.on("data", (data: Buffer) => {
|
|
604
|
+
stdout += data.toString();
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
proc.stderr.on("data", (data: Buffer) => {
|
|
608
|
+
stderr += data.toString();
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
proc.on("close", (code) => {
|
|
612
|
+
if (timer) clearTimeout(timer);
|
|
613
|
+
if (code !== 0 && code !== null) {
|
|
614
|
+
reject(new Error(`Antigravity CLI exited with code ${code}\nstderr: ${stderr}`));
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
resolve({
|
|
619
|
+
text: stdout.trim(),
|
|
620
|
+
raw: stdout,
|
|
621
|
+
elapsed: Date.now() - start,
|
|
622
|
+
});
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
proc.on("error", (err) => {
|
|
626
|
+
if (timer) clearTimeout(timer);
|
|
627
|
+
reject(err);
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
392
632
|
// ── 注册表(新增 CLI 工具时在这里加) ────────────────────────────────────────
|
|
393
633
|
|
|
394
634
|
const EXECUTORS: Record<
|
|
@@ -399,6 +639,7 @@ const EXECUTORS: Record<
|
|
|
399
639
|
gemini: executeGemini,
|
|
400
640
|
codex: executeCodex,
|
|
401
641
|
claude: executeClaude,
|
|
642
|
+
agy: executeAgy,
|
|
402
643
|
};
|
|
403
644
|
|
|
404
645
|
function formatCliSessionTask(messages: CliSessionMessage[]): string {
|
|
@@ -416,13 +657,10 @@ function buildCliSessionPrompt(session: CliSessionState, userInput: string): str
|
|
|
416
657
|
{ role: "user", content: userInput },
|
|
417
658
|
]);
|
|
418
659
|
|
|
419
|
-
return
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
transcript,
|
|
424
|
-
].join("\n\n"),
|
|
425
|
-
);
|
|
660
|
+
return [
|
|
661
|
+
"以下是当前对话,请基于完整上下文继续回答最后一条用户消息。",
|
|
662
|
+
transcript,
|
|
663
|
+
].join("\n\n");
|
|
426
664
|
}
|
|
427
665
|
|
|
428
666
|
function getCliSessionOrThrow(sessionId: string): CliSessionState {
|
|
@@ -438,7 +676,7 @@ function getCliSessionOrThrow(sessionId: string): CliSessionState {
|
|
|
438
676
|
/**
|
|
439
677
|
* 执行 CLI 任务
|
|
440
678
|
*
|
|
441
|
-
* @param provider CLI 工具类型(如 "copilot" | "gemini" | "codex" | "claude")
|
|
679
|
+
* @param provider CLI 工具类型(如 "copilot" | "gemini" | "codex" | "claude" | "agy")
|
|
442
680
|
* @param prompt 完整 prompt(system prompt 已由调用方拼好)
|
|
443
681
|
* @param options 执行选项
|
|
444
682
|
*/
|
|
@@ -451,7 +689,12 @@ export async function executeCli(
|
|
|
451
689
|
if (!executor) {
|
|
452
690
|
throw new Error(`Unknown CLI provider: "${provider}". Supported: ${Object.keys(EXECUTORS).join(", ")}`);
|
|
453
691
|
}
|
|
454
|
-
|
|
692
|
+
const resolved = resolveCliExecution(provider, prompt, options);
|
|
693
|
+
const result = await executor(resolved.prompt, resolved.options);
|
|
694
|
+
return {
|
|
695
|
+
...result,
|
|
696
|
+
warnings: [...resolved.warnings, ...(result.warnings ?? [])],
|
|
697
|
+
};
|
|
455
698
|
}
|
|
456
699
|
|
|
457
700
|
export { buildCliPrompt };
|
|
@@ -473,7 +716,17 @@ export function startCliSession(
|
|
|
473
716
|
model: options.model,
|
|
474
717
|
timeout: options.timeout,
|
|
475
718
|
cwd: options.cwd,
|
|
719
|
+
env: options.env,
|
|
476
720
|
yolo: options.yolo,
|
|
721
|
+
systemPrompt: options.systemPrompt,
|
|
722
|
+
reasoningEffort: options.reasoningEffort,
|
|
723
|
+
temperature: options.temperature,
|
|
724
|
+
topP: options.topP,
|
|
725
|
+
frequencyPenalty: options.frequencyPenalty,
|
|
726
|
+
presencePenalty: options.presencePenalty,
|
|
727
|
+
maxTokens: options.maxTokens,
|
|
728
|
+
enableThinking: options.enableThinking,
|
|
729
|
+
thinkingBudget: options.thinkingBudget,
|
|
477
730
|
},
|
|
478
731
|
messages: [],
|
|
479
732
|
createdAt: Date.now(),
|
|
@@ -567,31 +820,52 @@ export function executeCliStreaming(
|
|
|
567
820
|
prompt: string,
|
|
568
821
|
options: CliExecuteOptions & { onChunk: (chunk: string) => void }
|
|
569
822
|
): Promise<CliExecuteResult> {
|
|
823
|
+
const resolved = resolveCliExecution(provider, prompt, options);
|
|
824
|
+
const executor = EXECUTORS[provider];
|
|
570
825
|
if (provider === "gemini") {
|
|
571
|
-
return executeGeminiStreaming(prompt, options)
|
|
826
|
+
return executeGeminiStreaming(resolved.prompt, resolved.options as CliExecuteOptions & { onChunk: (chunk: string) => void })
|
|
827
|
+
.then((result) => ({ ...result, warnings: [...resolved.warnings, ...(result.warnings ?? [])] }));
|
|
572
828
|
}
|
|
573
829
|
if (provider === "codex") {
|
|
574
|
-
return
|
|
575
|
-
|
|
576
|
-
|
|
830
|
+
return executor(resolved.prompt, resolved.options).then((result) => {
|
|
831
|
+
const merged = { ...result, warnings: [...resolved.warnings, ...(result.warnings ?? [])] };
|
|
832
|
+
if (merged.text) options.onChunk(merged.text);
|
|
833
|
+
return merged;
|
|
577
834
|
});
|
|
578
835
|
}
|
|
579
836
|
if (provider === "claude") {
|
|
580
|
-
return
|
|
581
|
-
|
|
582
|
-
|
|
837
|
+
return executor(resolved.prompt, resolved.options).then((result) => {
|
|
838
|
+
const merged = { ...result, warnings: [...resolved.warnings, ...(result.warnings ?? [])] };
|
|
839
|
+
if (merged.text) options.onChunk(merged.text);
|
|
840
|
+
return merged;
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
if (provider === "agy") {
|
|
844
|
+
return executor(resolved.prompt, resolved.options).then((result) => {
|
|
845
|
+
const merged = { ...result, warnings: [...resolved.warnings, ...(result.warnings ?? [])] };
|
|
846
|
+
if (merged.text) options.onChunk(merged.text);
|
|
847
|
+
return merged;
|
|
583
848
|
});
|
|
584
849
|
}
|
|
585
850
|
if (provider !== "copilot") {
|
|
586
|
-
return
|
|
851
|
+
return executor(resolved.prompt, resolved.options).then((result) => ({
|
|
852
|
+
...result,
|
|
853
|
+
warnings: [...resolved.warnings, ...(result.warnings ?? [])],
|
|
854
|
+
}));
|
|
587
855
|
}
|
|
588
856
|
|
|
589
|
-
const {
|
|
857
|
+
const {
|
|
858
|
+
model,
|
|
859
|
+
timeout = 120_000,
|
|
860
|
+
cwd = process.cwd(),
|
|
861
|
+
yolo = true,
|
|
862
|
+
onChunk,
|
|
863
|
+
} = resolved.options as CliExecuteOptions & { onChunk: (chunk: string) => void };
|
|
590
864
|
|
|
591
865
|
return new Promise((resolve, reject) => {
|
|
592
866
|
const args = [
|
|
593
867
|
"copilot", "--",
|
|
594
|
-
"-p", prompt,
|
|
868
|
+
"-p", resolved.prompt,
|
|
595
869
|
"--silent",
|
|
596
870
|
"--disable-builtin-mcps",
|
|
597
871
|
];
|
|
@@ -636,7 +910,12 @@ export function executeCliStreaming(
|
|
|
636
910
|
.filter(filterNoiseLine)
|
|
637
911
|
.join("\n")
|
|
638
912
|
.trim();
|
|
639
|
-
resolve({
|
|
913
|
+
resolve({
|
|
914
|
+
text,
|
|
915
|
+
raw,
|
|
916
|
+
elapsed: Date.now() - start,
|
|
917
|
+
warnings: [...resolved.warnings],
|
|
918
|
+
});
|
|
640
919
|
});
|
|
641
920
|
|
|
642
921
|
proc.on("error", (err) => {
|
|
@@ -66,10 +66,10 @@ export const getCreateAgentSchema = (t: TFunction) =>
|
|
|
66
66
|
apiSource: z.enum(["platform", "custom", "cli"]).default("platform"),
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
* CLI provider(apiSource=cli 时有效):支持 "copilot" | "gemini" | "codex" | "claude"
|
|
69
|
+
* CLI provider(apiSource=cli 时有效):支持 "copilot" | "gemini" | "codex" | "claude" | "agy"
|
|
70
70
|
*/
|
|
71
71
|
cliProvider: z
|
|
72
|
-
.enum(["copilot", "gemini", "codex", "claude"])
|
|
72
|
+
.enum(["copilot", "gemini", "codex", "claude", "agy"])
|
|
73
73
|
.optional()
|
|
74
74
|
.or(z.literal("")),
|
|
75
75
|
|