create-windy 0.2.20 → 0.2.22
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 +1 -1
- package/dist/cli.js +93 -11
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/README.md +1 -0
- package/template/apps/agent-server/Dockerfile +20 -0
- package/template/apps/agent-server/README.md +46 -0
- package/template/apps/agent-server/pyproject.toml +44 -0
- package/template/apps/agent-server/src/southwind_agent_server/__init__.py +5 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +39 -0
- package/template/apps/agent-server/src/southwind_agent_server/app.py +263 -0
- package/template/apps/agent-server/src/southwind_agent_server/config.py +141 -0
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +99 -0
- package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +52 -0
- package/template/apps/agent-server/src/southwind_agent_server/engine.py +85 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +197 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +246 -0
- package/template/apps/agent-server/src/southwind_agent_server/service.py +180 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +317 -0
- package/template/apps/agent-server/src/southwind_agent_server/sse.py +41 -0
- package/template/apps/agent-server/src/southwind_agent_server/store.py +144 -0
- package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +80 -0
- package/template/apps/agent-server/tests/test_api.py +207 -0
- package/template/apps/agent-server/tests/test_config.py +56 -0
- package/template/apps/agent-server/tests/test_openai_provider.py +224 -0
- package/template/apps/agent-server/tests/test_sqlite_store.py +93 -0
- package/template/apps/agent-server/uv.lock +925 -0
- package/template/apps/server/src/agent/execution-grants.ts +89 -0
- package/template/apps/server/src/agent/remote-runtime.ts +128 -0
- package/template/apps/server/src/agent/run-contracts.ts +43 -0
- package/template/apps/server/src/agent/run-facade.test.ts +257 -0
- package/template/apps/server/src/agent/run-facade.ts +190 -0
- package/template/apps/server/src/agent/run-routes.ts +222 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +53 -0
- package/template/apps/server/src/agent/tool-host.test.ts +242 -0
- package/template/apps/server/src/agent/tool-host.ts +153 -0
- package/template/apps/server/src/index.ts +26 -22
- package/template/apps/server/src/module-composition.test.ts +9 -0
- package/template/apps/server/src/module-composition.ts +13 -0
- package/template/apps/server/src/module-host/initialize-contracts.ts +67 -0
- package/template/apps/server/src/module-host/initialize.test.ts +69 -0
- package/template/apps/server/src/module-host/initialize.ts +50 -53
- package/template/apps/server/src/module-host.ts +7 -0
- package/template/apps/server/src/module-runtime-validation.ts +39 -0
- package/template/docker-compose.yml +25 -0
- package/template/docs/architecture/ai-runtime.md +744 -0
- package/template/docs/platform/agent-runtime.md +128 -0
- package/template/docs/platform/agent-tools.md +8 -1
- package/template/package.json +1 -0
- package/template/packages/config/index.test.ts +43 -0
- package/template/packages/config/index.ts +1 -0
- package/template/packages/config/package.json +2 -1
- package/template/packages/config/src/ai-openai-compatible.ts +131 -0
- package/template/packages/server-sdk/index.ts +11 -0
- package/template/packages/server-sdk/package.json +4 -2
- package/template/packages/server-sdk/src/ai-operation-registration.ts +31 -0
- package/template/packages/server-sdk/src/module-host.ts +5 -0
- package/template/packages/server-sdk/src/tool-host-port.ts +22 -0
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
createSystemToolHandlers,
|
|
22
22
|
registerAgentRoutes,
|
|
23
23
|
} from "./agent/routes.js";
|
|
24
|
+
import { registerAgentPlatformRuntime } from "./agent/runtime-bootstrap.js";
|
|
24
25
|
// @windy-module system.agent end
|
|
25
26
|
import { registerAuthRoutes, registerAuthSessionRoute } from "./auth/routes.js";
|
|
26
27
|
import { createAuthRuntime } from "./auth/runtime.js";
|
|
@@ -55,13 +56,17 @@ import { registerNotificationRoutes } from "./notification/routes.js";
|
|
|
55
56
|
import { createStorageRuntime } from "./storage/runtime.js";
|
|
56
57
|
import { registerStorageRoutes } from "./storage/routes.js";
|
|
57
58
|
// @windy-module system.storage end
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
} from "./module-host.js";
|
|
59
|
+
import { validateInstalledRuntime } from "./module-runtime-validation.js";
|
|
60
|
+
import { installModuleRoutes } from "./module-host.js";
|
|
61
|
+
// @windy-module system.search begin
|
|
62
|
+
import { adaptModuleSearchProviders } from "./module-host.js";
|
|
63
|
+
// @windy-module system.search end
|
|
64
|
+
// @windy-module system.scheduler begin
|
|
65
|
+
import { createModuleTaskDefinitions } from "./module-host.js";
|
|
66
|
+
// @windy-module system.scheduler end
|
|
67
|
+
// @windy-module system.agent begin
|
|
68
|
+
import { createModuleToolHandlerMap } from "./module-host.js";
|
|
69
|
+
// @windy-module system.agent end
|
|
65
70
|
// @windy-module system.search begin
|
|
66
71
|
import { createSearchHost } from "./search/host.js";
|
|
67
72
|
// @windy-module system.search end
|
|
@@ -288,6 +293,14 @@ const toolHandlers = new Map([
|
|
|
288
293
|
...createModuleToolHandlerMap(moduleHosts),
|
|
289
294
|
]);
|
|
290
295
|
registerAgentRoutes(app, foundationModules, toolHandlers, runtime);
|
|
296
|
+
registerAgentPlatformRuntime({
|
|
297
|
+
app,
|
|
298
|
+
platformConfig,
|
|
299
|
+
modules: foundationModules,
|
|
300
|
+
hosts: moduleHosts,
|
|
301
|
+
runtime,
|
|
302
|
+
toolHandlers,
|
|
303
|
+
});
|
|
291
304
|
// @windy-module system.agent end
|
|
292
305
|
// @windy-module system.scheduler begin
|
|
293
306
|
registerSchedulerRoutes(app, scheduler, runtime, foundationSnapshot.features);
|
|
@@ -300,19 +313,21 @@ registerBulkDataRoutes(
|
|
|
300
313
|
foundationSnapshot.features,
|
|
301
314
|
);
|
|
302
315
|
// @windy-module system.bulk-data end
|
|
303
|
-
// @windy-module work-order begin
|
|
304
316
|
installModuleRoutes(moduleHosts, app, {
|
|
305
317
|
runtime,
|
|
306
318
|
features: foundationSnapshot.features,
|
|
319
|
+
// @windy-module system.scheduler begin
|
|
307
320
|
jobs: durableJobRuntime.service,
|
|
321
|
+
// @windy-module system.scheduler end
|
|
322
|
+
// @windy-module system.storage begin
|
|
308
323
|
storage: {
|
|
309
324
|
uploads: storageRuntime.uploads,
|
|
310
325
|
files: storageRuntime.files,
|
|
311
326
|
},
|
|
327
|
+
// @windy-module system.storage end
|
|
312
328
|
});
|
|
313
|
-
// @windy-module work-order end
|
|
314
329
|
|
|
315
|
-
|
|
330
|
+
validateInstalledRuntime({
|
|
316
331
|
modules: foundationModules,
|
|
317
332
|
routes: app.routes,
|
|
318
333
|
// @windy-module system.scheduler begin
|
|
@@ -324,18 +339,7 @@ validateServerModuleComposition({
|
|
|
324
339
|
// @windy-module system.search begin
|
|
325
340
|
providers: searchHost.providerKeys,
|
|
326
341
|
// @windy-module system.search end
|
|
327
|
-
|
|
328
|
-
routes: moduleHosts.routes.map(
|
|
329
|
-
({ definition }) => `${definition.method} ${definition.path}`,
|
|
330
|
-
),
|
|
331
|
-
tasks: moduleHosts.taskHandlers.map(
|
|
332
|
-
({ registration }) => registration.taskKey,
|
|
333
|
-
),
|
|
334
|
-
tools: moduleHosts.toolHandlers.map(
|
|
335
|
-
({ registration }) => registration.toolKey,
|
|
336
|
-
),
|
|
337
|
-
providers: moduleHosts.searchProviders.map(({ provider }) => provider.key),
|
|
338
|
-
},
|
|
342
|
+
hosts: moduleHosts,
|
|
339
343
|
});
|
|
340
344
|
|
|
341
345
|
const port = process.env.PORT ? Number(process.env.PORT) : 9_747;
|
|
@@ -73,6 +73,15 @@ describe("Server Module Composition", () => {
|
|
|
73
73
|
moduleRegistrations: { providers: ["system.unknown-search"] },
|
|
74
74
|
}),
|
|
75
75
|
).toThrow("搜索 Provider已注册但未在 Manifest 声明:system.unknown-search");
|
|
76
|
+
|
|
77
|
+
expect(() =>
|
|
78
|
+
validateServerModuleComposition({
|
|
79
|
+
...base,
|
|
80
|
+
moduleRegistrations: { aiOperations: ["system.unknown-operation"] },
|
|
81
|
+
}),
|
|
82
|
+
).toThrow(
|
|
83
|
+
"AI Operation Handler已注册但未在 Manifest 声明:system.unknown-operation",
|
|
84
|
+
);
|
|
76
85
|
});
|
|
77
86
|
});
|
|
78
87
|
|
|
@@ -16,6 +16,7 @@ export interface ModuleImplementationRegistrations {
|
|
|
16
16
|
routes?: readonly string[];
|
|
17
17
|
tasks?: readonly string[];
|
|
18
18
|
tools?: readonly string[];
|
|
19
|
+
aiOperations?: readonly string[];
|
|
19
20
|
providers?: readonly string[];
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -24,6 +25,7 @@ export interface ServerCompositionInput {
|
|
|
24
25
|
routes: readonly RegisteredHttpRoute[];
|
|
25
26
|
tasks?: readonly { key: string }[];
|
|
26
27
|
tools?: ReadonlyMap<string, unknown>;
|
|
28
|
+
aiOperations?: readonly string[];
|
|
27
29
|
providers?: readonly string[];
|
|
28
30
|
moduleRegistrations?: ModuleImplementationRegistrations;
|
|
29
31
|
}
|
|
@@ -35,6 +37,7 @@ export function validateServerModuleComposition(
|
|
|
35
37
|
apiRoutes: input.routes.map(apiRouteKey),
|
|
36
38
|
tasks: (input.tasks || []).map(({ key }) => key),
|
|
37
39
|
tools: [...(input.tools?.keys() || [])],
|
|
40
|
+
aiOperations: input.aiOperations,
|
|
38
41
|
providers: input.providers || [],
|
|
39
42
|
});
|
|
40
43
|
if (input.moduleRegistrations) {
|
|
@@ -55,6 +58,11 @@ function validateRegistrationConsistency(
|
|
|
55
58
|
const declaredTools = new Set(
|
|
56
59
|
modules.flatMap((module) => module.tools.map(({ key }) => key)),
|
|
57
60
|
);
|
|
61
|
+
const declaredAiOperations = new Set(
|
|
62
|
+
modules.flatMap((module) =>
|
|
63
|
+
(module.aiOperations ?? []).map(({ key }) => key),
|
|
64
|
+
),
|
|
65
|
+
);
|
|
58
66
|
const declaredProviders = new Set(
|
|
59
67
|
modules.flatMap((module) => module.providers.map(({ key }) => key)),
|
|
60
68
|
);
|
|
@@ -62,6 +70,11 @@ function validateRegistrationConsistency(
|
|
|
62
70
|
["模块路由", registrations.routes || [], declaredRoutes],
|
|
63
71
|
["定时任务 Handler", registrations.tasks || [], declaredTasks],
|
|
64
72
|
["Agent Tool Handler", registrations.tools || [], declaredTools],
|
|
73
|
+
[
|
|
74
|
+
"AI Operation Handler",
|
|
75
|
+
registrations.aiOperations || [],
|
|
76
|
+
declaredAiOperations,
|
|
77
|
+
],
|
|
65
78
|
["搜索 Provider", registrations.providers || [], declaredProviders],
|
|
66
79
|
] as const) {
|
|
67
80
|
for (const key of registered) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { DurableHandlerRegistry } from "@southwind-ai/jobs";
|
|
2
|
+
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
3
|
+
import type {
|
|
4
|
+
InstallableServerModule,
|
|
5
|
+
ModuleAiOperationHandlerRegistration,
|
|
6
|
+
ModuleInitializer,
|
|
7
|
+
ModuleRolePreset,
|
|
8
|
+
ModuleRouteDefinition,
|
|
9
|
+
ModuleSearchProvider,
|
|
10
|
+
ModuleTaskHandlerRegistration,
|
|
11
|
+
ModuleToolHandlerRegistration,
|
|
12
|
+
ModuleUploadPolicy,
|
|
13
|
+
} from "@southwind-ai/server-sdk";
|
|
14
|
+
|
|
15
|
+
export interface RegisteredModuleRoute {
|
|
16
|
+
readonly moduleName: string;
|
|
17
|
+
readonly definition: ModuleRouteDefinition;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RegisteredModuleTaskHandler {
|
|
21
|
+
readonly moduleName: string;
|
|
22
|
+
readonly registration: ModuleTaskHandlerRegistration;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RegisteredModuleToolHandler {
|
|
26
|
+
readonly moduleName: string;
|
|
27
|
+
readonly registration: ModuleToolHandlerRegistration;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RegisteredModuleAiOperationHandler {
|
|
31
|
+
readonly moduleName: string;
|
|
32
|
+
readonly registration: ModuleAiOperationHandlerRegistration;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RegisteredModuleRolePreset {
|
|
36
|
+
readonly moduleName: string;
|
|
37
|
+
readonly preset: ModuleRolePreset;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface RegisteredModuleSearchProvider {
|
|
41
|
+
readonly moduleName: string;
|
|
42
|
+
readonly provider: ModuleSearchProvider;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface InitializeModuleHostsInput {
|
|
46
|
+
modules: readonly ModuleManifest[];
|
|
47
|
+
/** Manifest 与 setup 由同一业务模块安装单元贡献。 */
|
|
48
|
+
installations?: readonly InstallableServerModule<ModuleManifest>[];
|
|
49
|
+
/** @deprecated 仅供旧模块迁移;新模块必须使用 installations。 */
|
|
50
|
+
initializers?: readonly ModuleInitializer[];
|
|
51
|
+
baseUploadPolicies?: readonly ModuleUploadPolicy[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface InitializedModuleHosts {
|
|
55
|
+
readonly manifests: readonly ModuleManifest[];
|
|
56
|
+
readonly uploadPolicies: readonly ModuleUploadPolicy[];
|
|
57
|
+
readonly routes: readonly RegisteredModuleRoute[];
|
|
58
|
+
readonly taskHandlers: readonly RegisteredModuleTaskHandler[];
|
|
59
|
+
readonly toolHandlers: readonly RegisteredModuleToolHandler[];
|
|
60
|
+
readonly aiOperationHandlers: readonly RegisteredModuleAiOperationHandler[];
|
|
61
|
+
readonly rolePresets: readonly RegisteredModuleRolePreset[];
|
|
62
|
+
readonly searchProviders: readonly RegisteredModuleSearchProvider[];
|
|
63
|
+
manifestOf(moduleName: string): ModuleManifest;
|
|
64
|
+
/** 该模块经 Host 注册的上传用途集合(不含平台基础用途)。 */
|
|
65
|
+
uploadPurposesOf(moduleName: string): ReadonlySet<string>;
|
|
66
|
+
installDurableHandlers(registry: DurableHandlerRegistry): void;
|
|
67
|
+
}
|
|
@@ -102,6 +102,75 @@ describe("模块 Host 初始化", () => {
|
|
|
102
102
|
}),
|
|
103
103
|
).rejects.toThrow("Server Module Manifest 与能力目录不是同一声明:known");
|
|
104
104
|
});
|
|
105
|
+
|
|
106
|
+
test("AI Operation Handler 只注册本模块 Manifest 声明", async () => {
|
|
107
|
+
const operation = {
|
|
108
|
+
key: "known.summarize",
|
|
109
|
+
kind: "agent" as const,
|
|
110
|
+
featureKey: "known.ai",
|
|
111
|
+
permissionKey: "known.ai.execute",
|
|
112
|
+
auditAction: "known.ai.execute",
|
|
113
|
+
inputSchemaKey: "known.input.v1",
|
|
114
|
+
outputSchemaKey: "known.output.v1",
|
|
115
|
+
requiredCapabilities: ["text-generation"],
|
|
116
|
+
allowedToolKeys: [],
|
|
117
|
+
dataClassification: "internal" as const,
|
|
118
|
+
execution: "streaming" as const,
|
|
119
|
+
publicNetworkAccess: "forbidden" as const,
|
|
120
|
+
limits: {
|
|
121
|
+
maxDurationSeconds: 60,
|
|
122
|
+
maxInputBytes: 4096,
|
|
123
|
+
maxOutputBytes: 4096,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
const known = manifest("known", { aiOperations: [operation] });
|
|
127
|
+
const initialized = await initializeModuleHosts({
|
|
128
|
+
modules: [known],
|
|
129
|
+
installations: [
|
|
130
|
+
{
|
|
131
|
+
manifest: known,
|
|
132
|
+
setup(host) {
|
|
133
|
+
host.registerAiOperationHandlers([
|
|
134
|
+
{
|
|
135
|
+
operationKey: operation.key,
|
|
136
|
+
prepare: () => ({
|
|
137
|
+
instructions: "按要求回答。",
|
|
138
|
+
userPrompt: "你好",
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
]);
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
});
|
|
146
|
+
expect(
|
|
147
|
+
initialized.aiOperationHandlers.map(
|
|
148
|
+
({ registration }) => registration.operationKey,
|
|
149
|
+
),
|
|
150
|
+
).toEqual(["known.summarize"]);
|
|
151
|
+
|
|
152
|
+
await expect(
|
|
153
|
+
initializeModuleHosts({
|
|
154
|
+
modules: [known],
|
|
155
|
+
installations: [
|
|
156
|
+
{
|
|
157
|
+
manifest: known,
|
|
158
|
+
setup(host) {
|
|
159
|
+
host.registerAiOperationHandlers([
|
|
160
|
+
{
|
|
161
|
+
operationKey: "known.unknown",
|
|
162
|
+
prepare: () => ({
|
|
163
|
+
instructions: "x",
|
|
164
|
+
userPrompt: "x",
|
|
165
|
+
}),
|
|
166
|
+
},
|
|
167
|
+
]);
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
}),
|
|
172
|
+
).rejects.toThrow("AI Operation Handler 未在 Manifest 声明");
|
|
173
|
+
});
|
|
105
174
|
});
|
|
106
175
|
|
|
107
176
|
function initializer(
|
|
@@ -5,64 +5,31 @@ import {
|
|
|
5
5
|
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
6
6
|
import {
|
|
7
7
|
requireModuleNamespace,
|
|
8
|
-
type InstallableServerModule,
|
|
9
8
|
type ModuleHost,
|
|
10
|
-
type ModuleInitializer,
|
|
11
|
-
type ModuleRolePreset,
|
|
12
9
|
type ModuleRouteDefinition,
|
|
13
|
-
type ModuleSearchProvider,
|
|
14
|
-
type ModuleTaskHandlerRegistration,
|
|
15
|
-
type ModuleToolHandlerRegistration,
|
|
16
10
|
type ModuleUploadPolicy,
|
|
17
11
|
} from "@southwind-ai/server-sdk";
|
|
12
|
+
import type {
|
|
13
|
+
InitializedModuleHosts,
|
|
14
|
+
InitializeModuleHostsInput,
|
|
15
|
+
RegisteredModuleAiOperationHandler,
|
|
16
|
+
RegisteredModuleRolePreset,
|
|
17
|
+
RegisteredModuleRoute,
|
|
18
|
+
RegisteredModuleSearchProvider,
|
|
19
|
+
RegisteredModuleTaskHandler,
|
|
20
|
+
RegisteredModuleToolHandler,
|
|
21
|
+
} from "./initialize-contracts.js";
|
|
18
22
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export interface RegisteredModuleToolHandler {
|
|
30
|
-
readonly moduleName: string;
|
|
31
|
-
readonly registration: ModuleToolHandlerRegistration;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface RegisteredModuleRolePreset {
|
|
35
|
-
readonly moduleName: string;
|
|
36
|
-
readonly preset: ModuleRolePreset;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface RegisteredModuleSearchProvider {
|
|
40
|
-
readonly moduleName: string;
|
|
41
|
-
readonly provider: ModuleSearchProvider;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface InitializeModuleHostsInput {
|
|
45
|
-
modules: readonly ModuleManifest[];
|
|
46
|
-
/** Manifest 与 setup 由同一业务模块安装单元贡献。 */
|
|
47
|
-
installations?: readonly InstallableServerModule<ModuleManifest>[];
|
|
48
|
-
/** @deprecated 仅供旧模块迁移;新模块必须使用 installations。 */
|
|
49
|
-
initializers?: readonly ModuleInitializer[];
|
|
50
|
-
baseUploadPolicies?: readonly ModuleUploadPolicy[];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface InitializedModuleHosts {
|
|
54
|
-
readonly manifests: readonly ModuleManifest[];
|
|
55
|
-
readonly uploadPolicies: readonly ModuleUploadPolicy[];
|
|
56
|
-
readonly routes: readonly RegisteredModuleRoute[];
|
|
57
|
-
readonly taskHandlers: readonly RegisteredModuleTaskHandler[];
|
|
58
|
-
readonly toolHandlers: readonly RegisteredModuleToolHandler[];
|
|
59
|
-
readonly rolePresets: readonly RegisteredModuleRolePreset[];
|
|
60
|
-
readonly searchProviders: readonly RegisteredModuleSearchProvider[];
|
|
61
|
-
manifestOf(moduleName: string): ModuleManifest;
|
|
62
|
-
/** 该模块经 Host 注册的上传用途集合(不含平台基础用途)。 */
|
|
63
|
-
uploadPurposesOf(moduleName: string): ReadonlySet<string>;
|
|
64
|
-
installDurableHandlers(registry: DurableHandlerRegistry): void;
|
|
65
|
-
}
|
|
23
|
+
export type {
|
|
24
|
+
InitializedModuleHosts,
|
|
25
|
+
InitializeModuleHostsInput,
|
|
26
|
+
RegisteredModuleAiOperationHandler,
|
|
27
|
+
RegisteredModuleRolePreset,
|
|
28
|
+
RegisteredModuleRoute,
|
|
29
|
+
RegisteredModuleSearchProvider,
|
|
30
|
+
RegisteredModuleTaskHandler,
|
|
31
|
+
RegisteredModuleToolHandler,
|
|
32
|
+
} from "./initialize-contracts.js";
|
|
66
33
|
|
|
67
34
|
type HandlerInstaller = (registry: DurableHandlerRegistry) => void;
|
|
68
35
|
|
|
@@ -94,6 +61,8 @@ export async function initializeModuleHosts(
|
|
|
94
61
|
taskKeys: new Set<string>(),
|
|
95
62
|
toolHandlers: [],
|
|
96
63
|
toolKeys: new Set<string>(),
|
|
64
|
+
aiOperationHandlers: [],
|
|
65
|
+
aiOperationKeys: new Set<string>(),
|
|
97
66
|
rolePresets: [],
|
|
98
67
|
rolePresetKeys: new Set<string>(),
|
|
99
68
|
searchProviders: [],
|
|
@@ -142,6 +111,7 @@ export async function initializeModuleHosts(
|
|
|
142
111
|
routes: [...state.routes],
|
|
143
112
|
taskHandlers: [...state.taskHandlers],
|
|
144
113
|
toolHandlers: [...state.toolHandlers],
|
|
114
|
+
aiOperationHandlers: [...state.aiOperationHandlers],
|
|
145
115
|
rolePresets: [...state.rolePresets],
|
|
146
116
|
searchProviders: [...state.searchProviders],
|
|
147
117
|
manifestOf(moduleName) {
|
|
@@ -170,6 +140,8 @@ interface HostCollections {
|
|
|
170
140
|
taskKeys: Set<string>;
|
|
171
141
|
toolHandlers: RegisteredModuleToolHandler[];
|
|
172
142
|
toolKeys: Set<string>;
|
|
143
|
+
aiOperationHandlers: RegisteredModuleAiOperationHandler[];
|
|
144
|
+
aiOperationKeys: Set<string>;
|
|
173
145
|
rolePresets: RegisteredModuleRolePreset[];
|
|
174
146
|
rolePresetKeys: Set<string>;
|
|
175
147
|
searchProviders: RegisteredModuleSearchProvider[];
|
|
@@ -253,6 +225,31 @@ function createScopedHost(
|
|
|
253
225
|
state.toolHandlers.push({ moduleName, registration });
|
|
254
226
|
}
|
|
255
227
|
},
|
|
228
|
+
registerAiOperationHandlers(registrations) {
|
|
229
|
+
for (const registration of registrations) {
|
|
230
|
+
requireModuleNamespace(
|
|
231
|
+
"AI Operation",
|
|
232
|
+
registration.operationKey,
|
|
233
|
+
moduleName,
|
|
234
|
+
);
|
|
235
|
+
if (
|
|
236
|
+
!manifest.aiOperations?.some(
|
|
237
|
+
({ key }) => key === registration.operationKey,
|
|
238
|
+
)
|
|
239
|
+
) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`AI Operation Handler 未在 Manifest 声明:${registration.operationKey}`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (state.aiOperationKeys.has(registration.operationKey)) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`AI Operation Handler 重复注册:${registration.operationKey}`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
state.aiOperationKeys.add(registration.operationKey);
|
|
250
|
+
state.aiOperationHandlers.push({ moduleName, registration });
|
|
251
|
+
}
|
|
252
|
+
},
|
|
256
253
|
registerRolePresets(presets) {
|
|
257
254
|
for (const preset of presets) {
|
|
258
255
|
requireModuleNamespace("角色预设", preset.key, moduleName);
|
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
type RegisteredModuleSearchProvider,
|
|
8
8
|
type RegisteredModuleTaskHandler,
|
|
9
9
|
type RegisteredModuleToolHandler,
|
|
10
|
+
type RegisteredModuleAiOperationHandler,
|
|
10
11
|
} from "./module-host/initialize.js";
|
|
11
12
|
export {
|
|
12
13
|
buildModuleRequestContext,
|
|
@@ -21,14 +22,20 @@ export {
|
|
|
21
22
|
moduleRolePresetId,
|
|
22
23
|
synchronizeModuleRolePresets,
|
|
23
24
|
} from "./module-host/role-presets.js";
|
|
25
|
+
// @windy-module system.search begin
|
|
24
26
|
export {
|
|
25
27
|
adaptModuleSearchProvider,
|
|
26
28
|
adaptModuleSearchProviders,
|
|
27
29
|
} from "./module-host/search-providers.js";
|
|
30
|
+
// @windy-module system.search end
|
|
28
31
|
export {
|
|
29
32
|
createModuleStoragePort,
|
|
30
33
|
type ModuleStorageScope,
|
|
31
34
|
type ModuleStorageServices,
|
|
32
35
|
} from "./module-host/storage-port.js";
|
|
36
|
+
// @windy-module system.scheduler begin
|
|
33
37
|
export { createModuleTaskDefinitions } from "./module-host/task-definitions.js";
|
|
38
|
+
// @windy-module system.scheduler end
|
|
39
|
+
// @windy-module system.agent begin
|
|
34
40
|
export { createModuleToolHandlerMap } from "./module-host/tool-handlers.js";
|
|
41
|
+
// @windy-module system.agent end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
2
|
+
import { validateServerModuleComposition } from "./module-composition.js";
|
|
3
|
+
import type { InitializedModuleHosts } from "./module-host.js";
|
|
4
|
+
|
|
5
|
+
export function validateInstalledRuntime(input: {
|
|
6
|
+
modules: ModuleManifest[];
|
|
7
|
+
routes: readonly { method: string; path: string }[];
|
|
8
|
+
tasks?: readonly { key: string }[];
|
|
9
|
+
tools?: ReadonlyMap<string, unknown>;
|
|
10
|
+
providers?: readonly string[];
|
|
11
|
+
hosts: InitializedModuleHosts;
|
|
12
|
+
}): void {
|
|
13
|
+
const aiOperations = input.hosts.aiOperationHandlers.map(
|
|
14
|
+
({ registration }) => registration.operationKey,
|
|
15
|
+
);
|
|
16
|
+
validateServerModuleComposition({
|
|
17
|
+
modules: input.modules,
|
|
18
|
+
routes: input.routes,
|
|
19
|
+
tasks: input.tasks,
|
|
20
|
+
tools: input.tools,
|
|
21
|
+
aiOperations,
|
|
22
|
+
providers: input.providers,
|
|
23
|
+
moduleRegistrations: {
|
|
24
|
+
routes: input.hosts.routes.map(
|
|
25
|
+
({ definition }) => `${definition.method} ${definition.path}`,
|
|
26
|
+
),
|
|
27
|
+
tasks: input.hosts.taskHandlers.map(
|
|
28
|
+
({ registration }) => registration.taskKey,
|
|
29
|
+
),
|
|
30
|
+
tools: input.hosts.toolHandlers.map(
|
|
31
|
+
({ registration }) => registration.toolKey,
|
|
32
|
+
),
|
|
33
|
+
aiOperations,
|
|
34
|
+
providers: input.hosts.searchProviders.map(
|
|
35
|
+
({ provider }) => provider.key,
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -42,6 +42,10 @@ services:
|
|
|
42
42
|
WINDY_CONTAINERIZED: "1"
|
|
43
43
|
BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD: "true"
|
|
44
44
|
WINDY_SYSTEM_USAGE_PATHS: /app/data/audit
|
|
45
|
+
PLATFORM_ENABLE_AI: ${PLATFORM_ENABLE_AI:-false}
|
|
46
|
+
AGENT_SERVER_URL: http://agent-server:8080
|
|
47
|
+
AGENT_TOOL_HOST_URL: http://server:9747
|
|
48
|
+
AGENT_SERVER_INTERNAL_TOKEN: ${AGENT_SERVER_INTERNAL_TOKEN:-}
|
|
45
49
|
ports:
|
|
46
50
|
- "9747:9747"
|
|
47
51
|
volumes:
|
|
@@ -52,6 +56,26 @@ services:
|
|
|
52
56
|
migrate:
|
|
53
57
|
condition: service_completed_successfully
|
|
54
58
|
|
|
59
|
+
agent-server:
|
|
60
|
+
profiles: ["agent"]
|
|
61
|
+
build:
|
|
62
|
+
context: .
|
|
63
|
+
dockerfile: apps/agent-server/Dockerfile
|
|
64
|
+
environment:
|
|
65
|
+
AGENT_SERVER_INTERNAL_TOKEN: ${AGENT_SERVER_INTERNAL_TOKEN:-}
|
|
66
|
+
AGENT_RUN_STORE_PATH: /app/data/agent/runs.sqlite3
|
|
67
|
+
QWEN_API_URL: ${QWEN_API_URL:-}
|
|
68
|
+
QWEN_API_KEY: ${QWEN_API_KEY:-}
|
|
69
|
+
QWEN_MODEL: ${QWEN_MODEL:-}
|
|
70
|
+
AI_PROVIDER_CONNECT_TIMEOUT_MS: ${AI_PROVIDER_CONNECT_TIMEOUT_MS:-5000}
|
|
71
|
+
AI_PROVIDER_REQUEST_TIMEOUT_MS: ${AI_PROVIDER_REQUEST_TIMEOUT_MS:-60000}
|
|
72
|
+
AI_PROVIDER_MAX_RESPONSE_BYTES: ${AI_PROVIDER_MAX_RESPONSE_BYTES:-2097152}
|
|
73
|
+
volumes:
|
|
74
|
+
- agent-run-data:/app/data/agent
|
|
75
|
+
depends_on:
|
|
76
|
+
server:
|
|
77
|
+
condition: service_started
|
|
78
|
+
|
|
55
79
|
web:
|
|
56
80
|
build:
|
|
57
81
|
context: .
|
|
@@ -85,3 +109,4 @@ services:
|
|
|
85
109
|
volumes:
|
|
86
110
|
postgres-data:
|
|
87
111
|
server-audit-data:
|
|
112
|
+
agent-run-data:
|