@k2b/cloud 0.7.0 → 0.8.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 +5 -4
- package/scripts/README.md +10 -0
- package/scripts/build.ts +6 -1
- package/scripts/preload.ts +7 -0
- package/scripts/sync-recovery-smoke.ts +21 -6
- package/src/_internal/build-metadata.ts +8 -1
- package/src/_internal/capabilities.ts +35 -12
- package/src/_internal/define-app.ts +28 -11
- package/src/_internal/page-responses.ts +1 -1
- package/src/_internal/readiness.ts +4 -1
- package/src/_internal/runtime-context.ts +1 -1
- package/src/access/PermissionEditor.tsx +15 -9
- package/src/access/PrincipalPicker.tsx +9 -3
- package/src/access/ResourceApiKeys.tsx +1 -1
- package/src/access/ui.ts +1 -2
- package/src/ai/admin.ts +2 -2
- package/src/ai/assistant-models.ts +1 -1
- package/src/ai/audio-tool.ts +1 -1
- package/src/ai/browser-code-contracts.ts +174 -52
- package/src/ai/browser.ts +4 -2
- package/src/ai/capabilities.ts +3 -3
- package/src/ai/chat/blocks.tsx +127 -50
- package/src/ai/chat/builtin-tools.tsx +2 -4
- package/src/ai/chat/capability-table.tsx +1 -1
- package/src/ai/chat/composer-adapter.ts +48 -13
- package/src/ai/chat/message-utils.ts +18 -5
- package/src/ai/chat/presentation.tsx +24 -11
- package/src/ai/chat/tool-disclosure.tsx +6 -2
- package/src/ai/chat/tool-groups.ts +8 -2
- package/src/ai/chat-quotas.ts +2 -2
- package/src/ai/chat-task-contracts.ts +9 -13
- package/src/ai/chat-tasks.ts +39 -18
- package/src/ai/client/controller.ts +87 -38
- package/src/ai/client/projection.ts +13 -6
- package/src/ai/client/transport.ts +4 -2
- package/src/ai/code-capability-routes.ts +22 -27
- package/src/ai/code-capability-transport.ts +2 -1
- package/src/ai/code-execution.ts +53 -0
- package/src/ai/code-mode-skill.ts +9 -5
- package/src/ai/code-runtime-tools.ts +16 -3
- package/src/ai/code-source-contracts.ts +100 -32
- package/src/ai/code-source-tools.ts +49 -6
- package/src/ai/compaction.ts +3 -3
- package/src/ai/default-tools.ts +87 -14
- package/src/ai/dictation-runtime.ts +1 -1
- package/src/ai/draft-content.ts +27 -12
- package/src/ai/enrich.ts +1 -1
- package/src/ai/executor.ts +8 -12
- package/src/ai/fetch-file-tool.ts +2 -2
- package/src/ai/file-content-version.ts +6 -1
- package/src/ai/file-tools.ts +8 -2
- package/src/ai/files-store.ts +55 -17
- package/src/ai/grids-skill.ts +2 -0
- package/src/ai/http.ts +18 -7
- package/src/ai/index.ts +24 -25
- package/src/ai/inference-calls.ts +3 -4
- package/src/ai/live.ts +1 -1
- package/src/ai/markdown-pdf-tool.ts +2 -2
- package/src/ai/memories.ts +30 -27
- package/src/ai/memory-learning-runs.ts +1 -1
- package/src/ai/memory-learning.ts +5 -5
- package/src/ai/memory-tool.ts +1 -5
- package/src/ai/memory-workflow-evidence.ts +9 -4
- package/src/ai/message-queue.ts +23 -12
- package/src/ai/migrate.ts +6 -4
- package/src/ai/model-pricing.ts +4 -4
- package/src/ai/pdf-render-worker.ts +3 -2
- package/src/ai/projects-routes.ts +15 -40
- package/src/ai/projects.ts +18 -13
- package/src/ai/quota-provider.ts +6 -5
- package/src/ai/quota-report.ts +5 -5
- package/src/ai/quotas.ts +3 -3
- package/src/ai/routes.ts +60 -34
- package/src/ai/run-timeout.ts +3 -1
- package/src/ai/runtime-tools.ts +6 -7
- package/src/ai/runtime.ts +38 -20
- package/src/ai/settings.ts +1 -1
- package/src/ai/short-id.ts +4 -5
- package/src/ai/skill-search.ts +21 -10
- package/src/ai/skill-seeds.ts +16 -7
- package/src/ai/skill-tool.ts +6 -1
- package/src/ai/skills-routes.ts +32 -15
- package/src/ai/skills.ts +54 -28
- package/src/ai/store.ts +80 -47
- package/src/ai/structured.ts +6 -2
- package/src/ai/system-prompt.ts +7 -5
- package/src/ai/task-contracts.ts +84 -0
- package/src/ai/task-execution.ts +92 -0
- package/src/ai/todo-contracts.ts +24 -12
- package/src/ai/todo-tool.ts +16 -13
- package/src/ai/tools.ts +1 -1
- package/src/ai/transcription.ts +4 -4
- package/src/ai/turn-timing.ts +1 -1
- package/src/ai/ui.tsx +2 -1
- package/src/ai/usage.ts +1 -1
- package/src/ai/vision-tool.ts +38 -17
- package/src/api/admin-ai-quotas.ts +14 -8
- package/src/api/admin-ai-skills.ts +3 -3
- package/src/api/admin-linux-identities.ts +10 -4
- package/src/api/admin-rail.ts +2 -2
- package/src/api/app-approval.ts +2 -2
- package/src/api/auth.ts +1 -1
- package/src/api/capabilities.ts +45 -13
- package/src/api/index.ts +5 -5
- package/src/api/mcp.ts +5 -12
- package/src/browser/CloudResourceSearch.tsx +1 -1
- package/src/browser/command-bridge.ts +1 -1
- package/src/browser/command-shortcuts.ts +1 -1
- package/src/browser/commands.ts +8 -7
- package/src/browser/testing.ts +2 -1
- package/src/capabilities/client.ts +1 -1
- package/src/capabilities/command-link.ts +1 -1
- package/src/capabilities/server.ts +2 -1
- package/src/cli/admin/ai-quotas.ts +5 -5
- package/src/cli/admin/app-credentials.ts +7 -9
- package/src/cli/admin/index.ts +3 -3
- package/src/cli/admin/instance.ts +2 -2
- package/src/cli/admin/linux.ts +4 -2
- package/src/cli/admin/sync.ts +1 -1
- package/src/cli/capabilities.ts +42 -29
- package/src/config/define-env.ts +97 -0
- package/src/config/env.ts +147 -54
- package/src/config/index.ts +3 -1
- package/src/contracts/capabilities.ts +8 -1
- package/src/contracts/index.ts +5 -7
- package/src/contracts/registry.ts +2 -0
- package/src/contracts/shared.ts +12 -3
- package/src/desktop/index.ts +1 -0
- package/src/desktop/solid.tsx +1 -1
- package/src/index.ts +8 -2
- package/src/server/index.ts +2 -2
- package/src/server/ratelimit.ts +1 -1
- package/src/server/services/access-revision.ts +3 -3
- package/src/server/services/access.ts +3 -1
- package/src/services/accounts/notification-sender.ts +12 -2
- package/src/services/announcements/index.ts +4 -4
- package/src/services/app-approval.ts +11 -10
- package/src/services/identity/key-config.ts +6 -4
- package/src/services/identity/runtime-config.ts +6 -5
- package/src/services/ipa/posix.ts +1 -1
- package/src/services/ipa/sync.ts +1 -1
- package/src/services/logging/index.ts +1 -1
- package/src/services/logging/trace.ts +1 -1
- package/src/services/mandates/index.ts +5 -2
- package/src/services/mandates/policy.ts +106 -6
- package/src/services/notifications/batches.ts +1 -0
- package/src/services/pdf/gotenberg.ts +50 -14
- package/src/services/pdf/index.ts +11 -11
- package/src/services/public-http.ts +1 -1
- package/src/services/rail-shortcuts.ts +1 -1
- package/src/services/rail-snapshot.ts +1 -1
- package/src/services/request-cache-redis.ts +2 -1
- package/src/services/session/user.ts +1 -1
- package/src/services/settings/app.ts +5 -1
- package/src/services/settings/core-settings.ts +6 -8
- package/src/services/settings/index.ts +3 -3
- package/src/services/settings/store.ts +3 -3
- package/src/services/webauthn.ts +1 -1
- package/src/shared/index.ts +3 -6
- package/src/shared/markdown/extensions/info-blocks.ts +1 -1
- package/src/ssr/AdminSidebar.tsx +2 -2
- package/src/ssr/AppLaunchpad.island.tsx +12 -2
- package/src/ssr/AppLaunchpadPanel.tsx +4 -4
- package/src/ssr/GlobalSearchDialog.tsx +6 -6
- package/src/ssr/GlobalSearchTrigger.island.tsx +2 -2
- package/src/ssr/Layout.tsx +2 -2
- package/src/ssr/LayoutHeader.tsx +1 -1
- package/src/ssr/LayoutHelp.tsx +4 -6
- package/src/ssr/LayoutHelpTrigger.island.tsx +2 -2
- package/src/ssr/MinimalLayout.tsx +1 -1
- package/src/ssr/MobileNavigation.tsx +2 -2
- package/src/ssr/ProfilePreferences.island.tsx +1 -1
- package/src/ssr/admin-navigation.ts +6 -2
- package/src/ssr/islands/index.ts +2 -2
- package/src/ssr/mobile-menu-history.ts +1 -1
- package/src/workflows/ai/index.ts +2 -2
- package/src/workflows/ai/runtime.ts +16 -91
- package/src/workflows/ai/store.ts +1 -1
- package/src/workflows/ai/types.ts +6 -82
- package/src/workflows/store/index.ts +2 -2
- package/src/server/services/freeipa/test-certificates.ts +0 -44
- package/src/services/session/test-fixture.ts +0 -18
|
@@ -1,54 +1,166 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
export const CodeResourceId = z
|
|
3
|
+
export const CodeResourceId = z
|
|
4
|
+
.string()
|
|
5
|
+
.regex(/^[23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz]{6}$/)
|
|
6
|
+
.describe("Public resource short ID returned by code_create or code_list.");
|
|
4
7
|
const id = CodeResourceId;
|
|
5
8
|
const runId = z.string().min(1).max(180).describe("Run ID returned by code_run in this conversation execution host.");
|
|
6
|
-
export const CODE_RUNTIME_TOOL_NAMES = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
9
|
+
export const CODE_RUNTIME_TOOL_NAMES = [
|
|
10
|
+
"code_run",
|
|
11
|
+
"code_action",
|
|
12
|
+
"code_inspect",
|
|
13
|
+
"code_interact",
|
|
14
|
+
"code_stop",
|
|
15
|
+
"code_open",
|
|
16
|
+
"code_export",
|
|
17
|
+
"code_present",
|
|
18
|
+
"code_secret",
|
|
19
|
+
] as const;
|
|
20
|
+
export const CodeRunInput = z
|
|
21
|
+
.object({
|
|
22
|
+
id: id.optional(),
|
|
23
|
+
resourceId: id
|
|
24
|
+
.optional()
|
|
25
|
+
.describe(
|
|
26
|
+
"Optional data context for one-off code. Requires Manage; uses this resource database and shared files/KV without changing its source. Local storage stays temporary.",
|
|
27
|
+
),
|
|
28
|
+
version: z
|
|
29
|
+
.number()
|
|
30
|
+
.int()
|
|
31
|
+
.positive()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Published version to run; resource admins only. Omit for the current accessible source."),
|
|
34
|
+
code: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(1024 * 1024)
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("One-off JavaScript/TypeScript entry exporting one function. Use code OR a saved resource id; no title or icon needed."),
|
|
40
|
+
inputPaths: z
|
|
41
|
+
.array(z.string().min(1).max(500))
|
|
42
|
+
.max(64)
|
|
43
|
+
.default([])
|
|
44
|
+
.describe(
|
|
45
|
+
"Explicit current-chat input files. Scripts can read them; app test runs expose them only through the simulated picker. User apps never receive chat files.",
|
|
46
|
+
),
|
|
47
|
+
})
|
|
48
|
+
.strict()
|
|
49
|
+
.refine((input) => Number(input.id !== undefined) + Number(input.code !== undefined) === 1, "Provide exactly one of id or code")
|
|
50
|
+
.refine((input) => input.version === undefined || input.id !== undefined, "A published version requires a saved resource id")
|
|
51
|
+
.refine((input) => input.resourceId === undefined || input.code !== undefined, "resourceId requires one-off code");
|
|
52
|
+
export const CodeActionInput = z
|
|
53
|
+
.object({
|
|
54
|
+
id,
|
|
55
|
+
action: z
|
|
56
|
+
.string()
|
|
57
|
+
.regex(/^[a-z][a-zA-Z0-9_]*$/)
|
|
58
|
+
.max(80)
|
|
59
|
+
.describe("Exact name returned by code_actions."),
|
|
60
|
+
publishedVersion: z
|
|
61
|
+
.number()
|
|
62
|
+
.int()
|
|
63
|
+
.positive()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe(
|
|
66
|
+
"Exact publication returned by code_actions; a changed publication requires fresh discovery. Supply this OR draft revision.",
|
|
67
|
+
),
|
|
68
|
+
revision: z
|
|
69
|
+
.number()
|
|
70
|
+
.int()
|
|
71
|
+
.positive()
|
|
72
|
+
.optional()
|
|
73
|
+
.describe("Exact draft revision returned by code_actions({draft:true}); Manage required. Supply this OR publishedVersion."),
|
|
74
|
+
input: z.json().describe("Action input matching the discovered inputSchema."),
|
|
75
|
+
})
|
|
76
|
+
.strict()
|
|
77
|
+
.refine(
|
|
78
|
+
(input) => Number(input.publishedVersion !== undefined) + Number(input.revision !== undefined) === 1,
|
|
79
|
+
"Supply publishedVersion OR draft revision",
|
|
80
|
+
);
|
|
81
|
+
export const CodeInspectInput = z
|
|
82
|
+
.object({
|
|
83
|
+
runId,
|
|
84
|
+
waitMs: z
|
|
85
|
+
.number()
|
|
86
|
+
.int()
|
|
87
|
+
.min(0)
|
|
88
|
+
.max(30000)
|
|
89
|
+
.default(0)
|
|
90
|
+
.describe("Wait up to this duration for background work to finish before returning its real state; never restarts work."),
|
|
91
|
+
nodeId: z.string().min(1).max(80).optional(),
|
|
92
|
+
offset: z.number().int().min(0).default(0),
|
|
93
|
+
limit: z.number().int().min(1).max(100).default(20),
|
|
94
|
+
})
|
|
95
|
+
.strict();
|
|
96
|
+
const CodeInteraction = z
|
|
97
|
+
.object({
|
|
98
|
+
id: z.string().min(1).max(80).describe("Control ID or pending modal ID returned by the snapshot."),
|
|
99
|
+
event: z
|
|
100
|
+
.discriminatedUnion("type", [
|
|
101
|
+
z
|
|
102
|
+
.object({
|
|
103
|
+
type: z.literal("change"),
|
|
104
|
+
value: z.union([
|
|
105
|
+
z.string(),
|
|
106
|
+
z.number().finite(),
|
|
107
|
+
z.boolean(),
|
|
108
|
+
z.null(),
|
|
109
|
+
z.array(z.string()),
|
|
110
|
+
z.object({ start: z.iso.date().nullable(), end: z.iso.date().nullable() }).strict(),
|
|
111
|
+
]),
|
|
112
|
+
})
|
|
113
|
+
.strict(),
|
|
114
|
+
z.object({ type: z.literal("select"), key: z.string().nullable() }).strict(),
|
|
115
|
+
z.object({ type: z.literal("view"), value: z.enum(["chart", "table"]) }).strict(),
|
|
116
|
+
z.object({ type: z.literal("refresh") }).strict(),
|
|
117
|
+
z.object({ type: z.literal("request"), request: z.record(z.string(), z.json()) }).strict(),
|
|
118
|
+
])
|
|
119
|
+
.optional()
|
|
120
|
+
.describe(
|
|
121
|
+
"An event object, never a JSON-encoded string. Omit to activate a button. Example: {type:'change',value:['Sued']} or {type:'view',value:'table'}.",
|
|
122
|
+
),
|
|
123
|
+
answer: z.json().optional().describe("Only for the pending modal ID: the modal answer, or null to cancel. Do not use for controls."),
|
|
124
|
+
})
|
|
125
|
+
.strict();
|
|
33
126
|
const validInteraction = (input: z.infer<typeof CodeInteraction>) => input.event === undefined || input.answer === undefined;
|
|
34
|
-
export const CodeInteractInput = CodeInteraction.partial({id:true})
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
127
|
+
export const CodeInteractInput = CodeInteraction.partial({ id: true })
|
|
128
|
+
.extend({
|
|
129
|
+
runId,
|
|
130
|
+
// Three normal 15-second callback budgets share the existing 45-second call budget.
|
|
131
|
+
steps: z
|
|
132
|
+
.array(CodeInteraction.refine(validInteraction, "Supply event OR answer"))
|
|
133
|
+
.min(1)
|
|
134
|
+
.max(3)
|
|
135
|
+
.optional()
|
|
136
|
+
.describe(
|
|
137
|
+
"Up to three sequential interactions in one call. Use steps OR the top-level id/event/answer. Stops on an error, pending modal or background work; returns completedSteps and nextStep.",
|
|
138
|
+
),
|
|
139
|
+
})
|
|
140
|
+
.strict()
|
|
141
|
+
.refine(
|
|
142
|
+
(input) =>
|
|
143
|
+
input.steps
|
|
144
|
+
? input.id === undefined && input.event === undefined && input.answer === undefined
|
|
145
|
+
: input.id !== undefined && (input.event === undefined || input.answer === undefined),
|
|
146
|
+
"Supply steps OR one id with event/answer.",
|
|
147
|
+
);
|
|
40
148
|
export const CodeStopInput = z.object({ runId }).strict();
|
|
41
149
|
export const CodeOpenInput = z.object({ id }).strict();
|
|
42
150
|
export const CodePresentInput = z.object({ runId, title: z.string().trim().min(1).max(120) }).strict();
|
|
43
|
-
export const CodeExportInput = z
|
|
151
|
+
export const CodeExportInput = z
|
|
152
|
+
.object({ runId, name: z.string().min(1).max(180).describe("Captured output filename returned by the snapshot.") })
|
|
153
|
+
.strict();
|
|
44
154
|
|
|
45
|
-
export const CodeSecretInput = z
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
155
|
+
export const CodeSecretInput = z
|
|
156
|
+
.object({
|
|
157
|
+
resourceId: id.optional().describe("Scope to this app/script; omit to configure the current chat only."),
|
|
158
|
+
name: z.string().regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,79}$/),
|
|
159
|
+
origin: z.string().url().max(2000).describe("Exact HTTPS origin allowed to receive the secret."),
|
|
160
|
+
header: z.string().min(1).max(80).default("authorization"),
|
|
161
|
+
prefix: z.string().max(160).default("Bearer "),
|
|
162
|
+
})
|
|
163
|
+
.strict();
|
|
52
164
|
|
|
53
165
|
// Internal bridge envelope. Each model-facing tool receives only its own flat schema.
|
|
54
166
|
export const CodeRuntimeInput = z.discriminatedUnion("operation", [
|
|
@@ -65,15 +177,25 @@ export const CodeRuntimeInput = z.discriminatedUnion("operation", [
|
|
|
65
177
|
export type CodeRuntimeInput = z.infer<typeof CodeRuntimeInput>;
|
|
66
178
|
export function parseCodeToolInput(name: string, args: unknown): CodeRuntimeInput {
|
|
67
179
|
switch (name) {
|
|
68
|
-
case "code_secret":
|
|
69
|
-
|
|
70
|
-
case "
|
|
71
|
-
|
|
72
|
-
case "
|
|
73
|
-
|
|
74
|
-
case "
|
|
75
|
-
|
|
76
|
-
case "
|
|
77
|
-
|
|
180
|
+
case "code_secret":
|
|
181
|
+
return { operation: "secret", ...CodeSecretInput.parse(args) };
|
|
182
|
+
case "code_action":
|
|
183
|
+
return { operation: "action", ...CodeActionInput.parse(args) };
|
|
184
|
+
case "code_run":
|
|
185
|
+
return { operation: "run", ...CodeRunInput.parse(args) };
|
|
186
|
+
case "code_inspect":
|
|
187
|
+
return { operation: "inspect", ...CodeInspectInput.parse(args) };
|
|
188
|
+
case "code_interact":
|
|
189
|
+
return { operation: "interact", ...CodeInteractInput.parse(args) };
|
|
190
|
+
case "code_stop":
|
|
191
|
+
return { operation: "stop", ...CodeStopInput.parse(args) };
|
|
192
|
+
case "code_open":
|
|
193
|
+
return { operation: "open", ...CodeOpenInput.parse(args) };
|
|
194
|
+
case "code_present":
|
|
195
|
+
return { operation: "present", ...CodePresentInput.parse(args) };
|
|
196
|
+
case "code_export":
|
|
197
|
+
return { operation: "export", ...CodeExportInput.parse(args) };
|
|
198
|
+
default:
|
|
199
|
+
throw new Error("Unknown code tool");
|
|
78
200
|
}
|
|
79
201
|
}
|
package/src/ai/browser.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { CODE_RUNTIME_TOOL_NAMES, CodeActionInput, CodeResourceId, CodeRuntimeInput, parseCodeToolInput } from "./browser-code-contracts";
|
|
2
|
+
export { type AiTaskRequest, type AiTaskRequestInput, AiTaskRequestSchema } from "./task-contracts";
|
|
3
|
+
export { type AiTodoPlan, parseAiTodoPlan } from "./todo-contracts";
|
|
4
|
+
|
|
3
5
|
import { AI_TURN_ATTACHMENT_MAX_ITEMS } from "./limits";
|
|
4
6
|
import type { AiConversation, AiDraftContentPart } from "./types";
|
|
5
7
|
|
package/src/ai/capabilities.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { createHelpReader, type HelpReaderFactory } from "../services/help";
|
|
2
|
-
import { createCodeSourceTool } from "./code-source-tools";
|
|
3
|
-
import { CODE_SOURCE_TOOLS } from "./code-source-contracts";
|
|
4
1
|
import { createHash } from "node:crypto";
|
|
5
2
|
import type { Tool, ToolContext, ToolResolver } from "@k2b/nessi";
|
|
6
3
|
import { z } from "zod";
|
|
@@ -15,7 +12,10 @@ import {
|
|
|
15
12
|
} from "../contracts/capabilities";
|
|
16
13
|
import type { CapabilityRegistryEntry } from "../contracts/registry";
|
|
17
14
|
import type { RequestActor } from "../server";
|
|
15
|
+
import { createHelpReader, type HelpReaderFactory } from "../services/help";
|
|
18
16
|
import { recordRejectedAiCapability } from "./capability-execution";
|
|
17
|
+
import { CODE_SOURCE_TOOLS } from "./code-source-contracts";
|
|
18
|
+
import { createCodeSourceTool } from "./code-source-tools";
|
|
19
19
|
import { CLOUD_AI_DEFERRED_BUILTIN_TOOL_NAMES } from "./default-tools";
|
|
20
20
|
import { type AiToolPreparationContext, defineAiTool, type PreparedAiTools, prepareAiTools } from "./tools";
|
|
21
21
|
import type { AiConversationService, AiRuntimeTool, AiToolPresentation } from "./types";
|
package/src/ai/chat/blocks.tsx
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { hasCapabilityTable } from "./capability-result";
|
|
2
1
|
import { dates } from "@k2b/stdlib";
|
|
3
2
|
import { mutation } from "@k2b/stdlib/solid";
|
|
4
|
-
import { Button, ButtonLink, Chat,
|
|
3
|
+
import { Button, ButtonLink, Chat, isStructuredDataValue, MarkdownView, SplitButton, StructuredDataPreview, useLocale } from "@k2b/ui";
|
|
5
4
|
import { createMemo, createSignal, For, type JSX, Match, Show, Switch } from "solid-js";
|
|
6
5
|
import type { CapabilityActionReview } from "../../contracts/capabilities";
|
|
7
6
|
import { markdown } from "../../shared";
|
|
8
|
-
import { groupToolBlocks, isFailedTool, summarizeToolGroup } from "./tool-groups";
|
|
9
7
|
import type { AiTurnBlock } from "../protocol";
|
|
10
8
|
import { isRenderableTurnBlock } from "../protocol";
|
|
11
9
|
import { hasSpecializedBuiltinToolView, SpecializedBuiltinToolBlock } from "./builtin-tools";
|
|
10
|
+
import { hasCapabilityTable } from "./capability-result";
|
|
12
11
|
import { CapabilityTablePreview } from "./capability-table";
|
|
13
12
|
import { PresentToolBlock } from "./file-tools";
|
|
14
13
|
import { useAiChatActions } from "./message-actions";
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
} from "./message-utils";
|
|
28
27
|
import { AssistantMarkdownBlock } from "./primitives";
|
|
29
28
|
import { AiToolActivity, AiToolDisclosureProvider, type AiToolDisclosureState, createAiToolDisclosureState } from "./tool-disclosure";
|
|
29
|
+
import { groupToolBlocks, isFailedTool, summarizeToolGroup } from "./tool-groups";
|
|
30
30
|
import { CloudCardBlock, CloudSurveyBlock, CloudSurveyResultBlock, CloudTextEditorBlock, CloudTextEditorResultBlock } from "./visual-tools";
|
|
31
31
|
import { FetchFileToolBlock, WebExtractToolBlock, WebSearchToolBlock } from "./web-tools";
|
|
32
32
|
|
|
@@ -655,7 +655,9 @@ function ToolBlockView(props: { turnId: string; block: ToolBlock; active?: boole
|
|
|
655
655
|
<Match when={props.block.presentation?.kind === "capability"}>
|
|
656
656
|
<CapabilityToolView block={props.block} />
|
|
657
657
|
</Match>
|
|
658
|
-
<Match
|
|
658
|
+
<Match
|
|
659
|
+
when={actions.renderCodePresentation && props.block.name === "code_present" && status() === "completed" && !props.block.isError}
|
|
660
|
+
>
|
|
659
661
|
{actions.renderCodePresentation?.(props.block.result)}
|
|
660
662
|
</Match>
|
|
661
663
|
<Match when={props.block.name === "present" && !props.block.isError}>
|
|
@@ -673,7 +675,9 @@ function ToolBlockView(props: { turnId: string; block: ToolBlock; active?: boole
|
|
|
673
675
|
<Match when={props.block.name === "memory"}>
|
|
674
676
|
<MemoryToolView block={props.block} />
|
|
675
677
|
</Match>
|
|
676
|
-
<Match
|
|
678
|
+
<Match
|
|
679
|
+
when={hasSpecializedBuiltinToolView(props.block.name, props.block.result) && status() === "completed" && !props.block.isError}
|
|
680
|
+
>
|
|
677
681
|
<SpecializedBuiltinToolBlock block={props.block} />
|
|
678
682
|
</Match>
|
|
679
683
|
<Match when={isCardToolName(props.block.name) && !props.block.isError}>
|
|
@@ -702,20 +706,18 @@ export function AiTurnBlockView(props: { block: AiTurnBlock; turnId: string; str
|
|
|
702
706
|
return (
|
|
703
707
|
<Switch>
|
|
704
708
|
<Match when={props.block.kind === "text" && props.block}>
|
|
705
|
-
{block => <AssistantMarkdownBlock html={markdown.renderSync(block().text)} />}
|
|
709
|
+
{(block) => <AssistantMarkdownBlock html={markdown.renderSync(block().text)} />}
|
|
706
710
|
</Match>
|
|
707
711
|
<Match when={props.block.kind === "thinking" && props.block}>
|
|
708
|
-
{block => <ThinkingBlockView text={block().text} streaming={props.streaming} />}
|
|
712
|
+
{(block) => <ThinkingBlockView text={block().text} streaming={props.streaming} />}
|
|
709
713
|
</Match>
|
|
710
714
|
<Match when={props.block.kind === "steer_applied"}>
|
|
711
715
|
<Chat.Activity label="Conversation steered" icon="ti ti-route" tone="ai" />
|
|
712
716
|
</Match>
|
|
713
717
|
<Match when={props.block.kind === "tool" && props.block}>
|
|
714
|
-
{block => <ToolBlockView turnId={props.turnId} block={block()} active={props.active} />}
|
|
715
|
-
</Match>
|
|
716
|
-
<Match when={props.block.kind === "compaction" && props.block}>
|
|
717
|
-
{block => <CompactionBlockView block={block()} />}
|
|
718
|
+
{(block) => <ToolBlockView turnId={props.turnId} block={block()} active={props.active} />}
|
|
718
719
|
</Match>
|
|
720
|
+
<Match when={props.block.kind === "compaction" && props.block}>{(block) => <CompactionBlockView block={block()} />}</Match>
|
|
719
721
|
</Switch>
|
|
720
722
|
);
|
|
721
723
|
}
|
|
@@ -723,18 +725,37 @@ export function AiTurnBlockView(props: { block: AiTurnBlock; turnId: string; str
|
|
|
723
725
|
function CompactToolRow(props: { block: ToolBlock; busy?: boolean }) {
|
|
724
726
|
const locale = useLocale();
|
|
725
727
|
const de = () => locale().startsWith("de");
|
|
726
|
-
const args = () => isRecord(props.block.args) ? props.block.args : {};
|
|
728
|
+
const args = () => (isRecord(props.block.args) ? props.block.args : {});
|
|
727
729
|
const detail = () => [args().path, args().name, args().query].find((value) => typeof value === "string");
|
|
728
730
|
const waiting = () => props.block.status === "awaiting_client";
|
|
729
|
-
return
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
731
|
+
return (
|
|
732
|
+
<AiToolActivity
|
|
733
|
+
blockId={props.block.id}
|
|
734
|
+
label={props.block.presentation?.title ?? displayToolName(props.block.name)}
|
|
735
|
+
description={[
|
|
736
|
+
props.block.status === "running" ? (props.block.progress ?? "") : "",
|
|
737
|
+
typeof detail() === "string" ? String(detail()) : "",
|
|
738
|
+
waiting() ? (de() ? "Wartet" : "Waiting") : isFailedTool(props.block) ? (de() ? "Fehlgeschlagen" : "Failed") : "",
|
|
739
|
+
]
|
|
740
|
+
.filter(Boolean)
|
|
741
|
+
.join(" · ")}
|
|
742
|
+
icon={waiting() ? "ti ti-clock" : aiToolIcon(props.block.name, props.block.presentation?.appIcon)}
|
|
743
|
+
tone={isFailedTool(props.block) ? "danger" : "neutral"}
|
|
744
|
+
busy={props.busy && !waiting()}
|
|
745
|
+
bodyInset={false}
|
|
746
|
+
renderBody={() => (
|
|
747
|
+
<div
|
|
748
|
+
class="max-h-72 overflow-auto overscroll-contain rounded-md bg-zinc-100 p-3 dark:bg-zinc-950"
|
|
749
|
+
tabIndex={0}
|
|
750
|
+
role="region"
|
|
751
|
+
aria-label={de() ? "Werkzeug-Eingabe und Ausgabe" : "Tool input and output"}
|
|
752
|
+
>
|
|
753
|
+
<ToolDetail title={de() ? "Eingabe" : "Input"} toolName={props.block.name} value={props.block.args} />
|
|
754
|
+
<ToolDetail title={de() ? "Ausgabe" : "Output"} toolName={props.block.name} value={props.block.result} />
|
|
755
|
+
</div>
|
|
756
|
+
)}
|
|
757
|
+
/>
|
|
758
|
+
);
|
|
738
759
|
}
|
|
739
760
|
|
|
740
761
|
function ToolGroupView(props: { blocks: ToolBlock[]; active: boolean }) {
|
|
@@ -744,20 +765,51 @@ function ToolGroupView(props: { blocks: ToolBlock[]; active: boolean }) {
|
|
|
744
765
|
const multiple = () => props.blocks.length > 1;
|
|
745
766
|
const detail = () => {
|
|
746
767
|
const args = last().args;
|
|
747
|
-
return isRecord(args) ? [args.path,args.name,args.query].find(value=>typeof value==="string") : undefined;
|
|
768
|
+
return isRecord(args) ? [args.path, args.name, args.query].find((value) => typeof value === "string") : undefined;
|
|
748
769
|
};
|
|
749
|
-
return
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
770
|
+
return (
|
|
771
|
+
<AiToolActivity
|
|
772
|
+
blockId={`group:${props.blocks[0]!.id}`}
|
|
773
|
+
bodyInset={false}
|
|
774
|
+
label={
|
|
775
|
+
props.active || !multiple()
|
|
776
|
+
? (last().presentation?.title ?? displayToolName(last().name))
|
|
777
|
+
: summarizeToolGroup(props.blocks, locale())
|
|
778
|
+
}
|
|
779
|
+
description={
|
|
780
|
+
waiting()
|
|
781
|
+
? locale().startsWith("de")
|
|
782
|
+
? "Wartet"
|
|
783
|
+
: "Waiting"
|
|
784
|
+
: last().status === "running"
|
|
785
|
+
? last().progress
|
|
786
|
+
: !multiple() && typeof detail() === "string"
|
|
787
|
+
? String(detail())
|
|
788
|
+
: undefined
|
|
789
|
+
}
|
|
790
|
+
icon={props.active || !multiple() ? (waiting() ? "ti ti-clock" : aiToolIcon(last().name)) : "ti ti-stack"}
|
|
791
|
+
tone={!multiple() && isFailedTool(last()) ? "danger" : "neutral"}
|
|
792
|
+
busy={props.active && !waiting()}
|
|
793
|
+
renderBody={() => (
|
|
794
|
+
<Show
|
|
795
|
+
when={multiple()}
|
|
796
|
+
fallback={
|
|
797
|
+
<div
|
|
798
|
+
class="max-h-72 overflow-auto overscroll-contain rounded-md bg-zinc-100 p-3 dark:bg-zinc-950"
|
|
799
|
+
tabIndex={0}
|
|
800
|
+
role="region"
|
|
801
|
+
aria-label={locale().startsWith("de") ? "Werkzeug-Eingabe und Ausgabe" : "Tool input and output"}
|
|
802
|
+
>
|
|
803
|
+
<ToolDetail title={locale().startsWith("de") ? "Eingabe" : "Input"} toolName={last().name} value={last().args} />
|
|
804
|
+
<ToolDetail title={locale().startsWith("de") ? "Ausgabe" : "Output"} toolName={last().name} value={last().result} />
|
|
805
|
+
</div>
|
|
806
|
+
}
|
|
807
|
+
>
|
|
808
|
+
<For each={props.blocks}>{(block) => <CompactToolRow block={block} />}</For>
|
|
809
|
+
</Show>
|
|
810
|
+
)}
|
|
811
|
+
/>
|
|
812
|
+
);
|
|
761
813
|
}
|
|
762
814
|
|
|
763
815
|
export function AiTurnBlockList(props: {
|
|
@@ -769,24 +821,49 @@ export function AiTurnBlockList(props: {
|
|
|
769
821
|
disclosureState?: AiToolDisclosureState;
|
|
770
822
|
}) {
|
|
771
823
|
const groups = createMemo(() => groupToolBlocks(props.blocks.filter(isRenderableTurnBlock)));
|
|
772
|
-
const keyedGroups = createMemo(
|
|
824
|
+
const keyedGroups = createMemo(
|
|
825
|
+
() => new Map(groups().map((group) => [group.kind === "tools" ? `tools:${group.blocks[0]!.id}` : `block:${group.block.id}`, group])),
|
|
826
|
+
);
|
|
773
827
|
const keys = createMemo(() => [...keyedGroups().keys()]);
|
|
774
828
|
const disclosureState = props.disclosureState ?? createAiToolDisclosureState();
|
|
775
829
|
return (
|
|
776
|
-
<Show when={groups().length > 0}
|
|
777
|
-
<
|
|
778
|
-
<
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
830
|
+
<Show when={groups().length > 0}>
|
|
831
|
+
<AiToolDisclosureProvider state={disclosureState}>
|
|
832
|
+
<div class={`flex flex-col ${props.compact ? "gap-1" : "gap-2"}`}>
|
|
833
|
+
<For each={keys()}>
|
|
834
|
+
{(key, index) => {
|
|
835
|
+
const group = () => keyedGroups().get(key)!;
|
|
836
|
+
return (
|
|
837
|
+
<Switch>
|
|
838
|
+
<Match
|
|
839
|
+
when={(() => {
|
|
840
|
+
const value = group();
|
|
841
|
+
return value.kind === "tools" ? value : undefined;
|
|
842
|
+
})()}
|
|
843
|
+
>
|
|
844
|
+
{(tools) => <ToolGroupView blocks={tools().blocks} active={Boolean(props.active && index() === keys().length - 1)} />}
|
|
845
|
+
</Match>
|
|
846
|
+
<Match
|
|
847
|
+
when={(() => {
|
|
848
|
+
const value = group();
|
|
849
|
+
return value.kind === "block" ? value : undefined;
|
|
850
|
+
})()}
|
|
851
|
+
>
|
|
852
|
+
{(item) => (
|
|
853
|
+
<AiTurnBlockView
|
|
854
|
+
block={item().block}
|
|
855
|
+
turnId={props.turnId}
|
|
856
|
+
streaming={props.streaming && index() === keys().length - 1}
|
|
857
|
+
active={props.active}
|
|
858
|
+
/>
|
|
859
|
+
)}
|
|
860
|
+
</Match>
|
|
861
|
+
</Switch>
|
|
862
|
+
);
|
|
863
|
+
}}
|
|
864
|
+
</For>
|
|
865
|
+
</div>
|
|
866
|
+
</AiToolDisclosureProvider>
|
|
867
|
+
</Show>
|
|
791
868
|
);
|
|
792
869
|
}
|
|
@@ -4,8 +4,8 @@ import { For, type JSX, Show } from "solid-js";
|
|
|
4
4
|
import { formatAiFileSize } from "../attachments";
|
|
5
5
|
import type { AiTurnBlock } from "../protocol";
|
|
6
6
|
import { aiToolIcon, displayToolName, formatToolDetailText, isRecord } from "./message-utils";
|
|
7
|
-
import { AiToolActivity } from "./tool-disclosure";
|
|
8
7
|
import { aiChatMessages } from "./messages";
|
|
8
|
+
import { AiToolActivity } from "./tool-disclosure";
|
|
9
9
|
|
|
10
10
|
type ToolBlock = Extract<AiTurnBlock, { kind: "tool" }>;
|
|
11
11
|
|
|
@@ -325,9 +325,7 @@ function ReadFileView(props: { block: ToolBlock }) {
|
|
|
325
325
|
const start = number(result().offset);
|
|
326
326
|
const end = number(result().nextOffset);
|
|
327
327
|
const t = aiChatMessages(locale());
|
|
328
|
-
return end > start
|
|
329
|
-
? t.byteRange({ start: start.toLocaleString(locale()), end: end.toLocaleString(locale()) })
|
|
330
|
-
: t.read;
|
|
328
|
+
return end > start ? t.byteRange({ start: start.toLocaleString(locale()), end: end.toLocaleString(locale()) }) : t.read;
|
|
331
329
|
};
|
|
332
330
|
return (
|
|
333
331
|
<CompletedActivity
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { capabilityTable } from "./capability-result";
|
|
2
1
|
import { ButtonLink, DataTable, type DataTableColumn, useLocale } from "@k2b/ui";
|
|
3
2
|
import { createMemo, For, Show } from "solid-js";
|
|
4
3
|
import { CapabilitySemanticLinkSchema, capabilityDataAtPath } from "../../contracts/capabilities";
|
|
4
|
+
import { capabilityTable } from "./capability-result";
|
|
5
5
|
import { aiChatMessages } from "./messages";
|
|
6
6
|
|
|
7
7
|
export const capabilityCellText = (value: unknown): string => {
|