@vibes.diy/api-svc 2.0.0-dev-cli-j → 2.0.0-dev-cli-l

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.
@@ -1,12 +1,12 @@
1
1
  import { Result, Option, EventoResult, exception2Result, chunkyAsync, BuildURI, pathOps, URI, } from "@adviser/cement";
2
2
  import { scopey } from "@adviser/scopey";
3
- import { isReqCreationPromptChatSection, isReqPromptApplicationChatSection, parseArrayWarning, PromptAndBlockMsgs, reqPromptChatSection, } from "@vibes.diy/api-types";
3
+ import { isReqCreationPromptChatSection, isReqPromptApplicationChatSection, isReqPromptFSChatSection, isReqPromptFSUpdateChatSection, isReqPromptImageChatSection, isReqPromptLLMChatSection, parseArrayWarning, PromptAndBlockMsgs, reqPromptChatSection, isPromptReq, isReqPromptFSSetChatSection, parseArray, vibeFile, isVibeCodeBlock, } from "@vibes.diy/api-types";
4
4
  import { ensureLogger } from "@fireproof/core-runtime";
5
5
  import { type } from "arktype";
6
6
  import { checkAuth } from "../check-auth.js";
7
7
  import { unwrapMsgBase, wrapMsgBase } from "../unwrap-msg-base.js";
8
- import { and, eq } from "drizzle-orm/sql/expressions";
9
- import { createStatsCollector, createLineStream, createDataStream, createSseStream, createDeltaStream, createSectionsStream, isBlockEnd, isCodeBegin, isCodeEnd, isCodeLine, isPromptReq, FileSystemRef, isBlockStreamMsg, } from "@vibes.diy/call-ai-v2";
8
+ import { and, desc, eq } from "drizzle-orm/sql/expressions";
9
+ import { createStatsCollector, createLineStream, createDataStream, createSseStream, createDeltaStream, createSectionsStream, isBlockEnd, isCodeBegin, isCodeEnd, isCodeLine, FileSystemRef, isBlockStreamMsg, } from "@vibes.diy/call-ai-v2";
10
10
  import { makeBaseSystemPrompt, resolveEffectiveModel } from "@vibes.diy/prompts";
11
11
  import { ensureAppSlugItem } from "./ensure-app-slug-item.js";
12
12
  import { getModelDefaults } from "../intern/get-model-defaults.js";
@@ -232,6 +232,340 @@ async function injectSystemPrompt(vctx, chatId, model) {
232
232
  ],
233
233
  });
234
234
  }
235
+ async function getResChatFromMode(vctx, req, orig) {
236
+ const iResChat = await vctx.sql.db
237
+ .select()
238
+ .from(vctx.sql.tables.chatContexts)
239
+ .where(and(eq(vctx.sql.tables.chatContexts.userId, req._auth.verifiedAuth.claims.userId), eq(vctx.sql.tables.chatContexts.chatId, req.chatId)))
240
+ .limit(1)
241
+ .then((r) => r[0]);
242
+ if (!iResChat) {
243
+ if (isReqCreationPromptChatSection(orig)) {
244
+ return Result.Err(`Creation Chat ID ${req.chatId} not found`);
245
+ }
246
+ else if (isReqPromptApplicationChatSection(orig)) {
247
+ return Result.Err(`Application Chat ID ${req.chatId} not found`);
248
+ }
249
+ else if (isReqPromptImageChatSection(orig)) {
250
+ return Result.Err(`Image Chat ID ${req.chatId} not found`);
251
+ }
252
+ }
253
+ const resChat = { ...iResChat, mode: orig.mode };
254
+ return Result.Ok(resChat);
255
+ }
256
+ async function handlerLlmRequest({ scope, ctx, vctx, blockSeq, req, resChat, promptId, }) {
257
+ await scope
258
+ .evalResult(async () => {
259
+ const r = await appendBlockEvent({
260
+ ctx,
261
+ vctx,
262
+ req,
263
+ promptId,
264
+ blockSeq: blockSeq,
265
+ evt: {
266
+ type: "prompt.req",
267
+ streamId: promptId,
268
+ chatId: req.chatId,
269
+ seq: blockSeq,
270
+ request: req.prompt,
271
+ timestamp: new Date(),
272
+ },
273
+ });
274
+ blockSeq++;
275
+ return r;
276
+ })
277
+ .do();
278
+ const modelId = await scope
279
+ .evalResult(async () => {
280
+ const r = await getModelDefaults(vctx, { appSlug: resChat.appSlug, userSlug: resChat.userSlug });
281
+ if (r.isErr()) {
282
+ return Result.Err(r);
283
+ }
284
+ switch (req.mode) {
285
+ case "chat":
286
+ return Result.Ok(req.prompt.model ?? r.Ok().chat.model.id);
287
+ case "app":
288
+ return Result.Ok(req.prompt.model ?? r.Ok().app.model.id);
289
+ case "img":
290
+ return Result.Ok(req.prompt.model ?? r.Ok().img.model.id);
291
+ default:
292
+ return Result.Err(`Unknown prompt mode: ${req.mode}`);
293
+ }
294
+ })
295
+ .do();
296
+ const withSystemPrompt = await scope
297
+ .evalResult(async () => {
298
+ let withSystemPrompt = Result.Ok({
299
+ model: modelId,
300
+ messages: [],
301
+ });
302
+ if (req.mode === "chat") {
303
+ withSystemPrompt = await injectSystemPrompt(vctx, req.chatId, req.prompt.model ?? modelId);
304
+ }
305
+ else if (req.mode === "app") {
306
+ withSystemPrompt = Result.Ok({
307
+ model: req.prompt.model ?? modelId,
308
+ messages: req.prompt.messages,
309
+ });
310
+ }
311
+ return withSystemPrompt;
312
+ })
313
+ .do();
314
+ const llmReq = {
315
+ ...{
316
+ ...req.prompt,
317
+ messages: withSystemPrompt.messages,
318
+ },
319
+ ...vctx.params.llm.enforced,
320
+ model: withSystemPrompt.model,
321
+ headers: vctx.params.llm.headers,
322
+ logprobs: true,
323
+ stream: true,
324
+ };
325
+ const res = await scope
326
+ .evalResult(async () => {
327
+ console.log(promptId, "Sending LLM request:", llmReq.model);
328
+ const res = await vctx.llmRequest(llmReq);
329
+ if (!res.ok) {
330
+ return Result.Err(`LLM request failed with status ${res.status} :${llmReq.model} : ${res.statusText}`);
331
+ }
332
+ if (!res.body) {
333
+ return Result.Err(`LLM request returned no body`);
334
+ }
335
+ return Result.Ok(res);
336
+ })
337
+ .do();
338
+ return { res, blockSeq };
339
+ }
340
+ async function handleEndMsg({ collectedMsgs, vctx, req, ctx, resChat, promptId, value, blockSeq, }) {
341
+ const r = await handlePromptContext({ vctx, req, promptId, resChat, value, blockSeq, collectedMsgs });
342
+ if (r.isErr()) {
343
+ return Result.Err(r);
344
+ }
345
+ blockSeq = r.Ok().blockSeq;
346
+ const rEvt = await appendBlockEvent({
347
+ ctx,
348
+ vctx,
349
+ req,
350
+ promptId,
351
+ blockSeq: blockSeq++,
352
+ evt: { ...value, fsRef: r.Ok().fsRef.toValue() },
353
+ emitMode: "emit-only",
354
+ });
355
+ for (const conn of vctx.connections) {
356
+ const chatCtx = conn.chatIds.get(req.chatId);
357
+ const promptIdCtx = chatCtx?.promptIds.get(promptId);
358
+ if (promptIdCtx && chatCtx) {
359
+ chatCtx.promptIds.delete(promptId);
360
+ }
361
+ }
362
+ if (rEvt.isErr()) {
363
+ return Result.Err(rEvt);
364
+ }
365
+ return Result.Ok(blockSeq);
366
+ }
367
+ async function handleLlmResponse({ scope, vctx, req, ctx, res, resChat, promptId, blockSeq, }) {
368
+ await scope
369
+ .evalResult(async () => {
370
+ const pipeline = res
371
+ .body.pipeThrough(createStatsCollector(promptId, 1000))
372
+ .pipeThrough(createLineStream(promptId))
373
+ .pipeThrough(createDataStream(promptId))
374
+ .pipeThrough(createSseStream(promptId))
375
+ .pipeThrough(createDeltaStream(promptId, () => vctx.sthis.nextId(12).str))
376
+ .pipeThrough(createSectionsStream(promptId, () => vctx.sthis.nextId(12).str));
377
+ const reader = pipeline.getReader();
378
+ let collectedMsgs;
379
+ let chatCtx;
380
+ for (const conn of vctx.connections) {
381
+ const tChatCtx = conn.chatIds.get(req.chatId);
382
+ if (tChatCtx) {
383
+ chatCtx = tChatCtx;
384
+ const promptIdCtx = chatCtx.promptIds.get(promptId);
385
+ if (!promptIdCtx) {
386
+ collectedMsgs = [];
387
+ chatCtx.promptIds.set(promptId, {
388
+ blocks: collectedMsgs,
389
+ promptId,
390
+ type: "vibes.diy.section-event",
391
+ chatId: req.chatId,
392
+ blockSeq: 0,
393
+ timestamp: new Date(),
394
+ });
395
+ }
396
+ else {
397
+ collectedMsgs = promptIdCtx.blocks;
398
+ }
399
+ }
400
+ }
401
+ if (!collectedMsgs) {
402
+ return Result.Err(`Chat context not found for chatId: ${req.chatId}`);
403
+ }
404
+ while (true) {
405
+ const { done, value } = await reader.read();
406
+ if (done) {
407
+ break;
408
+ }
409
+ if (!isBlockEnd(value)) {
410
+ if (!isBlockStreamMsg(value)) {
411
+ continue;
412
+ }
413
+ collectedMsgs.push(value);
414
+ const r = await appendBlockEvent({
415
+ ctx,
416
+ vctx,
417
+ req,
418
+ promptId,
419
+ blockSeq: blockSeq++,
420
+ evt: value,
421
+ emitMode: "emit-only",
422
+ });
423
+ if (r.isErr()) {
424
+ return Result.Err(r);
425
+ }
426
+ }
427
+ else {
428
+ collectedMsgs.push(value);
429
+ const x = await handleEndMsg({ collectedMsgs, vctx, req, ctx, resChat, promptId, value, blockSeq });
430
+ if (x.isErr()) {
431
+ return Result.Err(x);
432
+ }
433
+ collectedMsgs.splice(0, collectedMsgs.length);
434
+ }
435
+ }
436
+ return Result.Ok();
437
+ })
438
+ .do();
439
+ return blockSeq;
440
+ }
441
+ export async function handleFSPrompt({ scope, vctx, resChat, req, ctx, promptId, }) {
442
+ let fileSystem;
443
+ if (isReqPromptFSSetChatSection(req)) {
444
+ fileSystem = req.fsSet;
445
+ }
446
+ else if (isReqPromptFSUpdateChatSection(req)) {
447
+ const refFS = [];
448
+ if (!req.refFsId) {
449
+ const lastestPrompt = await vctx.sql.db
450
+ .select()
451
+ .from(vctx.sql.tables.promptContexts)
452
+ .innerJoin(vctx.sql.tables.apps, eq(vctx.sql.tables.apps.fsId, vctx.sql.tables.promptContexts.fsId))
453
+ .where(and(eq(vctx.sql.tables.promptContexts.chatId, req.chatId), eq(vctx.sql.tables.promptContexts.promptId, promptId)))
454
+ .orderBy(desc(vctx.sql.tables.promptContexts.created))
455
+ .limit(1)
456
+ .then((r) => r[0]);
457
+ if (lastestPrompt) {
458
+ refFS.push(...parseArray(lastestPrompt.Apps.fileSystem, vibeFile));
459
+ }
460
+ }
461
+ const mapFS = refFS.reduce((acc, file) => {
462
+ acc.set(file.filename, file);
463
+ return acc;
464
+ }, {});
465
+ req.fsUpdate.update.forEach((update) => {
466
+ mapFS.set(update.filename, update);
467
+ });
468
+ req.fsUpdate.remove?.forEach((item) => {
469
+ mapFS.delete(item.filename);
470
+ });
471
+ fileSystem = Array.from(mapFS.values());
472
+ }
473
+ await scope
474
+ .evalResult(async () => {
475
+ const sectionId = vctx.sthis.nextId(12).str;
476
+ let blockNr = 0;
477
+ const blockId = vctx.sthis.nextId(12).str;
478
+ let blockSeq = 0;
479
+ let bytes = 0;
480
+ const collectedMsgs = [
481
+ {
482
+ type: "block.begin",
483
+ blockId,
484
+ streamId: promptId,
485
+ seq: blockSeq++,
486
+ blockNr: blockNr++,
487
+ timestamp: new Date(),
488
+ },
489
+ ...fileSystem.flatMap((file) => {
490
+ if (!isVibeCodeBlock(file)) {
491
+ return [];
492
+ }
493
+ return [
494
+ {
495
+ type: "block.code.begin",
496
+ sectionId,
497
+ lang: file.lang,
498
+ blockId: blockId,
499
+ streamId: promptId,
500
+ seq: blockSeq++,
501
+ blockNr,
502
+ timestamp: new Date(),
503
+ },
504
+ ...file.content.split("\n").map((line, lineNr) => {
505
+ bytes += line.length + 1;
506
+ return {
507
+ type: "block.code.line",
508
+ sectionId,
509
+ blockId,
510
+ line,
511
+ streamId: promptId,
512
+ seq: blockSeq++,
513
+ timestamp: new Date(),
514
+ lang: file.lang,
515
+ blockNr,
516
+ lineNr,
517
+ };
518
+ }),
519
+ {
520
+ type: "block.code.end",
521
+ sectionId,
522
+ blockId,
523
+ streamId: promptId,
524
+ seq: blockSeq++,
525
+ timestamp: new Date(),
526
+ lang: file.lang,
527
+ blockNr,
528
+ },
529
+ ];
530
+ }),
531
+ ];
532
+ const value = {
533
+ type: "block.end",
534
+ stats: {
535
+ toplevel: { lines: 0, bytes: 0 },
536
+ code: { lines: blockSeq, bytes },
537
+ image: { lines: 0, bytes: 0 },
538
+ total: { lines: blockSeq, bytes },
539
+ },
540
+ usage: {
541
+ given: [],
542
+ calculated: {
543
+ prompt_tokens: 0,
544
+ completion_tokens: 0,
545
+ total_tokens: 0,
546
+ },
547
+ },
548
+ blockId: blockId,
549
+ streamId: promptId,
550
+ seq: blockSeq++,
551
+ blockNr: blockNr,
552
+ timestamp: new Date(),
553
+ };
554
+ collectedMsgs.push(value);
555
+ return handleEndMsg({
556
+ collectedMsgs,
557
+ vctx,
558
+ req,
559
+ ctx,
560
+ resChat,
561
+ promptId,
562
+ value,
563
+ blockSeq,
564
+ });
565
+ })
566
+ .do();
567
+ return Result.Ok();
568
+ }
235
569
  export const promptChatSection = {
236
570
  hash: "prompt-chat-section-handler",
237
571
  validate: unwrapMsgBase(async (msg) => {
@@ -248,33 +582,51 @@ export const promptChatSection = {
248
582
  const req = ctx.validated.payload;
249
583
  const orig = ctx.enRequest.payload;
250
584
  const vctx = ctx.ctx.getOrThrow("vibesApiCtx");
251
- let resChat;
252
- if (isReqCreationPromptChatSection(orig)) {
253
- const iResChat = await vctx.sql.db
254
- .select()
255
- .from(vctx.sql.tables.chatContexts)
256
- .where(and(eq(vctx.sql.tables.chatContexts.chatId, req.chatId), eq(vctx.sql.tables.chatContexts.userId, req._auth.verifiedAuth.claims.userId)))
257
- .limit(1)
258
- .then((r) => r[0]);
259
- if (!iResChat) {
260
- return Result.Err(`Creation Chat ID ${req.chatId} not found`);
261
- }
262
- resChat = { ...iResChat, mode: "chat" };
585
+ const rResChat = await getResChatFromMode(vctx, req, orig);
586
+ if (rResChat.isErr()) {
587
+ return Result.Err(rResChat);
263
588
  }
264
- if (isReqPromptApplicationChatSection(orig)) {
265
- const iResChat = await vctx.sql.db
266
- .select()
267
- .from(vctx.sql.tables.applicationChats)
268
- .where(and(eq(vctx.sql.tables.applicationChats.userId, req._auth.verifiedAuth.claims.userId), eq(vctx.sql.tables.applicationChats.chatId, req.chatId)))
269
- .limit(1)
270
- .then((r) => r[0]);
271
- if (!iResChat) {
272
- return Result.Err(`Application Chat ID ${req.chatId} not found`);
273
- }
274
- resChat = { ...iResChat, mode: "app" };
589
+ const resChat = rResChat.Ok();
590
+ let prompSectionAction;
591
+ if (isReqPromptLLMChatSection(orig)) {
592
+ prompSectionAction = async (scope, blockSeq) => {
593
+ const res = await handlerLlmRequest({
594
+ ctx,
595
+ blockSeq,
596
+ scope,
597
+ vctx,
598
+ req: req,
599
+ resChat,
600
+ promptId,
601
+ });
602
+ await handleLlmResponse({
603
+ scope,
604
+ vctx,
605
+ req: req,
606
+ ctx,
607
+ res: res.res,
608
+ resChat,
609
+ promptId,
610
+ blockSeq: res.blockSeq,
611
+ });
612
+ return Result.Ok();
613
+ };
614
+ }
615
+ if (isReqPromptFSChatSection(orig)) {
616
+ prompSectionAction = async (scope, blockSeq) => {
617
+ return handleFSPrompt({
618
+ scope,
619
+ vctx,
620
+ req: req,
621
+ ctx,
622
+ resChat,
623
+ promptId,
624
+ blockSeq,
625
+ });
626
+ };
275
627
  }
276
- if (!resChat) {
277
- return Result.Err(`Chat ID ${req.chatId} not found: ${req.mode}: ${isReqCreationPromptChatSection(orig) ? "creation" : isReqPromptApplicationChatSection(orig) ? "application" : "unknown"}`);
628
+ if (!prompSectionAction) {
629
+ return Result.Err(`Unsupported prompt chat section mode: ${orig.mode}`);
278
630
  }
279
631
  const promptId = vctx.sthis.nextId(96 / 8).str;
280
632
  await ctx.send.send(ctx, wrapMsgBase(ctx.validated, {
@@ -350,175 +702,7 @@ export const promptChatSection = {
350
702
  }
351
703
  })
352
704
  .do();
353
- await scope
354
- .evalResult(async () => {
355
- const r = await appendBlockEvent({
356
- ctx,
357
- vctx,
358
- req,
359
- promptId,
360
- blockSeq: blockSeq,
361
- evt: {
362
- type: "prompt.req",
363
- streamId: promptId,
364
- chatId: req.chatId,
365
- seq: blockSeq,
366
- request: req.prompt,
367
- timestamp: new Date(),
368
- },
369
- });
370
- blockSeq++;
371
- return r;
372
- })
373
- .do();
374
- const modelId = await scope
375
- .evalResult(async () => {
376
- const r = await getModelDefaults(vctx, { appSlug: resChat.appSlug, userSlug: resChat.userSlug });
377
- if (r.isErr()) {
378
- return Result.Err(r);
379
- }
380
- switch (req.mode) {
381
- case "chat":
382
- return Result.Ok(req.prompt.model ?? r.Ok().chat.model.id);
383
- case "app":
384
- return Result.Ok(req.prompt.model ?? r.Ok().app.model.id);
385
- case "img":
386
- return Result.Ok(req.prompt.model ?? r.Ok().img.model.id);
387
- default:
388
- return Result.Err(`Unknown prompt mode: ${req.mode}`);
389
- }
390
- })
391
- .do();
392
- const withSystemPrompt = await scope
393
- .evalResult(async () => {
394
- let withSystemPrompt = Result.Ok({
395
- model: modelId,
396
- messages: [],
397
- });
398
- if (req.mode === "chat") {
399
- withSystemPrompt = await injectSystemPrompt(vctx, req.chatId, req.prompt.model ?? modelId);
400
- }
401
- else if (req.mode === "app") {
402
- withSystemPrompt = Result.Ok({
403
- model: req.prompt.model ?? modelId,
404
- messages: req.prompt.messages,
405
- });
406
- }
407
- return withSystemPrompt;
408
- })
409
- .do();
410
- const llmReq = {
411
- ...{
412
- ...req.prompt,
413
- messages: withSystemPrompt.messages,
414
- },
415
- ...vctx.params.llm.enforced,
416
- model: withSystemPrompt.model,
417
- headers: vctx.params.llm.headers,
418
- logprobs: true,
419
- stream: true,
420
- };
421
- const res = await scope
422
- .evalResult(async () => {
423
- console.log(promptId, "Sending LLM request:", llmReq.model);
424
- const res = await vctx.llmRequest(llmReq);
425
- if (!res.ok) {
426
- return Result.Err(`LLM request failed with status ${res.status} :${llmReq.model} : ${res.statusText}`);
427
- }
428
- if (!res.body) {
429
- return Result.Err(`LLM request returned no body`);
430
- }
431
- return Result.Ok(res);
432
- })
433
- .do();
434
- await scope
435
- .evalResult(async () => {
436
- const pipeline = res
437
- .body.pipeThrough(createStatsCollector(promptId, 1000))
438
- .pipeThrough(createLineStream(promptId))
439
- .pipeThrough(createDataStream(promptId))
440
- .pipeThrough(createSseStream(promptId))
441
- .pipeThrough(createDeltaStream(promptId, () => vctx.sthis.nextId(12).str))
442
- .pipeThrough(createSectionsStream(promptId, () => vctx.sthis.nextId(12).str));
443
- const reader = pipeline.getReader();
444
- let collectedMsgs;
445
- let chatCtx;
446
- for (const conn of vctx.connections) {
447
- const tChatCtx = conn.chatIds.get(req.chatId);
448
- if (tChatCtx) {
449
- chatCtx = tChatCtx;
450
- const promptIdCtx = chatCtx.promptIds.get(promptId);
451
- if (!promptIdCtx) {
452
- collectedMsgs = [];
453
- chatCtx.promptIds.set(promptId, {
454
- blocks: collectedMsgs,
455
- promptId,
456
- type: "vibes.diy.section-event",
457
- chatId: req.chatId,
458
- blockSeq: 0,
459
- timestamp: new Date(),
460
- });
461
- }
462
- else {
463
- collectedMsgs = promptIdCtx.blocks;
464
- }
465
- }
466
- }
467
- if (!collectedMsgs) {
468
- return Result.Err(`Chat context not found for chatId: ${req.chatId}`);
469
- }
470
- while (true) {
471
- const { done, value } = await reader.read();
472
- if (done) {
473
- break;
474
- }
475
- if (!isBlockEnd(value)) {
476
- if (!isBlockStreamMsg(value)) {
477
- continue;
478
- }
479
- collectedMsgs.push(value);
480
- const r = await appendBlockEvent({
481
- ctx,
482
- vctx,
483
- req,
484
- promptId,
485
- blockSeq: blockSeq++,
486
- evt: value,
487
- emitMode: "emit-only",
488
- });
489
- if (r.isErr()) {
490
- return Result.Err(r);
491
- }
492
- }
493
- else {
494
- collectedMsgs.push(value);
495
- const r = await handlePromptContext({ vctx, req, promptId, resChat, value, blockSeq, collectedMsgs });
496
- if (r.isErr()) {
497
- return Result.Err(r);
498
- }
499
- const promptIdCtx = chatCtx.promptIds.get(promptId);
500
- if (promptIdCtx) {
501
- chatCtx.promptIds.delete(promptId);
502
- }
503
- blockSeq = r.Ok().blockSeq;
504
- const rEvt = await appendBlockEvent({
505
- ctx,
506
- vctx,
507
- req,
508
- promptId,
509
- blockSeq: blockSeq++,
510
- evt: { ...value, fsRef: r.Ok().fsRef.toValue() },
511
- emitMode: "emit-only",
512
- });
513
- if (rEvt.isErr()) {
514
- return Result.Err(rEvt);
515
- }
516
- collectedMsgs.splice(0, collectedMsgs.length);
517
- }
518
- }
519
- return Result.Ok();
520
- })
521
- .do();
705
+ await prompSectionAction(scope, blockSeq);
522
706
  });
523
707
  return Result.Ok(EventoResult.Continue);
524
708
  }),