@k2b/cloud 0.24.0 → 0.26.0
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/package.json +3 -2
- package/src/_internal/capabilities.ts +12 -0
- package/src/_internal/registry.ts +1 -0
- package/src/access/GroupCoverage.tsx +175 -0
- package/src/access/PermissionEditor.tsx +134 -93
- package/src/access/managers.ts +32 -0
- package/src/access/messages.ts +36 -0
- package/src/ai/approval-routes.ts +5 -5
- package/src/ai/capabilities.ts +34 -12
- package/src/ai/chat/blocks.tsx +86 -179
- package/src/ai/chat/builtin-tools.tsx +57 -30
- package/src/ai/chat/live-turn.browser-harness.tsx +37 -0
- package/src/ai/chat/message-actions.tsx +6 -2
- package/src/ai/chat/message-utils.ts +17 -14
- package/src/ai/chat/messages.ts +324 -2
- package/src/ai/chat/presentation.tsx +257 -103
- package/src/ai/chat/tool-groups.ts +55 -35
- package/src/ai/chat/turn-layout.ts +141 -0
- package/src/ai/chat/turn-view.tsx +609 -0
- package/src/ai/client/projection.ts +37 -6
- package/src/ai/executor.ts +38 -5
- package/src/ai/memory-learning.ts +7 -12
- package/src/ai/memory-workflow-evidence.ts +10 -2
- package/src/ai/migrate.ts +45 -2
- package/src/ai/model-access.ts +4 -2
- package/src/ai/prefs.ts +19 -5
- package/src/ai/projects.ts +5 -2
- package/src/ai/protocol.ts +20 -4
- package/src/ai/provider-fetch.ts +67 -15
- package/src/ai/provider-retry.ts +105 -0
- package/src/ai/quota-provider.ts +14 -5
- package/src/ai/skills.ts +5 -2
- package/src/ai/store.ts +108 -3
- package/src/ai/stream.ts +2 -0
- package/src/ai/timeline.ts +9 -11
- package/src/ai/turn-timing.ts +31 -3
- package/src/ai/types.ts +12 -2
- package/src/browser/FileChooser.tsx +600 -0
- package/src/browser/choose-files.browser-harness.tsx +32 -0
- package/src/browser/choose-files.tsx +70 -0
- package/src/browser/file-chooser-messages.ts +86 -0
- package/src/browser/file-providers.ts +217 -0
- package/src/browser/files.tsx +23 -0
- package/src/cli/admin/account-administration.ts +2 -2
- package/src/contracts/registry.ts +2 -0
- package/src/server/index.ts +1 -0
- package/src/server/services/access.ts +44 -11
- package/src/server/services/index.ts +1 -0
- package/src/shared/app-presentation.ts +10 -2
- package/src/ssr/platform-messages.ts +2 -2
- package/src/styles/effects.css +69 -0
- package/src/styles/file-chooser.css +169 -0
- package/src/styles/global.css +1 -0
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { listCapabilities } from "../_internal/registry";
|
|
5
5
|
import { ErrorResponseSchema } from "../contracts";
|
|
6
6
|
import type { CapabilityRegistryEntry } from "../contracts/registry";
|
|
7
|
-
import { type AuthContext, auth, expectUserBackedActor, jsonResponse, rateLimit, requiresAuth, v } from "../server";
|
|
7
|
+
import { type AuthContext, auth, expectUserBackedActor, getLocale, jsonResponse, rateLimit, requiresAuth, v } from "../server";
|
|
8
8
|
import { type AiToolApprovalPreference, listAiToolApprovalPreferences, revokeAiToolApprovalPreference } from "./approvals";
|
|
9
9
|
import { buildAiCapabilityCatalog } from "./capabilities";
|
|
10
10
|
|
|
@@ -70,7 +70,7 @@ export const createAiApprovalPreferenceRoutes = (dependencies: AiApprovalRouteDe
|
|
|
70
70
|
describeRoute({
|
|
71
71
|
tags: ["AI"],
|
|
72
72
|
summary: "List remembered AI approvals",
|
|
73
|
-
description: "Lists AI tool approvals remembered for the current user.",
|
|
73
|
+
description: "Lists AI tool approvals remembered for the current user, with titles in the request locale.",
|
|
74
74
|
...requiresAuth,
|
|
75
75
|
responses: {
|
|
76
76
|
200: jsonResponse(AiApprovalPreferenceListSchema, "Remembered approvals"),
|
|
@@ -84,16 +84,16 @@ export const createAiApprovalPreferenceRoutes = (dependencies: AiApprovalRouteDe
|
|
|
84
84
|
listPreferences(user.id),
|
|
85
85
|
registry().catch(() => [] as CapabilityRegistryEntry[]),
|
|
86
86
|
]);
|
|
87
|
-
const catalogByName = new Map(buildAiCapabilityCatalog(capabilities).map((entry) => [entry.name, entry]));
|
|
87
|
+
const catalogByName = new Map(buildAiCapabilityCatalog(capabilities, getLocale(c)).map((entry) => [entry.name, entry]));
|
|
88
88
|
const approvals: AiApprovalPreferenceView[] = preferences.map((preference) => {
|
|
89
89
|
const capability = catalogByName.get(preference.toolName);
|
|
90
90
|
return {
|
|
91
91
|
...preference,
|
|
92
|
-
title: capability?.title ?? fallbackTitle(preference.toolName),
|
|
92
|
+
title: capability?.display.title ?? fallbackTitle(preference.toolName),
|
|
93
93
|
app: capability
|
|
94
94
|
? {
|
|
95
95
|
id: capability.appId,
|
|
96
|
-
name: capability.appName,
|
|
96
|
+
name: capability.display.appName,
|
|
97
97
|
icon: capability.app.appIcon,
|
|
98
98
|
...(capability.app.appAccent ? { accent: capability.app.appAccent } : {}),
|
|
99
99
|
}
|
package/src/ai/capabilities.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import type { Tool, ToolContext, ToolResolver } from "@k2b/nessi";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { resolveCapabilityOperationTitle } from "../_internal/capabilities";
|
|
4
5
|
import { HELP_READ_MAX_CHARS, HELP_SEARCH_MAX_LIMIT, readHelpArticle } from "../_internal/help-catalog";
|
|
5
6
|
import {
|
|
6
7
|
type CapabilityActionManifest,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
import type { CapabilityRegistryEntry } from "../contracts/registry";
|
|
14
15
|
import type { RequestActor } from "../server";
|
|
15
16
|
import { createHelpReader, type HelpReaderFactory } from "../services/help";
|
|
17
|
+
import { resolveAppIdentityPresentation } from "../shared/app-presentation";
|
|
16
18
|
import { recordRejectedAiCapability } from "./capability-execution";
|
|
17
19
|
import { CODE_SOURCE_TOOLS } from "./code-source-contracts";
|
|
18
20
|
import { createCodeSourceTool } from "./code-source-tools";
|
|
@@ -44,6 +46,12 @@ export type AiCapabilityAppCatalogItem = {
|
|
|
44
46
|
export type AiCapabilityCatalogEntry = AiCapabilityCatalogItem & {
|
|
45
47
|
app: CapabilityRegistryEntry;
|
|
46
48
|
operation: CapabilityQueryManifest | CapabilityActionManifest;
|
|
49
|
+
/**
|
|
50
|
+
* What people see in tool rows and approvals, in the locale the catalog was built for. The model keeps
|
|
51
|
+
* the base `title`, `description`, and schemas: they are prompt text, and stable prompts do not change
|
|
52
|
+
* with the reader's language.
|
|
53
|
+
*/
|
|
54
|
+
display: { appName: string; title: string };
|
|
47
55
|
};
|
|
48
56
|
|
|
49
57
|
export type AiToolKind = "builtin" | AiCapabilityKind;
|
|
@@ -109,8 +117,11 @@ export const buildAiCapabilityAppCatalog = (apps: readonly CapabilityRegistryEnt
|
|
|
109
117
|
});
|
|
110
118
|
};
|
|
111
119
|
|
|
112
|
-
/**
|
|
113
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Build one deterministic, immutable view of the current live registry. `locale` selects the human
|
|
122
|
+
* presentation in `display`; model-facing fields always stay in the app's base presentation.
|
|
123
|
+
*/
|
|
124
|
+
export const buildAiCapabilityCatalog = (apps: CapabilityRegistryEntry[], locale?: string): AiCapabilityCatalogEntry[] => {
|
|
114
125
|
const entries = [...apps]
|
|
115
126
|
.sort(
|
|
116
127
|
(left, right) =>
|
|
@@ -119,12 +130,18 @@ export const buildAiCapabilityCatalog = (apps: CapabilityRegistryEntry[]): AiCap
|
|
|
119
130
|
left.appName.localeCompare(right.appName) ||
|
|
120
131
|
left.endpoint.localeCompare(right.endpoint),
|
|
121
132
|
)
|
|
122
|
-
.flatMap((app) =>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
.flatMap((app) => {
|
|
134
|
+
const appName = locale
|
|
135
|
+
? resolveAppIdentityPresentation({ name: app.appName, description: app.appDescription, presentation: app.appPresentation }, locale)
|
|
136
|
+
.name
|
|
137
|
+
: app.appName;
|
|
138
|
+
return [
|
|
139
|
+
...app.manifest.actions.map((operation) => ({ app, appName, operation, kind: "action" as const })),
|
|
140
|
+
...app.manifest.queries.map((operation) => ({ app, appName, operation, kind: "query" as const })),
|
|
141
|
+
];
|
|
142
|
+
})
|
|
126
143
|
.map(
|
|
127
|
-
({ app, operation, kind }): AiCapabilityCatalogEntry => ({
|
|
144
|
+
({ app, appName, operation, kind }): AiCapabilityCatalogEntry => ({
|
|
128
145
|
name: aiCapabilityId(app.appId, operation.localId),
|
|
129
146
|
providerName: aiCapabilityToolName(app.appId, kind, operation.localId),
|
|
130
147
|
appId: app.appId,
|
|
@@ -135,6 +152,12 @@ export const buildAiCapabilityCatalog = (apps: CapabilityRegistryEntry[]): AiCap
|
|
|
135
152
|
description: operation.description,
|
|
136
153
|
app,
|
|
137
154
|
operation,
|
|
155
|
+
display: {
|
|
156
|
+
appName,
|
|
157
|
+
title: locale
|
|
158
|
+
? resolveCapabilityOperationTitle(operation, kind === "action" ? "actions" : "queries", app.presentation, locale)
|
|
159
|
+
: operation.title,
|
|
160
|
+
},
|
|
138
161
|
}),
|
|
139
162
|
)
|
|
140
163
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
@@ -566,8 +589,7 @@ export const createLoadedAiCapabilityTools = (input: {
|
|
|
566
589
|
if (!input.authorizeBackground && entry.kind === "action" && (entry.operation as CapabilityActionManifest).approval !== "none") {
|
|
567
590
|
const review = (await input.review?.(entry, args, context)) ?? null;
|
|
568
591
|
if (review && context.callId) input.onReview?.(context.callId, review);
|
|
569
|
-
const message =
|
|
570
|
-
review?.message ?? `${entry.appName}: ${entry.title}\nReview the validated arguments below before running this Action.`;
|
|
592
|
+
const message = review?.message ?? `${entry.display.appName}: ${entry.display.title}`;
|
|
571
593
|
if (!(await context.requestApproval(message))) {
|
|
572
594
|
if (input.actor.kind === "user") {
|
|
573
595
|
await recordRejectedAiCapability({ entry, actor: input.actor, args }).catch(() => undefined);
|
|
@@ -667,7 +689,7 @@ export const createAiToolResolver =
|
|
|
667
689
|
});
|
|
668
690
|
}
|
|
669
691
|
const allowed = input.allowedTools == null ? null : new Set(input.allowedTools);
|
|
670
|
-
const capabilityCatalog = buildAiCapabilityCatalog(registry).filter((entry) => !allowed || allowed.has(entry.name));
|
|
692
|
+
const capabilityCatalog = buildAiCapabilityCatalog(registry, input.locale).filter((entry) => !allowed || allowed.has(entry.name));
|
|
671
693
|
const helpTools = input.help ? createAiHelpTools(input.help, input.locale) : [];
|
|
672
694
|
const resourceTool =
|
|
673
695
|
input.execute && (capabilityCatalog.length > 0 || input.staticTools.some((tool) => tool.def.name === "code_read"))
|
|
@@ -719,10 +741,10 @@ export const createAiToolResolver =
|
|
|
719
741
|
presentations.set(entry.providerName, {
|
|
720
742
|
kind: "capability",
|
|
721
743
|
appId: entry.appId,
|
|
722
|
-
appName: entry.appName,
|
|
744
|
+
appName: entry.display.appName,
|
|
723
745
|
appIcon: entry.app.appIcon,
|
|
724
746
|
appAccent: entry.app.appAccent,
|
|
725
|
-
title: entry.title,
|
|
747
|
+
title: entry.display.title,
|
|
726
748
|
capabilityKind: entry.kind,
|
|
727
749
|
});
|
|
728
750
|
// Rememberable scopes are resolved by the owning app for each concrete
|