😅 TRY: /new
This commit is contained in:
parent
c05b9241c0
commit
9fa5c96dd4
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()}`,
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user