@vibes.diy/api-svc 2.4.8 → 2.4.10

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.
Files changed (38) hide show
  1. package/cf-serve.js +16 -0
  2. package/cf-serve.js.map +1 -1
  3. package/create-handler.d.ts +10 -1
  4. package/create-handler.js +1 -0
  5. package/create-handler.js.map +1 -1
  6. package/index.d.ts +1 -0
  7. package/index.js +1 -0
  8. package/index.js.map +1 -1
  9. package/intern/prompt-assembly.d.ts +21 -0
  10. package/intern/prompt-assembly.js +194 -0
  11. package/intern/prompt-assembly.js.map +1 -0
  12. package/intern/prompt-asset-fetch.d.ts +6 -0
  13. package/intern/prompt-asset-fetch.js +18 -0
  14. package/intern/prompt-asset-fetch.js.map +1 -0
  15. package/intern/prompt-streaming.d.ts +48 -0
  16. package/intern/prompt-streaming.js +139 -0
  17. package/intern/prompt-streaming.js.map +1 -0
  18. package/package.json +11 -11
  19. package/public/access-function.d.ts +1 -0
  20. package/public/access-function.js +32 -0
  21. package/public/access-function.js.map +1 -1
  22. package/public/app-documents.js +316 -17
  23. package/public/app-documents.js.map +1 -1
  24. package/public/channel-read-filter.d.ts +9 -0
  25. package/public/channel-read-filter.js +22 -0
  26. package/public/channel-read-filter.js.map +1 -0
  27. package/public/ensure-app-slug-item.js +226 -1
  28. package/public/ensure-app-slug-item.js.map +1 -1
  29. package/public/grant-reduce.d.ts +25 -0
  30. package/public/grant-reduce.js +130 -0
  31. package/public/grant-reduce.js.map +1 -0
  32. package/public/prompt-chat-section.d.ts +11 -70
  33. package/public/prompt-chat-section.js +12 -343
  34. package/public/prompt-chat-section.js.map +1 -1
  35. package/public/report-top-vibes-by-members.js +9 -2
  36. package/public/report-top-vibes-by-members.js.map +1 -1
  37. package/types.d.ts +15 -1
  38. package/types.js.map +1 -1
@@ -0,0 +1,130 @@
1
+ function hasContent(c) {
2
+ return c.members.size > 0 || c.grantRoles.size > 0 || c.grantUsers.size > 0 || c.grantPublic.size > 0;
3
+ }
4
+ export function extractContribution(desc) {
5
+ const members = new Map();
6
+ if (desc.members) {
7
+ for (const [role, users] of Object.entries(desc.members)) {
8
+ members.set(role, new Set(users));
9
+ }
10
+ }
11
+ const grantRoles = new Map();
12
+ if (desc.grant?.roles) {
13
+ for (const [role, channels] of Object.entries(desc.grant.roles)) {
14
+ grantRoles.set(role, new Set(channels));
15
+ }
16
+ }
17
+ const grantUsers = new Map();
18
+ if (desc.grant?.users) {
19
+ for (const [user, channels] of Object.entries(desc.grant.users)) {
20
+ grantUsers.set(user, new Set(channels));
21
+ }
22
+ }
23
+ const grantPublic = new Set(desc.grant?.public ?? []);
24
+ return { members, grantRoles, grantUsers, grantPublic };
25
+ }
26
+ export class GrantReduce {
27
+ docContributions = new Map();
28
+ effectiveMembers = new Map();
29
+ roleGrants = new Map();
30
+ userGrants = new Map();
31
+ publicChannels = new Set();
32
+ _hydrated = false;
33
+ get isHydrated() {
34
+ return this._hydrated;
35
+ }
36
+ markHydrated() {
37
+ this._hydrated = true;
38
+ }
39
+ addDoc(docId, contribution) {
40
+ if (!hasContent(contribution)) {
41
+ if (this.docContributions.has(docId)) {
42
+ this.docContributions.delete(docId);
43
+ this.rebuild();
44
+ }
45
+ return;
46
+ }
47
+ const existed = this.docContributions.has(docId);
48
+ this.docContributions.set(docId, contribution);
49
+ if (existed) {
50
+ this.rebuild();
51
+ }
52
+ else {
53
+ this.unionContribution(contribution);
54
+ }
55
+ }
56
+ removeDoc(docId) {
57
+ const existed = this.docContributions.delete(docId);
58
+ if (existed) {
59
+ this.rebuild();
60
+ }
61
+ }
62
+ resolveEffectiveChannels(userSlug) {
63
+ const result = new Set();
64
+ const direct = this.userGrants.get(userSlug);
65
+ if (direct) {
66
+ for (const ch of direct) {
67
+ result.add(ch);
68
+ }
69
+ }
70
+ for (const [roleName, members] of this.effectiveMembers) {
71
+ if (members.has(userSlug)) {
72
+ const roleChannels = this.roleGrants.get(roleName);
73
+ if (roleChannels) {
74
+ for (const ch of roleChannels) {
75
+ result.add(ch);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ return result;
81
+ }
82
+ hasRole(userSlug, roleName) {
83
+ return this.effectiveMembers.get(roleName)?.has(userSlug) ?? false;
84
+ }
85
+ rebuild() {
86
+ this.effectiveMembers = new Map();
87
+ this.roleGrants = new Map();
88
+ this.userGrants = new Map();
89
+ this.publicChannels = new Set();
90
+ for (const contribution of this.docContributions.values()) {
91
+ this.unionContribution(contribution);
92
+ }
93
+ }
94
+ unionContribution(c) {
95
+ for (const [role, users] of c.members) {
96
+ let set = this.effectiveMembers.get(role);
97
+ if (!set) {
98
+ set = new Set();
99
+ this.effectiveMembers.set(role, set);
100
+ }
101
+ for (const u of users) {
102
+ set.add(u);
103
+ }
104
+ }
105
+ for (const [role, channels] of c.grantRoles) {
106
+ let set = this.roleGrants.get(role);
107
+ if (!set) {
108
+ set = new Set();
109
+ this.roleGrants.set(role, set);
110
+ }
111
+ for (const ch of channels) {
112
+ set.add(ch);
113
+ }
114
+ }
115
+ for (const [user, channels] of c.grantUsers) {
116
+ let set = this.userGrants.get(user);
117
+ if (!set) {
118
+ set = new Set();
119
+ this.userGrants.set(user, set);
120
+ }
121
+ for (const ch of channels) {
122
+ set.add(ch);
123
+ }
124
+ }
125
+ for (const ch of c.grantPublic) {
126
+ this.publicChannels.add(ch);
127
+ }
128
+ }
129
+ }
130
+ //# sourceMappingURL=grant-reduce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-reduce.js","sourceRoot":"","sources":["../../jsr/public/grant-reduce.ts"],"names":[],"mappings":"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"}
@@ -1,59 +1,15 @@
1
1
  import { EventoHandler, Result, Option, HandleTriggerCtx } from "@adviser/cement";
2
2
  import { Scope } from "@adviser/scopey";
3
- import { type PromptStyle, MsgBase, PromptAndBlockMsgs, ReqPromptChatSection, ReqPromptFSChatSection, ReqWithVerifiedAuth, VibeFile, VibesDiyError, W3CWebSocketEvent, type SelectedSlotInput, type SlotConfig } from "@vibes.diy/api-types";
3
+ import { type PromptStyle, MsgBase, PromptAndBlockMsgs, ReqPromptChatSection, ReqPromptFSChatSection, ReqWithVerifiedAuth, VibeFile, VibesDiyError, W3CWebSocketEvent } from "@vibes.diy/api-types";
4
4
  import { VibesApiSQLCtx } from "../types.js";
5
- import { ChatMessage, CodeMsg, CodeBeginMsg, CodeLineMsg, FileSystemRef, BlockEndMsg, CodeEndMsg, type ApplyEditsError, type FenceParseError } from "@vibes.diy/call-ai-v2";
6
- import type { Logger } from "@adviser/cement";
7
- export interface PromptAssetFetchDeps {
8
- readonly fetchAsset: (url: string) => Promise<Result<ReadableStream<Uint8Array>>>;
9
- }
10
- export declare function createPromptAssetFetch(deps: PromptAssetFetchDeps): typeof fetch;
11
- export declare function promptsPkgBaseUrl(workspace: string): string;
12
- interface CodeBlocks {
13
- begin: CodeBeginMsg;
14
- lines: CodeLineMsg[];
15
- end?: CodeMsg;
16
- }
17
- export declare function resolveCodeBlocksToFileSystem(blocks: readonly CodeBlocks[], seed?: ReadonlyMap<string, string>): VibeFile[];
18
- export interface ApplyErrorEvent {
19
- readonly chatId: string;
20
- readonly promptId: string;
21
- readonly blockId: string;
22
- readonly sectionId: string;
23
- readonly kind: "fence-parse" | "apply";
24
- readonly reason: string;
25
- readonly searchPrefix?: string;
26
- }
27
- export interface StreamingResolverDeps {
28
- readonly chatId: string;
29
- readonly promptId: string;
30
- readonly seed: ReadonlyMap<string, string>;
31
- readonly onApplyError: (evt: ApplyErrorEvent) => void;
32
- }
33
- export interface BlockApplyResult {
34
- readonly path: string;
35
- readonly errors: readonly ApplyErrorEvent[];
36
- }
37
- export interface StreamingResolver {
38
- readonly observeBlock: (block: {
39
- begin: CodeBeginMsg;
40
- lines: readonly CodeLineMsg[];
41
- end: CodeEndMsg;
42
- }) => BlockApplyResult;
43
- readonly getVfs: () => ReadonlyMap<string, string>;
44
- }
45
- export declare function createStreamingResolver(deps: StreamingResolverDeps): StreamingResolver;
46
- export interface ClosedCodeBlock {
47
- readonly begin: CodeBeginMsg;
48
- readonly lines: readonly CodeLineMsg[];
49
- readonly end: CodeEndMsg;
50
- }
51
- export interface BlockAccumulator {
52
- readonly ingest: (msg: unknown) => ClosedCodeBlock | undefined;
53
- }
54
- export declare function createBlockAccumulator(): BlockAccumulator;
55
- export declare function logApplyError(logger: Logger, evt: ApplyErrorEvent): void;
56
- export type { ApplyEditsError, FenceParseError };
5
+ import { FileSystemRef, BlockEndMsg } from "@vibes.diy/call-ai-v2";
6
+ import { createPromptAssetFetch, promptsPkgBaseUrl, type PromptAssetFetchDeps } from "../intern/prompt-asset-fetch.js";
7
+ import { resolveCodeBlocksToFileSystem, createStreamingResolver, createBlockAccumulator, logApplyError, type ApplyErrorEvent, type StreamingResolverDeps, type BlockApplyResult, type StreamingResolver, type ClosedCodeBlock, type BlockAccumulator, type ApplyEditsError, type FenceParseError } from "../intern/prompt-streaming.js";
8
+ import { reconstructConversationMessages, assemblePromptPayload, type ReconstructOpts, type AssemblePromptPayloadArgs } from "../intern/prompt-assembly.js";
9
+ export type { PromptAssetFetchDeps };
10
+ export { createPromptAssetFetch, promptsPkgBaseUrl };
11
+ export { resolveCodeBlocksToFileSystem, createStreamingResolver, createBlockAccumulator, logApplyError };
12
+ export type { ApplyErrorEvent, StreamingResolverDeps, BlockApplyResult, StreamingResolver, ClosedCodeBlock, BlockAccumulator, ApplyEditsError, FenceParseError, };
57
13
  export declare function handlePromptContext({ vctx, req, resChat, promptId, blockSeq, value, collectedMsgs: iCollectedMsgs, blockChunks, fileSystem, }: {
58
14
  vctx: VibesApiSQLCtx;
59
15
  req: ReqWithVerifiedAuth<ReqPromptChatSection>;
@@ -68,23 +24,8 @@ export declare function handlePromptContext({ vctx, req, resChat, promptId, bloc
68
24
  blockSeq: number;
69
25
  fsRef: Option<FileSystemRef>;
70
26
  }>>;
71
- export interface ReconstructOpts {
72
- readonly keepFullTurnStreamId?: string;
73
- }
74
- export declare function reconstructConversationMessages(sectionMsgs: PromptAndBlockMsgs[], opts?: ReconstructOpts): ChatMessage[];
75
- export interface AssemblePromptPayloadArgs {
76
- readonly chatId: string;
77
- readonly model: string;
78
- readonly newUserMessages: readonly ChatMessage[];
79
- readonly selected?: SelectedSlotInput;
80
- readonly slots?: SlotConfig;
81
- readonly focusPath?: string;
82
- readonly slotDeliveryMode?: "user" | "system";
83
- }
84
- export declare function assemblePromptPayload(vctx: VibesApiSQLCtx, args: AssemblePromptPayloadArgs): Promise<Result<{
85
- model: string;
86
- messages: ChatMessage[];
87
- }>>;
27
+ export { reconstructConversationMessages, assemblePromptPayload };
28
+ export type { ReconstructOpts, AssemblePromptPayloadArgs };
88
29
  interface ResChat {
89
30
  appSlug: string;
90
31
  ownerHandle: string;
@@ -1,177 +1,29 @@
1
- import { Result, Option, EventoResult, exception2Result, chunkyAsync, BuildURI, URI, } from "@adviser/cement";
1
+ import { Result, Option, EventoResult, exception2Result, chunkyAsync } from "@adviser/cement";
2
2
  import { storeAndAuditAsset } from "./store-and-audit-asset.js";
3
3
  import { convertImageEvtToFileRef } from "./convert-image-evt.js";
4
4
  import { scopey } from "@adviser/scopey";
5
- import { isReqCreationPromptChatSection, isReqPromptApplicationChatSection, isPromptFSStyle, isReqPromptFSChatSection, isReqPromptFSUpdateChatSection, isReqPromptImageChatSection, isReqPromptLLMChatSection, parseArrayWarning, PromptAndBlockMsgs, reqPromptChatSection, isPromptReq, isReqPromptFSSetChatSection, parseArray, vibeFile, isVibeCodeBlock, isActiveEnrichedPrompt, isActiveSkills, isActiveTheme, isActiveTitle, } from "@vibes.diy/api-types";
5
+ import { isReqCreationPromptChatSection, isReqPromptApplicationChatSection, isPromptFSStyle, isReqPromptFSChatSection, isReqPromptFSUpdateChatSection, isReqPromptImageChatSection, isReqPromptLLMChatSection, reqPromptChatSection, isReqPromptFSSetChatSection, parseArray, vibeFile, isVibeCodeBlock, } from "@vibes.diy/api-types";
6
6
  import { ensureLogger } from "@fireproof/core-runtime";
7
7
  import { type } from "arktype";
8
8
  import { checkAuth } from "../check-auth.js";
9
9
  import { unwrapMsgBase, wrapMsgBase } from "../unwrap-msg-base.js";
10
10
  import { and, desc, eq } from "drizzle-orm/sql/expressions";
11
- import { applyEdits, createStatsCollector, createLineStream, createDataStream, createSseStream, createDeltaStream, createSectionsStream, isBlockEnd, isCodeBegin, isCodeEnd, isCodeLine, isDeltaLine, isToplevelLine, parseFenceBody, FileSystemRef, isBlockStreamMsg, isBlockImage, } from "@vibes.diy/call-ai-v2";
12
- import { getRecoveryAddendum, getRecoveryStitchAddendum, makeBaseSystemPrompt, resolveEffectiveModel } from "@vibes.diy/prompts";
11
+ import { createStatsCollector, createLineStream, createDataStream, createSseStream, createDeltaStream, createSectionsStream, isBlockEnd, isDeltaLine, FileSystemRef, isBlockStreamMsg, isBlockImage, } from "@vibes.diy/call-ai-v2";
12
+ import { getRecoveryAddendum, getRecoveryStitchAddendum } from "@vibes.diy/prompts";
13
13
  import { ensureAppSlugItem } from "./ensure-app-slug-item.js";
14
14
  import { getModelDefaults } from "../intern/get-model-defaults.js";
15
15
  import { buildRecoveryRequest, buildTruncatedEvent, shouldAttemptRecovery, updateRecoveryCounter, } from "../intern/recovery.js";
16
- import { loadVersionTimeline, selectSlotSources, loadLatestPromptId } from "../intern/version-timeline.js";
17
- import { assembleSlotMessages, renderSlotMessagesAs, resolveSlotConfig } from "../intern/slot-assembler.js";
16
+ import { loadVersionTimeline } from "../intern/version-timeline.js";
17
+ import { resolveSlotConfig } from "../intern/slot-assembler.js";
18
+ import { createPromptAssetFetch, promptsPkgBaseUrl } from "../intern/prompt-asset-fetch.js";
19
+ import { resolveCodeBlocksToFileSystem, createStreamingResolver, createBlockAccumulator, logApplyError, } from "../intern/prompt-streaming.js";
20
+ import { reconstructConversationMessages, assemblePromptPayload, } from "../intern/prompt-assembly.js";
18
21
  import { bumpAppRecency } from "../intern/bump-app-recency.js";
19
22
  function clientWsSend(ctx) {
20
23
  return ctx.send.provider;
21
24
  }
22
- export function createPromptAssetFetch(deps) {
23
- return async (url, _init) => {
24
- const uri = URI.from(url);
25
- if (uri.protocol === "file:") {
26
- return fetch(url, _init);
27
- }
28
- const rRes = await deps.fetchAsset(uri.toString());
29
- if (rRes.isErr()) {
30
- return new Response(JSON.stringify({ error: rRes.Err() }), { status: 500 });
31
- }
32
- return new Response(rRes.Ok());
33
- };
34
- }
35
- export function promptsPkgBaseUrl(workspace) {
36
- return BuildURI.from(workspace).appendRelative("@vibes.diy/prompts/").toString();
37
- }
38
- export function resolveCodeBlocksToFileSystem(blocks, seed) {
39
- const byPath = new Map();
40
- for (const block of blocks) {
41
- if (!block.end)
42
- continue;
43
- const path = block.begin.path ?? "App.jsx";
44
- const langRaw = block.begin.lang.toLowerCase();
45
- const lang = ["js", "jsx"].includes(langRaw) ? "jsx" : langRaw;
46
- const acc = byPath.get(path) ?? { lang, lines: [] };
47
- acc.lines.push(block.lines.map((l) => l.line));
48
- byPath.set(path, acc);
49
- }
50
- const result = [];
51
- for (const [path, { lang, lines }] of byPath.entries()) {
52
- const filename = path.startsWith("/") ? path : `/${path}`;
53
- let resolved = seed?.get(filename) ?? seed?.get(path) ?? "";
54
- for (const blockLines of lines) {
55
- const parsed = parseFenceBody(blockLines);
56
- const r = applyEdits(resolved, parsed.edits);
57
- resolved = r.content;
58
- }
59
- result.push({
60
- type: "code-block",
61
- filename,
62
- lang,
63
- content: resolved,
64
- });
65
- }
66
- if (seed) {
67
- for (const [seededName, seededContent] of seed.entries()) {
68
- const filename = seededName.startsWith("/") ? seededName : `/${seededName}`;
69
- const path = filename.startsWith("/") ? filename.slice(1) : filename;
70
- if (byPath.has(path) || byPath.has(filename))
71
- continue;
72
- const ext = filename.match(/\.([^.]+)$/)?.[1] ?? "jsx";
73
- const lang = ["js", "jsx"].includes(ext.toLowerCase()) ? "jsx" : ext.toLowerCase();
74
- result.push({
75
- type: "code-block",
76
- filename,
77
- lang,
78
- content: seededContent,
79
- });
80
- }
81
- }
82
- return result;
83
- }
84
- function normalizeFilename(rawPath) {
85
- const path = rawPath ?? "App.jsx";
86
- return path.startsWith("/") ? path : `/${path}`;
87
- }
88
- function searchPrefixOf(search) {
89
- const firstLine = search.split("\n").find((l) => l.trim().length > 0) ?? "";
90
- return firstLine.length > 80 ? `${firstLine.slice(0, 80)}…` : firstLine;
91
- }
92
- export function createStreamingResolver(deps) {
93
- const vfs = new Map();
94
- const seedFor = (filename, rawPath) => {
95
- return deps.seed.get(filename) ?? deps.seed.get(rawPath) ?? "";
96
- };
97
- return {
98
- observeBlock(block) {
99
- const rawPath = block.begin.path ?? "App.jsx";
100
- const filename = normalizeFilename(rawPath);
101
- const current = vfs.has(filename) ? (vfs.get(filename) ?? "") : seedFor(filename, rawPath);
102
- const parsed = parseFenceBody(block.lines.map((l) => l.line));
103
- const errors = [];
104
- for (const fenceErr of parsed.errors) {
105
- const evt = {
106
- chatId: deps.chatId,
107
- promptId: deps.promptId,
108
- blockId: block.end.blockId,
109
- sectionId: block.end.sectionId,
110
- kind: "fence-parse",
111
- reason: fenceErr.kind,
112
- };
113
- deps.onApplyError(evt);
114
- errors.push(evt);
115
- }
116
- const applied = applyEdits(current, parsed.edits);
117
- for (const applyErr of applied.errors) {
118
- const evt = {
119
- chatId: deps.chatId,
120
- promptId: deps.promptId,
121
- blockId: block.end.blockId,
122
- sectionId: block.end.sectionId,
123
- kind: "apply",
124
- reason: applyErr.reason,
125
- searchPrefix: searchPrefixOf(applyErr.search),
126
- };
127
- deps.onApplyError(evt);
128
- errors.push(evt);
129
- }
130
- vfs.set(filename, applied.content);
131
- return { path: filename, errors };
132
- },
133
- getVfs() {
134
- return new Map(vfs);
135
- },
136
- };
137
- }
138
- export function createBlockAccumulator() {
139
- const open = new Map();
140
- return {
141
- ingest(msg) {
142
- if (isCodeBegin(msg)) {
143
- open.set(msg.blockId, { begin: msg, lines: [] });
144
- return undefined;
145
- }
146
- if (isCodeLine(msg)) {
147
- open.get(msg.blockId)?.lines.push(msg);
148
- return undefined;
149
- }
150
- if (isCodeEnd(msg)) {
151
- const acc = open.get(msg.blockId);
152
- if (!acc)
153
- return undefined;
154
- open.delete(msg.blockId);
155
- return { begin: acc.begin, lines: acc.lines, end: msg };
156
- }
157
- return undefined;
158
- },
159
- };
160
- }
161
- export function logApplyError(logger, evt) {
162
- logger
163
- .Debug()
164
- .Any({
165
- chatId: evt.chatId,
166
- promptId: evt.promptId,
167
- blockId: evt.blockId,
168
- sectionId: evt.sectionId,
169
- kind: evt.kind,
170
- reason: evt.reason,
171
- ...(evt.searchPrefix === undefined ? {} : { searchPrefix: evt.searchPrefix }),
172
- })
173
- .Msg("apply-error");
174
- }
25
+ export { createPromptAssetFetch, promptsPkgBaseUrl };
26
+ export { resolveCodeBlocksToFileSystem, createStreamingResolver, createBlockAccumulator, logApplyError };
175
27
  async function appendBlockEvent({ ctx, vctx, req, promptId, blockSeq, evt, emitMode = "store", resChat, }) {
176
28
  let processedEvt = evt;
177
29
  if (isBlockImage(evt) && evt.url && resChat) {
@@ -311,190 +163,7 @@ export async function handlePromptContext({ vctx, req, resChat, promptId, blockS
311
163
  iCollectedMsgs.splice(0, collectedMsgs.length);
312
164
  return Result.Ok({ blockSeq, fsRef });
313
165
  }
314
- export function reconstructConversationMessages(sectionMsgs, opts = {}) {
315
- const messages = [];
316
- const assistantLines = [];
317
- let currentStreamId;
318
- let blockBuffer = null;
319
- function flushAssistant() {
320
- if (assistantLines.length === 0)
321
- return;
322
- messages.push({
323
- role: "assistant",
324
- content: [{ type: "text", text: assistantLines.join("\n") }],
325
- });
326
- assistantLines.length = 0;
327
- }
328
- for (const msg of sectionMsgs) {
329
- switch (true) {
330
- case isPromptReq(msg):
331
- flushAssistant();
332
- currentStreamId = msg.streamId;
333
- messages.push(...msg.request.messages.filter((m) => m.role === "user"));
334
- break;
335
- case isToplevelLine(msg):
336
- assistantLines.push(msg.line);
337
- break;
338
- case isCodeBegin(msg): {
339
- const compact = opts.keepFullTurnStreamId !== undefined && currentStreamId !== opts.keepFullTurnStreamId;
340
- if (compact) {
341
- blockBuffer = { path: msg.path ?? "App.jsx", lineCount: 0 };
342
- }
343
- else {
344
- assistantLines.push("```" + msg.lang);
345
- }
346
- break;
347
- }
348
- case isCodeLine(msg):
349
- if (blockBuffer) {
350
- blockBuffer.lineCount++;
351
- if (!blockBuffer.firstNonBlank && msg.line.trim().length > 0) {
352
- blockBuffer.firstNonBlank = msg.line.trim();
353
- }
354
- }
355
- else {
356
- assistantLines.push(msg.line);
357
- }
358
- break;
359
- case isCodeEnd(msg):
360
- if (blockBuffer) {
361
- const isEdit = blockBuffer.firstNonBlank === "<<<<<<< SEARCH";
362
- if (isEdit) {
363
- assistantLines.push(`[${blockBuffer.lineCount}-line edit to ${blockBuffer.path}]`);
364
- }
365
- else {
366
- const lines = msg.stats.lines !== 0 ? msg.stats.lines : blockBuffer.lineCount;
367
- const bytes = msg.stats.bytes;
368
- assistantLines.push(`[Created ${blockBuffer.path} — ${lines} lines, ${bytes} bytes]`);
369
- }
370
- blockBuffer = null;
371
- }
372
- else {
373
- assistantLines.push("```");
374
- }
375
- break;
376
- }
377
- }
378
- flushAssistant();
379
- return messages;
380
- }
381
- async function loadActiveSettings(vctx, chatId) {
382
- const rChat = await exception2Result(() => vctx.sql.db
383
- .select({ appSlug: vctx.sql.tables.chatContexts.appSlug, ownerHandle: vctx.sql.tables.chatContexts.ownerHandle })
384
- .from(vctx.sql.tables.chatContexts)
385
- .where(eq(vctx.sql.tables.chatContexts.chatId, chatId))
386
- .limit(1)
387
- .then((r) => r[0]));
388
- if (rChat.isErr() || !rChat.Ok())
389
- return {};
390
- const { appSlug, ownerHandle } = rChat.Ok();
391
- const rApp = await exception2Result(() => vctx.sql.db
392
- .select({ settings: vctx.sql.tables.appSettings.settings })
393
- .from(vctx.sql.tables.appSettings)
394
- .where(and(eq(vctx.sql.tables.appSettings.appSlug, appSlug), eq(vctx.sql.tables.appSettings.ownerHandle, ownerHandle)))
395
- .limit(1)
396
- .then((r) => r[0]));
397
- if (rApp.isErr() || !rApp.Ok())
398
- return {};
399
- const entries = (rApp.Ok().settings ?? []);
400
- return {
401
- skills: entries.find(isActiveSkills)?.skills,
402
- theme: entries.find(isActiveTheme)?.theme,
403
- title: entries.find(isActiveTitle)?.title,
404
- enrichedPrompt: entries.find(isActiveEnrichedPrompt)?.enrichedPrompt,
405
- };
406
- }
407
- export async function assemblePromptPayload(vctx, args) {
408
- const { chatId, model, newUserMessages } = args;
409
- const sections = await vctx.sql.db
410
- .select()
411
- .from(vctx.sql.tables.chatSections)
412
- .where(eq(vctx.sql.tables.chatSections.chatId, chatId))
413
- .orderBy(vctx.sql.tables.chatSections.created);
414
- const allSectionMsgs = [];
415
- for (const rowSection of sections) {
416
- const { filtered: sectionMsgs, warning: sectionWarning } = parseArrayWarning(rowSection.blocks, PromptAndBlockMsgs);
417
- if (sectionWarning.length > 0) {
418
- ensureLogger(vctx.sthis, "assemblePromptPayload").Warn().Any({ parseErrors: sectionWarning }).Msg("skip");
419
- }
420
- allSectionMsgs.push(...sectionMsgs);
421
- }
422
- const timelineResult = await loadVersionTimeline(vctx, chatId);
423
- if (timelineResult.isErr())
424
- return Result.Err(timelineResult);
425
- const latestPromptIdResult = await loadLatestPromptId(vctx, chatId);
426
- if (latestPromptIdResult.isErr())
427
- return Result.Err(latestPromptIdResult);
428
- const timeline = timelineResult.Ok();
429
- const latestPromptId = latestPromptIdResult.Ok();
430
- const compactionDisabled = args.slots?.compaction === "off";
431
- const reconstructed = reconstructConversationMessages(allSectionMsgs, {
432
- keepFullTurnStreamId: compactionDisabled ? undefined : latestPromptId,
433
- });
434
- const newUserOnly = newUserMessages.filter((m) => m.role === "user");
435
- const { skills, theme, title, enrichedPrompt } = await loadActiveSettings(vctx, chatId);
436
- const isInitial = timeline.length === 0;
437
- const systemPrompt = await exception2Result(async () => {
438
- return makeBaseSystemPrompt(await resolveEffectiveModel({ model }, {}), {
439
- skills,
440
- theme,
441
- title,
442
- enrichedPrompt,
443
- demoData: false,
444
- variant: isInitial ? "initial" : "continuation",
445
- pkgBaseUrl: promptsPkgBaseUrl(vctx.params.pkgRepos.workspace),
446
- fetch: createPromptAssetFetch({ fetchAsset: vctx.fetchAsset }),
447
- });
448
- });
449
- if (systemPrompt.isErr()) {
450
- console.error("Failed to create system prompt:", systemPrompt.Err());
451
- return Result.Err(systemPrompt);
452
- }
453
- const hasUserMessage = [...reconstructed, ...newUserOnly].some((m) => m.role === "user");
454
- if (hasUserMessage === false) {
455
- return Result.Err(`No user messages found in the prompt`);
456
- }
457
- const slotSources = selectSlotSources(timeline);
458
- let selectedVersion;
459
- const sel = args.selected;
460
- if (sel?.kind === "version") {
461
- const idx = timeline.findIndex((t) => t.fsId === sel.fsId);
462
- if (idx >= 0) {
463
- selectedVersion = { vfs: timeline[idx].vfs, turnsAgo: timeline.length - 1 - idx };
464
- }
465
- }
466
- const selectedDraftMap = args.selected?.kind === "draft"
467
- ? new Map(args.selected.files.flatMap((f) => f.type === "code-block" || f.type === "str-asset-block" ? [[f.filename, f.content]] : []))
468
- : undefined;
469
- const slotMessages = assembleSlotMessages({
470
- original: slotSources.original !== undefined ? { vfs: slotSources.original.vfs, turnsAgo: timeline.length - 1 } : undefined,
471
- prev2: slotSources.prev2?.vfs,
472
- previous: slotSources.previous?.vfs,
473
- selectedVersion,
474
- selectedDraft: selectedDraftMap,
475
- focusPath: args.focusPath ?? "App.jsx",
476
- config: args.slots ?? {},
477
- });
478
- const slotDeliveryMode = args.slotDeliveryMode ?? (vctx.sthis.env.get("SLOT_DELIVERY_MODE") === "system" ? "system" : "user");
479
- const slotChatMessages = renderSlotMessagesAs(slotMessages, slotDeliveryMode);
480
- return Result.Ok({
481
- model,
482
- messages: [
483
- {
484
- role: "system",
485
- content: [
486
- {
487
- type: "text",
488
- text: systemPrompt.Ok().systemPrompt,
489
- },
490
- ],
491
- },
492
- ...reconstructed,
493
- ...slotChatMessages,
494
- ...newUserOnly,
495
- ],
496
- });
497
- }
166
+ export { reconstructConversationMessages, assemblePromptPayload };
498
167
  async function getResChatFromMode(vctx, req, orig) {
499
168
  let iResChat;
500
169
  if (isReqPromptApplicationChatSection(orig) || isReqPromptImageChatSection(orig)) {