create-windy 0.9.1 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1691 -1151
- package/package.json +2 -2
- package/template/.agents/skills/windy-business-module/SKILL.md +33 -1
- package/template/.windy-template.json +6 -2
- package/template/AGENTS.md +4 -0
- package/template/README.md +2 -0
- package/template/apps/agent-server/Dockerfile +1 -1
- package/template/apps/agent-server/README.md +1 -1
- package/template/apps/agent-server/native/EXTENSIONS.md +2 -2
- package/template/apps/agent-server/native/parallel-harness.ts +2 -0
- package/template/apps/agent-server/native/storage-lifecycle.test.ts +2 -1
- package/template/apps/agent-server/package.json +42 -41
- package/template/apps/agent-server/plugins/downloads/README.md +1 -1
- package/template/apps/agent-server/plugins/drop-overlay/README.md +1 -1
- package/template/apps/agent-server/plugins/settings/README.md +1 -1
- package/template/apps/agent-server/plugins/skill-library/client-chunks.test.ts +4 -1
- package/template/apps/agent-server/plugins/theme/README.md +5 -1
- package/template/apps/agent-server/plugins/theme/source-tokens.ts +0 -1
- package/template/apps/agent-server/plugins/theme/tokens.json +0 -4
- package/template/apps/agent-server/plugins/tool-catalog/README.md +6 -3
- package/template/apps/agent-server/plugins/tool-catalog/discovery.mjs +13 -10
- package/template/apps/agent-server/plugins/tool-catalog/discovery.test.ts +68 -6
- package/template/apps/agent-server/runtime/compatibility.ts +7 -1
- package/template/apps/agent-server/runtime/dsh-engine.ts +2 -0
- package/template/apps/agent-server/runtime/questions-workflow.nodecheck.ts +2 -0
- package/template/apps/server/Dockerfile +2 -1
- package/template/apps/server/package.json +11 -11
- package/template/apps/server/scripts/validate-module-composition-once.ts +2 -0
- package/template/apps/server/scripts/validate-module-composition.ts +8 -4
- package/template/apps/server/src/admin/routes.test.ts +29 -1
- package/template/apps/server/src/admin/routes.ts +20 -2
- package/template/apps/server/src/agent/client-session/completion.ts +1 -1
- package/template/apps/server/src/agent/client-session/manifest-admission.ts +1 -1
- package/template/apps/server/src/agent/client-session/request.ts +1 -1
- package/template/apps/server/src/agent/context-version-routes.ts +37 -13
- package/template/apps/server/src/agent/run-facade.ts +1 -1
- package/template/apps/server/src/agent/run-input-verification.ts +1 -1
- package/template/apps/server/src/agent/run-routes.ts +1 -14
- package/template/apps/server/src/agent/run-start-preparation.ts +1 -1
- package/template/apps/server/src/agent/runtime-bootstrap-input.ts +2 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +49 -157
- package/template/apps/server/src/agent/runtime-disabled-composition.ts +2 -1
- package/template/apps/server/src/agent/session-invalidation/authorization-revocation.ts +54 -0
- package/template/apps/server/src/agent/session-runtime-composition.ts +1 -51
- package/template/apps/server/src/agent/unavailable-routes.ts +13 -2
- package/template/apps/server/src/agent-workflow/runtime-composition.ts +3 -0
- package/template/apps/server/src/agent-workflow/service.ts +17 -1
- package/template/apps/server/src/ai-artifact/media-resource-route.test.ts +134 -0
- package/template/apps/server/src/ai-artifact/routes.ts +1 -1
- package/template/apps/server/src/ai-artifact/runtime.ts +12 -0
- package/template/apps/server/src/ai-runtime-readiness/operation-port.test-support.ts +1 -1
- package/template/apps/server/src/ai-runtime-readiness/operation-port.ts +8 -0
- package/template/apps/server/src/ai-runtime-security/internal-token.ts +14 -0
- package/template/apps/server/src/app/antivirus-composition.test.ts +63 -0
- package/template/apps/server/src/app/antivirus-composition.ts +29 -0
- package/template/apps/server/src/app/dsh-workbench-socket-audit.test.ts +2 -1
- package/template/apps/server/src/configuration/definition.ts +15 -11
- package/template/apps/server/src/document/facade-support.ts +2 -2
- package/template/apps/server/src/document/facade.ts +2 -2
- package/template/apps/server/src/document/output-artifact-composition.ts +9 -5
- package/template/apps/server/src/document/output-artifact.test-support.ts +1 -1
- package/template/apps/server/src/embedding/facade.ts +1 -1
- package/template/apps/server/src/embedding/input.ts +1 -1
- package/template/apps/server/src/embedding/routes.ts +1 -1
- package/template/apps/server/src/index.ts +60 -60
- package/template/apps/server/src/license/routes.ts +4 -1
- package/template/apps/server/src/license/runtime-business-access.test.ts +261 -0
- package/template/apps/server/src/media-runtime/composition.ts +157 -0
- package/template/apps/server/src/media-runtime/media-only-composition.ts +44 -0
- package/template/apps/server/src/media-runtime/module-ai-port-factory.test.ts +69 -0
- package/template/apps/server/src/media-runtime/module-ai-port-factory.ts +72 -0
- package/template/apps/server/src/{agent → media-runtime}/runtime-readiness-sources.ts +14 -6
- package/template/apps/server/src/media-runtime/shared-composition.ts +104 -0
- package/template/apps/server/src/module-composition.test.ts +22 -0
- package/template/apps/server/src/module-composition.ts +48 -0
- package/template/apps/server/src/module-host/ai-operation-port.ts +97 -30
- package/template/apps/server/src/module-host/ai-operation-speech-normalize.test.ts +1 -1
- package/template/apps/server/src/module-host/http-runtime.ts +9 -3
- package/template/apps/server/src/module-host/static-route-authorization.test.ts +6 -3
- package/template/apps/server/src/module-host/storage-authorization-binding.test.ts +4 -0
- package/template/apps/server/src/module-runtime-validation.ts +2 -0
- package/template/apps/server/src/observability/diagnostic-index.ts +26 -1
- package/template/apps/server/src/observability/diagnostic-repository.ts +40 -11
- package/template/apps/server/src/platform-http-runtime.ts +1 -1
- package/template/apps/server/src/runtime-feature.ts +5 -1
- package/template/apps/server/src/runtime.ts +3 -0
- package/template/apps/server/src/settings/drizzle-watermark-repository.ts +35 -4
- package/template/apps/server/src/settings/watermark-repository.ts +14 -0
- package/template/apps/server/src/settings/watermark-routes.test.ts +84 -2
- package/template/apps/server/src/settings/watermark-routes.ts +109 -0
- package/template/apps/server/src/settings/watermark-transfer.ts +79 -0
- package/template/apps/server/src/speech/facade-validation.ts +1 -1
- package/template/apps/server/src/speech/facade.ts +2 -2
- package/template/apps/server/src/startup-composition-validation.test.ts +32 -0
- package/template/apps/server/src/startup-finalization.ts +2 -0
- package/template/apps/server/src/startup-runtime.ts +77 -0
- package/template/apps/server/src/system/ai-runtime-build.ts +3 -0
- package/template/apps/server/src/system/ai-runtime-configuration.test.ts +36 -0
- package/template/apps/server/src/system/ai-runtime-configuration.ts +58 -0
- package/template/apps/server/src/system/diagnostic-routes.test.ts +45 -0
- package/template/apps/server/src/system/diagnostic-routes.ts +35 -0
- package/template/apps/server/src/system/environment-policy-reader.test.ts +74 -0
- package/template/apps/server/src/system/environment-policy-reader.ts +62 -0
- package/template/apps/server/src/system/feature-environment-assessment.test.ts +148 -0
- package/template/apps/server/src/system/feature-environment-assessment.ts +179 -0
- package/template/apps/server/src/system/host-diagnostics.test.ts +155 -0
- package/template/apps/server/src/system/host-diagnostics.ts +225 -0
- package/template/apps/server/src/system/menu-registry.test.ts +26 -0
- package/template/apps/server/src/system/menu-registry.ts +9 -7
- package/template/apps/server/src/system/operations.test.ts +5 -0
- package/template/apps/server/src/system/operations.ts +36 -12
- package/template/apps/server/src/system/role-authorization-postgres.integration.test.ts +181 -0
- package/template/apps/web/Dockerfile +7 -3
- package/template/apps/web/dev/dev-port.test.ts +6 -6
- package/template/apps/web/dev/dev-port.ts +1 -1
- package/template/apps/web/dev/start.ts +6 -1
- package/template/apps/web/index.html +1 -0
- package/template/apps/web/package.json +16 -16
- package/template/apps/web/runtime-server.test.ts +22 -1
- package/template/apps/web/runtime-server.ts +6 -0
- package/template/apps/web/src/App.vue +6 -3
- package/template/apps/web/src/assets/windy.svg +4 -0
- package/template/apps/web/src/components/auth/LoginForm.vue +2 -2
- package/template/apps/web/src/components/auth/PasswordChangeForm.vue +14 -3
- package/template/apps/web/src/components/common/FormDialog.vue +1 -1
- package/template/apps/web/src/components/license/LicenseFlow.webtest.ts +3 -0
- package/template/apps/web/src/components/license/LicenseMachineCodeQr.vue +99 -0
- package/template/apps/web/src/components/license/LicenseMachineCodeQr.webtest.ts +83 -0
- package/template/apps/web/src/components/license/LicensePairingCard.vue +1 -1
- package/template/apps/web/src/components/license/LicenseStatusCard.vue +14 -2
- package/template/apps/web/src/composables/useLoginFlow.ts +2 -2
- package/template/apps/web/src/composables/usePlatformSettings.ts +1 -1
- package/template/apps/web/src/composables/useWatermarkSettings.ts +1 -0
- package/template/apps/web/src/layout/AppSidebar.vue +5 -9
- package/template/apps/web/src/layout/AppSidebar.webtest.ts +4 -1
- package/template/apps/web/src/pages/auth/ChangePasswordPage.vue +67 -6
- package/template/apps/web/src/pages/auth/LoginPage.vue +3 -12
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +30 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +25 -14
- package/template/apps/web/src/pages/configuration/components/TimeZoneSelect.vue +55 -0
- package/template/apps/web/src/pages/profile/PersonalSettingsPage.vue +64 -11
- package/template/apps/web/src/pages/profile/PersonalSettingsPage.webtest.ts +21 -1
- package/template/apps/web/src/pages/settings/BrandingSettingsSection.vue +7 -18
- package/template/apps/web/src/pages/settings/BrandingSettingsSection.webtest.ts +9 -4
- package/template/apps/web/src/pages/settings/GlobalSettingsPage.vue +51 -6
- package/template/apps/web/src/pages/settings/GlobalSettingsPage.webtest.ts +19 -3
- package/template/apps/web/src/pages/settings/WatermarkSettingsSection.vue +1 -0
- package/template/apps/web/src/pages/settings/WatermarkYamlTransfer.vue +211 -0
- package/template/apps/web/src/pages/system/DiagnosticLookupPage.vue +18 -3
- package/template/apps/web/src/pages/system/DiagnosticLookupPage.webtest.ts +4 -1
- package/template/apps/web/src/pages/system/SystemOperationsPage.vue +23 -0
- package/template/apps/web/src/pages/system/components/DiagnosticLogList.vue +120 -0
- package/template/apps/web/src/pages/system/components/OperationEnvironmentPanel.vue +237 -0
- package/template/apps/web/src/pages/system/components/OperationFeatureAssessmentPanel.vue +131 -0
- package/template/apps/web/src/pages/system/components/PagedSelectionList.vue +31 -24
- package/template/apps/web/src/pages/system/components/SystemResourceActions.vue +2 -1
- package/template/apps/web/src/pages/system/components/SystemResourceEditor.vue +11 -2
- package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +1 -0
- package/template/apps/web/src/pages/system/components/SystemResourcePage.webtest.ts +6 -2
- package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.vue +18 -9
- package/template/apps/web/src/pages/system/components/agent-workbench/SessionReplayTimeline.vue +18 -9
- package/template/apps/web/src/pages/system/components/agent-workbench/TestRunComposer.vue +66 -34
- package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.vue +48 -33
- package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.webtest.ts +9 -2
- package/template/apps/web/src/pages/system/components/agent-workbench/ToolRuleDetail.vue +23 -16
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkJobDetail.vue +10 -7
- package/template/apps/web/src/pages/system/components/user-account/RolePermissionSummary.vue +81 -57
- package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.vue +6 -4
- package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.webtest.ts +20 -4
- package/template/apps/web/src/pages/system/resource-config.ts +9 -0
- package/template/apps/web/src/pages/work-orders/WorkOrderListPage.vue +1 -1
- package/template/apps/web/src/router/disabled-feature-loading.webtest.ts +78 -0
- package/template/apps/web/src/router/index.ts +3 -6
- package/template/apps/web/src/router/manifest-routes.ts +2 -3
- package/template/apps/web/src/router/platform-admin-pages.ts +21 -62
- package/template/apps/web/src/router/platform-admin-route-bindings.ts +4 -4
- package/template/apps/web/src/services/diagnostics-api.ts +13 -1
- package/template/apps/web/src/services/operations-api.ts +4 -0
- package/template/apps/web/src/services/platform-settings-api.ts +35 -1
- package/template/apps/web/vite.config.ts +9 -3
- package/template/deploy/environment/windy.environment.example.yaml +53 -0
- package/template/docker-compose.yml +4 -2
- package/template/docs/architecture/agent-admin-workbench-implementation.md +1 -1
- package/template/docs/architecture/agent-admin-workbench-plan.md +1 -1
- package/template/docs/architecture/agent-workflow.md +8 -0
- package/template/docs/architecture/durable-jobs.md +17 -0
- package/template/docs/architecture/embedded-dsh-integration.md +1 -1
- package/template/docs/development/dsh-plugins.md +1 -1
- package/template/docs/development/performance-engineering.md +24 -0
- package/template/docs/operations/admin-settings-yaml.md +29 -0
- package/template/docs/operations/dsh-agent-migration.md +2 -2
- package/template/docs/operations/environment-capabilities.md +185 -0
- package/template/docs/platform/module-configuration.md +18 -3
- package/template/docs/platform/platform-authentication.md +1 -1
- package/template/package.json +10 -8
- package/template/packages/config/package.json +2 -2
- package/template/packages/config/src/definition.ts +14 -4
- package/template/packages/config/src/environment-loader.ts +27 -3
- package/template/packages/config/src/platform-ai-runtime.test.ts +94 -0
- package/template/packages/config/src/platform.ts +5 -2
- package/template/packages/database/drizzle/0065_durable_job_lease_snapshot_lookup.sql +1 -0
- package/template/packages/database/drizzle/0066_agent_source_sequence_bigint.sql +3 -0
- package/template/packages/database/drizzle/0067_media_runtime_access.sql +46 -0
- package/template/packages/database/drizzle/meta/0065_snapshot.json +15370 -0
- package/template/packages/database/drizzle/meta/0066_snapshot.json +15370 -0
- package/template/packages/database/drizzle/meta/0067_snapshot.json +15370 -0
- package/template/packages/database/drizzle/meta/_journal.json +21 -0
- package/template/packages/database/package.json +3 -3
- package/template/packages/database/src/schema/agent-session.ts +4 -3
- package/template/packages/database/src/schema/durable-jobs.ts +4 -0
- package/template/packages/database/src/schema/index.ts +3 -1
- package/template/packages/database/src/schema-durable-recovery.test.ts +21 -1
- package/template/packages/database/src/schema-source-sequence.test.ts +24 -0
- package/template/packages/example-work-order/package.json +2 -2
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/admin-ui-boundary.test.ts +33 -0
- package/template/packages/modules/src/composition.ts +11 -28
- package/template/packages/modules/src/manifest.ts +2 -0
- package/template/packages/modules/src/menu-composition.ts +24 -0
- package/template/packages/modules/src/system-admin-routes.ts +2 -2
- package/template/packages/modules/src/system-admin-ui-catalog.ts +6 -1
- package/template/packages/modules/src/system-ai-api-bindings.ts +0 -16
- package/template/packages/modules/src/system-api-control-plane.ts +9 -1
- package/template/packages/modules/src/system-api-permissions.ts +7 -0
- package/template/packages/modules/src/system-api-watermark.ts +21 -0
- package/template/packages/modules/src/system-audit-actions.ts +3 -1
- package/template/packages/modules/src/system-features.ts +21 -3
- package/template/packages/modules/src/system-media-api-bindings.ts +97 -0
- package/template/packages/modules/src/system-module-audit-selection.ts +2 -0
- package/template/packages/modules/src/system-module-catalog.test.ts +13 -6
- package/template/packages/modules/src/system-module-catalog.ts +6 -241
- package/template/packages/modules/src/system-module-definitions.ts +260 -0
- package/template/packages/modules/src/system-modules-access.test.ts +2 -0
- package/template/packages/modules/src/system-modules.test.ts +7 -1
- package/template/packages/modules/src/system-modules.ts +25 -13
- package/template/packages/modules/src/system-permissions.ts +12 -0
- package/template/packages/server-sdk/package.json +1 -1
- package/template/packages/shared/index.ts +3 -0
- package/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/environment-assessment.ts +68 -0
- package/template/packages/shared/src/environment-policy.ts +205 -0
- package/template/packages/shared/src/license-console-capabilities.ts +7 -0
- package/template/packages/shared/src/license.ts +1 -0
- package/template/packages/shared/src/module-configuration.ts +2 -1
- package/template/scripts/operations/collect-device-info.py +230 -0
- package/template/apps/server/src/agent/module-ai-port-factory.ts +0 -41
- /package/template/apps/server/src/{agent → ai-runtime-security}/execution-grants.ts +0 -0
- /package/template/apps/server/src/{agent → ai-runtime-security}/idempotency-key.test.ts +0 -0
- /package/template/apps/server/src/{agent → ai-runtime-security}/idempotency-key.ts +0 -0
- /package/template/apps/server/src/{agent → ai-runtime-security}/provider-input-governance.test.ts +0 -0
- /package/template/apps/server/src/{agent → ai-runtime-security}/provider-input-governance.ts +0 -0
- /package/template/apps/server/src/{agent → media-runtime}/required-environment.ts +0 -0
- /package/template/apps/server/src/{agent → media-runtime}/runtime-readiness-sources.test.ts +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { systemModuleManifest } from "@southwind-ai/modules";
|
|
3
|
+
import {
|
|
4
|
+
operationKey,
|
|
5
|
+
readinessManifest,
|
|
6
|
+
readySnapshot,
|
|
7
|
+
} from "../ai-runtime-readiness/operation-port.test-support.js";
|
|
8
|
+
import { AiRuntimeReadinessTrustStoreV1 } from "../ai-runtime-readiness/trust-store.js";
|
|
9
|
+
import { createServerRuntime } from "../runtime.js";
|
|
10
|
+
import { createModuleAiPorts } from "./module-ai-port-factory.js";
|
|
11
|
+
|
|
12
|
+
test("已授权的业务 Operation 在 Document Feature 关闭时不探测远端", async () => {
|
|
13
|
+
const modules = [
|
|
14
|
+
readinessManifest(),
|
|
15
|
+
systemModuleManifest("system.media-runtime"),
|
|
16
|
+
];
|
|
17
|
+
const featureCatalog = modules.flatMap((module) => module.features);
|
|
18
|
+
const runtime = createServerRuntime(
|
|
19
|
+
{},
|
|
20
|
+
{
|
|
21
|
+
featureCatalog,
|
|
22
|
+
disabledFeatureKeys: new Set(["system.document"]),
|
|
23
|
+
licenseEnforced: false,
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
const context = await runtime.createGuardContextForActor(
|
|
27
|
+
new Request("http://localhost/evidence"),
|
|
28
|
+
{
|
|
29
|
+
id: "ocr-operator",
|
|
30
|
+
type: "user",
|
|
31
|
+
name: "OCR operator",
|
|
32
|
+
roleCodes: [],
|
|
33
|
+
permissionKeys: ["evidence.document.ocr.execute"],
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
let probes = 0;
|
|
37
|
+
const ports = createModuleAiPorts({
|
|
38
|
+
modules,
|
|
39
|
+
runtime,
|
|
40
|
+
sources: [
|
|
41
|
+
{
|
|
42
|
+
kind: "document",
|
|
43
|
+
async health() {
|
|
44
|
+
probes += 1;
|
|
45
|
+
return Response.json(readySnapshot());
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
operations: { modules },
|
|
50
|
+
trustStore: new AiRuntimeReadinessTrustStoreV1(),
|
|
51
|
+
});
|
|
52
|
+
const signal = AbortSignal.timeout(1_000);
|
|
53
|
+
await expect(
|
|
54
|
+
ports.readiness("evidence", context, signal).inspect({ operationKey }),
|
|
55
|
+
).resolves.toMatchObject({
|
|
56
|
+
runtimeKind: "document",
|
|
57
|
+
status: "unavailable",
|
|
58
|
+
unavailableReasons: [{ code: "RUNTIME_NOT_CONFIGURED" }],
|
|
59
|
+
});
|
|
60
|
+
expect(probes).toBe(0);
|
|
61
|
+
await expect(
|
|
62
|
+
ports.operations("evidence", context, signal).startDocument({
|
|
63
|
+
operationKey,
|
|
64
|
+
sources: [],
|
|
65
|
+
options: {},
|
|
66
|
+
idempotencyKey: "regression",
|
|
67
|
+
}),
|
|
68
|
+
).rejects.toMatchObject({ code: "AI_OPERATION_UNAVAILABLE" });
|
|
69
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { AiRuntimeKind } from "@southwind-ai/shared";
|
|
2
|
+
import { ModuleAiOperationError } from "@southwind-ai/server-sdk";
|
|
3
|
+
import { evaluateFeatureGuard } from "../guards.js";
|
|
4
|
+
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
5
|
+
import { createModuleAiOperationReadinessPort } from "../ai-runtime-readiness/operation-port.js";
|
|
6
|
+
import type { AiRuntimeReadinessTrustStoreV1 } from "../ai-runtime-readiness/trust-store.js";
|
|
7
|
+
import { createModuleAiOperationPort } from "../module-host/ai-operation-port.js";
|
|
8
|
+
import type { createServerRuntime } from "../runtime.js";
|
|
9
|
+
|
|
10
|
+
type OperationRuntime = Parameters<typeof createModuleAiOperationPort>[3];
|
|
11
|
+
type ReadinessInput = Parameters<
|
|
12
|
+
typeof createModuleAiOperationReadinessPort
|
|
13
|
+
>[0];
|
|
14
|
+
|
|
15
|
+
export function createModuleAiPorts(input: {
|
|
16
|
+
readonly modules: readonly ModuleManifest[];
|
|
17
|
+
readonly runtime: ReturnType<typeof createServerRuntime>;
|
|
18
|
+
readonly sources: ReadinessInput["sources"];
|
|
19
|
+
readonly trustStore: AiRuntimeReadinessTrustStoreV1;
|
|
20
|
+
readonly operations: OperationRuntime;
|
|
21
|
+
}) {
|
|
22
|
+
const features = new Map(
|
|
23
|
+
input.modules.flatMap((module) =>
|
|
24
|
+
module.features.map((feature) => [String(feature.key), feature] as const),
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
const runtimeAllowed = async (
|
|
28
|
+
guardContext: Parameters<typeof createModuleAiOperationPort>[1],
|
|
29
|
+
kind: AiRuntimeKind,
|
|
30
|
+
) => {
|
|
31
|
+
const feature = features.get(`system.${kind}`);
|
|
32
|
+
if (!feature) return false;
|
|
33
|
+
const decision = evaluateFeatureGuard(
|
|
34
|
+
guardContext,
|
|
35
|
+
await input.runtime.resolveFeature(guardContext, feature),
|
|
36
|
+
);
|
|
37
|
+
if (!decision.allowed) input.runtime.recordDecisions([decision]);
|
|
38
|
+
return decision.allowed;
|
|
39
|
+
};
|
|
40
|
+
const operations = (
|
|
41
|
+
moduleName: string,
|
|
42
|
+
guardContext: Parameters<typeof createModuleAiOperationPort>[1],
|
|
43
|
+
signal: AbortSignal,
|
|
44
|
+
) =>
|
|
45
|
+
createModuleAiOperationPort(moduleName, guardContext, signal, {
|
|
46
|
+
...input.operations,
|
|
47
|
+
async requireFeature(kind) {
|
|
48
|
+
if (!(await runtimeAllowed(guardContext, kind))) {
|
|
49
|
+
throw new ModuleAiOperationError(
|
|
50
|
+
"AI_OPERATION_UNAVAILABLE",
|
|
51
|
+
`${kind} Feature 未启用`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
const readiness = (
|
|
57
|
+
moduleName: string,
|
|
58
|
+
guardContext: Parameters<typeof createModuleAiOperationPort>[1],
|
|
59
|
+
signal: AbortSignal,
|
|
60
|
+
) =>
|
|
61
|
+
createModuleAiOperationReadinessPort({
|
|
62
|
+
moduleName,
|
|
63
|
+
guardContext,
|
|
64
|
+
signal,
|
|
65
|
+
modules: input.modules,
|
|
66
|
+
sources: input.sources,
|
|
67
|
+
trustStore: input.trustStore,
|
|
68
|
+
runtimeAllowed: (kind) => runtimeAllowed(guardContext, kind),
|
|
69
|
+
runtime: input.runtime,
|
|
70
|
+
});
|
|
71
|
+
return { operations, readiness };
|
|
72
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AiRuntimeSwitches } from "@southwind-ai/shared";
|
|
1
2
|
import type { AiRuntimeReadinessSourceV1 } from "../ai-runtime-readiness/operation-port.js";
|
|
2
3
|
|
|
3
4
|
interface HealthPort {
|
|
@@ -5,16 +6,22 @@ interface HealthPort {
|
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
export function createAiRuntimeReadinessSources(input: {
|
|
8
|
-
agent
|
|
9
|
+
agent?: HealthPort;
|
|
9
10
|
document: HealthPort;
|
|
10
11
|
speech: HealthPort;
|
|
11
12
|
embedding: HealthPort;
|
|
13
|
+
switches?: AiRuntimeSwitches;
|
|
12
14
|
}): readonly AiRuntimeReadinessSourceV1[] {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const agent = input.agent;
|
|
16
|
+
const sources: AiRuntimeReadinessSourceV1[] = [
|
|
17
|
+
...(agent
|
|
18
|
+
? [
|
|
19
|
+
{
|
|
20
|
+
kind: "agent" as const,
|
|
21
|
+
health: (signal?: AbortSignal) => agent.health(signal),
|
|
22
|
+
},
|
|
23
|
+
]
|
|
24
|
+
: []),
|
|
18
25
|
{
|
|
19
26
|
kind: "document",
|
|
20
27
|
health: (signal) => input.document.health(signal),
|
|
@@ -28,4 +35,5 @@ export function createAiRuntimeReadinessSources(input: {
|
|
|
28
35
|
health: (signal) => input.embedding.health(signal),
|
|
29
36
|
},
|
|
30
37
|
];
|
|
38
|
+
return sources.filter(({ kind }) => input.switches?.[kind] !== false);
|
|
31
39
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { AiArtifactCodec } from "../ai-artifact/codec.js";
|
|
2
|
+
import { registerAiArtifactRoutes } from "../ai-artifact/routes.js";
|
|
3
|
+
import { AiArtifactRuntime } from "../ai-artifact/runtime.js";
|
|
4
|
+
import { createModuleAiOperationReadinessPort } from "../ai-runtime-readiness/operation-port.js";
|
|
5
|
+
import { AiRuntimeReadinessTrustStoreV1 } from "../ai-runtime-readiness/trust-store.js";
|
|
6
|
+
import { connectMediaRuntimes, registerMediaRuntimes } from "./composition.js";
|
|
7
|
+
import { ExecutionGrantStore } from "../ai-runtime-security/execution-grants.js";
|
|
8
|
+
import type {
|
|
9
|
+
AiRuntimeSwitches,
|
|
10
|
+
FeatureFlagDefinition,
|
|
11
|
+
} from "@southwind-ai/shared";
|
|
12
|
+
import { createAiRuntimeReadinessSources } from "./runtime-readiness-sources.js";
|
|
13
|
+
import { createModuleAiPorts } from "./module-ai-port-factory.js";
|
|
14
|
+
|
|
15
|
+
type MediaInput = Parameters<typeof registerMediaRuntimes>[0];
|
|
16
|
+
type OperationServices = Parameters<
|
|
17
|
+
typeof createModuleAiPorts
|
|
18
|
+
>[0]["operations"];
|
|
19
|
+
|
|
20
|
+
export function composeSharedAiRuntime(
|
|
21
|
+
input: Pick<
|
|
22
|
+
MediaInput,
|
|
23
|
+
| "modules"
|
|
24
|
+
| "hosts"
|
|
25
|
+
| "runtime"
|
|
26
|
+
| "storage"
|
|
27
|
+
| "db"
|
|
28
|
+
| "resolveActor"
|
|
29
|
+
| "internalToken"
|
|
30
|
+
> & {
|
|
31
|
+
app: MediaInput["aiRouteApp"];
|
|
32
|
+
switches?: AiRuntimeSwitches;
|
|
33
|
+
features: readonly FeatureFlagDefinition[];
|
|
34
|
+
secret: string;
|
|
35
|
+
agent?: Parameters<typeof createAiRuntimeReadinessSources>[0]["agent"];
|
|
36
|
+
},
|
|
37
|
+
) {
|
|
38
|
+
const aiArtifacts = new AiArtifactRuntime(
|
|
39
|
+
new AiArtifactCodec(input.secret),
|
|
40
|
+
input.hosts,
|
|
41
|
+
input.runtime,
|
|
42
|
+
input.features,
|
|
43
|
+
input.storage,
|
|
44
|
+
input.resolveActor,
|
|
45
|
+
);
|
|
46
|
+
registerAiArtifactRoutes(input.app, aiArtifacts, input.internalToken);
|
|
47
|
+
const grants = new ExecutionGrantStore();
|
|
48
|
+
const media = connectMediaRuntimes(input.internalToken, input.switches);
|
|
49
|
+
const { documentRemote, speechRemote, embeddingRemote } = media;
|
|
50
|
+
const readinessSources = createAiRuntimeReadinessSources({
|
|
51
|
+
agent: input.agent,
|
|
52
|
+
document: documentRemote,
|
|
53
|
+
speech: speechRemote,
|
|
54
|
+
embedding: embeddingRemote,
|
|
55
|
+
switches: input.switches,
|
|
56
|
+
});
|
|
57
|
+
const readinessTrustStore = new AiRuntimeReadinessTrustStoreV1();
|
|
58
|
+
const aiReadiness = createModuleAiOperationReadinessPort({
|
|
59
|
+
modules: input.modules,
|
|
60
|
+
sources: readinessSources,
|
|
61
|
+
trustStore: readinessTrustStore,
|
|
62
|
+
runtime: input.runtime,
|
|
63
|
+
});
|
|
64
|
+
const { documentFacadeWithOutput, speechFacade, embeddingFacade } =
|
|
65
|
+
registerMediaRuntimes({
|
|
66
|
+
...media,
|
|
67
|
+
switches: input.switches,
|
|
68
|
+
modules: input.modules,
|
|
69
|
+
hosts: input.hosts,
|
|
70
|
+
runtime: input.runtime,
|
|
71
|
+
storage: input.storage,
|
|
72
|
+
db: input.db,
|
|
73
|
+
aiReadiness,
|
|
74
|
+
resolveActor: input.resolveActor,
|
|
75
|
+
aiArtifacts,
|
|
76
|
+
grants,
|
|
77
|
+
aiRouteApp: input.app,
|
|
78
|
+
internalToken: input.internalToken,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
aiArtifacts,
|
|
83
|
+
catalogReadiness: aiReadiness,
|
|
84
|
+
modulePorts(
|
|
85
|
+
agent: Pick<OperationServices, "agentFacade" | "agentRemote"> = {},
|
|
86
|
+
) {
|
|
87
|
+
return createModuleAiPorts({
|
|
88
|
+
modules: input.modules,
|
|
89
|
+
runtime: input.runtime,
|
|
90
|
+
sources: readinessSources,
|
|
91
|
+
trustStore: readinessTrustStore,
|
|
92
|
+
operations: {
|
|
93
|
+
...agent,
|
|
94
|
+
documentFacade: documentFacadeWithOutput,
|
|
95
|
+
documentRemote,
|
|
96
|
+
speechFacade,
|
|
97
|
+
speechRemote,
|
|
98
|
+
embeddingFacade,
|
|
99
|
+
modules: input.modules,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -53,6 +53,28 @@ describe("Server Module Composition", () => {
|
|
|
53
53
|
).toThrow("API Route Handler Key 重复:POST /api/auth/users/:id/password");
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
test("启动配置关闭的能力可省略 Handler,启用能力仍须完整注册", () => {
|
|
57
|
+
const module = fixture();
|
|
58
|
+
const feature = module.apiPermissions[0]!.featureKey!;
|
|
59
|
+
const input = { modules: [module], routes: [] };
|
|
60
|
+
expect(() => validateServerModuleComposition(input)).toThrow(
|
|
61
|
+
"缺少 Handler",
|
|
62
|
+
);
|
|
63
|
+
expect(() =>
|
|
64
|
+
validateServerModuleComposition({
|
|
65
|
+
...input,
|
|
66
|
+
disabledFeatureKeys: new Set([feature]),
|
|
67
|
+
}),
|
|
68
|
+
).not.toThrow();
|
|
69
|
+
expect(() =>
|
|
70
|
+
validateServerModuleComposition({
|
|
71
|
+
...input,
|
|
72
|
+
routes: [{ method: "GET", path: "/api/unregistered" }],
|
|
73
|
+
disabledFeatureKeys: new Set([feature]),
|
|
74
|
+
}),
|
|
75
|
+
).toThrow("未在 Manifest 声明");
|
|
76
|
+
});
|
|
77
|
+
|
|
56
78
|
test("Host 注册实现必须在 Manifest 声明", () => {
|
|
57
79
|
const app = new Elysia({ prefix: "/api" }).post(
|
|
58
80
|
"/auth/users/:id/password",
|
|
@@ -28,6 +28,7 @@ export interface ServerCompositionInput {
|
|
|
28
28
|
* 产品、运维、认证与恢复入口仍必须进入 Manifest。
|
|
29
29
|
*/
|
|
30
30
|
frameworkRoutes?: readonly string[];
|
|
31
|
+
disabledFeatureKeys?: ReadonlySet<string>;
|
|
31
32
|
tasks?: readonly { key: string }[];
|
|
32
33
|
tools?: ReadonlyMap<string, unknown>;
|
|
33
34
|
aiOperations?: readonly string[];
|
|
@@ -50,7 +51,37 @@ export function validateServerModuleComposition(
|
|
|
50
51
|
apiRoutes,
|
|
51
52
|
input.frameworkRoutes ?? [],
|
|
52
53
|
);
|
|
54
|
+
const disabledFeatures = disabledRuntimeFeatureClosure(
|
|
55
|
+
input.modules,
|
|
56
|
+
input.disabledFeatureKeys,
|
|
57
|
+
);
|
|
58
|
+
const registered = new Set(apiRoutes);
|
|
59
|
+
const outputPrefix = "/api/internal/ai/output-artifacts";
|
|
60
|
+
const hasOutputSink = input.routes.some(({ path }) =>
|
|
61
|
+
path.startsWith(outputPrefix),
|
|
62
|
+
);
|
|
63
|
+
const unavailableApiRoutes = new Set(
|
|
64
|
+
input.modules.flatMap((module) =>
|
|
65
|
+
module.apiPermissions
|
|
66
|
+
.filter(
|
|
67
|
+
({ featureKey, path }) =>
|
|
68
|
+
(featureKey !== undefined && disabledFeatures.has(featureKey)) ||
|
|
69
|
+
(!hasOutputSink &&
|
|
70
|
+
featureKey === "system.ai-artifact" &&
|
|
71
|
+
path.startsWith(outputPrefix)),
|
|
72
|
+
)
|
|
73
|
+
.map(apiRouteKey)
|
|
74
|
+
.filter((key) => !registered.has(key)),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
const unavailableTools = disabledFeatures.has("system.agent")
|
|
78
|
+
? new Set(
|
|
79
|
+
input.modules.flatMap((module) => module.tools.map(({ key }) => key)),
|
|
80
|
+
)
|
|
81
|
+
: undefined;
|
|
53
82
|
validateModuleComposition(input.modules, {
|
|
83
|
+
unavailableApiRoutes,
|
|
84
|
+
unavailableTools,
|
|
54
85
|
apiRoutes,
|
|
55
86
|
tasks: (input.tasks || []).map(({ key }) => key),
|
|
56
87
|
tools: [...(input.tools?.keys() || [])],
|
|
@@ -62,6 +93,23 @@ export function validateServerModuleComposition(
|
|
|
62
93
|
}
|
|
63
94
|
}
|
|
64
95
|
|
|
96
|
+
function disabledRuntimeFeatureClosure(
|
|
97
|
+
modules: readonly ModuleManifest[],
|
|
98
|
+
disabledKeys: ReadonlySet<string> | undefined,
|
|
99
|
+
) {
|
|
100
|
+
const disabled = new Set(disabledKeys);
|
|
101
|
+
const features = modules.flatMap((module) => module.features);
|
|
102
|
+
let previousSize = -1;
|
|
103
|
+
while (previousSize !== disabled.size) {
|
|
104
|
+
previousSize = disabled.size;
|
|
105
|
+
for (const feature of features) {
|
|
106
|
+
if (feature.dependencies?.some((key) => disabled.has(key)))
|
|
107
|
+
disabled.add(feature.key);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return disabled;
|
|
111
|
+
}
|
|
112
|
+
|
|
65
113
|
function validateHttpRouteRegistration(
|
|
66
114
|
modules: readonly ModuleManifest[],
|
|
67
115
|
registeredRoutes: readonly string[],
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// @windy-module system.
|
|
1
|
+
// @windy-module system.media-runtime begin
|
|
2
2
|
import type {
|
|
3
3
|
ModuleAiOperationDefinition,
|
|
4
4
|
ModuleManifest,
|
|
5
5
|
} from "@southwind-ai/modules";
|
|
6
6
|
import type {
|
|
7
|
+
ModuleAiArtifactRef,
|
|
7
8
|
ModuleAiJsonValue,
|
|
9
|
+
ModuleAiRunReceipt,
|
|
8
10
|
ModuleAiOperationPort,
|
|
9
11
|
} from "@southwind-ai/server-sdk";
|
|
10
12
|
import { ModuleAiOperationError } from "@southwind-ai/server-sdk";
|
|
11
|
-
import type { AgentRunFacade } from "../agent/run-facade.js";
|
|
12
|
-
import type { AgentRuntimePort } from "../agent/run-contracts.js";
|
|
13
13
|
import type { DocumentRuntimePort } from "../document/contracts.js";
|
|
14
14
|
import type { DocumentRunFacade } from "../document/facade.js";
|
|
15
15
|
import type { EmbeddingFacade } from "../embedding/facade.js";
|
|
@@ -17,14 +17,48 @@ import type { RequestGuardContext } from "../guards.js";
|
|
|
17
17
|
import type { SpeechRuntimePort } from "../speech/contracts.js";
|
|
18
18
|
import type { SpeechRunFacade } from "../speech/facade.js";
|
|
19
19
|
|
|
20
|
+
interface AgentOperationService {
|
|
21
|
+
start(
|
|
22
|
+
operationKey: string,
|
|
23
|
+
input: ModuleAiJsonValue,
|
|
24
|
+
idempotencyKey: string,
|
|
25
|
+
context: RequestGuardContext,
|
|
26
|
+
artifacts?: readonly ModuleAiArtifactRef[],
|
|
27
|
+
signal?: AbortSignal,
|
|
28
|
+
): Promise<ModuleAiRunReceipt>;
|
|
29
|
+
verifyRunInput(
|
|
30
|
+
operationKey: string,
|
|
31
|
+
runId: string,
|
|
32
|
+
input: ModuleAiJsonValue,
|
|
33
|
+
context: RequestGuardContext,
|
|
34
|
+
): Promise<void>;
|
|
35
|
+
authorizeRun(
|
|
36
|
+
operationKey: string,
|
|
37
|
+
runId: string,
|
|
38
|
+
context: RequestGuardContext,
|
|
39
|
+
): Promise<unknown>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface AgentRunTransport {
|
|
43
|
+
result(runId: string, signal?: AbortSignal): Promise<Response>;
|
|
44
|
+
cancel(
|
|
45
|
+
runId: string,
|
|
46
|
+
reason?: string,
|
|
47
|
+
signal?: AbortSignal,
|
|
48
|
+
): Promise<Response>;
|
|
49
|
+
}
|
|
50
|
+
|
|
20
51
|
export interface ModuleAiRuntimeServices {
|
|
21
|
-
readonly agentFacade
|
|
22
|
-
readonly agentRemote
|
|
23
|
-
readonly documentFacade
|
|
24
|
-
readonly documentRemote
|
|
25
|
-
readonly speechFacade
|
|
26
|
-
readonly speechRemote
|
|
27
|
-
readonly embeddingFacade
|
|
52
|
+
readonly agentFacade?: AgentOperationService;
|
|
53
|
+
readonly agentRemote?: AgentRunTransport;
|
|
54
|
+
readonly documentFacade?: DocumentRunFacade;
|
|
55
|
+
readonly documentRemote?: DocumentRuntimePort;
|
|
56
|
+
readonly speechFacade?: SpeechRunFacade;
|
|
57
|
+
readonly speechRemote?: SpeechRuntimePort;
|
|
58
|
+
readonly embeddingFacade?: EmbeddingFacade;
|
|
59
|
+
readonly requireFeature?: (
|
|
60
|
+
kind: "agent" | "document" | "speech" | "embedding",
|
|
61
|
+
) => Promise<void>;
|
|
28
62
|
readonly modules: readonly ModuleManifest[];
|
|
29
63
|
}
|
|
30
64
|
|
|
@@ -45,7 +79,8 @@ export function createModuleAiOperationPort(
|
|
|
45
79
|
return {
|
|
46
80
|
async startAgent(input) {
|
|
47
81
|
own(input.operationKey);
|
|
48
|
-
|
|
82
|
+
await services.requireFeature?.("agent");
|
|
83
|
+
return requireRuntime(services.agentFacade, "Agent").start(
|
|
49
84
|
input.operationKey,
|
|
50
85
|
input.input,
|
|
51
86
|
input.idempotencyKey,
|
|
@@ -56,7 +91,8 @@ export function createModuleAiOperationPort(
|
|
|
56
91
|
},
|
|
57
92
|
async verifyAgentRun(input) {
|
|
58
93
|
own(input.operationKey);
|
|
59
|
-
await services.
|
|
94
|
+
await services.requireFeature?.("agent");
|
|
95
|
+
await requireRuntime(services.agentFacade, "Agent").verifyRunInput(
|
|
60
96
|
input.operationKey,
|
|
61
97
|
input.runId,
|
|
62
98
|
input.input,
|
|
@@ -65,7 +101,8 @@ export function createModuleAiOperationPort(
|
|
|
65
101
|
},
|
|
66
102
|
async startDocument(input) {
|
|
67
103
|
own(input.operationKey);
|
|
68
|
-
|
|
104
|
+
await services.requireFeature?.("document");
|
|
105
|
+
return requireRuntime(services.documentFacade, "Document").start(
|
|
69
106
|
input.operationKey,
|
|
70
107
|
input.sources,
|
|
71
108
|
input.options,
|
|
@@ -76,12 +113,13 @@ export function createModuleAiOperationPort(
|
|
|
76
113
|
},
|
|
77
114
|
async startSpeech(input) {
|
|
78
115
|
own(input.operationKey);
|
|
116
|
+
await services.requireFeature?.("speech");
|
|
79
117
|
const definition = ownSpeechDefinition(
|
|
80
118
|
services.modules,
|
|
81
119
|
moduleName,
|
|
82
120
|
input.operationKey,
|
|
83
121
|
);
|
|
84
|
-
return services.speechFacade.start(
|
|
122
|
+
return requireRuntime(services.speechFacade, "Speech").start(
|
|
85
123
|
input.operationKey,
|
|
86
124
|
input.source,
|
|
87
125
|
input.options,
|
|
@@ -93,8 +131,9 @@ export function createModuleAiOperationPort(
|
|
|
93
131
|
},
|
|
94
132
|
async embed(input) {
|
|
95
133
|
own(input.operationKey);
|
|
134
|
+
await services.requireFeature?.("embedding");
|
|
96
135
|
return jsonValue(
|
|
97
|
-
await services.embeddingFacade.embed(
|
|
136
|
+
await requireRuntime(services.embeddingFacade, "Embedding").embed(
|
|
98
137
|
input.operationKey,
|
|
99
138
|
input.items,
|
|
100
139
|
input.options,
|
|
@@ -106,51 +145,69 @@ export function createModuleAiOperationPort(
|
|
|
106
145
|
},
|
|
107
146
|
async result(input) {
|
|
108
147
|
own(input.operationKey);
|
|
148
|
+
await services.requireFeature?.(input.kind);
|
|
109
149
|
if (input.kind === "agent") {
|
|
110
|
-
await services.agentFacade.authorizeRun(
|
|
150
|
+
await requireRuntime(services.agentFacade, "Agent").authorizeRun(
|
|
111
151
|
input.operationKey,
|
|
112
152
|
input.runId,
|
|
113
153
|
context,
|
|
114
154
|
);
|
|
115
155
|
return responseJson(
|
|
116
|
-
await services.agentRemote.result(
|
|
156
|
+
await requireRuntime(services.agentRemote, "Agent").result(
|
|
157
|
+
input.runId,
|
|
158
|
+
signal,
|
|
159
|
+
),
|
|
117
160
|
);
|
|
118
161
|
}
|
|
119
162
|
if (input.kind === "document") {
|
|
120
|
-
await services.documentFacade.authorizeRun(
|
|
163
|
+
await requireRuntime(services.documentFacade, "Document").authorizeRun(
|
|
164
|
+
input.runId,
|
|
165
|
+
context,
|
|
166
|
+
);
|
|
121
167
|
return responseJson(
|
|
122
|
-
await services.documentRemote.result(
|
|
168
|
+
await requireRuntime(services.documentRemote, "Document").result(
|
|
169
|
+
input.runId,
|
|
170
|
+
signal,
|
|
171
|
+
),
|
|
123
172
|
);
|
|
124
173
|
}
|
|
125
|
-
services.speechFacade.authorizeRun(
|
|
174
|
+
requireRuntime(services.speechFacade, "Speech").authorizeRun(
|
|
175
|
+
input.runId,
|
|
176
|
+
context,
|
|
177
|
+
);
|
|
126
178
|
return responseJson(
|
|
127
|
-
await services.speechRemote.result(
|
|
179
|
+
await requireRuntime(services.speechRemote, "Speech").result(
|
|
180
|
+
input.runId,
|
|
181
|
+
signal,
|
|
182
|
+
),
|
|
128
183
|
);
|
|
129
184
|
},
|
|
130
185
|
async cancel(input) {
|
|
131
186
|
own(input.operationKey);
|
|
187
|
+
await services.requireFeature?.(input.kind);
|
|
132
188
|
let response: Response;
|
|
133
189
|
if (input.kind === "agent") {
|
|
134
|
-
await services.agentFacade.authorizeRun(
|
|
190
|
+
await requireRuntime(services.agentFacade, "Agent").authorizeRun(
|
|
135
191
|
input.operationKey,
|
|
136
192
|
input.runId,
|
|
137
193
|
context,
|
|
138
194
|
);
|
|
139
|
-
response = await services.agentRemote.cancel(
|
|
195
|
+
response = await requireRuntime(services.agentRemote, "Agent").cancel(
|
|
140
196
|
input.runId,
|
|
141
197
|
input.reason,
|
|
142
198
|
signal,
|
|
143
199
|
);
|
|
144
200
|
} else if (input.kind === "document") {
|
|
145
|
-
response = await
|
|
201
|
+
response = await requireRuntime(
|
|
202
|
+
services.documentFacade,
|
|
203
|
+
"Document",
|
|
204
|
+
).cancel(input.runId, input.reason, context, signal);
|
|
205
|
+
} else {
|
|
206
|
+
requireRuntime(services.speechFacade, "Speech").authorizeRun(
|
|
146
207
|
input.runId,
|
|
147
|
-
input.reason,
|
|
148
208
|
context,
|
|
149
|
-
signal,
|
|
150
209
|
);
|
|
151
|
-
|
|
152
|
-
services.speechFacade.authorizeRun(input.runId, context);
|
|
153
|
-
response = await services.speechRemote.cancel(
|
|
210
|
+
response = await requireRuntime(services.speechRemote, "Speech").cancel(
|
|
154
211
|
input.runId,
|
|
155
212
|
input.reason,
|
|
156
213
|
signal,
|
|
@@ -161,6 +218,16 @@ export function createModuleAiOperationPort(
|
|
|
161
218
|
};
|
|
162
219
|
}
|
|
163
220
|
|
|
221
|
+
function requireRuntime<T>(service: T | undefined, kind: string): T {
|
|
222
|
+
if (service === undefined) {
|
|
223
|
+
throw new ModuleAiOperationError(
|
|
224
|
+
"AI_OPERATION_UNAVAILABLE",
|
|
225
|
+
`${kind} Runtime 未装配`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
return service;
|
|
229
|
+
}
|
|
230
|
+
|
|
164
231
|
function ownSpeechDefinition(
|
|
165
232
|
modules: readonly ModuleManifest[],
|
|
166
233
|
moduleName: string,
|
|
@@ -235,4 +302,4 @@ function operationErrorCode(status: number, remoteCode: string) {
|
|
|
235
302
|
function jsonValue(value: unknown): ModuleAiJsonValue {
|
|
236
303
|
return JSON.parse(JSON.stringify(value)) as ModuleAiJsonValue;
|
|
237
304
|
}
|
|
238
|
-
// @windy-module system.
|
|
305
|
+
// @windy-module system.media-runtime end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { expect, test } from "bun:test";
|
|
3
3
|
import type { ModuleManifest } from "@southwind-ai/modules";
|
|
4
4
|
import type { ModuleAiOperationReadinessV1 } from "@southwind-ai/server-sdk";
|
|
5
|
-
import { ExecutionGrantStore } from "../
|
|
5
|
+
import { ExecutionGrantStore } from "../ai-runtime-security/execution-grants.js";
|
|
6
6
|
import { createRequestGuardContext } from "../guards.js";
|
|
7
7
|
import { initializeModuleHosts } from "../module-host.js";
|
|
8
8
|
import { createServerRuntime } from "../runtime.js";
|
|
@@ -10,11 +10,13 @@ import type { ReportStagingService } from "../report-staging/service.js";
|
|
|
10
10
|
// @windy-module system.storage end
|
|
11
11
|
import type { RouteApp } from "../system/route-types.js";
|
|
12
12
|
import type { SystemRepositories } from "../system/seed.js";
|
|
13
|
-
// @windy-module system.
|
|
13
|
+
// @windy-module system.media-runtime begin
|
|
14
14
|
import type { RequestGuardContext } from "../guards.js";
|
|
15
15
|
import type { AiArtifactRuntime } from "../ai-artifact/runtime.js";
|
|
16
16
|
import type { ModuleAiOperationPort } from "@southwind-ai/server-sdk";
|
|
17
17
|
import type { ModuleAiOperationReadinessPortV1 } from "@southwind-ai/server-sdk";
|
|
18
|
+
// @windy-module system.media-runtime end
|
|
19
|
+
// @windy-module system.agent begin
|
|
18
20
|
import type { ModuleAiScreenshotIntakePortV1 } from "@southwind-ai/server-sdk";
|
|
19
21
|
import type { ModuleAgentSessionMemoryPortV1 } from "@southwind-ai/server-sdk";
|
|
20
22
|
import type { ModuleAuthoritativeSourceInvalidationPortV1 } from "@southwind-ai/server-sdk";
|
|
@@ -44,7 +46,7 @@ export function installModuleHttpRuntime(
|
|
|
44
46
|
reportStaging?: ReportStagingService;
|
|
45
47
|
// @windy-module system.storage end
|
|
46
48
|
systemRepositories: SystemRepositories;
|
|
47
|
-
// @windy-module system.
|
|
49
|
+
// @windy-module system.media-runtime begin
|
|
48
50
|
aiArtifacts?: AiArtifactRuntime;
|
|
49
51
|
aiOperations?: (
|
|
50
52
|
moduleName: string,
|
|
@@ -56,6 +58,8 @@ export function installModuleHttpRuntime(
|
|
|
56
58
|
guardContext: RequestGuardContext,
|
|
57
59
|
signal: AbortSignal,
|
|
58
60
|
) => ModuleAiOperationReadinessPortV1;
|
|
61
|
+
// @windy-module system.media-runtime end
|
|
62
|
+
// @windy-module system.agent begin
|
|
59
63
|
screenshots?: (
|
|
60
64
|
moduleName: string,
|
|
61
65
|
guardContext: RequestGuardContext,
|
|
@@ -95,7 +99,7 @@ export function installModuleHttpRuntime(
|
|
|
95
99
|
userDirectory: {
|
|
96
100
|
repositories: context.systemRepositories,
|
|
97
101
|
},
|
|
98
|
-
// @windy-module system.
|
|
102
|
+
// @windy-module system.media-runtime begin
|
|
99
103
|
aiArtifacts: context.aiArtifacts
|
|
100
104
|
? (moduleName, guardContext, signal) =>
|
|
101
105
|
context.aiArtifacts!.createModulePort(
|
|
@@ -114,6 +118,8 @@ export function installModuleHttpRuntime(
|
|
|
114
118
|
: undefined,
|
|
115
119
|
aiOperations: context.aiOperations,
|
|
116
120
|
aiReadiness: context.aiReadiness,
|
|
121
|
+
// @windy-module system.media-runtime end
|
|
122
|
+
// @windy-module system.agent begin
|
|
117
123
|
screenshots: context.screenshots,
|
|
118
124
|
sessionMemory: context.sessionMemory,
|
|
119
125
|
sourceInvalidation: context.sourceInvalidation,
|