create-windy 0.6.8 → 0.6.10
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 +4 -1
- package/dist/cli.js +1012 -329
- package/package.json +1 -1
- package/template/.windy-template.json +3 -3
- package/template/README.md +8 -2
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +2 -0
- package/template/apps/agent-server/tests/test_multimodal.py +30 -0
- package/template/apps/agent-server/tests/test_postgres_store.py +1 -0
- package/template/apps/agent-server/tests/test_sqlite_store.py +1 -0
- package/template/apps/server/src/agent/remote-runtime.test.ts +1 -0
- package/template/apps/server/src/agent/run-audit.ts +1 -0
- package/template/apps/server/src/agent/run-contracts.ts +1 -0
- package/template/apps/server/src/agent/run-facade.ts +2 -2
- package/template/apps/server/src/agent/run-operation-registry.ts +7 -0
- package/template/apps/server/src/agent/run-output-schema.ts +15 -0
- package/template/apps/server/src/agent/run-release.ts +11 -0
- package/template/apps/server/src/agent/supervisor-output-schema.test.ts +95 -0
- package/template/apps/server/src/agent/vision-input.ts +37 -2
- package/template/apps/server/src/license/pairing-http.ts +138 -0
- package/template/apps/server/src/license/pairing-routes.test.ts +282 -0
- package/template/apps/server/src/license/pairing-routes.ts +257 -0
- package/template/apps/server/src/license/pairing-service.test.ts +320 -0
- package/template/apps/server/src/license/pairing-service.ts +321 -0
- package/template/apps/server/src/license/restriction.test.ts +11 -0
- package/template/apps/server/src/license/restriction.ts +5 -0
- package/template/apps/server/src/license/routes.ts +8 -1
- package/template/apps/server/src/license/runtime-service.ts +20 -0
- package/template/apps/server/src/runtime-development.ts +1 -0
- package/template/apps/web/package.json +6 -4
- package/template/apps/web/src/components/license/LicensePairingCard.vue +177 -0
- package/template/apps/web/src/components/license/LicensePairingCard.webtest.ts +113 -0
- package/template/apps/web/src/composables/useLicensePairing.ts +168 -0
- package/template/apps/web/src/composables/useLicenseRuntime.ts +11 -0
- package/template/apps/web/src/layout/AppSidebar.vue +1 -0
- package/template/apps/web/src/pages/license/LicensePage.vue +8 -0
- package/template/apps/web/src/pages/ui/UiComponentPage.vue +7 -0
- package/template/apps/web/src/pages/ui/UiComponentPage.webtest.ts +94 -0
- package/template/apps/web/src/pages/ui/component-catalog.ts +248 -0
- package/template/apps/web/src/pages/ui/components/ComponentPreviewCard.vue +50 -0
- package/template/apps/web/src/pages/ui/components/DataComponentShowcases.vue +131 -0
- package/template/apps/web/src/pages/ui/components/FeedbackComponentShowcases.vue +158 -0
- package/template/apps/web/src/pages/ui/components/FoundationComponentShowcases.vue +129 -0
- package/template/apps/web/src/pages/ui/components/NavigationComponentShowcases.vue +155 -0
- package/template/apps/web/src/pages/ui/components/ProjectComponentShowcases.vue +31 -0
- package/template/apps/web/src/pages/ui/components/UiComponentGallery.vue +238 -0
- package/template/apps/web/src/router/index.ts +2 -0
- package/template/apps/web/src/router/manifest-routes.webtest.ts +1 -0
- package/template/apps/web/src/router/platform-admin-route-bindings.ts +3 -1
- package/template/apps/web/src/services/license-api.ts +60 -0
- package/template/apps/web/src/style.webtest.ts +5 -6
- package/template/docs/architecture/ai-runtime.md +5 -0
- package/template/docs/development/business-web-routes.md +3 -1
- package/template/docs/development/ui-component-gallery.md +44 -0
- package/template/docs/license/license-pairing-activation.md +67 -0
- package/template/docs/operations/incremental-delivery.md +10 -9
- package/template/docs/platform/agent-supervisor-output-contract.md +80 -0
- package/template/packages/ai-client/package.json +1 -1
- package/template/packages/ai-client/src/agent/contracts/final-answer.test.ts +67 -0
- package/template/packages/ai-client/src/agent/contracts/final-answer.ts +53 -0
- package/template/packages/ai-client/src/agent/contracts/index.ts +1 -0
- package/template/packages/modules/index.ts +1 -0
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/system-admin-routes.ts +8 -0
- package/template/packages/modules/src/system-admin-ui-catalog.ts +6 -2
- package/template/packages/modules/src/system-agent-supervisor.test.ts +48 -0
- package/template/packages/modules/src/system-agent-supervisor.ts +101 -0
- package/template/packages/modules/src/system-api-control-plane.ts +37 -0
- package/template/packages/modules/src/system-features.ts +5 -0
- package/template/packages/modules/src/system-license-pairing.test.ts +44 -0
- package/template/packages/modules/src/system-module-catalog.ts +10 -19
- package/template/packages/modules/src/system-module-menu-selection.ts +15 -0
- package/template/packages/modules/src/system-module-schema-catalog.ts +14 -0
- package/template/packages/modules/src/system-modules.ts +13 -0
- package/template/packages/modules/src/system-permissions.ts +2 -0
- package/template/packages/modules/src/system-ui-components.test.ts +36 -0
- package/template/packages/server-sdk/index.ts +5 -0
- package/template/packages/server-sdk/package.json +3 -1
- package/template/packages/server-sdk/src/ai-operation-registration.ts +4 -0
- package/template/packages/server-sdk/src/system-agent-supervisor.test.ts +87 -0
- package/template/packages/server-sdk/src/system-agent-supervisor.ts +89 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { systemControlPlaneApiPermissionBindings } from "./system-api-control-plane.js";
|
|
3
|
+
|
|
4
|
+
describe("License 手机配对 API 注册", () => {
|
|
5
|
+
test("完整绑定创建、状态、确认与匿名回传入口", () => {
|
|
6
|
+
const bindings = systemControlPlaneApiPermissionBindings().filter(
|
|
7
|
+
({ path }) => path.startsWith("/api/license/runtime/pairing/"),
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
expect(bindings).toEqual([
|
|
11
|
+
expect.objectContaining({
|
|
12
|
+
method: "POST",
|
|
13
|
+
path: "/api/license/runtime/pairing/sessions",
|
|
14
|
+
permissionKey: "system.license.manage",
|
|
15
|
+
featureKey: "system.license",
|
|
16
|
+
auditAction: "license.verify",
|
|
17
|
+
}),
|
|
18
|
+
expect.objectContaining({
|
|
19
|
+
method: "GET",
|
|
20
|
+
path: "/api/license/runtime/pairing/sessions/:sessionId",
|
|
21
|
+
permissionKey: "system.license.manage",
|
|
22
|
+
featureKey: "system.license",
|
|
23
|
+
auditAction: "license.verify",
|
|
24
|
+
}),
|
|
25
|
+
expect.objectContaining({
|
|
26
|
+
method: "POST",
|
|
27
|
+
path: "/api/license/runtime/pairing/sessions/:sessionId/confirm",
|
|
28
|
+
permissionKey: "system.license.manage",
|
|
29
|
+
featureKey: "system.license",
|
|
30
|
+
auditAction: "license.update",
|
|
31
|
+
}),
|
|
32
|
+
expect.objectContaining({
|
|
33
|
+
method: "OPTIONS",
|
|
34
|
+
path: "/api/license/runtime/pairing/sessions/:sessionId/deliver",
|
|
35
|
+
anonymous: true,
|
|
36
|
+
}),
|
|
37
|
+
expect.objectContaining({
|
|
38
|
+
method: "POST",
|
|
39
|
+
path: "/api/license/runtime/pairing/sessions/:sessionId/deliver",
|
|
40
|
+
anonymous: true,
|
|
41
|
+
}),
|
|
42
|
+
]);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { MenuNode } from "@southwind-ai/shared";
|
|
2
1
|
import type { ModuleFactory, ModuleManifest } from "./manifest.js";
|
|
2
|
+
import { selectSystemMenus } from "./system-module-menu-selection.js";
|
|
3
3
|
import { systemFoundationModule } from "./system-modules.js";
|
|
4
|
+
import { selectSystemJsonSchemas } from "./system-module-schema-catalog.js";
|
|
4
5
|
|
|
5
6
|
export interface SystemModuleDefinition {
|
|
6
7
|
name: string;
|
|
@@ -21,12 +22,13 @@ export const systemModuleDefinitions = [
|
|
|
21
22
|
version: "0.1.0",
|
|
22
23
|
label: "系统核心",
|
|
23
24
|
description: "管理面准入、Feature 治理、数据库基线与审计动作目录。",
|
|
24
|
-
resources: ["admin", "runtime", "auth", "feature"],
|
|
25
|
+
resources: ["admin", "runtime", "auth", "feature", "ui-components"],
|
|
25
26
|
featureKeys: [
|
|
26
27
|
"system.admin",
|
|
27
28
|
"system.runtime",
|
|
28
29
|
"system.auth",
|
|
29
30
|
"system.feature",
|
|
31
|
+
"system.ui-components",
|
|
30
32
|
"system.ruoyi-compat",
|
|
31
33
|
],
|
|
32
34
|
},
|
|
@@ -117,7 +119,7 @@ export const systemModuleDefinitions = [
|
|
|
117
119
|
// @windy-module system.agent begin
|
|
118
120
|
{
|
|
119
121
|
name: "system.agent",
|
|
120
|
-
version: "0.1.
|
|
122
|
+
version: "0.1.1",
|
|
121
123
|
label: "Agent Tool",
|
|
122
124
|
description: "受 Feature、RBAC 和审计保护的 Agent 工具调用。",
|
|
123
125
|
dependencies: [
|
|
@@ -264,7 +266,7 @@ function createSystemCapabilityModule(
|
|
|
264
266
|
label: definition.label,
|
|
265
267
|
description: definition.description,
|
|
266
268
|
dependencies: [...(definition.dependencies ?? (isCore ? [] : ["system"]))],
|
|
267
|
-
menus:
|
|
269
|
+
menus: selectSystemMenus(aggregate.menus, ownsGuard),
|
|
268
270
|
adminRoutes: aggregate.adminRoutes.filter((route) =>
|
|
269
271
|
route.key === "system.settings"
|
|
270
272
|
? definition.name === "system.settings"
|
|
@@ -283,7 +285,10 @@ function createSystemCapabilityModule(
|
|
|
283
285
|
.map((feature) => ({ ...feature, module: definition.name })),
|
|
284
286
|
migrations: isCore ? aggregate.migrations : [],
|
|
285
287
|
schemaExports: isCore ? aggregate.schemaExports : [],
|
|
286
|
-
jsonSchemas:
|
|
288
|
+
jsonSchemas: selectSystemJsonSchemas(
|
|
289
|
+
definition.name,
|
|
290
|
+
aggregate.jsonSchemas,
|
|
291
|
+
),
|
|
287
292
|
tasks: aggregate.tasks.filter(ownsGuard),
|
|
288
293
|
tools: aggregate.tools.filter(ownsGuard),
|
|
289
294
|
providers: aggregate.providers.filter(ownsGuard),
|
|
@@ -331,17 +336,3 @@ function permissionResource(permissionKey: string): string {
|
|
|
331
336
|
const parts = permissionKey.split(".");
|
|
332
337
|
return parts.length >= 3 ? parts.slice(1, -1).join(".") : "";
|
|
333
338
|
}
|
|
334
|
-
|
|
335
|
-
function selectMenus(
|
|
336
|
-
menus: readonly MenuNode[],
|
|
337
|
-
ownsGuard: (guard: {
|
|
338
|
-
permissionKey?: string;
|
|
339
|
-
featureKey?: string;
|
|
340
|
-
}) => boolean,
|
|
341
|
-
): MenuNode[] {
|
|
342
|
-
return menus.flatMap((menu) => {
|
|
343
|
-
const children = selectMenus(menu.children || [], ownsGuard);
|
|
344
|
-
if (!children.length && !ownsGuard(menu)) return [];
|
|
345
|
-
return [{ ...menu, children: children.length ? children : undefined }];
|
|
346
|
-
});
|
|
347
|
-
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MenuNode } from "@southwind-ai/shared";
|
|
2
|
+
|
|
3
|
+
export function selectSystemMenus(
|
|
4
|
+
menus: readonly MenuNode[],
|
|
5
|
+
ownsGuard: (guard: {
|
|
6
|
+
permissionKey?: string;
|
|
7
|
+
featureKey?: string;
|
|
8
|
+
}) => boolean,
|
|
9
|
+
): MenuNode[] {
|
|
10
|
+
return menus.flatMap((menu) => {
|
|
11
|
+
const children = selectSystemMenus(menu.children || [], ownsGuard);
|
|
12
|
+
if (!children.length && !ownsGuard(menu)) return [];
|
|
13
|
+
return [{ ...menu, children: children.length ? children : undefined }];
|
|
14
|
+
});
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ModuleManifest } from "./manifest.js";
|
|
2
|
+
|
|
3
|
+
export function selectSystemJsonSchemas(
|
|
4
|
+
moduleName: string,
|
|
5
|
+
schemas: ModuleManifest["jsonSchemas"],
|
|
6
|
+
): ModuleManifest["jsonSchemas"] {
|
|
7
|
+
if (moduleName === "system.agent") {
|
|
8
|
+
return schemas?.filter(({ key }) => key.startsWith("system.agent."));
|
|
9
|
+
}
|
|
10
|
+
if (moduleName === "system") {
|
|
11
|
+
return schemas?.filter(({ key }) => !key.startsWith("system.agent."));
|
|
12
|
+
}
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
systemAgentToolSchemas,
|
|
5
5
|
systemAgentTools,
|
|
6
6
|
} from "./system-agent-tools.js";
|
|
7
|
+
import { systemAgentSupervisorSchemas } from "./system-agent-supervisor.js";
|
|
7
8
|
// @windy-module system.agent end
|
|
8
9
|
import { systemAdminRoutes } from "./system-admin-routes.js";
|
|
9
10
|
import { systemApiPermissionBindings } from "./system-api-permissions.js";
|
|
@@ -169,6 +170,17 @@ export function systemFoundationModule(): ModuleManifest {
|
|
|
169
170
|
featureKey: "system.config",
|
|
170
171
|
},
|
|
171
172
|
// @windy-module system.configuration end
|
|
173
|
+
{
|
|
174
|
+
key: "system.ui-components",
|
|
175
|
+
title: "组件总览",
|
|
176
|
+
type: "menu",
|
|
177
|
+
order: 70,
|
|
178
|
+
visible: true,
|
|
179
|
+
path: "/ui/component",
|
|
180
|
+
icon: "blocks",
|
|
181
|
+
permissionKey: "system.ui-components.read",
|
|
182
|
+
featureKey: "system.ui-components",
|
|
183
|
+
},
|
|
172
184
|
],
|
|
173
185
|
},
|
|
174
186
|
{
|
|
@@ -270,6 +282,7 @@ export function systemFoundationModule(): ModuleManifest {
|
|
|
270
282
|
jsonSchemas: [
|
|
271
283
|
// @windy-module system.agent begin
|
|
272
284
|
...systemAgentToolSchemas,
|
|
285
|
+
...systemAgentSupervisorSchemas,
|
|
273
286
|
// @windy-module system.agent end
|
|
274
287
|
],
|
|
275
288
|
tasks: systemModuleTasks,
|
|
@@ -11,6 +11,7 @@ const systemResourceLabels = {
|
|
|
11
11
|
menu: "菜单管理",
|
|
12
12
|
dict: "字典管理",
|
|
13
13
|
feature: "功能开关",
|
|
14
|
+
"ui-components": "UI 组件总览",
|
|
14
15
|
search: "全局搜索",
|
|
15
16
|
settings: "全局设置",
|
|
16
17
|
config: "配置版本",
|
|
@@ -96,6 +97,7 @@ export const systemPermissions: ModuleManifest["permissions"] = [
|
|
|
96
97
|
permission("dict", "manage"),
|
|
97
98
|
permission("feature", "read"),
|
|
98
99
|
permission("feature", "manage"),
|
|
100
|
+
permission("ui-components", "read"),
|
|
99
101
|
// @windy-module system.search begin
|
|
100
102
|
permission("search", "read"),
|
|
101
103
|
permission("search", "manage"),
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { systemFoundationModule } from "./system-modules.js";
|
|
3
|
+
|
|
4
|
+
describe("系统组件展厅能力注册", () => {
|
|
5
|
+
test("以同一能力 Key 注册 Feature、Permission、菜单和路由", () => {
|
|
6
|
+
const manifest = systemFoundationModule();
|
|
7
|
+
const menus = flattenMenus(manifest.menus);
|
|
8
|
+
|
|
9
|
+
expect(manifest.features).toContainEqual(
|
|
10
|
+
expect.objectContaining({ key: "system.ui-components" }),
|
|
11
|
+
);
|
|
12
|
+
expect(manifest.permissions).toContainEqual(
|
|
13
|
+
expect.objectContaining({ key: "system.ui-components.read" }),
|
|
14
|
+
);
|
|
15
|
+
expect(
|
|
16
|
+
menus.find(({ key }) => key === "system.ui-components"),
|
|
17
|
+
).toMatchObject({
|
|
18
|
+
path: "/ui/component",
|
|
19
|
+
permissionKey: "system.ui-components.read",
|
|
20
|
+
featureKey: "system.ui-components",
|
|
21
|
+
});
|
|
22
|
+
expect(
|
|
23
|
+
manifest.adminRoutes.find(({ key }) => key === "system.ui-components"),
|
|
24
|
+
).toMatchObject({
|
|
25
|
+
path: "/ui/component",
|
|
26
|
+
permissionKey: "system.ui-components.read",
|
|
27
|
+
featureKey: "system.ui-components",
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
function flattenMenus(
|
|
33
|
+
menus: ReturnType<typeof systemFoundationModule>["menus"],
|
|
34
|
+
): ReturnType<typeof systemFoundationModule>["menus"] {
|
|
35
|
+
return menus.flatMap((menu) => [menu, ...flattenMenus(menu.children || [])]);
|
|
36
|
+
}
|
|
@@ -246,3 +246,8 @@ export type {
|
|
|
246
246
|
ModuleDocumentOperationPlan,
|
|
247
247
|
ModuleSpeechOperationPlan,
|
|
248
248
|
} from "./src/ai-operation-registration.js";
|
|
249
|
+
export {
|
|
250
|
+
defineSystemAgentSupervisorHandler,
|
|
251
|
+
type SystemAgentSupervisorBusinessRelease,
|
|
252
|
+
type SystemAgentSupervisorHandlerOptions,
|
|
253
|
+
} from "./src/system-agent-supervisor.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@southwind-ai/server-sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"src/secret-binding.ts",
|
|
45
45
|
"src/secret-port.ts",
|
|
46
46
|
"src/storage-port.ts",
|
|
47
|
+
"src/system-agent-supervisor.ts",
|
|
47
48
|
"src/task-registration.ts",
|
|
48
49
|
"src/tool-registration.ts",
|
|
49
50
|
"src/tool-host-port.ts",
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"@southwind-ai/jobs": "workspace:^",
|
|
60
|
+
"@southwind-ai/modules": "workspace:^",
|
|
59
61
|
"@southwind-ai/shared": "workspace:^0.2.5",
|
|
60
62
|
"@southwind-ai/storage": "workspace:^"
|
|
61
63
|
},
|
|
@@ -40,6 +40,10 @@ export interface ModuleEmbeddingOperationPlan {
|
|
|
40
40
|
|
|
41
41
|
export interface ModuleAiOperationHandlerRegistration {
|
|
42
42
|
readonly operationKey: string;
|
|
43
|
+
readonly supervisor?: {
|
|
44
|
+
readonly contractVersion: 1;
|
|
45
|
+
readonly finalAnswerSchemaVersion: 1;
|
|
46
|
+
};
|
|
43
47
|
/**
|
|
44
48
|
* 不可变发布坐标。修改 Workflow、Prompt 或 Route 时必须提升对应版本;
|
|
45
49
|
* 宿主以这些坐标和 Manifest/Tool Schema 摘要固定每个 Run。
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
composeSystemAgentFinalAnswerSchemaV1,
|
|
4
|
+
SYSTEM_AGENT_SUPERVISOR_INSTRUCTIONS,
|
|
5
|
+
} from "@southwind-ai/modules";
|
|
6
|
+
import { defineSystemAgentSupervisorHandler } from "./system-agent-supervisor.js";
|
|
7
|
+
|
|
8
|
+
describe("system.agent Supervisor handler seam", () => {
|
|
9
|
+
test("平台指令、业务指令与发布坐标共同冻结", async () => {
|
|
10
|
+
const schema = composeSystemAgentFinalAnswerSchemaV1();
|
|
11
|
+
const handler = defineSystemAgentSupervisorHandler({
|
|
12
|
+
operationKey: "business.copilot",
|
|
13
|
+
release: {
|
|
14
|
+
workflowVersion: "business-w2",
|
|
15
|
+
promptVersion: "business-p3",
|
|
16
|
+
routeVersion: "business-r4",
|
|
17
|
+
},
|
|
18
|
+
prepare: () => ({
|
|
19
|
+
instructions: "只使用当前案件的数据。",
|
|
20
|
+
userPrompt: "汇总案件事实",
|
|
21
|
+
outputSchema: schema,
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
const plan = await handler.prepare?.(
|
|
25
|
+
{},
|
|
26
|
+
{
|
|
27
|
+
actor: {
|
|
28
|
+
id: "actor-1",
|
|
29
|
+
type: "user",
|
|
30
|
+
name: "用户",
|
|
31
|
+
roleCodes: ["user"],
|
|
32
|
+
permissionKeys: [],
|
|
33
|
+
},
|
|
34
|
+
requestId: "request-1",
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(plan?.instructions).toBe(
|
|
39
|
+
`${SYSTEM_AGENT_SUPERVISOR_INSTRUCTIONS}\n\n只使用当前案件的数据。`,
|
|
40
|
+
);
|
|
41
|
+
expect(plan?.outputSchema).toEqual(schema);
|
|
42
|
+
expect(handler.supervisor).toEqual({
|
|
43
|
+
contractVersion: 1,
|
|
44
|
+
finalAnswerSchemaVersion: 1,
|
|
45
|
+
});
|
|
46
|
+
expect(handler.release).toEqual({
|
|
47
|
+
workflowVersion:
|
|
48
|
+
"system-agent-supervisor-workflow-1+business-business-w2",
|
|
49
|
+
promptVersion: "system-agent-supervisor-prompt-1+business-business-p3",
|
|
50
|
+
routeVersion: "system-agent-supervisor-route-1+business-business-r4",
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("拒绝没有 canonical finalAnswer 的业务输出 Schema", async () => {
|
|
55
|
+
const handler = defineSystemAgentSupervisorHandler({
|
|
56
|
+
operationKey: "business.copilot",
|
|
57
|
+
release: {
|
|
58
|
+
workflowVersion: "1",
|
|
59
|
+
promptVersion: "1",
|
|
60
|
+
routeVersion: "1",
|
|
61
|
+
},
|
|
62
|
+
prepare: () => ({
|
|
63
|
+
instructions: "业务指令",
|
|
64
|
+
userPrompt: "问题",
|
|
65
|
+
outputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: { text: { type: "string" } },
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
await expect(
|
|
72
|
+
handler.prepare?.(
|
|
73
|
+
{},
|
|
74
|
+
{
|
|
75
|
+
actor: {
|
|
76
|
+
id: "actor-1",
|
|
77
|
+
type: "user",
|
|
78
|
+
name: "用户",
|
|
79
|
+
roleCodes: ["user"],
|
|
80
|
+
permissionKeys: [],
|
|
81
|
+
},
|
|
82
|
+
requestId: "request-1",
|
|
83
|
+
},
|
|
84
|
+
),
|
|
85
|
+
).rejects.toThrow("canonical finalAnswer V1");
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertSystemAgentFinalAnswerSchemaV1,
|
|
3
|
+
SYSTEM_AGENT_FINAL_ANSWER_SCHEMA_VERSION,
|
|
4
|
+
SYSTEM_AGENT_SUPERVISOR_INSTRUCTIONS,
|
|
5
|
+
SYSTEM_AGENT_SUPERVISOR_PROMPT_VERSION,
|
|
6
|
+
SYSTEM_AGENT_SUPERVISOR_ROUTE_VERSION,
|
|
7
|
+
SYSTEM_AGENT_SUPERVISOR_WORKFLOW_VERSION,
|
|
8
|
+
} from "@southwind-ai/modules";
|
|
9
|
+
import type {
|
|
10
|
+
ModuleAiOperationContext,
|
|
11
|
+
ModuleAiOperationHandlerRegistration,
|
|
12
|
+
ModuleAiOperationPlan,
|
|
13
|
+
ModuleAiJsonValue,
|
|
14
|
+
} from "./ai-operation-registration.js";
|
|
15
|
+
|
|
16
|
+
export interface SystemAgentSupervisorBusinessRelease {
|
|
17
|
+
readonly workflowVersion: string;
|
|
18
|
+
readonly promptVersion: string;
|
|
19
|
+
readonly routeVersion: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SystemAgentSupervisorHandlerOptions {
|
|
23
|
+
readonly operationKey: string;
|
|
24
|
+
readonly release: SystemAgentSupervisorBusinessRelease;
|
|
25
|
+
prepare(
|
|
26
|
+
input: ModuleAiJsonValue,
|
|
27
|
+
context: ModuleAiOperationContext,
|
|
28
|
+
): Promise<ModuleAiOperationPlan> | ModuleAiOperationPlan;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 把业务 Operation 接入 system.agent 的通用规划、Tool 汇总和 typed final-answer 协议。
|
|
33
|
+
* 业务仍拥有输入、权限、数据范围与附加输出字段;平台拥有 Supervisor 指令和发布坐标。
|
|
34
|
+
*/
|
|
35
|
+
export function defineSystemAgentSupervisorHandler(
|
|
36
|
+
options: SystemAgentSupervisorHandlerOptions,
|
|
37
|
+
): ModuleAiOperationHandlerRegistration {
|
|
38
|
+
requireVersion(options.operationKey, "Operation Key");
|
|
39
|
+
requireVersion(options.release.workflowVersion, "业务 workflowVersion");
|
|
40
|
+
requireVersion(options.release.promptVersion, "业务 promptVersion");
|
|
41
|
+
requireVersion(options.release.routeVersion, "业务 routeVersion");
|
|
42
|
+
return {
|
|
43
|
+
operationKey: options.operationKey,
|
|
44
|
+
release: {
|
|
45
|
+
workflowVersion: coordinate(
|
|
46
|
+
"workflow",
|
|
47
|
+
SYSTEM_AGENT_SUPERVISOR_WORKFLOW_VERSION,
|
|
48
|
+
options.release.workflowVersion,
|
|
49
|
+
),
|
|
50
|
+
promptVersion: coordinate(
|
|
51
|
+
"prompt",
|
|
52
|
+
SYSTEM_AGENT_SUPERVISOR_PROMPT_VERSION,
|
|
53
|
+
options.release.promptVersion,
|
|
54
|
+
),
|
|
55
|
+
routeVersion: coordinate(
|
|
56
|
+
"route",
|
|
57
|
+
SYSTEM_AGENT_SUPERVISOR_ROUTE_VERSION,
|
|
58
|
+
options.release.routeVersion,
|
|
59
|
+
),
|
|
60
|
+
},
|
|
61
|
+
supervisor: {
|
|
62
|
+
contractVersion: 1,
|
|
63
|
+
finalAnswerSchemaVersion: SYSTEM_AGENT_FINAL_ANSWER_SCHEMA_VERSION,
|
|
64
|
+
},
|
|
65
|
+
async prepare(input, context) {
|
|
66
|
+
const plan = await options.prepare(input, context);
|
|
67
|
+
assertSystemAgentFinalAnswerSchemaV1(plan.outputSchema);
|
|
68
|
+
return {
|
|
69
|
+
...plan,
|
|
70
|
+
instructions: [
|
|
71
|
+
SYSTEM_AGENT_SUPERVISOR_INSTRUCTIONS,
|
|
72
|
+
plan.instructions.trim(),
|
|
73
|
+
]
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
.join("\n\n"),
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function coordinate(kind: string, platform: string, business: string) {
|
|
82
|
+
return `system-agent-supervisor-${kind}-${platform}+business-${business}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function requireVersion(value: string, label: string): void {
|
|
86
|
+
if (!value.trim() || value.length > 32 || !/^[A-Za-z0-9._-]+$/.test(value)) {
|
|
87
|
+
throw new Error(`${label} 无效`);
|
|
88
|
+
}
|
|
89
|
+
}
|