create-windy 0.6.6 → 0.6.8
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 +2 -2
- package/dist/cli.js +11 -68
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/apps/agent-server/README.md +4 -4
- package/template/apps/server/Dockerfile +3 -2
- package/template/apps/server/src/ai-runtime-report/actor-handle.test.ts +2 -1
- package/template/apps/server/src/data-access/drizzle-predicate.ts +16 -6
- package/template/apps/web/Dockerfile +1 -0
- package/template/docs/architecture/ai-egress.md +1 -1
- package/template/docs/architecture/ai-runtime-readiness.md +2 -2
- package/template/docs/architecture/ai-runtime.md +15 -15
- package/template/docs/architecture/module-secret-resolution.md +4 -4
- package/template/docs/architecture/report-staging.md +1 -1
- package/template/docs/development/custom-login-page.md +3 -3
- package/template/docs/license/license-offline-activation-code.md +2 -2
- package/template/docs/operations/incremental-delivery.md +213 -0
- package/template/docs/platform/agent-runtime.md +4 -4
- package/template/docs/platform/document-ai-runtime.md +3 -3
- package/template/docs/platform/speech-ai-runtime.md +1 -1
- package/template/docs/platform/vision-ai-runtime.md +1 -1
- package/template/docs/product/built-in-roles.md +9 -1
- package/template/package.json +2 -1
- package/template/packages/delivery/bin/windy-delivery +2 -0
- package/template/packages/delivery/index.ts +14 -0
- package/template/packages/delivery/package.json +23 -0
- package/template/packages/delivery/src/archive-portability.test.ts +84 -0
- package/template/packages/delivery/src/archive.ts +247 -0
- package/template/packages/delivery/src/blob-store.ts +242 -0
- package/template/packages/delivery/src/builder.ts +199 -0
- package/template/packages/delivery/src/checksums.ts +83 -0
- package/template/packages/delivery/src/cli.ts +331 -0
- package/template/packages/delivery/src/delivery.test.ts +332 -0
- package/template/packages/delivery/src/digest.ts +31 -0
- package/template/packages/delivery/src/manifest.ts +255 -0
- package/template/packages/delivery/src/negotiation.ts +68 -0
- package/template/packages/delivery/src/pack.test.ts +165 -0
- package/template/packages/delivery/src/paths.ts +27 -0
- package/template/packages/delivery/src/process-command.ts +49 -0
- package/template/packages/delivery/src/redact.ts +14 -0
- package/template/packages/delivery/src/registry.test.ts +166 -0
- package/template/packages/delivery/src/registry.ts +148 -0
- package/template/packages/delivery/src/security.test.ts +41 -0
- package/template/packages/delivery/src/ssh-capabilities.ts +65 -0
- package/template/packages/delivery/src/ssh-process.ts +349 -0
- package/template/packages/delivery/src/ssh-sync.test.ts +236 -0
- package/template/packages/delivery/src/ssh-sync.ts +167 -0
- package/template/packages/delivery/src/staging.ts +241 -0
- package/template/packages/delivery/src/transfer.ts +54 -0
- package/template/packages/delivery/src/types.ts +78 -0
- package/template/packages/delivery/tsconfig.json +16 -0
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ bun run windy update --dry-run
|
|
|
137
137
|
bun run windy update
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
`0.
|
|
140
|
+
`0.6.6` 是 Starter 更新的最低支持基线。更新器不检查 Git 工作区是否干净:只规划
|
|
141
141
|
目标版本实际变更的受管文件,从 source Project Lock 指向的精确 npm artifact 重建
|
|
142
142
|
Base,并以 Base/Ours/Theirs 合并共享脚手架。未触及的业务修改不会进入更新判断;
|
|
143
143
|
`package.json` 使用字段级合并;已发布 migration 只允许追加;冲突发生时不写项目,
|
|
@@ -146,7 +146,7 @@ Base,并以 Base/Ours/Theirs 合并共享脚手架。未触及的业务修改
|
|
|
146
146
|
|
|
147
147
|
受管清单使用 schema v4:`hash` 冻结下游实际正文,`artifactHash` 在两者不同时记录
|
|
148
148
|
公开模板基线;无正文的 missing tombstone 记住客户删除的 `project-owned` 路径。
|
|
149
|
-
低于 `0.
|
|
149
|
+
低于 `0.6.6` 的 Project Lock、旧清单 schema、损坏的 artifact lineage 或 recipe
|
|
150
150
|
缺口都会在写文件前 fail closed,不提供旧状态的自动迁移路径。
|
|
151
151
|
|
|
152
152
|
生成后的整个 `apps/web/src` 与整个 `apps/server/src/app` 都是 project-owned。普通
|
package/dist/cli.js
CHANGED
|
@@ -3282,6 +3282,7 @@ License \u7B7E\u53D1\u4E2D\u5FC3\u3001\u72EC\u7ACB\u7B7E\u540D\u670D\u52A1\u3001
|
|
|
3282
3282
|
${includeStorage ? "- \u5927\u62A5\u544A\u5BFC\u5165\uFF1A[\u53D7\u6CBB\u7406\u7684\u5927\u62A5\u544A\u6682\u5B58](./architecture/report-staging.md)\u3002" : ""}
|
|
3283
3283
|
${includeOfflineLicense ? "- License \u6D88\u8D39\u7AEF\uFF1A[\u79BB\u7EBF\u6FC0\u6D3B\u4E0E\u5B89\u88C5\u534F\u8BAE](./license/license-offline-activation-code.md)\uFF1B\u8FD0\u884C\u65F6\u80FD\u529B\u7531 npm \u4F9D\u8D56 `@southwind-ai/license` \u63D0\u4F9B\u3002" : ""}
|
|
3284
3284
|
- \u8FD0\u7EF4\uFF1A[\u53EF\u89C2\u6D4B\u6027](./operations/observability.md)${includeOperations ? " \u4E0E [\u8FD0\u7EF4\u603B\u89C8](./platform/operations-overview.md)" : ""}\u3002
|
|
3285
|
+
- \u4EA4\u4ED8\uFF1A[\u6309 registry digest \u4E0E OCI blob \u5DEE\u91CF\u53D1\u5E03](./operations/incremental-delivery.md)\u3002
|
|
3285
3286
|
${includeAgent ? "- Agent\u3001\u591A\u6A21\u6001 Runtime \u4E0E MCP\uFF1A[Agent Runtime \u63A5\u5165](./platform/agent-runtime.md)\u3001[Document AI Runtime](./platform/document-ai-runtime.md)\u3001[Speech AI Runtime](./platform/speech-ai-runtime.md)\u3001[\u53D7\u63A7\u5DE5\u5177](./platform/agent-tools.md)\u4E0E[MCP \u4E1A\u52A1\u80FD\u529B](./architecture/mcp-business-capabilities.md)\u3002" : ""}
|
|
3286
3287
|
- \u517C\u5BB9\uFF1A[RuoYi-Vue Adapter](./adapters/ruoyi-vue-compatibility.md)\u3002
|
|
3287
3288
|
`;
|
|
@@ -3659,6 +3660,7 @@ var templateDirectories = [
|
|
|
3659
3660
|
"packages/config",
|
|
3660
3661
|
"packages/crud-generator",
|
|
3661
3662
|
"packages/database",
|
|
3663
|
+
"packages/delivery",
|
|
3662
3664
|
"packages/example-work-order",
|
|
3663
3665
|
"packages/jobs",
|
|
3664
3666
|
"packages/modules",
|
|
@@ -3694,6 +3696,7 @@ var templateDocumentationFiles = [
|
|
|
3694
3696
|
"docs/development/module-lifecycle.md",
|
|
3695
3697
|
"docs/license/license-offline-activation-code.md",
|
|
3696
3698
|
"docs/operations/observability.md",
|
|
3699
|
+
"docs/operations/incremental-delivery.md",
|
|
3697
3700
|
"docs/platform/agent-run-attestation.md",
|
|
3698
3701
|
"docs/platform/agent-tools.md",
|
|
3699
3702
|
"docs/platform/agent-runtime.md",
|
|
@@ -7713,77 +7716,17 @@ async function diagnoseProject(projectDirectory, repair = false) {
|
|
|
7713
7716
|
}
|
|
7714
7717
|
|
|
7715
7718
|
// src/update/recipes.ts
|
|
7716
|
-
var minimumSupportedUpdateVersion = "0.
|
|
7719
|
+
var minimumSupportedUpdateVersion = "0.6.6";
|
|
7717
7720
|
var recipes = [
|
|
7718
7721
|
{
|
|
7719
|
-
id: "starter-0.
|
|
7720
|
-
from: "0.
|
|
7721
|
-
to: "0.
|
|
7722
|
+
id: "starter-0.6.6-to-0.6.7",
|
|
7723
|
+
from: "0.6.6",
|
|
7724
|
+
to: "0.6.7"
|
|
7722
7725
|
},
|
|
7723
7726
|
{
|
|
7724
|
-
id: "starter-0.
|
|
7725
|
-
from: "0.
|
|
7726
|
-
to: "0.
|
|
7727
|
-
},
|
|
7728
|
-
{
|
|
7729
|
-
id: "starter-0.3.19-to-0.4.0",
|
|
7730
|
-
from: "0.3.19",
|
|
7731
|
-
to: "0.4.0"
|
|
7732
|
-
},
|
|
7733
|
-
{
|
|
7734
|
-
id: "starter-0.4.0-to-0.4.1",
|
|
7735
|
-
from: "0.4.0",
|
|
7736
|
-
to: "0.4.1"
|
|
7737
|
-
},
|
|
7738
|
-
{
|
|
7739
|
-
id: "starter-0.4.1-to-0.5.0",
|
|
7740
|
-
from: "0.4.1",
|
|
7741
|
-
to: "0.5.0"
|
|
7742
|
-
},
|
|
7743
|
-
{
|
|
7744
|
-
id: "starter-0.5.0-to-0.5.1",
|
|
7745
|
-
from: "0.5.0",
|
|
7746
|
-
to: "0.5.1"
|
|
7747
|
-
},
|
|
7748
|
-
{
|
|
7749
|
-
id: "starter-0.5.1-to-0.5.2",
|
|
7750
|
-
from: "0.5.1",
|
|
7751
|
-
to: "0.5.2"
|
|
7752
|
-
},
|
|
7753
|
-
{
|
|
7754
|
-
id: "starter-0.5.2-to-0.6.0",
|
|
7755
|
-
from: "0.5.2",
|
|
7756
|
-
to: "0.6.0"
|
|
7757
|
-
},
|
|
7758
|
-
{
|
|
7759
|
-
id: "starter-0.6.0-to-0.6.1",
|
|
7760
|
-
from: "0.6.0",
|
|
7761
|
-
to: "0.6.1"
|
|
7762
|
-
},
|
|
7763
|
-
{
|
|
7764
|
-
id: "starter-0.6.1-to-0.6.2",
|
|
7765
|
-
from: "0.6.1",
|
|
7766
|
-
to: "0.6.2"
|
|
7767
|
-
},
|
|
7768
|
-
{
|
|
7769
|
-
id: "starter-0.6.2-to-0.6.3",
|
|
7770
|
-
from: "0.6.2",
|
|
7771
|
-
to: "0.6.3"
|
|
7772
|
-
},
|
|
7773
|
-
{
|
|
7774
|
-
id: "starter-0.6.3-to-0.6.4",
|
|
7775
|
-
from: "0.6.3",
|
|
7776
|
-
to: "0.6.4"
|
|
7777
|
-
},
|
|
7778
|
-
{
|
|
7779
|
-
id: "starter-0.6.4-to-0.6.5",
|
|
7780
|
-
from: "0.6.4",
|
|
7781
|
-
to: "0.6.5"
|
|
7782
|
-
},
|
|
7783
|
-
{
|
|
7784
|
-
id: "starter-0.6.5-to-0.6.6",
|
|
7785
|
-
from: "0.6.5",
|
|
7786
|
-
to: "0.6.6"
|
|
7727
|
+
id: "starter-0.6.7-to-0.6.8",
|
|
7728
|
+
from: "0.6.7",
|
|
7729
|
+
to: "0.6.8"
|
|
7787
7730
|
}
|
|
7788
7731
|
];
|
|
7789
7732
|
function resolveRecipeChain(sourceVersion, targetVersion) {
|
|
@@ -8238,7 +8181,7 @@ async function deriveDockerfilePlans(files, snapshots, paths, targetWorkspaceMan
|
|
|
8238
8181
|
continue;
|
|
8239
8182
|
const source = new TextDecoder().decode(dockerSource);
|
|
8240
8183
|
if (!hasDockerfileCopyAnchors(source, target)) {
|
|
8241
|
-
dockerPlan.conflict = "Dockerfile \u7F3A\u5C11 0.
|
|
8184
|
+
dockerPlan.conflict = "Dockerfile \u7F3A\u5C11 0.6.6 \u57FA\u7EBF\u7684 COPY \u951A\u70B9\uFF0C\u5DF2\u505C\u6B62\u81EA\u52A8\u8FC1\u79FB\u65E7\u683C\u5F0F";
|
|
8242
8185
|
continue;
|
|
8243
8186
|
}
|
|
8244
8187
|
let next;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Windy Agent Server
|
|
2
2
|
|
|
3
|
-
Python 3.12 Agent 运行时。HTTP 层只公开
|
|
3
|
+
Python 3.12 Agent 运行时。HTTP 层只公开 Windy 的 canonical Agent 契约;真实业务
|
|
4
4
|
Run 在内部通过 Google ADK 2.5 的 Runner、Session、LlmAgent 和 Event 执行,ADK 类型不会
|
|
5
5
|
越过 `AgentEngineAdapter`。模型调用继续复用受治理的 OpenAI-compatible
|
|
6
6
|
`/chat/completions` Provider。
|
|
@@ -64,12 +64,12 @@ HTTP。Provider 请求包含连接和总超时、响应大小限制、错误脱
|
|
|
64
64
|
readiness。缺少 URL/Model 时回退
|
|
65
65
|
未配置的 `AdkEngineAdapter` 并返回 unavailable,不调用模型。测试另使用
|
|
66
66
|
`DeterministicEngineAdapter`。每个 ADK Tool 只声明 Operation 已允许的 Key;其执行
|
|
67
|
-
函数只回调
|
|
67
|
+
函数只回调 Windy Tool Host,并携带当前 Run 的 opaque Execution Grant。
|
|
68
68
|
|
|
69
69
|
未设置 `AGENT_RUN_STORE_PATH` 时使用的 `InMemoryRunStore` **仅用于 deterministic
|
|
70
70
|
测试**。配置路径后使用有界 SQLite Store,可在单副本重启后保留 Run/Event/Result 和
|
|
71
71
|
cursor;多副本部署仍必须替换为共享 Store。Execution Grant 与 Tool 授权由
|
|
72
|
-
|
|
72
|
+
Windy Server 签发和复核,Agent Server 不能自行扩大 Operation 的
|
|
73
73
|
`allowedToolKeys`。
|
|
74
74
|
|
|
75
75
|
每次实际 `/chat/completions` HTTP 调用前,Runtime 会对 Manifest 允许的输入 JSON
|
|
@@ -15,6 +15,7 @@ COPY packages/config/package.json packages/config/package.json
|
|
|
15
15
|
COPY packages/create-windy/package.json packages/create-windy/package.json
|
|
16
16
|
COPY packages/crud-generator/package.json packages/crud-generator/package.json
|
|
17
17
|
COPY packages/database/package.json packages/database/package.json
|
|
18
|
+
COPY packages/delivery/package.json packages/delivery/package.json
|
|
18
19
|
COPY packages/example-work-order/package.json packages/example-work-order/package.json
|
|
19
20
|
COPY packages/jobs/package.json packages/jobs/package.json
|
|
20
21
|
COPY packages/license-sdk/package.json packages/license-sdk/package.json
|
|
@@ -35,8 +36,8 @@ RUN set -eu; \
|
|
|
35
36
|
echo "$WINDY_DEBIAN_MIRROR" | grep -Eq '^https?://[A-Za-z0-9./:_-]+$'; \
|
|
36
37
|
echo "$WINDY_DEBIAN_SECURITY_MIRROR" | grep -Eq '^https?://[A-Za-z0-9./:_-]+$'; \
|
|
37
38
|
sed -i "s|http://deb.debian.org/debian-security|$WINDY_DEBIAN_SECURITY_MIRROR|g; s|http://deb.debian.org/debian|$WINDY_DEBIAN_MIRROR|g" /etc/apt/sources.list.d/debian.sources; \
|
|
38
|
-
if ! timeout --kill-after=5s
|
|
39
|
-
echo "APT 包源不可用或
|
|
39
|
+
if ! timeout --kill-after=5s 180s sh -c 'apt-get update -o Acquire::http::AllowRedirect=false -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o Acquire::Retries=0 && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --yes build-essential libarchive-dev libarchive-tools'; then \
|
|
40
|
+
echo "APT 包源不可用或 180 秒总时限已到:无法安装 report-staging 依赖" >&2; exit 70; \
|
|
40
41
|
fi
|
|
41
42
|
# @windy-module system.storage end
|
|
42
43
|
COPY drizzle.config.ts drizzle.config.ts
|
|
@@ -17,8 +17,9 @@ describe("AI Runtime Actor handle", () => {
|
|
|
17
17
|
test("篡改或更换密钥后 fail closed", () => {
|
|
18
18
|
const codec = new AiRuntimeActorHandleCodec("internal-token-for-tests");
|
|
19
19
|
const handle = codec.issue("user-1");
|
|
20
|
+
const tampered = `${handle.slice(0, -1)}${handle.endsWith("A") ? "B" : "A"}`;
|
|
20
21
|
|
|
21
|
-
expect(codec.verify(
|
|
22
|
+
expect(codec.verify(tampered)).toBeUndefined();
|
|
22
23
|
expect(
|
|
23
24
|
new AiRuntimeActorHandleCodec("different-internal-token").verify(handle),
|
|
24
25
|
).toBeUndefined();
|
|
@@ -3,12 +3,16 @@ import type { DataScopeQuerySpecification } from "./query-specification.js";
|
|
|
3
3
|
|
|
4
4
|
export class DataScopeBindingError extends Error {}
|
|
5
5
|
|
|
6
|
+
export interface DrizzleDataScopeColumn {
|
|
7
|
+
getSQL(): unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
export interface DrizzleDataScopeBinding {
|
|
7
|
-
readonly ownerId?:
|
|
11
|
+
readonly ownerId?: DrizzleDataScopeColumn;
|
|
8
12
|
readonly tenant?:
|
|
9
|
-
| { readonly mode: "column"; readonly column:
|
|
13
|
+
| { readonly mode: "column"; readonly column: DrizzleDataScopeColumn }
|
|
10
14
|
| { readonly mode: "fixed"; readonly tenantId: string };
|
|
11
|
-
readonly dimensions?: Readonly<Record<string,
|
|
15
|
+
readonly dimensions?: Readonly<Record<string, DrizzleDataScopeColumn>>;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
export function compileDrizzleDataScopePredicate(
|
|
@@ -28,13 +32,13 @@ export function compileDrizzleDataScopePredicate(
|
|
|
28
32
|
if (tenant.tenantId === branch.tenantId) return undefined;
|
|
29
33
|
continue;
|
|
30
34
|
}
|
|
31
|
-
predicates.push(eq(tenant.column, branch.tenantId));
|
|
35
|
+
predicates.push(eq(drizzleColumn(tenant.column), branch.tenantId));
|
|
32
36
|
}
|
|
33
37
|
if (branch.kind === "owner") {
|
|
34
38
|
if (!binding.ownerId) {
|
|
35
39
|
throw new DataScopeBindingError("scope binding missing ownerId");
|
|
36
40
|
}
|
|
37
|
-
predicates.push(eq(binding.ownerId, branch.ownerId));
|
|
41
|
+
predicates.push(eq(drizzleColumn(binding.ownerId), branch.ownerId));
|
|
38
42
|
}
|
|
39
43
|
if (branch.kind === "dimension") {
|
|
40
44
|
const column = binding.dimensions?.[branch.dimension];
|
|
@@ -43,8 +47,14 @@ export function compileDrizzleDataScopePredicate(
|
|
|
43
47
|
`scope binding missing dimension: ${branch.dimension}`,
|
|
44
48
|
);
|
|
45
49
|
}
|
|
46
|
-
if (branch.values.length)
|
|
50
|
+
if (branch.values.length) {
|
|
51
|
+
predicates.push(inArray(drizzleColumn(column), branch.values));
|
|
52
|
+
}
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
55
|
return or(...predicates) || sql<boolean>`false`;
|
|
50
56
|
}
|
|
57
|
+
|
|
58
|
+
function drizzleColumn(column: DrizzleDataScopeColumn): AnyColumn {
|
|
59
|
+
return column as unknown as AnyColumn;
|
|
60
|
+
}
|
|
@@ -15,6 +15,7 @@ COPY packages/config/package.json packages/config/package.json
|
|
|
15
15
|
COPY packages/create-windy/package.json packages/create-windy/package.json
|
|
16
16
|
COPY packages/crud-generator/package.json packages/crud-generator/package.json
|
|
17
17
|
COPY packages/database/package.json packages/database/package.json
|
|
18
|
+
COPY packages/delivery/package.json packages/delivery/package.json
|
|
18
19
|
COPY packages/example-work-order/package.json packages/example-work-order/package.json
|
|
19
20
|
COPY packages/jobs/package.json packages/jobs/package.json
|
|
20
21
|
COPY packages/license-sdk/package.json packages/license-sdk/package.json
|
|
@@ -72,7 +72,7 @@ OpenAI-compatible Adapter 只使用 Agent Server 启动配置的一个 Endpoint
|
|
|
72
72
|
配置还必须通过 `AI_PROVIDER_HTTPS_HOST_ALLOWLIST` 的精确 Host 匹配;不支持通配符、
|
|
73
73
|
scheme、port 或重复 Host。内网 HTTP 继续受既有私有地址校验约束。
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
Windy Server 向 Agent Server 只发送 Operation 的 policy mode 与 Deployment
|
|
76
76
|
Key。Agent Server 在发出模型请求前核对:
|
|
77
77
|
|
|
78
78
|
1. policy 必须是 `configured-endpoint`;
|
|
@@ -12,7 +12,7 @@ deployment pin 和真实 `/health/ready` snapshot 投影新版 Operation;未
|
|
|
12
12
|
|
|
13
13
|
## 目标
|
|
14
14
|
|
|
15
|
-
AI Runtime Readiness V1 为
|
|
15
|
+
AI Runtime Readiness V1 为 Windy Server、Module Operation Host 和各独立
|
|
16
16
|
Runtime 提供同一套失败关闭契约。它回答的是:
|
|
17
17
|
|
|
18
18
|
> 当前这个 Operation 能否在一个已经过真实探测、身份和 release 均未漂移的
|
|
@@ -440,7 +440,7 @@ Readiness 不替代以下权威检查:
|
|
|
440
440
|
- Provider egress、DLP 和 Tool network policy;
|
|
441
441
|
- Run 幂等、取消、审计和输出校验。
|
|
442
442
|
|
|
443
|
-
这些 Guard 仍由
|
|
443
|
+
这些 Guard 仍由 Windy Server 在每次执行的相应阶段重新检查。对未授权调用方,
|
|
444
444
|
Host 不应通过 readiness 暴露跨模块或跨租户的 Deployment 细节。
|
|
445
445
|
|
|
446
446
|
Readiness 也不是 GPU、CPU、显存、队列或并发槽位的资源预留。resource limits 描述该
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Windy AI Runtime 架构
|
|
2
2
|
|
|
3
3
|
更新时间:2026-07-31。
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ Vision 已提供 `agent.vision` 的多图片受控输入、像素限制、逐次
|
|
|
18
18
|
|
|
19
19
|
## 目标
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Windy 为生成项目提供可选的 AI Runtime。它统一治理模型 Deployment、业务 Operation、Feature Flag、RBAC Permission、License、Audit、Secret、用量和离线部署,但不自行重做通用 Agent Framework、LLM Router、OCR 引擎或语音模型。
|
|
22
22
|
|
|
23
23
|
首期目标:
|
|
24
24
|
|
|
@@ -34,14 +34,14 @@ Southwind AI 为生成项目提供可选的 AI Runtime。它统一治理模型 D
|
|
|
34
34
|
|
|
35
35
|
## 核心决策
|
|
36
36
|
|
|
37
|
-
1. Agent Runtime 是
|
|
37
|
+
1. Agent Runtime 是 Windy 的官方可选底座能力,不是每个业务 Module 自行实现的功能。
|
|
38
38
|
2. Agent Server 独立部署,首期使用 Python ADK;ADK 只属于内部 Implementation。
|
|
39
39
|
3. 首个文本切片由 Agent Server 内置 OpenAI-compatible Adapter;需要多 Provider
|
|
40
40
|
路由、fallback 与集中限流时,再引入独立自托管 LiteLLM Proxy。
|
|
41
41
|
4. OCR 和文档解析由独立 Document AI Server 执行,不放入 Agent Server 或 LiteLLM。
|
|
42
42
|
5. ASR、TTS 和 AI Dictation 由独立 Speech Server 执行;实时 Agent 会话由 Agent Server 编排。
|
|
43
43
|
6. 文本 LLM、VLM 和 Agent 输出使用 SSE;实时音频/视频需要双向传输,使用 WebSocket。
|
|
44
|
-
7.
|
|
44
|
+
7. Windy Server 是身份、Feature、Permission、License、数据范围、Tool 授权和 Audit 的事实源。
|
|
45
45
|
8. 所有业务文件通过 `ArtifactRef` 传递,不在跨服务 DTO 中携带大型 Base64 文件或本地绝对路径。
|
|
46
46
|
|
|
47
47
|
## 总体拓扑
|
|
@@ -51,7 +51,7 @@ Southwind AI 为生成项目提供可选的 AI Runtime。它统一治理模型 D
|
|
|
51
51
|
│
|
|
52
52
|
│ AgentOperation / DocumentOperation / SpeechOperation
|
|
53
53
|
▼
|
|
54
|
-
|
|
54
|
+
Windy Server
|
|
55
55
|
├── Feature / RBAC / License / Audit / Data Scope
|
|
56
56
|
├── AI Deployment Registry
|
|
57
57
|
├── Agent Tool Host
|
|
@@ -81,7 +81,7 @@ Southwind AI Server
|
|
|
81
81
|
|
|
82
82
|
## Module 与部署职责
|
|
83
83
|
|
|
84
|
-
###
|
|
84
|
+
### Windy Server
|
|
85
85
|
|
|
86
86
|
拥有:
|
|
87
87
|
|
|
@@ -109,12 +109,12 @@ Southwind AI Server
|
|
|
109
109
|
- ADK Runner、Workflow、Session、Checkpoint、Eval;
|
|
110
110
|
- Agent、Workflow 和 Prompt Release;
|
|
111
111
|
- Run 生命周期、取消、恢复和 canonical event;
|
|
112
|
-
- ADK Event 到
|
|
112
|
+
- ADK Event 到 Windy Event 的转换;
|
|
113
113
|
- Agent Step、Prompt Version、Tool Call 和模型 attempt 的关联;
|
|
114
114
|
- 开发环境 ADK Web;
|
|
115
115
|
- 实时 Agent 会话编排。
|
|
116
116
|
|
|
117
|
-
Agent Server 不直接访问业务 Repository。模型产生 Tool Call 只表示执行意图;每次真实 Tool 执行都必须回到
|
|
117
|
+
Agent Server 不直接访问业务 Repository。模型产生 Tool Call 只表示执行意图;每次真实 Tool 执行都必须回到 Windy Tool Host,重新检查当前 Feature、License、Permission 和数据范围。
|
|
118
118
|
|
|
119
119
|
### LiteLLM Proxy
|
|
120
120
|
|
|
@@ -187,7 +187,7 @@ credential 删除 scope,缺少 credential 时如实保留 Host TTL cleanup pen
|
|
|
187
187
|
Document、Speech 与 Embedding Interface 已分别由 `./document`、`./speech`、
|
|
188
188
|
`./embedding` 子路径交付。
|
|
189
189
|
|
|
190
|
-
npm Module 数量与部署进程数量是两个不同维度。
|
|
190
|
+
npm Module 数量与部署进程数量是两个不同维度。Windy Server、Agent Server、
|
|
191
191
|
Document AI Server 和 Speech Server 仍独立部署:它们具有不同的协议、资源和故障域;
|
|
192
192
|
业务侧则只学习一个稳定入口。`ai-client` 内部通过 Agent、Document、Speech Adapter
|
|
193
193
|
隔离远端 Implementation,不能把 ADK、LiteLLM、PaddleOCR 或 Provider SDK 类型暴露给业务。
|
|
@@ -379,7 +379,7 @@ Endpoint 配置属于高风险管理动作,必须具备独立 Permission 和
|
|
|
379
379
|
|
|
380
380
|
SSE 是单向 Server-to-Client 协议。创建、取消、审批、恢复和 Tool continuation 使用独立 HTTP command,不在 SSE 连接中反向发送。
|
|
381
381
|
|
|
382
|
-
|
|
382
|
+
Windy Server 与 Agent Server 之间使用本节定义的 canonical SSE;Agent Server 调用 LiteLLM 的文本 LLM/VLM 时使用 OpenAI-compatible SSE streaming。Provider 专有流协议在 LiteLLM Adapter 内终止,不能越过该 Seam。VLM 的图片或视频作为请求 Artifact 发送,模型的文本与结构化响应仍通过 SSE 返回。
|
|
383
383
|
|
|
384
384
|
实时语音和视频需要客户端与服务端同时发送媒体帧,因此使用 WebSocket,不属于本节 SSE 约束。
|
|
385
385
|
|
|
@@ -663,7 +663,7 @@ type DictationEvent =
|
|
|
663
663
|
- 级联:ASR → ADK Agent/LLM → TTS;
|
|
664
664
|
- 原生双向模型:音频/视频 ⇄ Realtime Model。
|
|
665
665
|
|
|
666
|
-
客户端先向
|
|
666
|
+
客户端先向 Windy Server 创建 Live Session 并通过 Guard,再使用短时、绑定 Session 和 audience 的凭证连接 Agent Server WebSocket。Tool Call 仍回到 Windy Tool Host 二次授权。
|
|
667
667
|
|
|
668
668
|
首期不新增独立 Realtime Server。连接规模、电话线路、WebRTC 或媒体转码成为真实需求后,再把媒体数据面拆出。
|
|
669
669
|
|
|
@@ -703,7 +703,7 @@ published version 不可原地修改。每次 Run 固定:
|
|
|
703
703
|
|
|
704
704
|
首期优先使用代码或 YAML、Git、Eval 和不可变 Release。只有出现非开发人员在线编辑的真实需求后,再扩展 diff、审批、回滚、fixture、route 对比和发布管理。
|
|
705
705
|
|
|
706
|
-
生产 Trace 优先输出到客户本地 OTel Collector 与 Jaeger/Tempo。
|
|
706
|
+
生产 Trace 优先输出到客户本地 OTel Collector 与 Jaeger/Tempo。Windy 控制面提供脱敏 Run 摘要和受权限保护的 Trace 入口,不复制 ADK Web。
|
|
707
707
|
|
|
708
708
|
生产默认不持久化完整 Prompt、响应、音频、图片或 Tool 参数。明文诊断需要专门 Feature、Permission、加密、脱敏、TTL 和访问审计。
|
|
709
709
|
|
|
@@ -720,12 +720,12 @@ published version 不可原地修改。每次 Run 固定:
|
|
|
720
720
|
| TTS | 输入字符数、输出音频秒数、GPU 时间 |
|
|
721
721
|
| Live | Session 时长、输入/输出音频秒数、LLM token、Tool 次数 |
|
|
722
722
|
|
|
723
|
-
每条事实标记 `provider-reported`、`estimated` 或 `unknown`;缺失不能记为零。成本绑定调用时的价格快照。LiteLLM 保存 Provider/Deployment 原始事实,Agent Server 保存 Run/Step 归属,Document AI 和 Speech Server 保存各自模态事实,
|
|
723
|
+
每条事实标记 `provider-reported`、`estimated` 或 `unknown`;缺失不能记为零。成本绑定调用时的价格快照。LiteLLM 保存 Provider/Deployment 原始事实,Agent Server 保存 Run/Step 归属,Document AI 和 Speech Server 保存各自模态事实,Windy 通过共享 invocation ID 汇总展示。
|
|
724
724
|
|
|
725
725
|
## 安全与授权
|
|
726
726
|
|
|
727
727
|
- 浏览器和普通业务前端不能直接使用 LiteLLM master key;
|
|
728
|
-
-
|
|
728
|
+
- Windy Server 在发起 Run 前执行 License → Feature → Permission Guard;
|
|
729
729
|
- Remote Runtime 只接受短时、限 audience、限 Operation、绑定 actor、run 和 expiry 的 Execution Grant;
|
|
730
730
|
- Grant 不能携带长期有效的 Permission 列表作为授权事实;
|
|
731
731
|
- Tool 执行、人工批准后的继续和后台重试都重新读取当前授权;
|
|
@@ -797,7 +797,7 @@ fail closed。开发 ADK Web 已作为 localhost-only 的受控调试入口交
|
|
|
797
797
|
- 文本 LLM、VLM 和 Agent 输出统一通过 canonical SSE;
|
|
798
798
|
- SSE 断线后使用 cursor 恢复,不重新执行模型调用;
|
|
799
799
|
- Feature、Permission、License 任一拒绝都会 fail-closed;
|
|
800
|
-
- 模型 Tool Call 不能绕过
|
|
800
|
+
- 模型 Tool Call 不能绕过 Windy Tool Host;
|
|
801
801
|
- 同一 Run 能关联 Audit、ADK Trace、LiteLLM attempt 和 Usage;
|
|
802
802
|
- 本地/内网模型可配置协议、主机、端口和 Base Path;
|
|
803
803
|
- 完全断网环境仍可运行已配置的本地 LLM、OCR 和 Speech Operation;
|
|
@@ -221,14 +221,14 @@ Resolver 不会被调用。
|
|
|
221
221
|
泄漏,但不能识别回调返回的其它未知凭据,也不能把故意通过网络或其它副作用发送凭据的
|
|
222
222
|
恶意模块变成安全代码。这些边界必须继续通过代码审查、模块来源治理和网络策略控制。
|
|
223
223
|
|
|
224
|
-
##
|
|
224
|
+
## SMB / SFTP 业务模块接入示例
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
业务项目升级到包含该契约的 Windy 版本后,按以下方式接入,不需要修改 Windy 的配置
|
|
227
227
|
Registry 或 Agent Tool Runtime:
|
|
228
228
|
|
|
229
|
-
1. 在拥有 SMB/SFTP
|
|
229
|
+
1. 在拥有 SMB/SFTP 同步能力的业务 Module Manifest 分别声明 password/private-key
|
|
230
230
|
handle、稳定 connection/purpose,以及同基础 Key Feature、Permission 和审计动作;
|
|
231
|
-
2.
|
|
231
|
+
2. 在项目的 project-owned `server-composition.ts` 为每个声明添加
|
|
232
232
|
SDK 根导出的 `createModuleSecretBinding()`,生产 Resolver 指向客户批准的 Secret
|
|
233
233
|
Store;
|
|
234
234
|
3. Route/Service 在一次连接操作内使用
|
|
@@ -148,7 +148,7 @@ Starter 会同时裁剪 helper 源码、编译步骤和依赖。非官方镜像
|
|
|
148
148
|
需要自行提供同一 helper;缺失或 RAR5 真实读取失败会返回
|
|
149
149
|
`REPORT_STAGING_UNSUPPORTED_ARCHIVE`,不会回退旧 `bsdtar -x` 或其他外部命令。
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
相较旧的外部命令直解压方案,当前实现保留已由真实 probe 验证的 RAR5 streaming
|
|
152
152
|
reader,但把落盘所有权和逐 write 配额检查收回 Host,并用可严格解析的 framing 取代
|
|
153
153
|
人类可读 listing。V1 callback 刻意不提供 seek/reopen;需要随机 seek 的 RAR4、ZIP 或
|
|
154
154
|
其他格式会 fail closed,当前不承诺与通用 `archive_read_open_filenames` 格式等价。
|
|
@@ -30,13 +30,13 @@ export const loginPageComponent = defineLoginPageComponent(PlatformLoginPage);
|
|
|
30
30
|
## 完整业务页面
|
|
31
31
|
|
|
32
32
|
将业务页面放在同一个 project-owned 目录,例如
|
|
33
|
-
`apps/web/src/app/auth/
|
|
33
|
+
`apps/web/src/app/auth/ProjectLoginPage.vue`,然后只修改 selector:
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
|
-
import
|
|
36
|
+
import ProjectLoginPage from "./ProjectLoginPage.vue";
|
|
37
37
|
import { defineLoginPageComponent } from "@/pages/auth/login-page-extension";
|
|
38
38
|
|
|
39
|
-
export const loginPageComponent = defineLoginPageComponent(
|
|
39
|
+
export const loginPageComponent = defineLoginPageComponent(ProjectLoginPage);
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
业务 SFC 使用 Vue 3 Composition API 和 TypeScript。认证提交必须复用
|
|
@@ -50,8 +50,8 @@ W1 是同一份 `SignedLicenseV1` 的离线传输编码,用于客户电脑没
|
|
|
50
50
|
|
|
51
51
|
下表由当前固定 V1 测试向量测得。`完整编码字符`包含 `W1`、段分隔连字符和校验字符;Base32 本身不包含易混的 `I/L/O/U`。V1 现在只携带单一 License 版本标记,不再包含数量可变的能力列表。
|
|
52
52
|
|
|
53
|
-
| 样本
|
|
54
|
-
|
|
|
53
|
+
| 样本 | canonical JSON 字节 | 段数 | 完整编码字符 |
|
|
54
|
+
| ------------------------ | ------------------: | ---: | -----------: |
|
|
55
55
|
| 仓库固定 V1 版本标记向量 | 673 | 20 | 519 |
|
|
56
56
|
|
|
57
57
|
因此 W1 仍然只是无 U 盘、无摄像头时的兜底入口,不能承诺 150~300 字符。仅 64 字节 ED25519 签名转为 Base32 就需要约 103 个数据字符,V1 还签入客户、项目、合同、设备、时间、公钥 ID 和 License 版本等完整展示字段。
|