create-windy 0.2.23 → 0.2.24
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/dist/cli.js +21 -1
- package/package.json +1 -1
- package/template/.agents/skills/windy-business-module/SKILL.md +43 -0
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +2 -0
- package/template/apps/server/package.json +3 -1
- package/template/apps/server/src/agent/data-scope-routes.test.ts +20 -20
- package/template/apps/server/src/agent/remote-runtime.test.ts +59 -0
- package/template/apps/server/src/agent/remote-runtime.ts +22 -4
- package/template/apps/server/src/agent/routes.test.ts +16 -8
- package/template/apps/server/src/agent/routes.ts +103 -169
- package/template/apps/server/src/agent/run-facade.test.ts +30 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +3 -3
- package/template/apps/server/src/agent/tool-host.test.ts +61 -8
- package/template/apps/server/src/agent/tool-host.ts +17 -73
- package/template/apps/server/src/agent/tool-registry.test.ts +117 -0
- package/template/apps/server/src/agent/tool-registry.ts +318 -0
- package/template/apps/server/src/http-app.test.ts +87 -0
- package/template/apps/server/src/http-app.ts +43 -25
- package/template/apps/server/src/index.ts +14 -2
- package/template/apps/server/src/license/runtime-service.test.ts +6 -3
- package/template/apps/server/src/mcp/adapter.test.ts +195 -0
- package/template/apps/server/src/mcp/adapter.ts +204 -0
- package/template/apps/server/src/mcp/routes.ts +21 -0
- package/template/apps/server/src/module-host/tool-handlers.ts +6 -5
- package/template/apps/server/src/observability/http-observability.test.ts +21 -0
- package/template/apps/server/src/observability/http-observability.ts +1 -0
- package/template/apps/server/src/observability/metrics.ts +5 -2
- package/template/docs/operations/observability.md +9 -1
- package/template/docs/platform/agent-runtime.md +15 -3
- package/template/docs/platform/agent-tools.md +88 -28
- package/template/packages/modules/index.ts +1 -0
- package/template/packages/modules/src/ai-operation-composition.test.ts +30 -0
- package/template/packages/modules/src/ai-operation-composition.ts +13 -0
- package/template/packages/modules/src/composition.test.ts +42 -0
- package/template/packages/modules/src/composition.ts +3 -0
- package/template/packages/modules/src/manifest.ts +20 -1
- package/template/packages/modules/src/system-agent-tools.ts +53 -1
- package/template/packages/modules/src/system-api-permissions.ts +5 -0
- package/template/packages/modules/src/system-module-catalog.ts +1 -0
- package/template/packages/modules/src/system-modules.test.ts +32 -0
- package/template/packages/modules/src/system-modules.ts +9 -1
- package/template/packages/modules/src/tool-composition.ts +86 -0
- package/template/packages/server-sdk/index.ts +1 -0
- package/template/packages/server-sdk/package.json +1 -0
- package/template/packages/server-sdk/src/ai-operation-registration.ts +2 -7
- package/template/packages/server-sdk/src/tool-registration.ts +6 -7
- package/template/packages/shared/index.ts +1 -0
- package/template/packages/shared/src/json.ts +8 -0
package/dist/cli.js
CHANGED
|
@@ -231,14 +231,28 @@ var optionalModuleManifests = [
|
|
|
231
231
|
"system",
|
|
232
232
|
"system.audit"
|
|
233
233
|
]),
|
|
234
|
+
registryDependencies: [
|
|
235
|
+
{
|
|
236
|
+
sourceName: "@modelcontextprotocol/sdk",
|
|
237
|
+
name: "@modelcontextprotocol/sdk",
|
|
238
|
+
version: "^1.29.0"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
sourceName: "ajv",
|
|
242
|
+
name: "ajv",
|
|
243
|
+
version: "^8.20.0"
|
|
244
|
+
}
|
|
245
|
+
],
|
|
234
246
|
fileRoots: [
|
|
235
247
|
"apps/agent-server",
|
|
236
248
|
"apps/server/src/agent",
|
|
249
|
+
"apps/server/src/mcp",
|
|
237
250
|
"apps/server/src/module-host/tool-handlers.ts",
|
|
238
251
|
"packages/modules/src/system-agent-tools.ts"
|
|
239
252
|
],
|
|
240
253
|
documentation: [
|
|
241
254
|
"docs/architecture/ai-runtime.md",
|
|
255
|
+
"docs/architecture/mcp-business-capabilities.md",
|
|
242
256
|
"docs/platform/agent-runtime.md",
|
|
243
257
|
"docs/platform/agent-tools.md"
|
|
244
258
|
]
|
|
@@ -1689,6 +1703,10 @@ bun run dev:agent
|
|
|
1689
1703
|
公网 Provider URL 必须使用 HTTPS;本机、容器服务名和内网地址允许 HTTP。
|
|
1690
1704
|
\`QWEN_API_KEY\` 只进入 Agent Server,不会进入 Web 环境或返回给客户端。运行与模块
|
|
1691
1705
|
接入细节见 [Agent Runtime 接入](./docs/platform/agent-runtime.md)。
|
|
1706
|
+
|
|
1707
|
+
MCP 客户端使用 \`http://localhost:9747/api/mcp\`,并通过平台 Bearer Token 或 Session
|
|
1708
|
+
Cookie 鉴权。该入口只发现当前账号获准的只读 Tool;每次调用都会重新执行 Feature、
|
|
1709
|
+
RBAC 和数据范围校验。
|
|
1692
1710
|
` : ""}
|
|
1693
1711
|
|
|
1694
1712
|
## 页面与登录
|
|
@@ -1861,6 +1879,7 @@ var templateRootFiles = [
|
|
|
1861
1879
|
"package.json"
|
|
1862
1880
|
];
|
|
1863
1881
|
var templateDirectories = [
|
|
1882
|
+
".agents/skills/windy-business-module",
|
|
1864
1883
|
"apps/server",
|
|
1865
1884
|
"apps/agent-server",
|
|
1866
1885
|
"apps/web",
|
|
@@ -4288,7 +4307,8 @@ var recipes = [
|
|
|
4288
4307
|
{ id: "starter-0.2.19-to-0.2.20", from: "0.2.19", to: "0.2.20" },
|
|
4289
4308
|
{ id: "starter-0.2.20-to-0.2.21", from: "0.2.20", to: "0.2.21" },
|
|
4290
4309
|
{ id: "starter-0.2.21-to-0.2.22", from: "0.2.21", to: "0.2.22" },
|
|
4291
|
-
{ id: "starter-0.2.22-to-0.2.23", from: "0.2.22", to: "0.2.23" }
|
|
4310
|
+
{ id: "starter-0.2.22-to-0.2.23", from: "0.2.22", to: "0.2.23" },
|
|
4311
|
+
{ id: "starter-0.2.23-to-0.2.24", from: "0.2.23", to: "0.2.24" }
|
|
4292
4312
|
];
|
|
4293
4313
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
4294
4314
|
if (sourceVersion === targetVersion)
|
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: windy-business-module
|
|
3
|
+
description: "Windy 业务模块、Manifest、Repository、Service、Agent Tool 与 MCP 接入开发。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Windy 业务模块开发
|
|
7
|
+
|
|
8
|
+
用于新增或修改业务能力。先读取仓库 `AGENTS.md`、`CONTEXT.md` 和直接相关的
|
|
9
|
+
`docs/architecture/`、`docs/development/`、`docs/platform/` 文档。
|
|
10
|
+
|
|
11
|
+
## 工作流
|
|
12
|
+
|
|
13
|
+
1. 选择一个稳定的能力基础 Key 和模块命名空间。先定义业务边界、Actor、数据归属与
|
|
14
|
+
失败语义,再改代码。
|
|
15
|
+
2. 在业务 package 的 Module Manifest 一次性注册 Feature、Permission、API、
|
|
16
|
+
菜单/入口、审计动作,以及需要的 Task、Provider、JSON Schema 和 Tool。
|
|
17
|
+
3. 数据层使用 Drizzle Schema、前向 Migration 和 Repository;Service 持有业务规则,
|
|
18
|
+
其它模块只能通过 Service、公开 Port 或模块注册机制协作。
|
|
19
|
+
4. Server 通过 `InstallableServerModule` 和 `ModuleHost` 注册 Guarded Route、Task、
|
|
20
|
+
Provider 或 Tool Handler。Handler 调用 Service,不直接访问其它模块 Repository。
|
|
21
|
+
5. Tool 输入输出只使用 Manifest 已注册的顶层 object JSON Schema。Actor、Permission、
|
|
22
|
+
Feature、License 和 Data Scope 只来自 `ModuleToolContext` 与平台 Runtime。
|
|
23
|
+
6. 若项目包含 `system.agent`,`operation=query` 的 Tool 会由同一 Registry 自动进入
|
|
24
|
+
MCP;不要编辑 MCP Adapter 或复制 Tool 定义。写操作在幂等、审批和结果追踪闭环前
|
|
25
|
+
不通过 MCP 暴露。
|
|
26
|
+
7. 补 Manifest/Composition、Repository/Service、Guard 拒绝和 Handler 契约测试。
|
|
27
|
+
涉及 Tool 时还要覆盖 Schema 拒绝、数据范围与未授权发现/调用;涉及可选模块时覆盖
|
|
28
|
+
Starter 的文件、依赖和数据库裁剪。
|
|
29
|
+
8. 更新长期文档,运行受影响测试、`bun run typecheck` 和 `bun run lint`,按一个完整
|
|
30
|
+
小切片提交。
|
|
31
|
+
|
|
32
|
+
## 代码事实源
|
|
33
|
+
|
|
34
|
+
- Manifest 与 Tool 类型:`packages/modules/src/manifest.ts`
|
|
35
|
+
- Tool 组合校验:`packages/modules/src/tool-composition.ts`
|
|
36
|
+
- 模块 Host 契约:`packages/server-sdk/src/module-host.ts`
|
|
37
|
+
- Tool Handler 契约:`packages/server-sdk/src/tool-registration.ts`
|
|
38
|
+
- 可移除业务示例:`packages/example-work-order/`、`apps/server/src/work-order/`
|
|
39
|
+
- 业务模块安装入口:`apps/server/src/installed-business-modules.ts`
|
|
40
|
+
- MCP 与统一执行边界:`docs/architecture/mcp-business-capabilities.md`
|
|
41
|
+
|
|
42
|
+
缺少 `system.agent` 或某个事实源文件时,先说明当前生成组合的物理边界,不在业务层补一套
|
|
43
|
+
替代实现。
|
package/template/AGENTS.md
CHANGED
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
|
|
43
43
|
## 常用入口
|
|
44
44
|
|
|
45
|
+
- `.agents/skills/windy-business-module/SKILL.md`:新增或修改业务模块、Agent Tool
|
|
46
|
+
或 MCP 暴露时使用的仓库内开发流程。
|
|
45
47
|
- `bun run dev`:复用 Docker 镜像启动 PostgreSQL、自动 migration、Server 与支持热更新的 Web。
|
|
46
48
|
- `bun run dev:build`:依赖、Dockerfile 或 lockfile 变化后重建并启动开发环境。
|
|
47
49
|
- `bun run dev:web`:启动 Web 开发服务。
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@elysiajs/swagger": "^1.3.1",
|
|
13
|
+
"@modelcontextprotocol/sdk": "^1",
|
|
14
|
+
"@noble/ed25519": "^3.1.0",
|
|
13
15
|
"@southwind-ai/config": "workspace:*",
|
|
14
16
|
"@southwind-ai/database": "workspace:*",
|
|
15
17
|
"@southwind-ai/example-work-order": "workspace:*",
|
|
@@ -19,7 +21,7 @@
|
|
|
19
21
|
"@southwind-ai/server-sdk": "workspace:*",
|
|
20
22
|
"@southwind-ai/shared": "workspace:*",
|
|
21
23
|
"@southwind-ai/storage": "workspace:*",
|
|
22
|
-
"
|
|
24
|
+
"ajv": "^8.20.0",
|
|
23
25
|
"argon2": "^0.44.0",
|
|
24
26
|
"drizzle-orm": "^0.45.2",
|
|
25
27
|
"elysia": "^1.4.29",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type ModuleToolHandlers,
|
|
13
13
|
registerAgentRoutes,
|
|
14
14
|
} from "./routes.js";
|
|
15
|
+
import { GovernedToolRegistry } from "./tool-registry.js";
|
|
15
16
|
|
|
16
17
|
describe("Agent Tool data scope", () => {
|
|
17
18
|
test("启动时拒绝 Manifest 与 Handler 不一致", () => {
|
|
@@ -27,21 +28,16 @@ describe("Agent Tool data scope", () => {
|
|
|
27
28
|
execute: () => ({ items: [], total: 0, page: 1, pageSize: 10 }),
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
expect(
|
|
31
|
-
|
|
32
|
-
new
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
expect(
|
|
32
|
+
() =>
|
|
33
|
+
new GovernedToolRegistry(
|
|
34
|
+
loadFoundationModules(),
|
|
35
|
+
missing as ModuleToolHandlers,
|
|
36
|
+
runtime,
|
|
37
|
+
),
|
|
37
38
|
).toThrow("缺少 Handler");
|
|
38
|
-
expect(
|
|
39
|
-
|
|
40
|
-
new FakeRouteApp(),
|
|
41
|
-
loadFoundationModules(),
|
|
42
|
-
extra,
|
|
43
|
-
runtime,
|
|
44
|
-
),
|
|
39
|
+
expect(
|
|
40
|
+
() => new GovernedToolRegistry(loadFoundationModules(), extra, runtime),
|
|
45
41
|
).toThrow("Handler 未声明");
|
|
46
42
|
});
|
|
47
43
|
|
|
@@ -70,9 +66,11 @@ describe("Agent Tool data scope", () => {
|
|
|
70
66
|
);
|
|
71
67
|
registerAgentRoutes(
|
|
72
68
|
app,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
new GovernedToolRegistry(
|
|
70
|
+
loadFoundationModules(),
|
|
71
|
+
createSystemToolHandlers(repositories, runtime),
|
|
72
|
+
runtime,
|
|
73
|
+
),
|
|
76
74
|
);
|
|
77
75
|
guardContext.actor = {
|
|
78
76
|
...guardContext.actor,
|
|
@@ -103,9 +101,11 @@ describe("Agent Tool data scope", () => {
|
|
|
103
101
|
const app = new FakeRouteApp();
|
|
104
102
|
registerAgentRoutes(
|
|
105
103
|
app,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
new GovernedToolRegistry(
|
|
105
|
+
loadFoundationModules(),
|
|
106
|
+
createSystemToolHandlers(createSystemRepositories(snapshot), runtime),
|
|
107
|
+
runtime,
|
|
108
|
+
),
|
|
109
109
|
);
|
|
110
110
|
const guardContext = await runtime.createGuardContext(
|
|
111
111
|
authenticatedRequest(),
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import type { AgentRuntimeOperation } from "./run-contracts.js";
|
|
3
|
+
import { RemoteAgentRuntime } from "./remote-runtime.js";
|
|
4
|
+
|
|
5
|
+
const servers: Bun.Server<unknown>[] = [];
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
for (const server of servers.splice(0)) server.stop(true);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe("RemoteAgentRuntime", () => {
|
|
12
|
+
test("只向 Agent Server 序列化远端支持的运行限制", async () => {
|
|
13
|
+
let received: unknown;
|
|
14
|
+
const server = Bun.serve({
|
|
15
|
+
port: 0,
|
|
16
|
+
async fetch(request) {
|
|
17
|
+
received = await request.json();
|
|
18
|
+
return Response.json({
|
|
19
|
+
runId: "run_1",
|
|
20
|
+
status: "accepted",
|
|
21
|
+
eventsUrl: "/api/agent/runs/run_1/events",
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
servers.push(server);
|
|
26
|
+
|
|
27
|
+
const manifestLimits = {
|
|
28
|
+
maxDurationSeconds: 60,
|
|
29
|
+
maxInputBytes: 4_096,
|
|
30
|
+
maxOutputBytes: 8_192,
|
|
31
|
+
};
|
|
32
|
+
const operation: AgentRuntimeOperation = {
|
|
33
|
+
operationKey: "business.answer",
|
|
34
|
+
input: { question: "你好" },
|
|
35
|
+
instructions: "只回答当前业务问题。",
|
|
36
|
+
userPrompt: "你好",
|
|
37
|
+
allowedTools: [],
|
|
38
|
+
limits: manifestLimits,
|
|
39
|
+
executionGrant: "grant_1",
|
|
40
|
+
};
|
|
41
|
+
const runtime = new RemoteAgentRuntime({
|
|
42
|
+
baseUrl: server.url.toString(),
|
|
43
|
+
internalToken: "test-token",
|
|
44
|
+
toolHostUrl: "http://server.internal/api/agent/tools",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await runtime.start(operation, "request-1");
|
|
48
|
+
|
|
49
|
+
expect(received).toMatchObject({
|
|
50
|
+
limits: {
|
|
51
|
+
maxDurationSeconds: 60,
|
|
52
|
+
maxOutputBytes: 8_192,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
expect(
|
|
56
|
+
(received as { limits: Record<string, unknown> }).limits,
|
|
57
|
+
).not.toHaveProperty("maxInputBytes");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -27,16 +27,26 @@ export class RemoteAgentRuntime implements AgentRuntimePort {
|
|
|
27
27
|
request: AgentRuntimeOperation,
|
|
28
28
|
idempotencyKey: string,
|
|
29
29
|
): Promise<AgentRuntimeStartResponse> {
|
|
30
|
+
const remoteRequest: RemoteStartRunRequest = {
|
|
31
|
+
operationKey: request.operationKey,
|
|
32
|
+
input: request.input,
|
|
33
|
+
instructions: request.instructions,
|
|
34
|
+
userPrompt: request.userPrompt,
|
|
35
|
+
allowedTools: request.allowedTools,
|
|
36
|
+
limits: {
|
|
37
|
+
maxDurationSeconds: request.limits.maxDurationSeconds,
|
|
38
|
+
maxOutputBytes: request.limits.maxOutputBytes,
|
|
39
|
+
},
|
|
40
|
+
executionGrant: request.executionGrant,
|
|
41
|
+
toolHostUrl: this.options.toolHostUrl,
|
|
42
|
+
};
|
|
30
43
|
const response = await this.request("/api/agent/runs", {
|
|
31
44
|
method: "POST",
|
|
32
45
|
headers: {
|
|
33
46
|
"content-type": "application/json",
|
|
34
47
|
"idempotency-key": idempotencyKey,
|
|
35
48
|
},
|
|
36
|
-
body: JSON.stringify(
|
|
37
|
-
...request,
|
|
38
|
-
toolHostUrl: this.options.toolHostUrl,
|
|
39
|
-
}),
|
|
49
|
+
body: JSON.stringify(remoteRequest),
|
|
40
50
|
});
|
|
41
51
|
if (!response.ok) throw await remoteError(response);
|
|
42
52
|
return (await response.json()) as AgentRuntimeStartResponse;
|
|
@@ -96,6 +106,14 @@ export class RemoteAgentRuntime implements AgentRuntimePort {
|
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
108
|
|
|
109
|
+
interface RemoteStartRunRequest extends Omit<AgentRuntimeOperation, "limits"> {
|
|
110
|
+
limits: {
|
|
111
|
+
maxDurationSeconds: number;
|
|
112
|
+
maxOutputBytes: number;
|
|
113
|
+
};
|
|
114
|
+
toolHostUrl: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
99
117
|
function normalizeInternalUrl(raw: string): string {
|
|
100
118
|
const url = new URL(raw);
|
|
101
119
|
if (!["http:", "https:"].includes(url.protocol)) {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
entitlementKey,
|
|
4
|
+
type FeatureFlagDefinition,
|
|
5
|
+
} from "@southwind-ai/shared";
|
|
3
6
|
import {
|
|
4
7
|
createFoundationSnapshot,
|
|
5
8
|
loadFoundationModules,
|
|
@@ -8,6 +11,7 @@ import { createServerRuntime } from "../runtime.js";
|
|
|
8
11
|
import type { RouteApp } from "../system/routes.js";
|
|
9
12
|
import { createSystemRepositories } from "../system/seed.js";
|
|
10
13
|
import { createSystemToolHandlers, registerAgentRoutes } from "./routes.js";
|
|
14
|
+
import { GovernedToolRegistry } from "./tool-registry.js";
|
|
11
15
|
|
|
12
16
|
class FakeRouteApp implements RouteApp {
|
|
13
17
|
readonly handlers = new Map<string, (context: unknown) => unknown>();
|
|
@@ -44,12 +48,14 @@ function routeFixture(features?: FeatureFlagDefinition[]) {
|
|
|
44
48
|
}
|
|
45
49
|
registerAgentRoutes(
|
|
46
50
|
app,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
new GovernedToolRegistry(
|
|
52
|
+
modules,
|
|
53
|
+
createSystemToolHandlers(
|
|
54
|
+
createSystemRepositories(createFoundationSnapshot()),
|
|
55
|
+
runtime,
|
|
56
|
+
),
|
|
50
57
|
runtime,
|
|
51
58
|
),
|
|
52
|
-
runtime,
|
|
53
59
|
);
|
|
54
60
|
return { app, runtime };
|
|
55
61
|
}
|
|
@@ -191,9 +197,11 @@ describe("agent routes", () => {
|
|
|
191
197
|
const app = new FakeRouteApp();
|
|
192
198
|
registerAgentRoutes(
|
|
193
199
|
app,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
new GovernedToolRegistry(
|
|
201
|
+
loadFoundationModules(),
|
|
202
|
+
createSystemToolHandlers(repositories, runtime),
|
|
203
|
+
runtime,
|
|
204
|
+
),
|
|
197
205
|
);
|
|
198
206
|
const request = () =>
|
|
199
207
|
new Request(
|