refactor: extract shared SSE parser and add eslint to iknowyou

Deduplicate SSE chunk parsing from input-bar.tsx and vllm.ts into a
shared lib/sse.ts consumeSSEChunk helper. Add eslint + next lint config.
Silence monorepo lockfile warning via outputFileTracingRoot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jordan 2026-02-25 16:51:48 -07:00
parent eca7765e8d
commit 51ac377376
8 changed files with 4579 additions and 22 deletions

View File

@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

View File

@ -2,6 +2,7 @@
import { useRef, useCallback } from "react";
import { useChatStore } from "@/lib/store";
import { consumeSSEChunk } from "@/lib/sse";
export function InputBar() {
const textareaRef = useRef<HTMLTextAreaElement>(null);
@ -58,17 +59,15 @@ export function InputBar() {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop()!;
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed.startsWith("data: ") || trimmed === "data: [DONE]")
continue;
const { jsonLines, buffer: next } = consumeSSEChunk(
buffer,
decoder.decode(value, { stream: true })
);
buffer = next;
for (const jsonStr of jsonLines) {
try {
const data = JSON.parse(trimmed.slice(6));
const data = JSON.parse(jsonStr);
if (data.error) {
setError(data.error);
return;

View File

@ -0,0 +1,27 @@
/**
* Append a decoded SSE chunk to the running buffer and extract complete data lines.
*
* Returns the raw JSON strings from each `data: {...}` line and the updated
* buffer (partial-line remainder). Skips the `[DONE]` sentinel.
*
* Both the vLLM server-side reader and the client-side chat reader share
* this logic keeping buffer management in one place prevents drift when
* the SSE wire format changes.
*/
export function consumeSSEChunk(
buffer: string,
chunk: string
): { jsonLines: string[]; buffer: string } {
const full = buffer + chunk;
const parts = full.split("\n");
const newBuffer = parts.pop()!;
const jsonLines: string[] = [];
for (const part of parts) {
const trimmed = part.trim();
if (!trimmed.startsWith("data: ") || trimmed === "data: [DONE]") continue;
jsonLines.push(trimmed.slice(6));
}
return { jsonLines, buffer: newBuffer };
}

View File

@ -1,4 +1,5 @@
import type { CommunicationBrief } from "./types";
import { consumeSSEChunk } from "./sse";
const VLLM_BASE = process.env.VLLM_URL ?? "http://msd5685.mjhst.com:8000";
const MODEL = "Qwen/Qwen3-8B";
@ -147,17 +148,15 @@ export async function* streamChat(
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop()!;
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed.startsWith("data: ") || trimmed === "data: [DONE]")
continue;
const { jsonLines, buffer: next } = consumeSSEChunk(
buffer,
decoder.decode(value, { stream: true })
);
buffer = next;
for (const jsonStr of jsonLines) {
try {
const chunk = JSON.parse(trimmed.slice(6));
const chunk = JSON.parse(jsonStr);
const token = chunk.choices?.[0]?.delta?.content;
if (token) yield token;
} catch {

View File

@ -1,5 +1,10 @@
import type { NextConfig } from "next";
import path from "path";
const nextConfig: NextConfig = {};
const nextConfig: NextConfig = {
// Silence the "multiple lockfiles" warning — this project lives inside a
// larger monorepo and has its own lockfile by design.
outputFileTracingRoot: path.join(__dirname, "../../"),
};
export default nextConfig;

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,8 @@
"dev:engine": "cargo run -p iknowyou-engine --bin server --features synap-aux",
"dev:all": "sh -c 'npm run dev:engine & npm run dev'",
"build": "next build",
"start": "next start -p 59521"
"start": "next start -p 59521",
"lint": "next lint"
},
"dependencies": {
"next": "^15.3.3",
@ -20,6 +21,8 @@
"@types/node": "^22.15.21",
"@types/react": "^19.1.4",
"@types/react-dom": "^19.1.5",
"eslint": "^8.57.1",
"eslint-config-next": "^15.5.12",
"tailwindcss": "^4.1.8",
"typescript": "^5.8.3"
}

File diff suppressed because one or more lines are too long