@capybara-hq/kernel 0.1.0-rc.12 → 0.1.0-rc.14
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/admin/admin.schemas.d.ts +13 -0
- package/dist/agents/agent-lookup.d.ts +5 -0
- package/dist/agents/agent-lookup.js +15 -0
- package/dist/background/background.module.js +2 -2
- package/dist/background/launch-lock.d.ts +1 -1
- package/dist/background/launch-lock.js +1 -1
- package/dist/background/poll.job.d.ts +2 -2
- package/dist/background/poll.job.js +10 -10
- package/dist/background/stop.d.ts +1 -1
- package/dist/background/stop.js +3 -3
- package/dist/background/store.d.ts +5 -5
- package/dist/background/store.js +5 -5
- package/dist/background/tasks.service.d.ts +6 -6
- package/dist/background/tasks.service.js +13 -13
- package/dist/catalog/admin-catalog.controller.d.ts +13 -2
- package/dist/catalog/admin-catalog.controller.js +24 -3
- package/dist/catalog/admin-catalog.schemas.d.ts +10 -0
- package/dist/catalog/admin-catalog.schemas.js +7 -0
- package/dist/catalog/catalog-content.d.ts +9 -1
- package/dist/catalog/catalog-content.js +2 -1
- package/dist/catalog/catalog-files.d.ts +3 -2
- package/dist/catalog/catalog-files.js +8 -5
- package/dist/catalog/component-scope.service.d.ts +14 -1
- package/dist/catalog/component-scope.service.js +12 -2
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-catalog.controller.d.ts +5 -4
- package/dist/catalog/org-catalog.controller.js +5 -4
- package/dist/catalog/org-catalog.schemas.d.ts +18 -2
- package/dist/catalog/org-catalog.schemas.js +16 -2
- package/dist/catalog/org-catalog.service.js +8 -2
- package/dist/catalog/plugin-import.js +1 -1
- package/dist/catalog/plugin-package.js +37 -9
- package/dist/catalog/plugin-upgrade.d.ts +15 -1
- package/dist/catalog/plugin-upgrade.js +18 -5
- package/dist/channels/channels.module.js +2 -2
- package/dist/channels/connections.controller.d.ts +1 -1
- package/dist/channels/connections.controller.js +1 -1
- package/dist/channels/connections.service.d.ts +22 -5
- package/dist/channels/connections.service.js +56 -10
- package/dist/channels/inbound.d.ts +8 -8
- package/dist/channels/inbound.js +31 -31
- package/dist/channels/phrases.d.ts +27 -27
- package/dist/channels/phrases.js +27 -27
- package/dist/channels/webhook.d.ts +21 -1
- package/dist/channels/webhook.js +39 -4
- package/dist/config/docs.js +1 -1
- package/dist/config/schema.d.ts +2 -2
- package/dist/config/schema.js +21 -21
- package/dist/conversations/conversations.controller.d.ts +11 -11
- package/dist/conversations/conversations.controller.js +15 -15
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +7 -7
- package/dist/conversations/conversations.schemas.js +1 -1
- package/dist/conversations/conversations.service.d.ts +14 -14
- package/dist/conversations/conversations.service.js +19 -19
- package/dist/conversations/{environment-status.d.ts → device-status.d.ts} +9 -9
- package/dist/conversations/{environment-status.js → device-status.js} +18 -18
- package/dist/conversations/event-log.d.ts +1 -1
- package/dist/conversations/event-log.js +1 -1
- package/dist/conversations/events.d.ts +1 -1
- package/dist/conversations/events.js +2 -2
- package/dist/ctx/create-ctx.d.ts +26 -3
- package/dist/ctx/create-ctx.js +134 -26
- package/dist/db/kernel-schema.d.ts +37 -25
- package/dist/{environments → devices}/access.d.ts +19 -19
- package/dist/{environments → devices}/access.js +28 -28
- package/dist/devices/conversation-devices.d.ts +75 -0
- package/dist/{environments/conversation-environments.js → devices/conversation-devices.js} +71 -72
- package/dist/devices/devices.controller.d.ts +36 -0
- package/dist/{environments/environments.controller.js → devices/devices.controller.js} +37 -37
- package/dist/devices/devices.module.d.ts +5 -13
- package/dist/devices/devices.module.js +16 -29
- package/dist/devices/devices.schemas.d.ts +3 -0
- package/dist/devices/devices.schemas.js +14 -0
- package/dist/{environments/environments.service.d.ts → devices/devices.service.d.ts} +70 -70
- package/dist/{environments/environments.service.js → devices/devices.service.js} +122 -122
- package/dist/devices/dto.d.ts +13 -54
- package/dist/devices/dto.js +7 -39
- package/dist/devices/label.d.ts +11 -0
- package/dist/{environments → devices}/label.js +7 -7
- package/dist/{environments → devices}/legacy-cleanup.job.d.ts +3 -3
- package/dist/{environments → devices}/legacy-cleanup.job.js +3 -3
- package/dist/errors.d.ts +29 -25
- package/dist/errors.js +29 -25
- package/dist/evals/recorded-tools.d.ts +2 -2
- package/dist/evals/recorded-tools.js +6 -6
- package/dist/extensions/admin-ops.js +1 -0
- package/dist/extensions/admin-view.js +2 -0
- package/dist/extensions/effective-config.d.ts +6 -0
- package/dist/extensions/effective-config.js +18 -7
- package/dist/extensions/guide-places.d.ts +66 -0
- package/dist/extensions/guide-places.js +152 -0
- package/dist/extensions/host.d.ts +13 -2
- package/dist/extensions/host.js +27 -6
- package/dist/extensions/instance.d.ts +17 -2
- package/dist/extensions/instance.js +21 -0
- package/dist/extensions/ledger.d.ts +1 -1
- package/dist/extensions/permission-set.d.ts +16 -2
- package/dist/extensions/permission-set.js +17 -3
- package/dist/extensions/permission-view.d.ts +10 -1
- package/dist/extensions/plugin-guides.d.ts +207 -54
- package/dist/extensions/plugin-guides.js +436 -165
- package/dist/files/previewers.d.ts +1 -1
- package/dist/files/previewers.js +1 -1
- package/dist/http/api.module.js +16 -6
- package/dist/http/gateway-routes.d.ts +1 -1
- package/dist/http/gateway-routes.js +1 -1
- package/dist/identity/settings.d.ts +32 -0
- package/dist/identity/settings.js +26 -2
- package/dist/infra/config/kernel-config.service.js +4 -4
- package/dist/infra/lock/lock.service.d.ts +8 -0
- package/dist/infra/lock/lock.service.js +27 -0
- package/dist/infra/throttler/named-throttlers.d.ts +4 -1
- package/dist/infra/throttler/named-throttlers.js +16 -1
- package/dist/infra/throttler/throttler.guard.js +1 -1
- package/dist/kernel.module.js +3 -3
- package/dist/{devices → local-devices}/device-auth.controller.d.ts +6 -6
- package/dist/{devices → local-devices}/device-auth.controller.js +5 -5
- package/dist/{devices → local-devices}/device-auth.d.ts +20 -20
- package/dist/{devices → local-devices}/device-auth.js +51 -53
- package/dist/local-devices/device-auth.module.d.ts +7 -0
- package/dist/{devices → local-devices}/device-auth.module.js +5 -5
- package/dist/{devices → local-devices}/device-routes.d.ts +3 -3
- package/dist/{devices → local-devices}/device-routes.js +2 -2
- package/dist/local-devices/dto.d.ts +66 -0
- package/dist/local-devices/dto.js +44 -0
- package/dist/{devices → local-devices}/keys.d.ts +11 -11
- package/dist/{devices → local-devices}/keys.js +11 -11
- package/dist/{devices/device-gateway.d.ts → local-devices/local-device-gateway.d.ts} +14 -14
- package/dist/{devices/device-gateway.js → local-devices/local-device-gateway.js} +44 -44
- package/dist/{devices/device-provider.d.ts → local-devices/local-device-provider.d.ts} +15 -15
- package/dist/{devices/device-provider.js → local-devices/local-device-provider.js} +23 -23
- package/dist/local-devices/local-devices.module.d.ts +16 -0
- package/dist/local-devices/local-devices.module.js +44 -0
- package/dist/{devices → local-devices}/machines.d.ts +26 -26
- package/dist/{devices → local-devices}/machines.js +71 -71
- package/dist/{devices → local-devices}/relay.d.ts +15 -15
- package/dist/{devices → local-devices}/relay.js +55 -55
- package/dist/{devices → local-devices}/targets.d.ts +8 -8
- package/dist/{devices → local-devices}/targets.js +14 -14
- package/dist/orgs/offboarding.d.ts +6 -6
- package/dist/orgs/offboarding.js +12 -12
- package/dist/orgs/settings.service.d.ts +28 -0
- package/dist/orgs/settings.service.js +20 -1
- package/dist/overrides.d.ts +3 -1
- package/dist/overrides.js +2 -0
- package/dist/platform/exclusions.js +48 -8
- package/dist/platform/operation.js +10 -2
- package/dist/platform/ops/admin.ops.js +8 -2
- package/dist/platform/ops/connectors.ops.js +2 -0
- package/dist/platform/ops/conversations.ops.d.ts +3 -3
- package/dist/platform/ops/conversations.ops.js +9 -9
- package/dist/platform/ops/devices.ops.d.ts +26 -0
- package/dist/platform/ops/devices.ops.js +311 -0
- package/dist/platform/ops/org-settings.ops.js +2 -2
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/setup.ops.d.ts +24 -0
- package/dist/platform/ops/setup.ops.js +212 -0
- package/dist/platform/ops/ui.ops.d.ts +8 -0
- package/dist/platform/ops/ui.ops.js +41 -0
- package/dist/platform/platform-ops.module.d.ts +4 -2
- package/dist/platform/platform-ops.module.js +13 -5
- package/dist/platform/route-schemas.js +11 -3
- package/dist/roles/gateway-role.d.ts +3 -3
- package/dist/roles/gateway-role.js +4 -4
- package/dist/roles/gateway.module.d.ts +1 -1
- package/dist/roles/gateway.module.js +5 -5
- package/dist/roles/worker.module.js +1 -1
- package/dist/runtime/context/build.d.ts +1 -1
- package/dist/runtime/context/build.js +6 -6
- package/dist/runtime/context/compaction.js +1 -1
- package/dist/runtime/context/{environment-paths.d.ts → device-paths.d.ts} +11 -11
- package/dist/runtime/context/{environment-paths.js → device-paths.js} +13 -13
- package/dist/runtime/maintenance.d.ts +1 -1
- package/dist/sandbox/jobs.d.ts +13 -13
- package/dist/sandbox/jobs.js +20 -20
- package/dist/sandbox/leases.d.ts +9 -9
- package/dist/sandbox/leases.js +14 -14
- package/dist/sandbox/providers.d.ts +8 -8
- package/dist/sandbox/providers.js +8 -8
- package/dist/sandbox/sandbox.module.d.ts +1 -1
- package/dist/sandbox/sandbox.module.js +1 -1
- package/dist/sandbox/sandbox.service.d.ts +76 -76
- package/dist/sandbox/sandbox.service.js +230 -230
- package/dist/setup/kernel-checks.d.ts +91 -0
- package/dist/setup/kernel-checks.js +295 -0
- package/dist/setup/oauth-token-probe.d.ts +47 -0
- package/dist/setup/oauth-token-probe.js +108 -0
- package/dist/setup/redact-check.d.ts +18 -0
- package/dist/setup/redact-check.js +46 -0
- package/dist/setup/setup-check-registry.d.ts +86 -0
- package/dist/setup/setup-check-registry.js +75 -0
- package/dist/setup/setup-checks.controller.d.ts +28 -0
- package/dist/setup/setup-checks.controller.js +78 -0
- package/dist/setup/setup-checks.schemas.d.ts +38 -0
- package/dist/setup/setup-checks.schemas.js +43 -0
- package/dist/setup/setup-checks.service.d.ts +144 -0
- package/dist/setup/setup-checks.service.js +683 -0
- package/dist/setup/setup-guides.controller.d.ts +18 -0
- package/dist/setup/setup-guides.controller.js +48 -0
- package/dist/setup/setup-guides.schemas.d.ts +10 -0
- package/dist/setup/setup-guides.schemas.js +6 -0
- package/dist/setup/setup-guides.service.d.ts +126 -0
- package/dist/setup/setup-guides.service.js +315 -0
- package/dist/setup/setup.module.d.ts +8 -0
- package/dist/setup/setup.module.js +31 -0
- package/dist/tools/builtins/builtin-tools.d.ts +2 -2
- package/dist/tools/builtins/builtin-tools.js +5 -5
- package/dist/tools/builtins/platform.js +1 -1
- package/dist/tools/builtins/sandbox/bash.js +6 -6
- package/dist/tools/builtins/sandbox/common.d.ts +25 -25
- package/dist/tools/builtins/sandbox/common.js +51 -51
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +6 -6
- package/dist/tools/builtins/sandbox/task-output.js +10 -10
- package/dist/tools/builtins/sandbox/task-stop.js +2 -2
- package/dist/tools/builtins/sandbox/write.js +2 -2
- package/dist/tools/builtins/skill-load.d.ts +1 -1
- package/dist/tools/builtins/skill-load.js +2 -2
- package/dist/tools/connectors.controller.d.ts +28 -11
- package/dist/tools/connectors.controller.js +49 -14
- package/dist/tools/connectors.schemas.d.ts +4 -0
- package/dist/tools/connectors.schemas.js +4 -0
- package/dist/tools/connectors.service.d.ts +30 -2
- package/dist/tools/connectors.service.js +98 -3
- package/dist/tools/credentials.d.ts +20 -0
- package/dist/tools/credentials.js +90 -1
- package/dist/tools/oauth/tokens.d.ts +20 -0
- package/dist/tools/oauth/tokens.js +49 -24
- package/dist/tools/pipeline.js +4 -3
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/tools.module.js +3 -3
- package/dist/ui/admin-ui.controller.d.ts +56 -0
- package/dist/ui/admin-ui.controller.js +192 -0
- package/dist/ui/arrangement.d.ts +74 -0
- package/dist/ui/arrangement.js +98 -0
- package/dist/ui/embed-token.d.ts +2 -2
- package/dist/ui/embed-token.js +30 -5
- package/dist/ui/registry.d.ts +29 -14
- package/dist/ui/registry.js +31 -10
- package/dist/ui/slots.controller.d.ts +11 -0
- package/dist/ui/slots.controller.js +25 -0
- package/dist/ui/ui-stream.d.ts +20 -3
- package/dist/ui/ui-stream.js +25 -7
- package/dist/ui/ui.schemas.d.ts +66 -0
- package/dist/ui/ui.schemas.js +65 -0
- package/dist/ui/views.controller.d.ts +35 -49
- package/dist/ui/views.controller.js +48 -70
- package/dist/ui/views.d.ts +84 -18
- package/dist/ui/views.js +201 -38
- package/package.json +3 -3
- package/src/migrations/0105_devices_rename.sql +136 -0
- package/src/migrations/0106_setup_guides_v2.sql +10 -0
- package/dist/devices/device-auth.module.d.ts +0 -7
- package/dist/environments/conversation-environments.d.ts +0 -75
- package/dist/environments/dto.d.ts +0 -25
- package/dist/environments/dto.js +0 -12
- package/dist/environments/environments.controller.d.ts +0 -36
- package/dist/environments/environments.module.d.ts +0 -8
- package/dist/environments/environments.module.js +0 -31
- package/dist/environments/environments.schemas.d.ts +0 -3
- package/dist/environments/environments.schemas.js +0 -14
- package/dist/environments/label.d.ts +0 -11
- package/dist/platform/ops/environments.ops.d.ts +0 -26
- package/dist/platform/ops/environments.ops.js +0 -311
package/dist/ui/embed-token.js
CHANGED
|
@@ -24,10 +24,12 @@ const B64URL = /^[A-Za-z0-9_-]+$/;
|
|
|
24
24
|
const PLUGIN_RE = /^[a-z][a-z0-9-]{1,40}$/;
|
|
25
25
|
const CLAIM_KEYS = new Set([
|
|
26
26
|
"plugin",
|
|
27
|
+
"scope",
|
|
27
28
|
"orgId",
|
|
28
29
|
"accountId",
|
|
29
30
|
"role",
|
|
30
31
|
"conversationId",
|
|
32
|
+
"agentId",
|
|
31
33
|
"fileId",
|
|
32
34
|
"contribution",
|
|
33
35
|
"exp",
|
|
@@ -44,7 +46,11 @@ function decodeStrict(s) {
|
|
|
44
46
|
const buf = Buffer.from(s, "base64url");
|
|
45
47
|
return buf.toString("base64url") === s ? buf : null;
|
|
46
48
|
}
|
|
47
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* 逐字段核对声明:只认已知字段、类型正确,返回只含已知字段的新对象。The scope decides the shape:
|
|
51
|
+
* `"platform"` exactly when `orgId` is absent and `role` is `"superAdmin"`, with no
|
|
52
|
+
* `conversationId` / `agentId` / `fileId`; `"org"` needs an `orgId` and one of the org roles.
|
|
53
|
+
*/
|
|
48
54
|
function parseClaims(v) {
|
|
49
55
|
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
50
56
|
return null;
|
|
@@ -53,22 +59,41 @@ function parseClaims(v) {
|
|
|
53
59
|
return null;
|
|
54
60
|
if (typeof c.plugin !== "string" || !PLUGIN_RE.test(c.plugin))
|
|
55
61
|
return null;
|
|
56
|
-
if (!isId(c.
|
|
62
|
+
if (!isId(c.accountId) || !isId(c.contribution))
|
|
57
63
|
return null;
|
|
58
|
-
if (!
|
|
64
|
+
if (typeof c.exp !== "number" || !Number.isSafeInteger(c.exp))
|
|
65
|
+
return null;
|
|
66
|
+
if (c.scope === "platform") {
|
|
67
|
+
if (c.orgId !== undefined || c.role !== "superAdmin")
|
|
68
|
+
return null;
|
|
69
|
+
if (c.conversationId !== undefined || c.agentId !== undefined || c.fileId !== undefined) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
plugin: c.plugin,
|
|
74
|
+
scope: "platform",
|
|
75
|
+
accountId: c.accountId,
|
|
76
|
+
role: "superAdmin",
|
|
77
|
+
contribution: c.contribution,
|
|
78
|
+
exp: c.exp,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (c.scope !== "org" || !isId(c.orgId) || !ROLES.has(c.role))
|
|
59
82
|
return null;
|
|
60
83
|
if (c.conversationId !== undefined && !isId(c.conversationId))
|
|
61
84
|
return null;
|
|
62
|
-
if (c.
|
|
85
|
+
if (c.agentId !== undefined && (!isId(c.agentId) || c.conversationId !== undefined))
|
|
63
86
|
return null;
|
|
64
|
-
if (
|
|
87
|
+
if (c.fileId !== undefined && (!isId(c.fileId) || c.conversationId === undefined))
|
|
65
88
|
return null;
|
|
66
89
|
return {
|
|
67
90
|
plugin: c.plugin,
|
|
91
|
+
scope: "org",
|
|
68
92
|
orgId: c.orgId,
|
|
69
93
|
accountId: c.accountId,
|
|
70
94
|
role: c.role,
|
|
71
95
|
...(c.conversationId !== undefined && { conversationId: c.conversationId }),
|
|
96
|
+
...(c.agentId !== undefined && { agentId: c.agentId }),
|
|
72
97
|
...(c.fileId !== undefined && { fileId: c.fileId }),
|
|
73
98
|
contribution: c.contribution,
|
|
74
99
|
exp: c.exp,
|
package/dist/ui/registry.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { ExtensionManifest, UiActionArgs, UiActionResult,
|
|
1
|
+
import type { ExtensionManifest, UiActionArgs, UiActionResult, UiRenderArgs, UiSlotSpec, UiView } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { type OrgRole } from "../orgs/roles.js";
|
|
3
3
|
/** 会话 id 的格式(UUID)。 */
|
|
4
4
|
export declare const UUID_RE: RegExp;
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare
|
|
5
|
+
/**
|
|
6
|
+
* Whether an org role may use contributions in this slot (UI slots spec §7): never a `superAdmin`
|
|
7
|
+
* slot (`platform.page` is served only by the org-less platform routes), else the slot's
|
|
8
|
+
* `minRole`. The slot's scope rule (conversation, agent, file) is checked after this.
|
|
9
|
+
*/
|
|
10
|
+
export declare function canUseSlot(slot: UiSlotSpec, role: OrgRole): boolean;
|
|
11
11
|
/** 插件视图的 render 函数(`ctx.ui.view` 注册)。 */
|
|
12
12
|
export type UiRender = (args: UiRenderArgs) => Promise<UiView>;
|
|
13
13
|
/** 插件视图的动作处理函数(`ctx.ui.action` 注册)。 */
|
|
@@ -17,7 +17,22 @@ export type UiActionHandler = (args: UiActionArgs) => Promise<UiActionResult>;
|
|
|
17
17
|
* 对话视图的刷新走会话主题 `conv.<id>`(与事件、增量共用),见 `conversationTopic`。
|
|
18
18
|
*/
|
|
19
19
|
export declare const orgUiTopic: (orgId: string) => string;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* The kernel bus topic of the platform refresh (namespace `kernel`): `ctx.ui.invalidate` of a
|
|
22
|
+
* `platform.page` contribution (no `orgId`), read by `GET /api/v1/admin/ui/stream`.
|
|
23
|
+
*/
|
|
24
|
+
export declare const PLATFORM_UI_TOPIC = "platform-ui";
|
|
25
|
+
/** A checked `ui.invalidate` target: an org's (optionally one conversation's) or the platform's. */
|
|
26
|
+
export type UiInvalidateTarget = {
|
|
27
|
+
scope: "org";
|
|
28
|
+
orgId: string;
|
|
29
|
+
conversationId?: string;
|
|
30
|
+
contribution: string;
|
|
31
|
+
} | {
|
|
32
|
+
scope: "platform";
|
|
33
|
+
contribution: string;
|
|
34
|
+
};
|
|
35
|
+
/** 界面刷新消息:`conv.<id>`、`org-ui.<orgId>` 与 `platform-ui` 上的 `{ kind: "ui", plugin, contribution }`。 */
|
|
21
36
|
export interface UiBusMessage {
|
|
22
37
|
kind: "ui";
|
|
23
38
|
plugin: string;
|
|
@@ -48,11 +63,11 @@ export declare class PluginUiRegistration {
|
|
|
48
63
|
seal(): void;
|
|
49
64
|
view(id: string, render: UiRender): void;
|
|
50
65
|
action(id: string, handler: UiActionHandler): void;
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
/**
|
|
67
|
+
* 校验 invalidate 的目标。A contribution in `platform` (the ids of the extension's `platform.page`
|
|
68
|
+
* contributions) takes no `orgId` and no `conversationId`; every other contribution needs an
|
|
69
|
+
* `orgId`.
|
|
70
|
+
*/
|
|
71
|
+
target(t: unknown, platform: ReadonlySet<string>): UiInvalidateTarget;
|
|
57
72
|
private register;
|
|
58
73
|
}
|
package/dist/ui/registry.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { roleAtLeast } from "../orgs/roles.js";
|
|
2
2
|
/** 会话 id 的格式(UUID)。 */
|
|
3
3
|
export const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
4
|
+
/**
|
|
5
|
+
* Whether an org role may use contributions in this slot (UI slots spec §7): never a `superAdmin`
|
|
6
|
+
* slot (`platform.page` is served only by the org-less platform routes), else the slot's
|
|
7
|
+
* `minRole`. The slot's scope rule (conversation, agent, file) is checked after this.
|
|
8
|
+
*/
|
|
9
|
+
export function canUseSlot(slot, role) {
|
|
10
|
+
return slot.minRole !== "superAdmin" && roleAtLeast(role, slot.minRole);
|
|
11
|
+
}
|
|
10
12
|
/**
|
|
11
13
|
* 组织级界面刷新的内核 bus 主题(命名空间 `kernel`):`org-ui.<orgId>`。
|
|
12
14
|
* 对话视图的刷新走会话主题 `conv.<id>`(与事件、增量共用),见 `conversationTopic`。
|
|
13
15
|
*/
|
|
14
16
|
export const orgUiTopic = (orgId) => `org-ui.${orgId}`;
|
|
17
|
+
/**
|
|
18
|
+
* The kernel bus topic of the platform refresh (namespace `kernel`): `ctx.ui.invalidate` of a
|
|
19
|
+
* `platform.page` contribution (no `orgId`), read by `GET /api/v1/admin/ui/stream`.
|
|
20
|
+
*/
|
|
21
|
+
export const PLATFORM_UI_TOPIC = "platform-ui";
|
|
15
22
|
/** 是否为界面刷新消息(bus 上的消息来自其他副本,按形状核对)。 */
|
|
16
23
|
export function isUiBusMessage(m) {
|
|
17
24
|
if (typeof m !== "object" || m === null)
|
|
@@ -52,13 +59,15 @@ export class PluginUiRegistration {
|
|
|
52
59
|
action(id, handler) {
|
|
53
60
|
this.register("action", this.actions, id, handler);
|
|
54
61
|
}
|
|
55
|
-
/**
|
|
56
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 校验 invalidate 的目标。A contribution in `platform` (the ids of the extension's `platform.page`
|
|
64
|
+
* contributions) takes no `orgId` and no `conversationId`; every other contribution needs an
|
|
65
|
+
* `orgId`.
|
|
66
|
+
*/
|
|
67
|
+
target(t, platform) {
|
|
57
68
|
const name = this.manifest.name;
|
|
58
69
|
const x = (typeof t === "object" && t !== null ? t : {});
|
|
59
70
|
const id = (v) => typeof v === "string" && v !== "" && v.length <= 200;
|
|
60
|
-
if (!id(x.orgId))
|
|
61
|
-
throw new Error(`plugin ${name}: ui.invalidate needs a non-empty orgId`);
|
|
62
71
|
if (x.conversationId !== undefined &&
|
|
63
72
|
(typeof x.conversationId !== "string" || !UUID_RE.test(x.conversationId))) {
|
|
64
73
|
throw new Error(`plugin ${name}: ui.invalidate conversationId must be a UUID`);
|
|
@@ -66,7 +75,19 @@ export class PluginUiRegistration {
|
|
|
66
75
|
if (typeof x.contribution !== "string" || !this.contributions.has(x.contribution)) {
|
|
67
76
|
throw new Error(`plugin ${name}: ui.invalidate: ${JSON.stringify(x.contribution)} is not a ui contribution in the manifest`);
|
|
68
77
|
}
|
|
78
|
+
if (platform.has(x.contribution)) {
|
|
79
|
+
if (x.orgId !== undefined) {
|
|
80
|
+
throw new Error(`plugin ${name}: ui.invalidate: ${x.contribution} is a platform page; omit orgId`);
|
|
81
|
+
}
|
|
82
|
+
if (x.conversationId !== undefined) {
|
|
83
|
+
throw new Error(`plugin ${name}: ui.invalidate: ${x.contribution} is a platform page; omit conversationId`);
|
|
84
|
+
}
|
|
85
|
+
return { scope: "platform", contribution: x.contribution };
|
|
86
|
+
}
|
|
87
|
+
if (!id(x.orgId))
|
|
88
|
+
throw new Error(`plugin ${name}: ui.invalidate needs a non-empty orgId`);
|
|
69
89
|
return {
|
|
90
|
+
scope: "org",
|
|
70
91
|
orgId: x.orgId,
|
|
71
92
|
...(x.conversationId !== undefined && { conversationId: x.conversationId }),
|
|
72
93
|
contribution: x.contribution,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type UiSlotSpec } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* The slot catalog (UI slots spec §3): every slot an extension can contribute to, verbatim from
|
|
4
|
+
* the SDK. Static, so any signed-in person may read it; no org is involved.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SlotsController {
|
|
7
|
+
/** `GET /api/v1/ui/slots` → `{ slots }`. */
|
|
8
|
+
slots(): {
|
|
9
|
+
slots: readonly UiSlotSpec[];
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { UI_SLOTS } from "@capybara-hq/plugin-sdk";
|
|
8
|
+
import { Controller, Get } from "@nestjs/common";
|
|
9
|
+
/**
|
|
10
|
+
* The slot catalog (UI slots spec §3): every slot an extension can contribute to, verbatim from
|
|
11
|
+
* the SDK. Static, so any signed-in person may read it; no org is involved.
|
|
12
|
+
*/
|
|
13
|
+
let SlotsController = class SlotsController {
|
|
14
|
+
/** `GET /api/v1/ui/slots` → `{ slots }`. */
|
|
15
|
+
slots() {
|
|
16
|
+
return { slots: UI_SLOTS };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
__decorate([
|
|
20
|
+
Get("slots")
|
|
21
|
+
], SlotsController.prototype, "slots", null);
|
|
22
|
+
SlotsController = __decorate([
|
|
23
|
+
Controller("api/v1/ui")
|
|
24
|
+
], SlotsController);
|
|
25
|
+
export { SlotsController };
|
package/dist/ui/ui-stream.d.ts
CHANGED
|
@@ -6,20 +6,37 @@ import { GracefulShutdown } from "../infra/lifecycle/graceful-shutdown.service.j
|
|
|
6
6
|
import { type OrgRole } from "../orgs/roles.js";
|
|
7
7
|
import { type SseOutput, type StreamBus, type StreamHandle } from "../runtime/stream.js";
|
|
8
8
|
export interface OrgUiStreamParams {
|
|
9
|
+
scope?: "org";
|
|
9
10
|
orgId: string;
|
|
10
11
|
viewerAccountId: string;
|
|
11
12
|
credential: CredentialCheck;
|
|
12
13
|
}
|
|
14
|
+
/** The platform refresh stream (`GET /api/v1/admin/ui/stream`): a super admin's, no org. */
|
|
15
|
+
export interface PlatformUiStreamParams {
|
|
16
|
+
scope: "platform";
|
|
17
|
+
viewerAccountId: string;
|
|
18
|
+
credential: CredentialCheck;
|
|
19
|
+
}
|
|
20
|
+
export type UiStreamParams = OrgUiStreamParams | PlatformUiStreamParams;
|
|
13
21
|
/** The org role the org UI stream re-checks. */
|
|
14
22
|
export declare class UiStreamMembership {
|
|
15
23
|
private readonly db;
|
|
16
24
|
constructor(db: KernelDb);
|
|
17
25
|
/** 组织成员角色(一条查询):组织未删除、账号 active、仍有成员关系。 */
|
|
18
26
|
role(orgId: string, accountId: string): Promise<OrgRole | undefined>;
|
|
27
|
+
/** Whether the account is an active super admin (one query). */
|
|
28
|
+
superAdmin(accountId: string): Promise<boolean>;
|
|
19
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* The org refresh stream is member and above (UI slots spec §7): it carries `org.page` and
|
|
32
|
+
* `org.settings.section` refreshes; an `agent.detail.section` a guest views refreshes on navigation.
|
|
33
|
+
*/
|
|
34
|
+
export declare const ORG_STREAM_MIN_ROLE: OrgRole;
|
|
20
35
|
/**
|
|
21
36
|
* 组织级界面刷新流(SSE):订阅内核主题 `org-ui.<orgId>`,把插件 `ctx.ui.invalidate`(不带对话)的刷新
|
|
22
|
-
* 转发为 `event: ui`(`data: {"plugin","contribution"}
|
|
37
|
+
* 转发为 `event: ui`(`data: {"plugin","contribution"}`)。The platform variant subscribes
|
|
38
|
+
* `platform-ui` (`invalidate` of a `platform.page`, no org) for a super admin, re-checked on the
|
|
39
|
+
* same interval (losing super admin ends it with `event: error`, code `forbidden`).跨副本只经 Redis bus;进程内只持有连接本身的资源
|
|
23
40
|
* (订阅、心跳与复核定时器),停机时一并关闭。
|
|
24
41
|
*/
|
|
25
42
|
export declare class OrgUiStreams {
|
|
@@ -33,9 +50,9 @@ export declare class OrgUiStreams {
|
|
|
33
50
|
* an event stream. Without `GracefulShutdown` (a standalone HTTP application, tests only) the
|
|
34
51
|
* streams end with their connections.
|
|
35
52
|
*/
|
|
36
|
-
constructor(bus: StreamBus, membership: Pick<UiStreamMembership, "role">, config: Pick<KernelConfigService, "get">, log: Pick<Logger, "warn">, shutdown?: Pick<GracefulShutdown, "signal">);
|
|
53
|
+
constructor(bus: StreamBus, membership: Pick<UiStreamMembership, "role" | "superAdmin">, config: Pick<KernelConfigService, "get">, log: Pick<Logger, "warn">, shutdown?: Pick<GracefulShutdown, "signal">);
|
|
37
54
|
/** 复核凭据与成员关系并订阅;失败时尚未写响应,调用方按普通错误返回。 */
|
|
38
|
-
open(p:
|
|
55
|
+
open(p: UiStreamParams, out: SseOutput): Promise<StreamHandle>;
|
|
39
56
|
/** Closes every stream of this process (at shutdown) and latches, like `ConversationStreams`. */
|
|
40
57
|
closeAll(): void;
|
|
41
58
|
get size(): number;
|
package/dist/ui/ui-stream.js
CHANGED
|
@@ -8,6 +8,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
10
|
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
11
|
+
import { currentPlatformAccount } from "../ctx/create-ctx.js";
|
|
11
12
|
import { ApiError } from "../errors.js";
|
|
12
13
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
13
14
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
@@ -15,7 +16,9 @@ import { GracefulShutdown } from "../infra/lifecycle/graceful-shutdown.service.j
|
|
|
15
16
|
import { KERNEL_BUS, KERNEL_LOGGER } from "../infra/tokens.js";
|
|
16
17
|
import { roleAtLeast } from "../orgs/roles.js";
|
|
17
18
|
import { endedStream, } from "../runtime/stream.js";
|
|
18
|
-
import { isUiBusMessage, orgUiTopic,
|
|
19
|
+
import { isUiBusMessage, orgUiTopic, PLATFORM_UI_TOPIC, uiFrame } from "./registry.js";
|
|
20
|
+
/** The log field naming the stream: its org, or the platform scope. */
|
|
21
|
+
const whereOf = (p) => p.scope === "platform" ? { scope: "platform" } : { orgId: p.orgId };
|
|
19
22
|
/** The org role the org UI stream re-checks. */
|
|
20
23
|
let UiStreamMembership = class UiStreamMembership {
|
|
21
24
|
db;
|
|
@@ -36,26 +39,39 @@ let UiStreamMembership = class UiStreamMembership {
|
|
|
36
39
|
.executeTakeFirst();
|
|
37
40
|
return row?.role;
|
|
38
41
|
}
|
|
42
|
+
/** Whether the account is an active super admin (one query). */
|
|
43
|
+
superAdmin(accountId) {
|
|
44
|
+
return currentPlatformAccount(this.db.db, accountId);
|
|
45
|
+
}
|
|
39
46
|
};
|
|
40
47
|
UiStreamMembership = __decorate([
|
|
41
48
|
Injectable(),
|
|
42
49
|
__param(0, Inject(KernelDb))
|
|
43
50
|
], UiStreamMembership);
|
|
44
51
|
export { UiStreamMembership };
|
|
52
|
+
/**
|
|
53
|
+
* The org refresh stream is member and above (UI slots spec §7): it carries `org.page` and
|
|
54
|
+
* `org.settings.section` refreshes; an `agent.detail.section` a guest views refreshes on navigation.
|
|
55
|
+
*/
|
|
56
|
+
export const ORG_STREAM_MIN_ROLE = "member";
|
|
45
57
|
async function authorize(d, p) {
|
|
46
58
|
const denied = await p.credential();
|
|
47
59
|
if (denied !== null)
|
|
48
60
|
return denied;
|
|
61
|
+
if (p.scope === "platform")
|
|
62
|
+
return (await d.superAdmin(p.viewerAccountId)) ? null : "forbidden";
|
|
49
63
|
const role = await d.memberRole(p.orgId, p.viewerAccountId);
|
|
50
64
|
if (role === undefined)
|
|
51
65
|
return "org.not_found";
|
|
52
|
-
return roleAtLeast(role,
|
|
66
|
+
return roleAtLeast(role, ORG_STREAM_MIN_ROLE) ? null : "ui.not_found";
|
|
53
67
|
}
|
|
54
68
|
/** 慢客户端的积压上限(刷新帧很小,超过即说明客户端不读了)。 */
|
|
55
69
|
const MAX_BACKLOG_BYTES = 1024 * 1024;
|
|
56
70
|
/**
|
|
57
71
|
* 组织级界面刷新流(SSE):订阅内核主题 `org-ui.<orgId>`,把插件 `ctx.ui.invalidate`(不带对话)的刷新
|
|
58
|
-
* 转发为 `event: ui`(`data: {"plugin","contribution"}
|
|
72
|
+
* 转发为 `event: ui`(`data: {"plugin","contribution"}`)。The platform variant subscribes
|
|
73
|
+
* `platform-ui` (`invalidate` of a `platform.page`, no org) for a super admin, re-checked on the
|
|
74
|
+
* same interval (losing super admin ends it with `event: error`, code `forbidden`).跨副本只经 Redis bus;进程内只持有连接本身的资源
|
|
59
75
|
* (订阅、心跳与复核定时器),停机时一并关闭。
|
|
60
76
|
*/
|
|
61
77
|
let OrgUiStreams = class OrgUiStreams {
|
|
@@ -73,6 +89,7 @@ let OrgUiStreams = class OrgUiStreams {
|
|
|
73
89
|
this.d = {
|
|
74
90
|
bus,
|
|
75
91
|
memberRole: (orgId, accountId) => membership.role(orgId, accountId),
|
|
92
|
+
superAdmin: (accountId) => membership.superAdmin(accountId),
|
|
76
93
|
config,
|
|
77
94
|
log,
|
|
78
95
|
};
|
|
@@ -140,7 +157,8 @@ class OrgUiConnection {
|
|
|
140
157
|
this.onClosed = onClosed;
|
|
141
158
|
}
|
|
142
159
|
async subscribe() {
|
|
143
|
-
const
|
|
160
|
+
const topic = this.p.scope === "platform" ? PLATFORM_UI_TOPIC : orgUiTopic(this.p.orgId);
|
|
161
|
+
const un = await this.d.bus.subscribe(topic, (m) => {
|
|
144
162
|
// begin() 之前(响应头还没写)到达的刷新丢掉:网页连上后会先取一次视图
|
|
145
163
|
if (this.begun && isUiBusMessage(m))
|
|
146
164
|
this.write(uiFrame(m));
|
|
@@ -166,7 +184,7 @@ class OrgUiConnection {
|
|
|
166
184
|
this.timers = [];
|
|
167
185
|
const un = this.unsubscribe;
|
|
168
186
|
this.unsubscribe = undefined;
|
|
169
|
-
un?.().catch((err) => this.d.log.warn("org ui stream unsubscribe failed", {
|
|
187
|
+
un?.().catch((err) => this.d.log.warn("org ui stream unsubscribe failed", { ...whereOf(this.p), err }));
|
|
170
188
|
if (this.begun) {
|
|
171
189
|
try {
|
|
172
190
|
if (mode === "abort")
|
|
@@ -191,7 +209,7 @@ class OrgUiConnection {
|
|
|
191
209
|
return;
|
|
192
210
|
}
|
|
193
211
|
if (this.out.backlog() > MAX_BACKLOG_BYTES) {
|
|
194
|
-
this.d.log.warn("org ui stream client too slow; closing",
|
|
212
|
+
this.d.log.warn("org ui stream client too slow; closing", whereOf(this.p));
|
|
195
213
|
this.close("abort");
|
|
196
214
|
}
|
|
197
215
|
}
|
|
@@ -206,7 +224,7 @@ class OrgUiConnection {
|
|
|
206
224
|
}
|
|
207
225
|
catch (err) {
|
|
208
226
|
this.d.log.warn("org ui stream access re-check failed; closing", {
|
|
209
|
-
|
|
227
|
+
...whereOf(this.p),
|
|
210
228
|
err,
|
|
211
229
|
});
|
|
212
230
|
code = "internal";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { RouteSchemas } from "../platform/route-schemas.js";
|
|
3
|
+
/** The contribution named in a view / action / embed path (`:plugin/:id`). */
|
|
4
|
+
export declare const ContributionParams: z.ZodObject<{
|
|
5
|
+
plugin: z.ZodString;
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
/** `GET contributions?slot=`: one catalog slot, or every org-reachable slot when omitted. */
|
|
9
|
+
export declare const ContributionsQuery: z.ZodObject<{
|
|
10
|
+
slot: z.ZodOptional<z.ZodEnum<{
|
|
11
|
+
"agent.detail.section": "agent.detail.section";
|
|
12
|
+
"conversation.panel": "conversation.panel";
|
|
13
|
+
"conversation.properties.section": "conversation.properties.section";
|
|
14
|
+
"conversation.tool-result.card": "conversation.tool-result.card";
|
|
15
|
+
"file.preview": "file.preview";
|
|
16
|
+
"org.page": "org.page";
|
|
17
|
+
"org.settings.section": "org.settings.section";
|
|
18
|
+
"platform.page": "platform.page";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
export declare const ViewQuery: z.ZodObject<{
|
|
22
|
+
conversationId: z.ZodOptional<z.ZodString>;
|
|
23
|
+
agentId: z.ZodOptional<z.ZodUUID>;
|
|
24
|
+
locale: z.ZodDefault<z.ZodEnum<{
|
|
25
|
+
en: "en";
|
|
26
|
+
zh: "zh";
|
|
27
|
+
}>>;
|
|
28
|
+
item: z.ZodOptional<z.ZodString>;
|
|
29
|
+
callId: z.ZodOptional<z.ZodString>;
|
|
30
|
+
key: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export declare const ActionBody: z.ZodObject<{
|
|
33
|
+
actionId: z.ZodString;
|
|
34
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
35
|
+
answer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
36
|
+
conversationId: z.ZodOptional<z.ZodString>;
|
|
37
|
+
agentId: z.ZodOptional<z.ZodUUID>;
|
|
38
|
+
locale: z.ZodDefault<z.ZodEnum<{
|
|
39
|
+
en: "en";
|
|
40
|
+
zh: "zh";
|
|
41
|
+
}>>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
export declare const EmbedTokenBody: z.ZodDefault<z.ZodObject<{
|
|
44
|
+
conversationId: z.ZodOptional<z.ZodString>;
|
|
45
|
+
agentId: z.ZodOptional<z.ZodUUID>;
|
|
46
|
+
fileId: z.ZodOptional<z.ZodUUID>;
|
|
47
|
+
}, z.core.$strip>>;
|
|
48
|
+
/** `GET /api/v1/admin/ui/views/:plugin/:id?locale=`: a platform page takes no context id. */
|
|
49
|
+
export declare const PlatformViewQuery: z.ZodObject<{
|
|
50
|
+
locale: z.ZodDefault<z.ZodEnum<{
|
|
51
|
+
en: "en";
|
|
52
|
+
zh: "zh";
|
|
53
|
+
}>>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
/** `POST /api/v1/admin/ui/actions/:plugin/:id`: an action of a platform page (no context id). */
|
|
56
|
+
export declare const PlatformActionBody: z.ZodObject<{
|
|
57
|
+
actionId: z.ZodString;
|
|
58
|
+
payload: z.ZodOptional<z.ZodUnknown>;
|
|
59
|
+
answer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
|
|
60
|
+
locale: z.ZodDefault<z.ZodEnum<{
|
|
61
|
+
en: "en";
|
|
62
|
+
zh: "zh";
|
|
63
|
+
}>>;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
/** The slot catalog route the Platform operation `ui.slots` mirrors (`check:platform-ops` key). */
|
|
66
|
+
export declare const UI_ROUTES: readonly RouteSchemas[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { UI_LIMITS, UI_SLOT_IDS } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/** The DTO schemas of the org UI routes (`views.controller.ts`). */
|
|
4
|
+
const Locale = z.enum(["zh", "en"]).default("en");
|
|
5
|
+
const Id = z.string().min(1).max(100);
|
|
6
|
+
/** The contribution named in a view / action / embed path (`:plugin/:id`). */
|
|
7
|
+
export const ContributionParams = z.object({ plugin: Id, id: Id });
|
|
8
|
+
/** `GET contributions?slot=`: one catalog slot, or every org-reachable slot when omitted. */
|
|
9
|
+
export const ContributionsQuery = z.object({ slot: z.enum(UI_SLOT_IDS).optional() });
|
|
10
|
+
export const ViewQuery = z
|
|
11
|
+
.object({
|
|
12
|
+
conversationId: z.string().min(1).max(100).optional(),
|
|
13
|
+
/** Only an agent view (`agent.detail.section`). */
|
|
14
|
+
agentId: z.uuid().optional(),
|
|
15
|
+
locale: Locale,
|
|
16
|
+
/** A panel opened from an open target: the item to scroll to. */
|
|
17
|
+
item: z.string().min(1).max(200).optional(),
|
|
18
|
+
/** An inline card: the tool call it hangs off, and its `ToolResult.card.key`. */
|
|
19
|
+
callId: z.string().min(1).max(200).optional(),
|
|
20
|
+
key: z.string().min(1).max(200).optional(),
|
|
21
|
+
})
|
|
22
|
+
.refine((q) => q.key === undefined || q.callId !== undefined, {
|
|
23
|
+
message: "key needs callId",
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* 表单答案(plugin-sdk 的 `FormAnswer`)。SDK 的 InputForm 没有单独的字段数 / 选项数上限,
|
|
27
|
+
* 这里沿用视图的上限:键数与多选数组长度 ≤ `UI_LIMITS.tableRows`,单个文本 ≤ `UI_LIMITS.textChars`。
|
|
28
|
+
*/
|
|
29
|
+
const AnswerText = z.string().max(UI_LIMITS.textChars);
|
|
30
|
+
const FormAnswerSchema = z
|
|
31
|
+
.record(z.string().max(100), z.union([AnswerText, z.number(), z.boolean(), z.array(AnswerText).max(UI_LIMITS.tableRows)]))
|
|
32
|
+
.refine((a) => Object.keys(a).length <= UI_LIMITS.tableRows, {
|
|
33
|
+
message: `answer must have at most ${UI_LIMITS.tableRows} fields`,
|
|
34
|
+
});
|
|
35
|
+
/** 按钮 payload 的 JSON 序列化后 UTF-8 字节数(与 `validateUiView` 对按钮 payload 的上限一致)。 */
|
|
36
|
+
const payloadBytes = (v) => Buffer.byteLength(JSON.stringify(v) ?? "", "utf8");
|
|
37
|
+
export const ActionBody = z.object({
|
|
38
|
+
actionId: z.string().min(1).max(200),
|
|
39
|
+
payload: z
|
|
40
|
+
.unknown()
|
|
41
|
+
.optional()
|
|
42
|
+
.refine((v) => v === undefined || payloadBytes(v) <= UI_LIMITS.payloadBytes, {
|
|
43
|
+
message: `payload must be at most ${UI_LIMITS.payloadBytes} bytes as JSON`,
|
|
44
|
+
}),
|
|
45
|
+
answer: FormAnswerSchema.optional(),
|
|
46
|
+
conversationId: z.string().min(1).max(100).optional(),
|
|
47
|
+
/** Only an agent view (`agent.detail.section`). */
|
|
48
|
+
agentId: z.uuid().optional(),
|
|
49
|
+
locale: Locale,
|
|
50
|
+
});
|
|
51
|
+
export const EmbedTokenBody = z
|
|
52
|
+
.object({
|
|
53
|
+
conversationId: z.string().min(1).max(100).optional(),
|
|
54
|
+
/** Only an agent embed (`agent.detail.section`). */
|
|
55
|
+
agentId: z.uuid().optional(),
|
|
56
|
+
/** Only a `file.preview` embed: the file version it previews. */
|
|
57
|
+
fileId: z.uuid().optional(),
|
|
58
|
+
})
|
|
59
|
+
.default({});
|
|
60
|
+
/** `GET /api/v1/admin/ui/views/:plugin/:id?locale=`: a platform page takes no context id. */
|
|
61
|
+
export const PlatformViewQuery = z.object({ locale: Locale });
|
|
62
|
+
/** `POST /api/v1/admin/ui/actions/:plugin/:id`: an action of a platform page (no context id). */
|
|
63
|
+
export const PlatformActionBody = ActionBody.omit({ conversationId: true, agentId: true });
|
|
64
|
+
/** The slot catalog route the Platform operation `ui.slots` mirrors (`check:platform-ops` key). */
|
|
65
|
+
export const UI_ROUTES = [{ route: "GET /api/v1/ui/slots" }];
|