|
@@ -3,7 +3,7 @@ import os from "os"
|
|
|
import fs from "fs/promises"
|
|
import fs from "fs/promises"
|
|
|
import z from "zod"
|
|
import z from "zod"
|
|
|
import { Filesystem } from "../util/filesystem"
|
|
import { Filesystem } from "../util/filesystem"
|
|
|
-import { Identifier } from "../id/id"
|
|
|
|
|
|
|
+import { SessionID, MessageID, PartID } from "./schema"
|
|
|
import { MessageV2 } from "./message-v2"
|
|
import { MessageV2 } from "./message-v2"
|
|
|
import { Log } from "../util/log"
|
|
import { Log } from "../util/log"
|
|
|
import { SessionRevert } from "./revert"
|
|
import { SessionRevert } from "./revert"
|
|
@@ -84,14 +84,14 @@ export namespace SessionPrompt {
|
|
|
},
|
|
},
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- export function assertNotBusy(sessionID: string) {
|
|
|
|
|
|
|
+ export function assertNotBusy(sessionID: SessionID) {
|
|
|
const match = state()[sessionID]
|
|
const match = state()[sessionID]
|
|
|
if (match) throw new Session.BusyError(sessionID)
|
|
if (match) throw new Session.BusyError(sessionID)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const PromptInput = z.object({
|
|
export const PromptInput = z.object({
|
|
|
- sessionID: Identifier.schema("session"),
|
|
|
|
|
- messageID: Identifier.schema("message").optional(),
|
|
|
|
|
|
|
+ sessionID: SessionID.zod,
|
|
|
|
|
+ messageID: MessageID.zod.optional(),
|
|
|
model: z
|
|
model: z
|
|
|
.object({
|
|
.object({
|
|
|
providerID: z.string(),
|
|
providerID: z.string(),
|
|
@@ -254,7 +254,7 @@ export namespace SessionPrompt {
|
|
|
return s[sessionID].abort.signal
|
|
return s[sessionID].abort.signal
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- export function cancel(sessionID: string) {
|
|
|
|
|
|
|
+ export function cancel(sessionID: SessionID) {
|
|
|
log.info("cancel", { sessionID })
|
|
log.info("cancel", { sessionID })
|
|
|
const s = state()
|
|
const s = state()
|
|
|
const match = s[sessionID]
|
|
const match = s[sessionID]
|
|
@@ -269,7 +269,7 @@ export namespace SessionPrompt {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const LoopInput = z.object({
|
|
export const LoopInput = z.object({
|
|
|
- sessionID: Identifier.schema("session"),
|
|
|
|
|
|
|
+ sessionID: SessionID.zod,
|
|
|
resume_existing: z.boolean().optional(),
|
|
resume_existing: z.boolean().optional(),
|
|
|
})
|
|
})
|
|
|
export const loop = fn(LoopInput, async (input) => {
|
|
export const loop = fn(LoopInput, async (input) => {
|
|
@@ -354,7 +354,7 @@ export namespace SessionPrompt {
|
|
|
const taskTool = await TaskTool.init()
|
|
const taskTool = await TaskTool.init()
|
|
|
const taskModel = task.model ? await Provider.getModel(task.model.providerID, task.model.modelID) : model
|
|
const taskModel = task.model ? await Provider.getModel(task.model.providerID, task.model.modelID) : model
|
|
|
const assistantMessage = (await Session.updateMessage({
|
|
const assistantMessage = (await Session.updateMessage({
|
|
|
- id: Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: MessageID.ascending(),
|
|
|
role: "assistant",
|
|
role: "assistant",
|
|
|
parentID: lastUser.id,
|
|
parentID: lastUser.id,
|
|
|
sessionID,
|
|
sessionID,
|
|
@@ -379,7 +379,7 @@ export namespace SessionPrompt {
|
|
|
},
|
|
},
|
|
|
})) as MessageV2.Assistant
|
|
})) as MessageV2.Assistant
|
|
|
let part = (await Session.updatePart({
|
|
let part = (await Session.updatePart({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: assistantMessage.id,
|
|
messageID: assistantMessage.id,
|
|
|
sessionID: assistantMessage.sessionID,
|
|
sessionID: assistantMessage.sessionID,
|
|
|
type: "tool",
|
|
type: "tool",
|
|
@@ -448,7 +448,7 @@ export namespace SessionPrompt {
|
|
|
})
|
|
})
|
|
|
const attachments = result?.attachments?.map((attachment) => ({
|
|
const attachments = result?.attachments?.map((attachment) => ({
|
|
|
...attachment,
|
|
...attachment,
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
sessionID,
|
|
sessionID,
|
|
|
messageID: assistantMessage.id,
|
|
messageID: assistantMessage.id,
|
|
|
}))
|
|
}))
|
|
@@ -503,7 +503,7 @@ export namespace SessionPrompt {
|
|
|
// If we create assistant messages w/ out user ones following mid loop thinking signatures
|
|
// If we create assistant messages w/ out user ones following mid loop thinking signatures
|
|
|
// will be missing and it can cause errors for models like gemini for example
|
|
// will be missing and it can cause errors for models like gemini for example
|
|
|
const summaryUserMsg: MessageV2.User = {
|
|
const summaryUserMsg: MessageV2.User = {
|
|
|
- id: Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: MessageID.ascending(),
|
|
|
sessionID,
|
|
sessionID,
|
|
|
role: "user",
|
|
role: "user",
|
|
|
time: {
|
|
time: {
|
|
@@ -514,7 +514,7 @@ export namespace SessionPrompt {
|
|
|
}
|
|
}
|
|
|
await Session.updateMessage(summaryUserMsg)
|
|
await Session.updateMessage(summaryUserMsg)
|
|
|
await Session.updatePart({
|
|
await Session.updatePart({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: summaryUserMsg.id,
|
|
messageID: summaryUserMsg.id,
|
|
|
sessionID,
|
|
sessionID,
|
|
|
type: "text",
|
|
type: "text",
|
|
@@ -567,7 +567,7 @@ export namespace SessionPrompt {
|
|
|
|
|
|
|
|
const processor = SessionProcessor.create({
|
|
const processor = SessionProcessor.create({
|
|
|
assistantMessage: (await Session.updateMessage({
|
|
assistantMessage: (await Session.updateMessage({
|
|
|
- id: Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: MessageID.ascending(),
|
|
|
parentID: lastUser.id,
|
|
parentID: lastUser.id,
|
|
|
role: "assistant",
|
|
role: "assistant",
|
|
|
mode: agent.name,
|
|
mode: agent.name,
|
|
@@ -731,7 +731,7 @@ export namespace SessionPrompt {
|
|
|
throw new Error("Impossible")
|
|
throw new Error("Impossible")
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- async function lastModel(sessionID: string) {
|
|
|
|
|
|
|
+ async function lastModel(sessionID: SessionID) {
|
|
|
for await (const item of MessageV2.stream(sessionID)) {
|
|
for await (const item of MessageV2.stream(sessionID)) {
|
|
|
if (item.info.role === "user" && item.info.model) return item.info.model
|
|
if (item.info.role === "user" && item.info.model) return item.info.model
|
|
|
}
|
|
}
|
|
@@ -813,7 +813,7 @@ export namespace SessionPrompt {
|
|
|
...result,
|
|
...result,
|
|
|
attachments: result.attachments?.map((attachment) => ({
|
|
attachments: result.attachments?.map((attachment) => ({
|
|
|
...attachment,
|
|
...attachment,
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
sessionID: ctx.sessionID,
|
|
sessionID: ctx.sessionID,
|
|
|
messageID: input.processor.message.id,
|
|
messageID: input.processor.message.id,
|
|
|
})),
|
|
})),
|
|
@@ -916,7 +916,7 @@ export namespace SessionPrompt {
|
|
|
output: truncated.content,
|
|
output: truncated.content,
|
|
|
attachments: attachments.map((attachment) => ({
|
|
attachments: attachments.map((attachment) => ({
|
|
|
...attachment,
|
|
...attachment,
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
sessionID: ctx.sessionID,
|
|
sessionID: ctx.sessionID,
|
|
|
messageID: input.processor.message.id,
|
|
messageID: input.processor.message.id,
|
|
|
})),
|
|
})),
|
|
@@ -970,7 +970,7 @@ export namespace SessionPrompt {
|
|
|
const variant = input.variant ?? (agent.variant && full?.variants?.[agent.variant] ? agent.variant : undefined)
|
|
const variant = input.variant ?? (agent.variant && full?.variants?.[agent.variant] ? agent.variant : undefined)
|
|
|
|
|
|
|
|
const info: MessageV2.Info = {
|
|
const info: MessageV2.Info = {
|
|
|
- id: input.messageID ?? Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: input.messageID ?? MessageID.ascending(),
|
|
|
role: "user",
|
|
role: "user",
|
|
|
sessionID: input.sessionID,
|
|
sessionID: input.sessionID,
|
|
|
time: {
|
|
time: {
|
|
@@ -988,7 +988,7 @@ export namespace SessionPrompt {
|
|
|
type Draft<T> = T extends MessageV2.Part ? Omit<T, "id"> & { id?: string } : never
|
|
type Draft<T> = T extends MessageV2.Part ? Omit<T, "id"> & { id?: string } : never
|
|
|
const assign = (part: Draft<MessageV2.Part>): MessageV2.Part => ({
|
|
const assign = (part: Draft<MessageV2.Part>): MessageV2.Part => ({
|
|
|
...part,
|
|
...part,
|
|
|
- id: part.id ?? Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: part.id ? PartID.make(part.id) : PartID.ascending(),
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const parts = await Promise.all(
|
|
const parts = await Promise.all(
|
|
@@ -1334,7 +1334,7 @@ export namespace SessionPrompt {
|
|
|
if (!Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE) {
|
|
if (!Flag.OPENCODE_EXPERIMENTAL_PLAN_MODE) {
|
|
|
if (input.agent.name === "plan") {
|
|
if (input.agent.name === "plan") {
|
|
|
userMessage.parts.push({
|
|
userMessage.parts.push({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: userMessage.info.id,
|
|
messageID: userMessage.info.id,
|
|
|
sessionID: userMessage.info.sessionID,
|
|
sessionID: userMessage.info.sessionID,
|
|
|
type: "text",
|
|
type: "text",
|
|
@@ -1345,7 +1345,7 @@ export namespace SessionPrompt {
|
|
|
const wasPlan = input.messages.some((msg) => msg.info.role === "assistant" && msg.info.agent === "plan")
|
|
const wasPlan = input.messages.some((msg) => msg.info.role === "assistant" && msg.info.agent === "plan")
|
|
|
if (wasPlan && input.agent.name === "build") {
|
|
if (wasPlan && input.agent.name === "build") {
|
|
|
userMessage.parts.push({
|
|
userMessage.parts.push({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: userMessage.info.id,
|
|
messageID: userMessage.info.id,
|
|
|
sessionID: userMessage.info.sessionID,
|
|
sessionID: userMessage.info.sessionID,
|
|
|
type: "text",
|
|
type: "text",
|
|
@@ -1365,7 +1365,7 @@ export namespace SessionPrompt {
|
|
|
const exists = await Filesystem.exists(plan)
|
|
const exists = await Filesystem.exists(plan)
|
|
|
if (exists) {
|
|
if (exists) {
|
|
|
const part = await Session.updatePart({
|
|
const part = await Session.updatePart({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: userMessage.info.id,
|
|
messageID: userMessage.info.id,
|
|
|
sessionID: userMessage.info.sessionID,
|
|
sessionID: userMessage.info.sessionID,
|
|
|
type: "text",
|
|
type: "text",
|
|
@@ -1384,7 +1384,7 @@ export namespace SessionPrompt {
|
|
|
const exists = await Filesystem.exists(plan)
|
|
const exists = await Filesystem.exists(plan)
|
|
|
if (!exists) await fs.mkdir(path.dirname(plan), { recursive: true })
|
|
if (!exists) await fs.mkdir(path.dirname(plan), { recursive: true })
|
|
|
const part = await Session.updatePart({
|
|
const part = await Session.updatePart({
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: userMessage.info.id,
|
|
messageID: userMessage.info.id,
|
|
|
sessionID: userMessage.info.sessionID,
|
|
sessionID: userMessage.info.sessionID,
|
|
|
type: "text",
|
|
type: "text",
|
|
@@ -1467,7 +1467,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const ShellInput = z.object({
|
|
export const ShellInput = z.object({
|
|
|
- sessionID: Identifier.schema("session"),
|
|
|
|
|
|
|
+ sessionID: SessionID.zod,
|
|
|
agent: z.string(),
|
|
agent: z.string(),
|
|
|
model: z
|
|
model: z
|
|
|
.object({
|
|
.object({
|
|
@@ -1504,7 +1504,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
const agent = await Agent.get(input.agent)
|
|
const agent = await Agent.get(input.agent)
|
|
|
const model = input.model ?? agent.model ?? (await lastModel(input.sessionID))
|
|
const model = input.model ?? agent.model ?? (await lastModel(input.sessionID))
|
|
|
const userMsg: MessageV2.User = {
|
|
const userMsg: MessageV2.User = {
|
|
|
- id: Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: MessageID.ascending(),
|
|
|
sessionID: input.sessionID,
|
|
sessionID: input.sessionID,
|
|
|
time: {
|
|
time: {
|
|
|
created: Date.now(),
|
|
created: Date.now(),
|
|
@@ -1519,7 +1519,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
await Session.updateMessage(userMsg)
|
|
await Session.updateMessage(userMsg)
|
|
|
const userPart: MessageV2.Part = {
|
|
const userPart: MessageV2.Part = {
|
|
|
type: "text",
|
|
type: "text",
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: userMsg.id,
|
|
messageID: userMsg.id,
|
|
|
sessionID: input.sessionID,
|
|
sessionID: input.sessionID,
|
|
|
text: "The following tool was executed by the user",
|
|
text: "The following tool was executed by the user",
|
|
@@ -1528,7 +1528,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
await Session.updatePart(userPart)
|
|
await Session.updatePart(userPart)
|
|
|
|
|
|
|
|
const msg: MessageV2.Assistant = {
|
|
const msg: MessageV2.Assistant = {
|
|
|
- id: Identifier.ascending("message"),
|
|
|
|
|
|
|
+ id: MessageID.ascending(),
|
|
|
sessionID: input.sessionID,
|
|
sessionID: input.sessionID,
|
|
|
parentID: userMsg.id,
|
|
parentID: userMsg.id,
|
|
|
mode: input.agent,
|
|
mode: input.agent,
|
|
@@ -1554,7 +1554,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
await Session.updateMessage(msg)
|
|
await Session.updateMessage(msg)
|
|
|
const part: MessageV2.Part = {
|
|
const part: MessageV2.Part = {
|
|
|
type: "tool",
|
|
type: "tool",
|
|
|
- id: Identifier.ascending("part"),
|
|
|
|
|
|
|
+ id: PartID.ascending(),
|
|
|
messageID: msg.id,
|
|
messageID: msg.id,
|
|
|
sessionID: input.sessionID,
|
|
sessionID: input.sessionID,
|
|
|
tool: "bash",
|
|
tool: "bash",
|
|
@@ -1718,8 +1718,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const CommandInput = z.object({
|
|
export const CommandInput = z.object({
|
|
|
- messageID: Identifier.schema("message").optional(),
|
|
|
|
|
- sessionID: Identifier.schema("session"),
|
|
|
|
|
|
|
+ messageID: MessageID.zod.optional(),
|
|
|
|
|
+ sessionID: SessionID.zod,
|
|
|
agent: z.string().optional(),
|
|
agent: z.string().optional(),
|
|
|
model: z.string().optional(),
|
|
model: z.string().optional(),
|
|
|
arguments: z.string(),
|
|
arguments: z.string(),
|