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
|
@@ -156,8 +156,11 @@ export type TaskRunReview = {
|
|
|
156
156
|
export type TaskRunAutonomy = "manual" | "supervised" | "auto24h";
|
|
157
157
|
|
|
158
158
|
export type TaskRunBudgetRule = {
|
|
159
|
+
agentKey?: string;
|
|
159
160
|
provider?: string;
|
|
160
161
|
model?: string;
|
|
162
|
+
customProviderUrl?: string;
|
|
163
|
+
apiKeyHeader?: string;
|
|
161
164
|
freeUntil?: string;
|
|
162
165
|
dailyUsdLimit?: number;
|
|
163
166
|
hardStopAfter?: string;
|
|
@@ -193,6 +196,7 @@ export type TaskRunControlPolicy = {
|
|
|
193
196
|
autonomy?: TaskRunAutonomy;
|
|
194
197
|
nextWakeAt?: string;
|
|
195
198
|
pausedReason?: string;
|
|
199
|
+
runtimeToolPolicy?: Record<string, unknown>;
|
|
196
200
|
budget?: {
|
|
197
201
|
dailyUsdLimit?: number;
|
|
198
202
|
modelBudget?: Record<string, TaskRunBudgetRule>;
|
|
@@ -248,20 +252,31 @@ export const DEFAULT_TASK_RUN_CONTROL_POLICY: TaskRunControlPolicy = {
|
|
|
248
252
|
budget: {
|
|
249
253
|
modelBudget: {
|
|
250
254
|
projectManager: {
|
|
255
|
+
agentKey: "agent-b2e06f801f-01MIMO25MONTH00000001PGT4X",
|
|
251
256
|
provider: "custom",
|
|
252
|
-
model: "
|
|
253
|
-
|
|
257
|
+
model: "mimo-v2.5-pro",
|
|
258
|
+
customProviderUrl: "https://token-plan-cn.xiaomimimo.com/v1",
|
|
259
|
+
apiKeyHeader: "api-key",
|
|
260
|
+
freeUntil: "2026-05-31",
|
|
261
|
+
note: "Default PM and execution routing uses the monthly Mimo custom-key pool; medium intelligence, no marginal cost through the current month.",
|
|
254
262
|
},
|
|
255
263
|
frontend: {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
agentKey: "agent-b2e06f801f-01MIMO25MONTH00000001PGT4X",
|
|
265
|
+
provider: "custom",
|
|
266
|
+
model: "mimo-v2.5-pro",
|
|
267
|
+
customProviderUrl: "https://token-plan-cn.xiaomimimo.com/v1",
|
|
268
|
+
apiKeyHeader: "api-key",
|
|
269
|
+
freeUntil: "2026-05-31",
|
|
270
|
+
note: "Frontend implementation uses the monthly Mimo custom-key pool by default; escalate to Codex only for quality gates or hard unblocks.",
|
|
260
271
|
},
|
|
261
272
|
mimoCustomKey: {
|
|
262
|
-
|
|
273
|
+
agentKey: "agent-b2e06f801f-01MIMO25MONTH00000001PGT4X",
|
|
274
|
+
provider: "custom",
|
|
275
|
+
model: "mimo-v2.5-pro",
|
|
276
|
+
customProviderUrl: "https://token-plan-cn.xiaomimimo.com/v1",
|
|
277
|
+
apiKeyHeader: "api-key",
|
|
263
278
|
freeUntil: "2026-05-31",
|
|
264
|
-
note: "
|
|
279
|
+
note: "Use the existing monthly Mimo custom-key agent/config for high-token routine implementation, long-context reads, table/doc processing, and low-risk probes.",
|
|
265
280
|
},
|
|
266
281
|
},
|
|
267
282
|
},
|
|
@@ -857,11 +872,11 @@ export function recordTaskRunReview(args: {
|
|
|
857
872
|
meta.review = review;
|
|
858
873
|
let nextMeta = meta;
|
|
859
874
|
const targetWorkItemId = args.targetWorkItemId ?? meta.review?.targetWorkItemId;
|
|
860
|
-
if (args.status === "needs_changes" && targetWorkItemId) {
|
|
875
|
+
if ((args.status === "needs_changes" || args.status === "blocked") && targetWorkItemId) {
|
|
861
876
|
nextMeta = updateTaskRunWorkItem({
|
|
862
877
|
meta: nextMeta,
|
|
863
878
|
id: targetWorkItemId,
|
|
864
|
-
status:
|
|
879
|
+
status: args.status,
|
|
865
880
|
artifactRefs: args.artifactIds,
|
|
866
881
|
dialogIds: args.dialogId ? [args.dialogId] : undefined,
|
|
867
882
|
now,
|
|
@@ -64,6 +64,7 @@ export type ModelUsageQueryResult = {
|
|
|
64
64
|
threshold: {
|
|
65
65
|
costCredits: number | null;
|
|
66
66
|
costUsd: number | null;
|
|
67
|
+
usedPercent: number | null;
|
|
67
68
|
exceeded: boolean;
|
|
68
69
|
};
|
|
69
70
|
};
|
|
@@ -83,6 +84,17 @@ const toNumber = (value: unknown): number =>
|
|
|
83
84
|
|
|
84
85
|
const round6 = (value: number): number => Number(value.toFixed(6));
|
|
85
86
|
|
|
87
|
+
const clampPercent = (value: number): number =>
|
|
88
|
+
Math.max(0, Math.min(100, Math.round(value)));
|
|
89
|
+
|
|
90
|
+
const calculateThresholdUsedPercent = (
|
|
91
|
+
costCredits: number,
|
|
92
|
+
thresholdCredits: number | null,
|
|
93
|
+
): number | null => {
|
|
94
|
+
if (thresholdCredits == null || thresholdCredits <= 0) return null;
|
|
95
|
+
return clampPercent((costCredits / thresholdCredits) * 100);
|
|
96
|
+
};
|
|
97
|
+
|
|
86
98
|
const normalizeDateKey = (value: unknown): string | null => {
|
|
87
99
|
if (typeof value !== "string" || !value.trim()) return null;
|
|
88
100
|
const trimmed = value.trim();
|
|
@@ -227,6 +239,10 @@ export async function queryModelUsage(
|
|
|
227
239
|
: thresholdCredits == null
|
|
228
240
|
? null
|
|
229
241
|
: round6(thresholdCredits / creditsPerUsd);
|
|
242
|
+
const thresholdUsedPercent = calculateThresholdUsedPercent(
|
|
243
|
+
total.costCredits,
|
|
244
|
+
thresholdCredits,
|
|
245
|
+
);
|
|
230
246
|
|
|
231
247
|
return {
|
|
232
248
|
scope,
|
|
@@ -246,6 +262,7 @@ export async function queryModelUsage(
|
|
|
246
262
|
threshold: {
|
|
247
263
|
costCredits: thresholdCredits,
|
|
248
264
|
costUsd: thresholdUsd,
|
|
265
|
+
usedPercent: thresholdUsedPercent,
|
|
249
266
|
exceeded: thresholdCredits == null ? false : total.costCredits > thresholdCredits,
|
|
250
267
|
},
|
|
251
268
|
};
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
createAgentToolFunctionSchema,
|
|
9
9
|
createAgentToolFunc,
|
|
10
10
|
} from "./createAgentTool";
|
|
11
|
+
import {
|
|
12
|
+
prepareAgentDraftToolFunctionSchema,
|
|
13
|
+
prepareAgentDraftToolFunc,
|
|
14
|
+
} from "./prepareAgentDraftTool";
|
|
11
15
|
import {
|
|
12
16
|
createSkillAgentToolFunctionSchema,
|
|
13
17
|
createSkillAgentToolFunc,
|
|
@@ -28,6 +32,10 @@ import {
|
|
|
28
32
|
streamParallelAgentsFunctionSchema,
|
|
29
33
|
streamParallelAgentsFunc,
|
|
30
34
|
} from "./streamParallelAgentsTool";
|
|
35
|
+
import {
|
|
36
|
+
startAgentDialogFunctionSchema,
|
|
37
|
+
startAgentDialogFunc,
|
|
38
|
+
} from "./startAgentDialogTool";
|
|
31
39
|
import {
|
|
32
40
|
createDialogFunctionSchema,
|
|
33
41
|
createDialogFunc,
|
|
@@ -44,6 +52,23 @@ import {
|
|
|
44
52
|
import type { ToolDefinition } from "../index";
|
|
45
53
|
|
|
46
54
|
export const agentToolDefinitions: ToolDefinition[] = [
|
|
55
|
+
{
|
|
56
|
+
id: "prepareAgentDraft",
|
|
57
|
+
schema: prepareAgentDraftToolFunctionSchema,
|
|
58
|
+
executor: prepareAgentDraftToolFunc,
|
|
59
|
+
description: {
|
|
60
|
+
name: "prepareAgentDraft",
|
|
61
|
+
description:
|
|
62
|
+
"整理 Agent 创建草稿并交给用户预览确认,不创建真实 Agent。",
|
|
63
|
+
category: "计划与编排",
|
|
64
|
+
},
|
|
65
|
+
behavior: "data",
|
|
66
|
+
uiGroup: "agent",
|
|
67
|
+
capability: "general",
|
|
68
|
+
riskLevel: "low",
|
|
69
|
+
costLevel: "low",
|
|
70
|
+
defaultConsent: "auto",
|
|
71
|
+
},
|
|
47
72
|
{
|
|
48
73
|
id: "createAgent",
|
|
49
74
|
schema: createAgentToolFunctionSchema,
|
|
@@ -151,6 +176,19 @@ export const agentToolDefinitions: ToolDefinition[] = [
|
|
|
151
176
|
behavior: "orchestrator",
|
|
152
177
|
uiGroup: "agent",
|
|
153
178
|
},
|
|
179
|
+
{
|
|
180
|
+
id: "startAgentDialog",
|
|
181
|
+
schema: startAgentDialogFunctionSchema,
|
|
182
|
+
executor: startAgentDialogFunc,
|
|
183
|
+
description: {
|
|
184
|
+
name: "startAgentDialog",
|
|
185
|
+
description:
|
|
186
|
+
"启动一个子 Agent dialog,返回 childDialogId,供调用方后续查询、接管或投影状态。",
|
|
187
|
+
category: "计划与编排",
|
|
188
|
+
},
|
|
189
|
+
behavior: "orchestrator",
|
|
190
|
+
uiGroup: "agent",
|
|
191
|
+
},
|
|
154
192
|
{
|
|
155
193
|
id: "createDialog",
|
|
156
194
|
schema: createDialogFunctionSchema,
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { DEFAULT_MODEL } from "ai/llm/providers";
|
|
2
|
+
import {
|
|
3
|
+
GUIDED_AGENT_CAPABILITIES,
|
|
4
|
+
mapCapabilityIdsToToolIds,
|
|
5
|
+
} from "ai/agent/guidedCreation/capabilities";
|
|
6
|
+
import type {
|
|
7
|
+
GuidedAgentCapabilityId,
|
|
8
|
+
GuidedAgentDraft,
|
|
9
|
+
GuidedAgentReferenceChoice,
|
|
10
|
+
} from "ai/agent/guidedCreation/types";
|
|
11
|
+
|
|
12
|
+
export type PrepareAgentDraftToolArgs = Partial<GuidedAgentDraft>;
|
|
13
|
+
|
|
14
|
+
const capabilityIds = new Set(Object.keys(GUIDED_AGENT_CAPABILITIES));
|
|
15
|
+
|
|
16
|
+
const trim = (value: unknown) =>
|
|
17
|
+
typeof value === "string" ? value.trim() : "";
|
|
18
|
+
|
|
19
|
+
const stringArray = (value: unknown): string[] =>
|
|
20
|
+
Array.isArray(value)
|
|
21
|
+
? value.map((item) => trim(item)).filter(Boolean)
|
|
22
|
+
: [];
|
|
23
|
+
|
|
24
|
+
const guidedCapabilityArray = (value: unknown): GuidedAgentCapabilityId[] =>
|
|
25
|
+
stringArray(value).filter((id): id is GuidedAgentCapabilityId =>
|
|
26
|
+
capabilityIds.has(id)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const referencesArray = (value: unknown): GuidedAgentReferenceChoice[] =>
|
|
30
|
+
Array.isArray(value)
|
|
31
|
+
? value
|
|
32
|
+
.filter((item): item is Record<string, unknown> =>
|
|
33
|
+
!!item && typeof item === "object" && !Array.isArray(item)
|
|
34
|
+
)
|
|
35
|
+
.map((item) => ({
|
|
36
|
+
dbKey: trim(item.dbKey),
|
|
37
|
+
title: trim(item.title),
|
|
38
|
+
type: item.type === "instruction" ? "instruction" : "knowledge",
|
|
39
|
+
selected: item.selected === true,
|
|
40
|
+
...(trim(item.reason) ? { reason: trim(item.reason) } : {}),
|
|
41
|
+
}))
|
|
42
|
+
.filter((item) => item.dbKey)
|
|
43
|
+
: [];
|
|
44
|
+
|
|
45
|
+
const buildPrompt = (args: PrepareAgentDraftToolArgs) => {
|
|
46
|
+
const prompt = trim(args.prompt);
|
|
47
|
+
if (prompt) return prompt;
|
|
48
|
+
const name = trim(args.name) || "用户的专属 AI";
|
|
49
|
+
const summary = trim(args.promptSummary) || trim(args.introduction);
|
|
50
|
+
return [
|
|
51
|
+
`你是${name}。`,
|
|
52
|
+
summary || "你需要理解用户目标,并给出清晰、可执行、有边界的帮助。",
|
|
53
|
+
"如果信息不足,先提出必要澄清问题;不要编造用户没有确认的资料来源。",
|
|
54
|
+
].join("\n");
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const buildPreparedAgentDraft = (
|
|
58
|
+
args: PrepareAgentDraftToolArgs
|
|
59
|
+
): GuidedAgentDraft => {
|
|
60
|
+
const selectedCapabilities = guidedCapabilityArray(args.capabilityIds);
|
|
61
|
+
const providedToolIds = stringArray(args.toolIds);
|
|
62
|
+
const mappedToolIds = mapCapabilityIdsToToolIds(selectedCapabilities);
|
|
63
|
+
return {
|
|
64
|
+
name: trim(args.name),
|
|
65
|
+
introduction: trim(args.introduction),
|
|
66
|
+
prompt: buildPrompt(args),
|
|
67
|
+
promptSummary: trim(args.promptSummary),
|
|
68
|
+
provider: trim(args.provider) || DEFAULT_MODEL.provider,
|
|
69
|
+
model: trim(args.model) || DEFAULT_MODEL.name,
|
|
70
|
+
isPublic: args.isPublic === true,
|
|
71
|
+
capabilityIds: selectedCapabilities,
|
|
72
|
+
toolIds: Array.from(new Set([...providedToolIds, ...mappedToolIds])),
|
|
73
|
+
references: referencesArray(args.references),
|
|
74
|
+
tags: stringArray(args.tags),
|
|
75
|
+
unresolved: stringArray(args.unresolved),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const prepareAgentDraftToolFunctionSchema = {
|
|
80
|
+
name: "prepareAgentDraft",
|
|
81
|
+
description:
|
|
82
|
+
"整理一个可预览的 Agent 创建草稿。只生成草稿,不创建真实 Agent 记录。",
|
|
83
|
+
parameters: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
name: { type: "string", description: "建议的 Agent 名称。" },
|
|
87
|
+
introduction: { type: "string", description: "面向用户展示的简介。" },
|
|
88
|
+
prompt: { type: "string", description: "完整系统 prompt 草稿。" },
|
|
89
|
+
promptSummary: { type: "string", description: "prompt 的简短摘要。" },
|
|
90
|
+
provider: { type: "string", description: "建议 provider。" },
|
|
91
|
+
model: { type: "string", description: "建议模型名称。" },
|
|
92
|
+
isPublic: { type: "boolean", description: "是否建议公开。" },
|
|
93
|
+
capabilityIds: {
|
|
94
|
+
type: "array",
|
|
95
|
+
items: {
|
|
96
|
+
type: "string",
|
|
97
|
+
enum: Object.keys(GUIDED_AGENT_CAPABILITIES),
|
|
98
|
+
},
|
|
99
|
+
description: "已确认或高度确定的能力标签。",
|
|
100
|
+
},
|
|
101
|
+
toolIds: {
|
|
102
|
+
type: "array",
|
|
103
|
+
items: { type: "string" },
|
|
104
|
+
description: "可选的底层工具名;通常由 capabilityIds 推导。",
|
|
105
|
+
},
|
|
106
|
+
references: {
|
|
107
|
+
type: "array",
|
|
108
|
+
items: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
dbKey: { type: "string" },
|
|
112
|
+
title: { type: "string" },
|
|
113
|
+
type: { type: "string", enum: ["knowledge", "instruction"] },
|
|
114
|
+
selected: { type: "boolean" },
|
|
115
|
+
reason: { type: "string" },
|
|
116
|
+
},
|
|
117
|
+
required: ["dbKey"],
|
|
118
|
+
},
|
|
119
|
+
description: "建议挂载的知识引用,默认等待用户确认。",
|
|
120
|
+
},
|
|
121
|
+
tags: {
|
|
122
|
+
type: "array",
|
|
123
|
+
items: { type: "string" },
|
|
124
|
+
},
|
|
125
|
+
unresolved: {
|
|
126
|
+
type: "array",
|
|
127
|
+
items: { type: "string" },
|
|
128
|
+
description: "仍需确认的字段或问题。",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
required: ["name", "introduction", "promptSummary"],
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export async function prepareAgentDraftToolFunc(
|
|
136
|
+
args: PrepareAgentDraftToolArgs
|
|
137
|
+
): Promise<{
|
|
138
|
+
rawData: { draft: GuidedAgentDraft; createUrl: string };
|
|
139
|
+
displayData: string;
|
|
140
|
+
}> {
|
|
141
|
+
const draft = buildPreparedAgentDraft(args);
|
|
142
|
+
const missing = draft.unresolved.length
|
|
143
|
+
? `\n- 待确认: ${draft.unresolved.join(", ")}`
|
|
144
|
+
: "";
|
|
145
|
+
return {
|
|
146
|
+
rawData: {
|
|
147
|
+
draft,
|
|
148
|
+
createUrl: "/create/agent",
|
|
149
|
+
},
|
|
150
|
+
displayData: [
|
|
151
|
+
`Agent 草稿: ${draft.name || "未命名 AI"}`,
|
|
152
|
+
draft.promptSummary ? `- 摘要: ${draft.promptSummary}` : "",
|
|
153
|
+
draft.capabilityIds.length
|
|
154
|
+
? `- 能力: ${draft.capabilityIds.join(", ")}`
|
|
155
|
+
: "",
|
|
156
|
+
missing,
|
|
157
|
+
].filter(Boolean).join("\n"),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export const startAgentDialogFunctionSchema = {
|
|
2
|
+
name: "startAgentDialog",
|
|
3
|
+
description:
|
|
4
|
+
"启动一个子 Agent dialog 并立即返回 childDialogId。用于通用 agent 派发/交接,不等待子 Agent 完成,也不替调用方决定任务状态。",
|
|
5
|
+
parameters: {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: {
|
|
8
|
+
targetAgentKey: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "要启动的目标 Agent key。",
|
|
11
|
+
},
|
|
12
|
+
message: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "发送给目标 Agent 的自然语言任务或上下文。",
|
|
15
|
+
},
|
|
16
|
+
parentDialogId: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "可选。父 dialogId;未提供时使用当前 dialogId。",
|
|
19
|
+
},
|
|
20
|
+
subjectRefs: {
|
|
21
|
+
type: "array",
|
|
22
|
+
description: "可选。与本次子 dialog 相关的业务对象引用,保持行业中立。",
|
|
23
|
+
items: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
kind: { type: "string" },
|
|
27
|
+
id: { type: "string" },
|
|
28
|
+
role: { type: "string" },
|
|
29
|
+
},
|
|
30
|
+
required: ["kind", "id"],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
idempotencyKey: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "可选。调用方用于去重的稳定 key;当前版本仅透传给运行上下文。",
|
|
36
|
+
},
|
|
37
|
+
serverBase: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description:
|
|
40
|
+
"可选。目标 Agent 所在的 nolo server origin;跨域目标必须由服务端 AGENT_TOOL_ALLOWED_SERVER_BASES 放行。",
|
|
41
|
+
},
|
|
42
|
+
timeoutMs: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "可选。子 Agent background run 的执行超时预算(毫秒)。",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ["targetAgentKey", "message"],
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export async function startAgentDialogFunc(): Promise<never> {
|
|
52
|
+
throw new Error("startAgentDialog is a server-side agent tool. Use it through /api/agent/run.");
|
|
53
|
+
}
|
package/ai/tools/checkEnvTool.ts
CHANGED
|
@@ -3,39 +3,60 @@
|
|
|
3
3
|
|
|
4
4
|
import { callToolApi } from "./toolApiClient";
|
|
5
5
|
|
|
6
|
-
export type CheckEnvArgs = {
|
|
7
|
-
check?: "build" | "context";
|
|
8
|
-
|
|
6
|
+
export type CheckEnvArgs = {
|
|
7
|
+
check?: "build" | "context";
|
|
8
|
+
key?: string;
|
|
9
|
+
};
|
|
9
10
|
|
|
10
11
|
export const checkEnvFunctionSchema = {
|
|
11
12
|
name: "checkEnv",
|
|
12
13
|
description: [
|
|
13
|
-
"执行环境检查并返回结构化结果。",
|
|
14
|
-
"check='context' 可查看当前平台、工作目录与可用 shell;check='build' 可快速验证是否可编译。",
|
|
14
|
+
"执行环境检查并返回结构化结果。",
|
|
15
|
+
"check='context' 可查看当前平台、工作目录与可用 shell;check='build' 可快速验证是否可编译。",
|
|
16
|
+
"key 可检查某个本地工具,例如 key='gemini' 会探测本机 Gemini CLI 与 npm 最新版本。",
|
|
15
17
|
].join("\n"),
|
|
16
18
|
parameters: {
|
|
17
19
|
type: "object",
|
|
18
20
|
properties: {
|
|
19
|
-
check: {
|
|
20
|
-
type: "string",
|
|
21
|
-
enum: ["build", "context"],
|
|
22
|
-
description: "检查项:context 返回当前运行环境;build 执行构建检查。",
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
check: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["build", "context"],
|
|
24
|
+
description: "检查项:context 返回当前运行环境;build 执行构建检查。",
|
|
25
|
+
},
|
|
26
|
+
key: {
|
|
27
|
+
type: "string",
|
|
28
|
+
enum: ["gemini", "node", "npm", "bun", "python", "git", "shell"],
|
|
29
|
+
description: "可选:探测某个本地工具,不执行 build。常用值如 gemini、node、npm、bun、python、git、shell。",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const formatProbeOutput = (probe: any): string => {
|
|
36
|
+
const status = probe?.ok ? "OK" : "FAIL";
|
|
37
|
+
const lines = [`- [${status}] ${probe?.label ?? "probe"}`];
|
|
38
|
+
const stdout = typeof probe?.stdout === "string" ? probe.stdout.trim() : "";
|
|
39
|
+
const stderr = typeof probe?.stderr === "string" ? probe.stderr.trim() : "";
|
|
40
|
+
const error = typeof probe?.error === "string" ? probe.error.trim() : "";
|
|
41
|
+
if (stdout) lines.push(` stdout: ${stdout}`);
|
|
42
|
+
if (stderr) lines.push(` stderr: ${stderr}`);
|
|
43
|
+
if (error) lines.push(` error: ${error}`);
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
};
|
|
27
46
|
|
|
28
47
|
export async function checkEnvFunc(
|
|
29
48
|
args: CheckEnvArgs,
|
|
30
49
|
thunkApi: any,
|
|
31
50
|
context?: { agentKey?: string }
|
|
32
51
|
): Promise<{ rawData: any; displayData: string }> {
|
|
33
|
-
const
|
|
34
|
-
|
|
52
|
+
const key = typeof args?.key === "string" ? args.key.trim().toLowerCase() : "";
|
|
53
|
+
const check = args?.check === "context" ? "context" : "build";
|
|
54
|
+
const payload = key ? { key } : { check };
|
|
55
|
+
|
|
35
56
|
const result = await callToolApi<any>(
|
|
36
57
|
thunkApi,
|
|
37
58
|
"/api/check-env",
|
|
38
|
-
|
|
59
|
+
payload,
|
|
39
60
|
{
|
|
40
61
|
withAuth: true,
|
|
41
62
|
agentKey: context?.agentKey,
|
|
@@ -45,7 +66,18 @@ export async function checkEnvFunc(
|
|
|
45
66
|
const ok = !!result?.ok;
|
|
46
67
|
const exitCode = typeof result?.exitCode === "number" ? result.exitCode : -1;
|
|
47
68
|
|
|
48
|
-
if (check === "
|
|
69
|
+
if (result?.check === "tool") {
|
|
70
|
+
const probes = Array.isArray(result?.probes) ? result.probes : [];
|
|
71
|
+
return {
|
|
72
|
+
rawData: result,
|
|
73
|
+
displayData: [
|
|
74
|
+
`本地工具检查: ${result?.key ?? key}`,
|
|
75
|
+
...probes.map(formatProbeOutput),
|
|
76
|
+
].join("\n"),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (check === "context") {
|
|
49
81
|
const displayParts = [
|
|
50
82
|
`平台: ${result?.platform ?? "unknown"}`,
|
|
51
83
|
`cwd: ${result?.cwd ?? "unknown"}`,
|
|
@@ -59,9 +91,9 @@ export async function checkEnvFunc(
|
|
|
59
91
|
rawData: result,
|
|
60
92
|
displayData: `🧭 当前环境\n${displayParts.join("\n")}`,
|
|
61
93
|
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
65
97
|
rawData: result,
|
|
66
98
|
displayData: ok
|
|
67
99
|
? `✅ 环境检查通过: ${check}`
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { convertMarxistsBookToOfflineHtml } from "./marxistsOfflineBook";
|
|
2
|
+
|
|
3
|
+
export const convertMarxistsBookToOfflineHtmlFunctionSchema = {
|
|
4
|
+
name: "convertMarxistsBookToOfflineHtml",
|
|
5
|
+
description:
|
|
6
|
+
"将 Marxists.org 中文旧式书籍页面转换成离线单 HTML。会从章节 URL 推导目录页,下载同目录章节、CSS 和背景图,保留原始排版并内嵌资源,适合 iPad/移动设备离线阅读。",
|
|
7
|
+
parameters: {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
startUrl: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description:
|
|
13
|
+
"任意一个 Marxists.org 中文书籍章节 URL,例如 https://www.marxists.org/chinese/fromm/1973/01.htm。",
|
|
14
|
+
},
|
|
15
|
+
encoding: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "源站 HTML/CSS 编码,老中文页面通常是 gb2312。默认 gb2312。",
|
|
18
|
+
default: "gb2312",
|
|
19
|
+
},
|
|
20
|
+
outputMode: {
|
|
21
|
+
type: "string",
|
|
22
|
+
enum: ["summary", "html"],
|
|
23
|
+
description:
|
|
24
|
+
"summary 只返回元数据和文件引用;html 同时返回完整 HTML 字符串。需要直接拿到文件内容时用 html。",
|
|
25
|
+
default: "summary",
|
|
26
|
+
},
|
|
27
|
+
singleFileName: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description:
|
|
30
|
+
"生成文件建议名称,默认根据书名或 URL 生成;server-side agent 可用它作为保存文件名。",
|
|
31
|
+
},
|
|
32
|
+
maxPages: {
|
|
33
|
+
type: "number",
|
|
34
|
+
description: "最多允许抓取的同目录章节页数量,默认 80,防止误抓整个站点。",
|
|
35
|
+
default: 80,
|
|
36
|
+
},
|
|
37
|
+
saveAsFile: {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
description:
|
|
40
|
+
"server-side agent 可设为 true,将 HTML 保存为 Nolo 文件并返回下载 URL;如果只需要 HTML 字符串,可设为 false。",
|
|
41
|
+
default: true,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["startUrl"],
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ConvertMarxistsBookToolArgs = {
|
|
49
|
+
startUrl: string;
|
|
50
|
+
encoding?: string;
|
|
51
|
+
outputMode?: "summary" | "html";
|
|
52
|
+
singleFileName?: string;
|
|
53
|
+
maxPages?: number;
|
|
54
|
+
saveAsFile?: boolean;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export async function convertMarxistsBookToOfflineHtmlFunc(
|
|
58
|
+
args: ConvertMarxistsBookToolArgs,
|
|
59
|
+
): Promise<{ rawData: Record<string, unknown>; displayData: string }> {
|
|
60
|
+
const result = await convertMarxistsBookToOfflineHtml({
|
|
61
|
+
startUrl: args.startUrl,
|
|
62
|
+
encoding: args.encoding,
|
|
63
|
+
maxPages: args.maxPages,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const rawData: Record<string, unknown> = {
|
|
67
|
+
title: result.title,
|
|
68
|
+
startUrl: result.startUrl,
|
|
69
|
+
indexUrl: result.indexUrl,
|
|
70
|
+
stylesheetUrl: result.stylesheetUrl,
|
|
71
|
+
pages: result.pages,
|
|
72
|
+
validation: result.validation,
|
|
73
|
+
fileName: args.singleFileName,
|
|
74
|
+
};
|
|
75
|
+
if (args.outputMode === "html") {
|
|
76
|
+
rawData.html = result.html;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
rawData,
|
|
81
|
+
displayData: formatMarxistsOfflineBookDisplayData({
|
|
82
|
+
...rawData,
|
|
83
|
+
htmlIncluded: args.outputMode === "html",
|
|
84
|
+
}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function formatMarxistsOfflineBookDisplayData(data: Record<string, unknown>): string {
|
|
89
|
+
const validation = (data.validation ?? {}) as any;
|
|
90
|
+
const pages = Array.isArray(data.pages) ? data.pages : [];
|
|
91
|
+
return [
|
|
92
|
+
"✅ 已生成离线 HTML",
|
|
93
|
+
`书名:${data.title || "未知"}`,
|
|
94
|
+
`章节数:${validation.pageCount ?? pages.length}`,
|
|
95
|
+
`大小:${validation.byteLength ?? "未知"} bytes`,
|
|
96
|
+
`资源内嵌:${validation.hasEmbeddedAssets ? "是" : "否"}`,
|
|
97
|
+
`残留网络 URL:${validation.hasNetworkUrls ? "是" : "否"}`,
|
|
98
|
+
data.fileUrl ? `文件:${data.fileUrl}` : undefined,
|
|
99
|
+
data.htmlIncluded ? "已在 rawData.html 返回完整 HTML。" : undefined,
|
|
100
|
+
]
|
|
101
|
+
.filter(Boolean)
|
|
102
|
+
.join("\n");
|
|
103
|
+
}
|