mioku-service-webui 4.9.0 → 4.10.1

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/index.ts CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  createConfigRoutes,
27
27
  createWebUISettingsRoutes,
28
28
  createAIRoutes,
29
+ createAgentRoutes,
29
30
  createDBRoutes,
30
31
  createPluginConfigRoutes,
31
32
  createServiceConfigRoutes,
@@ -120,6 +121,7 @@ class WebUIRuntime {
120
121
  this.app.route("/api/config", createConfigRoutes());
121
122
  this.app.route("/api/settings", createWebUISettingsRoutes());
122
123
  this.app.route("/api/ai", createAIRoutes());
124
+ this.app.route("/api/agent", createAgentRoutes());
123
125
  this.app.route("/api/manage", createManageRoutes());
124
126
  this.app.route("/api/store", createStoreRoutes());
125
127
  this.app.route("/api/db", createDBRoutes());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mioku-service-webui",
3
- "version": "4.9.0",
3
+ "version": "4.10.1",
4
4
  "description": "Mioku WebUI 服务",
5
5
  "main": "index.ts",
6
6
  "type": "module",
@@ -0,0 +1,132 @@
1
+ import { Hono } from "hono";
2
+ import { logger } from "mioku";
3
+ import { getAgentConfig, updateAgentConfig } from "../system";
4
+ import aiService from "mioku-service-ai";
5
+
6
+ const PERMISSION_LEVELS = new Set([
7
+ "read-only",
8
+ "workspace-write",
9
+ "auto",
10
+ "full",
11
+ "yolo",
12
+ ]);
13
+
14
+ function normalizeIdList(input: unknown): number[] {
15
+ if (!Array.isArray(input)) return [];
16
+ return Array.from(
17
+ new Set(
18
+ input
19
+ .map((item) => Math.floor(Number(item)))
20
+ .filter((id: number) => Number.isFinite(id) && id > 0),
21
+ ),
22
+ );
23
+ }
24
+
25
+ function sanitizeAccess(input: any): any {
26
+ const access = input && typeof input === "object" ? input : {};
27
+ return {
28
+ allowAdmins: Boolean(access.allowAdmins),
29
+ users: normalizeIdList(access.users),
30
+ };
31
+ }
32
+
33
+ function sanitizeBaseForSave(body: any): any {
34
+ if (!body || typeof body !== "object") return body;
35
+ const next = { ...body };
36
+ delete next.persona;
37
+ delete next.roleBindings;
38
+ next.access = sanitizeAccess(next.access);
39
+ next.workspaceDir = String(next.workspaceDir ?? "").trim();
40
+ next.permissionLevel = PERMISSION_LEVELS.has(next.permissionLevel)
41
+ ? next.permissionLevel
42
+ : "workspace-write";
43
+ next.model = String(next.model ?? "").trim();
44
+ return next;
45
+ }
46
+
47
+ function sanitizeSettingsForSave(body: any): any {
48
+ if (!body || typeof body !== "object") return body;
49
+ const next = { ...body };
50
+ const positive = (value: unknown, fallback: number) => {
51
+ const num = Math.floor(Number(value));
52
+ return Number.isFinite(num) && num > 0 ? num : fallback;
53
+ };
54
+ delete next.temperature;
55
+ delete next.enableMediaRecognition;
56
+ next.maxIterations = positive(next.maxIterations, 500);
57
+ next.maxContextTokens = positive(next.maxContextTokens, 524288);
58
+ next.stream = next.stream !== false;
59
+ next.enableMarkdownScreenshot = next.enableMarkdownScreenshot !== false;
60
+ next.compaction = {
61
+ enabled: next.compaction?.enabled !== false,
62
+ keepRecentMessages: positive(next.compaction?.keepRecentMessages, 20),
63
+ };
64
+ next.webSearch = {
65
+ enabled: next.webSearch?.enabled !== false,
66
+ baseUrl: String(next.webSearch?.baseUrl ?? "").trim(),
67
+ timeoutMs: positive(next.webSearch?.timeoutMs, 8000),
68
+ defaultLimit: positive(next.webSearch?.defaultLimit, 5),
69
+ maxLimit: positive(next.webSearch?.maxLimit, 8),
70
+ maxSearchCount: positive(next.webSearch?.maxSearchCount, 50),
71
+ };
72
+ next.webFetch = {
73
+ enabled: next.webFetch?.enabled !== false,
74
+ timeoutMs: positive(next.webFetch?.timeoutMs, 15000),
75
+ maxChars: positive(next.webFetch?.maxChars, 12000),
76
+ };
77
+ next.bash = {
78
+ enabled: next.bash?.enabled !== false,
79
+ timeoutMs: positive(next.bash?.timeoutMs, 120000),
80
+ approvalTimeoutMs: positive(next.bash?.approvalTimeoutMs, 300000),
81
+ };
82
+ next.dataCollection = { enabled: next.dataCollection?.enabled !== false };
83
+ next.debug = Boolean(next.debug);
84
+ return next;
85
+ }
86
+
87
+ function getAIApi() {
88
+ return aiService?.api as any;
89
+ }
90
+
91
+ export function createAgentRoutes() {
92
+ const app = new Hono();
93
+
94
+ app.get("/base", (c) =>
95
+ c.json({ ok: true, data: getAgentConfig("base.json") }),
96
+ );
97
+
98
+ app.put("/base", async (c) => {
99
+ const body = sanitizeBaseForSave(await c.req.json());
100
+ logger.info(`[webui-action] agent.base.update`, {
101
+ permissionLevel: body?.permissionLevel,
102
+ });
103
+ return c.json({ ok: true, data: updateAgentConfig("base.json", body) });
104
+ });
105
+
106
+ app.get("/settings", (c) =>
107
+ c.json({ ok: true, data: getAgentConfig("settings.json") }),
108
+ );
109
+
110
+ app.put("/settings", async (c) => {
111
+ const body = sanitizeSettingsForSave(await c.req.json());
112
+ logger.info(`[webui-action] agent.settings.update`);
113
+ return c.json({ ok: true, data: updateAgentConfig("settings.json", body) });
114
+ });
115
+
116
+ app.get("/status", (c) => {
117
+ const api = getAIApi();
118
+ const bindings = api?.getRoleBindings?.() ?? {};
119
+ const base = getAgentConfig("base.json");
120
+ return c.json({
121
+ ok: true,
122
+ data: {
123
+ aiConfigured: Boolean(bindings.main),
124
+ mainModel: bindings.main ?? "",
125
+ permissionLevel: base?.permissionLevel ?? "workspace-write",
126
+ workspaceDir: base?.workspaceDir ?? "",
127
+ },
128
+ });
129
+ });
130
+
131
+ return app;
132
+ }
package/routes/ai.ts CHANGED
@@ -142,6 +142,7 @@ function sanitizeBaseForSave(body: any): any {
142
142
  delete next.workingModel;
143
143
  delete next.multimodalWorkingModel;
144
144
  delete next.isMultimodal;
145
+ delete next.mainSupportsVision;
145
146
  return next;
146
147
  }
147
148
 
package/routes/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createConfigRoutes } from "./config";
2
2
  export { createWebUISettingsRoutes } from "./webui";
3
3
  export { createAIRoutes } from "./ai";
4
+ export { createAgentRoutes } from "./agent";
4
5
  export { createDBRoutes, createPluginConfigRoutes, createMemeRoutes, createServiceConfigRoutes } from "./db";
5
6
  export { createAdapterConfigRoutes } from "./adapter-config";
6
7
  export { createManageRoutes } from "./manage";
package/system.ts CHANGED
@@ -16,6 +16,7 @@ import type {
16
16
  } from "./types";
17
17
  import {
18
18
  AUTH_PATH,
19
+ AGENT_CONFIG_DIR,
19
20
  CHAT_CONFIG_DIR,
20
21
  CONFIG_DIR,
21
22
  defaultWebUISettings,
@@ -2419,6 +2420,17 @@ export function updateChatConfig(fileName: string, data: any): any {
2419
2420
  return data;
2420
2421
  }
2421
2422
 
2423
+ export function getAgentConfig(fileName: string): any {
2424
+ const filePath = path.join(AGENT_CONFIG_DIR, fileName);
2425
+ return readJsonFile(filePath, {});
2426
+ }
2427
+
2428
+ export function updateAgentConfig(fileName: string, data: any): any {
2429
+ const filePath = path.join(AGENT_CONFIG_DIR, fileName);
2430
+ writeJsonFile(filePath, data);
2431
+ return data;
2432
+ }
2433
+
2422
2434
  export function getAdapterConfigs(adapterName: string): any {
2423
2435
  const rootPkg = readRootPackageJson();
2424
2436
  const adapters = rootPkg?.mioku?.adapters ?? {};
package/utils.ts CHANGED
@@ -28,6 +28,7 @@ export const DATA_DIR = getDataDir();
28
28
  export const PLUGINS_DIR = path.join(process.cwd(), "plugins");
29
29
  export const SERVICES_DIR = path.join(process.cwd(), "node_modules");
30
30
  export const CHAT_CONFIG_DIR = path.join(getConfigDir(), "chat");
31
+ export const AGENT_CONFIG_DIR = path.join(getConfigDir(), "agent");
31
32
  export const CHAT_DATA_DIR = path.join(getDataDir(), "chat");
32
33
  export const LOGS_DIR = path.join(process.cwd(), "logs");
33
34
  export const NODE_MODULES_DIR = path.join(process.cwd(), "node_modules");