@k2b/cloud 0.16.1 → 0.17.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k2b/cloud",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Application platform library for independently deployed Hono and SolidJS services behind a dynamic gateway.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"@tailwindcss/typography": "0.5.20",
|
|
100
100
|
"@k2b/nessi": "0.12.1",
|
|
101
101
|
"@k2b/ssr": "0.14.0",
|
|
102
|
-
"@k2b/ui": "0.
|
|
102
|
+
"@k2b/ui": "0.7.0",
|
|
103
103
|
"@k2b/stdlib": "0.26.0",
|
|
104
104
|
"@k2b/sync": "6.5.0",
|
|
105
105
|
"@nats-io/transport-node": "3.4.0",
|
package/src/ai/chat/blocks.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
jsonPreview,
|
|
25
25
|
memoryToolPresentation,
|
|
26
26
|
} from "./message-utils";
|
|
27
|
+
import { aiChatMessages } from "./messages";
|
|
27
28
|
import { AssistantMarkdownBlock } from "./primitives";
|
|
28
29
|
import { AiToolActivity, AiToolDisclosureProvider, type AiToolDisclosureState, createAiToolDisclosureState } from "./tool-disclosure";
|
|
29
30
|
import { groupToolBlocks, isFailedTool, summarizeToolGroup } from "./tool-groups";
|
|
@@ -57,16 +58,18 @@ function ReviewDetailValue(props: { detail: ReviewDetail }) {
|
|
|
57
58
|
// turn streams, so every branch must re-evaluate when the store updates.
|
|
58
59
|
|
|
59
60
|
function ThinkingBlockView(props: { text: string; streaming?: boolean }) {
|
|
61
|
+
const locale = useLocale();
|
|
62
|
+
const t = () => aiChatMessages(locale());
|
|
60
63
|
return (
|
|
61
64
|
<Show
|
|
62
65
|
when={props.text.trim()}
|
|
63
66
|
fallback={
|
|
64
67
|
<Show when={props.streaming}>
|
|
65
|
-
<Chat.Activity label=
|
|
68
|
+
<Chat.Activity label={t().thinking} icon="ti ti-sparkles" tone="ai" busy />
|
|
66
69
|
</Show>
|
|
67
70
|
}
|
|
68
71
|
>
|
|
69
|
-
<Chat.Activity label=
|
|
72
|
+
<Chat.Activity label={t().showReasoning} icon="ti ti-sparkles" tone="ai" bodyInset={false}>
|
|
70
73
|
<pre class="max-h-52 w-full min-w-0 overflow-auto whitespace-pre-wrap rounded-md bg-zinc-100/70 p-2 text-[11px] leading-5 text-secondary [box-shadow:var(--ui-control-recess)] dark:bg-zinc-950/70">
|
|
71
74
|
{props.text}
|
|
72
75
|
</pre>
|
package/src/ai/chat/messages.ts
CHANGED
|
@@ -18,6 +18,8 @@ const messages = i18n.define({
|
|
|
18
18
|
toolIssues: "Tool issues",
|
|
19
19
|
none: "None",
|
|
20
20
|
read: "Read",
|
|
21
|
+
thinking: "Thinking",
|
|
22
|
+
showReasoning: "Show reasoning",
|
|
21
23
|
byteRange: ({ start, end }: { start: string; end: string }) => `Bytes ${start}–${end}`,
|
|
22
24
|
},
|
|
23
25
|
de: {
|
|
@@ -36,6 +38,8 @@ const messages = i18n.define({
|
|
|
36
38
|
toolIssues: "Werkzeugprobleme",
|
|
37
39
|
none: "Keine",
|
|
38
40
|
read: "Gelesen",
|
|
41
|
+
thinking: "Denkt nach",
|
|
42
|
+
showReasoning: "Denkprozess anzeigen",
|
|
39
43
|
byteRange: ({ start, end }) => `Bytes ${start}–${end}`,
|
|
40
44
|
},
|
|
41
45
|
},
|
|
@@ -27,10 +27,15 @@ export type AiChatTimelineSession = {
|
|
|
27
27
|
|
|
28
28
|
export { type AiChatActions, AiChatActionsProvider };
|
|
29
29
|
|
|
30
|
-
const isWideBlock = (block: AiAssistantTimelineItem["blocks"][number]) => block.kind === "tool";
|
|
31
|
-
|
|
32
30
|
type AssistantBlock = AiAssistantTimelineItem["blocks"][number];
|
|
33
31
|
|
|
32
|
+
// Activity blocks span the full message column so disclosure chevrons share one
|
|
33
|
+
// right edge. Tool and compaction blocks count even while busy; reasoning counts
|
|
34
|
+
// only once it has text, because empty reasoning renders at most a busy row and
|
|
35
|
+
// must not widen a prose-only reply.
|
|
36
|
+
const isWideBlock = (block: AssistantBlock) =>
|
|
37
|
+
block.kind === "tool" || block.kind === "compaction" || (block.kind === "thinking" && block.text.trim().length > 0);
|
|
38
|
+
|
|
34
39
|
type SurveyResultBlock = Extract<AssistantBlock, { kind: "tool" }>;
|
|
35
40
|
type SurveySegment = { type: "assistant"; blocks: AssistantBlock[] } | { type: "survey"; block: SurveyResultBlock };
|
|
36
41
|
|
package/src/ai/routes.ts
CHANGED
|
@@ -200,6 +200,7 @@ const MemoryUpdateSchema = MemoryCreateSchema.partial().refine((value) => Object
|
|
|
200
200
|
const MemoryIdSchema = z.string().regex(AI_SHORT_ID_PATTERN);
|
|
201
201
|
|
|
202
202
|
const notFound = (c: Context<AuthContext>) => respond(c, fail(err.notFound("Conversation")));
|
|
203
|
+
const fileNotFound = (c: Context<AuthContext>) => respond(c, fail(err.notFound("File")));
|
|
203
204
|
|
|
204
205
|
const publicConversation = (conversation: AiConversation, projectId: string | null = null) => ({
|
|
205
206
|
...conversation,
|
|
@@ -1294,9 +1295,9 @@ export const aiRoutes = (() => {
|
|
|
1294
1295
|
const conversation = await loadConversation(c, ctx);
|
|
1295
1296
|
if (!conversation) return notFound(c);
|
|
1296
1297
|
const path = normalizeAiFilePath(c.req.valid("query").path);
|
|
1297
|
-
if (!path) return
|
|
1298
|
+
if (!path) return fileNotFound(c);
|
|
1298
1299
|
const stored = await aiFileStore.read({ conversationId: conversation.id, path });
|
|
1299
|
-
if (!stored) return
|
|
1300
|
+
if (!stored) return fileNotFound(c);
|
|
1300
1301
|
const filename = path.slice(path.lastIndexOf("/") + 1).replaceAll('"', "");
|
|
1301
1302
|
return c.body(stored.bytes as unknown as ArrayBuffer, 200, {
|
|
1302
1303
|
"Content-Type": stored.mediaType || "application/octet-stream",
|
|
@@ -1311,9 +1312,9 @@ export const aiRoutes = (() => {
|
|
|
1311
1312
|
const conversation = await loadConversation(c, ctx);
|
|
1312
1313
|
if (!conversation) return notFound(c);
|
|
1313
1314
|
const path = normalizeAiFilePath(c.req.valid("query").path);
|
|
1314
|
-
if (!path) return
|
|
1315
|
+
if (!path) return fileNotFound(c);
|
|
1315
1316
|
const removed = await aiFileStore.remove({ conversationId: conversation.id, path, recursive: false });
|
|
1316
|
-
if (removed === 0) return
|
|
1317
|
+
if (removed === 0) return fileNotFound(c);
|
|
1317
1318
|
return respond(c, ok({ deleted: true }));
|
|
1318
1319
|
})
|
|
1319
1320
|
.put("/conversations/:conversationId/files/content", v("json", FileWriteSchema), async (c) => {
|