😅 TRY: /new

This commit is contained in:
kumarabhirup 2026-02-05 21:27:51 -08:00
parent c05b9241c0
commit 9fa5c96dd4
No known key found for this signature in database
GPG Key ID: DB7CA2289CAB0167
4 changed files with 138 additions and 15 deletions

View File

@ -23,6 +23,7 @@ import {
import { logVerbose } from "../../globals.js";
import { clearCommandLane, getQueueSize } from "../../process/command-queue.js";
import { normalizeMainKey } from "../../routing/session-key.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
import { hasControlCommand } from "../command-detection.js";
import { buildInboundMediaNote } from "../media-note.js";
@ -294,15 +295,20 @@ export async function runPreparedReply(
modelLabel === defaultLabel
? `✅ New session started · model: ${modelLabel}`
: `✅ New session started · model: ${modelLabel} (default: ${defaultLabel})`;
await routeReply({
payload: { text },
channel,
to,
sessionKey,
accountId: ctx.AccountId,
threadId: ctx.MessageThreadId,
cfg,
});
// Webchat isn't supported by routeReply; use onBlockReply callback instead.
if (channel === INTERNAL_MESSAGE_CHANNEL && opts?.onBlockReply) {
await opts.onBlockReply({ text });
} else {
await routeReply({
payload: { text },
channel,
to,
sessionKey,
accountId: ctx.AccountId,
threadId: ctx.MessageThreadId,
cfg,
});
}
}
}
const sessionIdFinal = sessionId ?? crypto.randomUUID();

View File

@ -144,6 +144,73 @@ function appendAssistantTranscriptMessage(params: {
return { ok: true, messageId, message: transcriptEntry.message };
}
function appendUserTranscriptMessage(params: {
message: string;
images: ChatImageContent[];
sessionId: string;
storePath: string | undefined;
sessionFile?: string;
createIfMissing?: boolean;
}): TranscriptAppendResult {
const transcriptPath = resolveTranscriptPath({
sessionId: params.sessionId,
storePath: params.storePath,
sessionFile: params.sessionFile,
});
if (!transcriptPath) {
return { ok: false, error: "transcript path not resolved" };
}
if (!fs.existsSync(transcriptPath)) {
if (!params.createIfMissing) {
return { ok: false, error: "transcript file not found" };
}
const ensured = ensureTranscriptFile({
transcriptPath,
sessionId: params.sessionId,
});
if (!ensured.ok) {
return { ok: false, error: ensured.error ?? "failed to create transcript file" };
}
}
const now = Date.now();
const messageId = randomUUID().slice(0, 8);
const content: Array<Record<string, unknown>> = [];
if (params.message.trim()) {
content.push({ type: "text", text: params.message });
}
for (const image of params.images) {
content.push({
type: "image",
source: {
type: "base64",
media_type: image.mimeType,
data: image.data,
},
});
}
const messageBody: Record<string, unknown> = {
role: "user",
content: content.length > 0 ? content : [],
timestamp: now,
};
const transcriptEntry = {
type: "message",
id: messageId,
timestamp: new Date(now).toISOString(),
message: messageBody,
};
try {
fs.appendFileSync(transcriptPath, `${JSON.stringify(transcriptEntry)}\n`, "utf-8");
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : String(err) };
}
return { ok: true, messageId, message: transcriptEntry.message };
}
function nextChatSeq(context: { agentRunSeq: Map<string, number> }, runId: string) {
const next = (context.agentRunSeq.get(runId) ?? 0) + 1;
context.agentRunSeq.set(runId, next);
@ -487,7 +554,7 @@ export const chatHandlers: GatewayRequestHandlers = {
context.logGateway.warn(`webchat dispatch failed: ${formatForLog(err)}`);
},
deliver: async (payload, info) => {
if (info.kind !== "final") {
if (info.kind !== "final" && info.kind !== "block") {
return;
}
const text = payload.text?.trim() ?? "";
@ -498,7 +565,28 @@ export const chatHandlers: GatewayRequestHandlers = {
},
});
const shouldPersistUser = parsedMessage.trim().startsWith("/");
let agentRunStarted = false;
let userAppended = false;
const appendUserMessage = () => {
if (!shouldPersistUser || userAppended) return;
userAppended = true;
const { storePath: latestStorePath, entry: latestEntry } = loadSessionEntry(p.sessionKey);
const sessionId = latestEntry?.sessionId ?? entry?.sessionId ?? clientRunId;
const appendedUser = appendUserTranscriptMessage({
message: parsedMessage,
images: parsedImages,
sessionId,
storePath: latestStorePath,
sessionFile: latestEntry?.sessionFile,
createIfMissing: true,
});
if (!appendedUser.ok) {
context.logGateway.warn(
`webchat transcript user append failed: ${appendedUser.error ?? "unknown error"}`,
);
}
};
void dispatchInboundMessage({
ctx,
cfg,
@ -510,6 +598,7 @@ export const chatHandlers: GatewayRequestHandlers = {
disableBlockStreaming: true,
onAgentRunStart: () => {
agentRunStarted = true;
appendUserMessage();
},
onModelSelected: (ctx) => {
prefixContext.provider = ctx.provider;
@ -527,11 +616,27 @@ export const chatHandlers: GatewayRequestHandlers = {
.join("\n\n")
.trim();
let message: Record<string, unknown> | undefined;
const { storePath: latestStorePath, entry: latestEntry } = loadSessionEntry(
p.sessionKey,
);
const sessionId = latestEntry?.sessionId ?? entry?.sessionId ?? clientRunId;
if (!userAppended) {
const appendedUser = appendUserTranscriptMessage({
message: parsedMessage,
images: parsedImages,
sessionId,
storePath: latestStorePath,
sessionFile: latestEntry?.sessionFile,
createIfMissing: true,
});
userAppended = true;
if (!appendedUser.ok) {
context.logGateway.warn(
`webchat transcript user append failed: ${appendedUser.error ?? "unknown error"}`,
);
}
}
if (combinedReply) {
const { storePath: latestStorePath, entry: latestEntry } = loadSessionEntry(
p.sessionKey,
);
const sessionId = latestEntry?.sessionId ?? entry?.sessionId ?? clientRunId;
const appended = appendAssistantTranscriptMessage({
message: combinedReply,
sessionId,

View File

@ -11,6 +11,8 @@ import {
resolveAgentWorkspaceDir,
resolveAgentDir,
} from "../agents/agent-scope.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
/**
@ -38,6 +40,13 @@ ${params.sessionContent.slice(0, 2000)}
Reply with ONLY the slug, nothing else. Examples: "vendor-pitch", "api-design", "bug-fix"`;
// Resolve the configured model to avoid falling back to DEFAULT_PROVIDER
const modelRef = resolveConfiguredModelRef({
cfg: params.cfg,
defaultProvider: DEFAULT_PROVIDER,
defaultModel: DEFAULT_MODEL,
});
const result = await runEmbeddedPiAgent({
sessionId: `slug-generator-${Date.now()}`,
sessionKey: "temp:slug-generator",
@ -45,6 +54,8 @@ Reply with ONLY the slug, nothing else. Examples: "vendor-pitch", "api-design",
workspaceDir,
agentDir,
config: params.cfg,
provider: modelRef.provider,
model: modelRef.model,
prompt,
timeoutMs: 15_000, // 15 second timeout
runId: `slug-gen-${Date.now()}`,

View File

@ -161,6 +161,7 @@ export async function handleSendChat(
}
const refreshSessions = isChatResetCommand(message);
if (messageOverride == null) {
host.chatMessage = "";
// Clear attachments when sending
@ -172,7 +173,7 @@ export async function handleSendChat(
return;
}
await sendChatMessageNow(host, message, {
return await sendChatMessageNow(host, message, {
previousDraft: messageOverride == null ? previousDraft : undefined,
restoreDraft: Boolean(messageOverride && opts?.restoreDraft),
attachments: hasAttachments ? attachmentsToSend : undefined,