|
|
@@ -263,41 +263,44 @@ export namespace SessionPrompt {
|
|
|
if (["tool-calls", "unknown"].includes(message.finish)) return
|
|
|
if ((yield* status.get(input.sessionID)).type !== "idle") return
|
|
|
|
|
|
- const ag = yield* agents.get("title")
|
|
|
- if (!ag) return
|
|
|
-
|
|
|
- const model = yield* Effect.promise(async () => {
|
|
|
- const small = await Provider.getSmallModel(message.providerID).catch(() => undefined)
|
|
|
- if (small) return small
|
|
|
- return Provider.getModel(message.providerID, message.modelID).catch(() => undefined)
|
|
|
- })
|
|
|
+ // Use the same model for prompt-cache hit on the conversation prefix
|
|
|
+ const model = yield* Effect.promise(async () =>
|
|
|
+ Provider.getModel(message.providerID, message.modelID).catch(() => undefined),
|
|
|
+ )
|
|
|
if (!model) return
|
|
|
|
|
|
- const msgs = yield* Effect.promise(() => MessageV2.filterCompacted(MessageV2.stream(input.sessionID)))
|
|
|
- const history = msgs.slice(-8)
|
|
|
+ const ag = yield* agents.get(message.agent ?? "code")
|
|
|
+ if (!ag) return
|
|
|
+
|
|
|
+ // Full message history so the cached KV from the main conversation is reused
|
|
|
+ const msgs = yield* MessageV2.filterCompactedEffect(input.sessionID)
|
|
|
const real = (item: MessageV2.WithParts) =>
|
|
|
item.info.role === "user" && !item.parts.every((part) => "synthetic" in part && part.synthetic)
|
|
|
const parent = msgs.find((item) => item.info.id === message.parentID)
|
|
|
const user = parent && real(parent) ? parent.info : msgs.findLast((item) => real(item))?.info
|
|
|
if (!user || user.role !== "user") return
|
|
|
|
|
|
+ // Rebuild system prompt identical to the main loop for cache hit
|
|
|
+ const skills = yield* Effect.promise(() => SystemPrompt.skills(ag))
|
|
|
+ const env = yield* Effect.promise(() => SystemPrompt.environment(model))
|
|
|
+ const instructions = yield* instruction.system().pipe(Effect.orDie)
|
|
|
+ const modelMsgs = yield* Effect.promise(() => MessageV2.toModelMessages(msgs, model))
|
|
|
+ const system = [...env, ...(skills ? [skills] : []), ...instructions]
|
|
|
+
|
|
|
const text = yield* Effect.promise(async (signal) => {
|
|
|
const result = await LLM.stream({
|
|
|
- agent: {
|
|
|
- ...ag,
|
|
|
- name: "suggest-next",
|
|
|
- prompt: PROMPT_SUGGEST_NEXT,
|
|
|
- },
|
|
|
+ agent: ag,
|
|
|
user,
|
|
|
- system: [],
|
|
|
- small: true,
|
|
|
+ system,
|
|
|
+ small: false,
|
|
|
tools: {},
|
|
|
model,
|
|
|
abort: signal,
|
|
|
sessionID: input.sessionID,
|
|
|
retries: 1,
|
|
|
toolChoice: "none",
|
|
|
- messages: await MessageV2.toModelMessages(history, model),
|
|
|
+ // Append suggestion instruction after the full conversation
|
|
|
+ messages: [...modelMsgs, { role: "user" as const, content: PROMPT_SUGGEST_NEXT }],
|
|
|
})
|
|
|
return result.text
|
|
|
})
|
|
|
@@ -318,7 +321,7 @@ export namespace SessionPrompt {
|
|
|
|
|
|
const suggestion = line.length > 240 ? line.slice(0, 237) + "..." : line
|
|
|
if ((yield* status.get(input.sessionID)).type !== "idle") return
|
|
|
- yield* status.set(input.sessionID, { type: "idle", suggestion })
|
|
|
+ yield* status.suggest(input.sessionID, suggestion)
|
|
|
})
|
|
|
|
|
|
const insertReminders = Effect.fn("SessionPrompt.insertReminders")(function* (input: {
|