Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/opencode/src/cli/cmd/debug/agent.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Provider } from "@/provider/provider"
import { Session } from "@/session/session"
import type { MessageV2 } from "../../../session/message-v2"
import { MessageID, PartID } from "../../../session/schema"
import { Identifier } from "@/id/id"
import { ToolRegistry } from "@/tool/registry"
import { Permission } from "../../../permission"
import { iife } from "../../../util/iife"
Expand Down Expand Up @@ -129,7 +130,6 @@ const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(functio
) {
const sessionSvc = yield* Session.Service
const session = yield* sessionSvc.create({ title: `Debug tool run (${agent.name})` })
const messageID = MessageID.ascending()
const model = agent.model
? agent.model
: yield* Effect.gen(function* () {
Expand All @@ -149,12 +149,13 @@ const createToolContext = Effect.fn("Cli.debug.agent.createToolContext")(functio
}),
)
})
const now = Date.now()
const created = Date.now()
const messageID = MessageID.ascending(Identifier.create("msg", "ascending", created))
const message: SessionV1.Assistant = {
id: messageID,
sessionID: session.id,
role: "assistant",
time: { created: now },
time: { created },
parentID: messageID,
modelID: model.modelID,
providerID: model.providerID,
Expand Down
4 changes: 1 addition & 3 deletions packages/opencode/src/cli/cmd/github.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { InstanceRef } from "@/effect/instance-ref"
import { SessionShare } from "@/share/session"
import { Session } from "@/session/session"
import type { SessionID } from "../../session/schema"
import { MessageID, PartID } from "../../session/schema"
import { PartID } from "../../session/schema"
import { Provider } from "@/provider/provider"
import { MessageV2 } from "../../session/message-v2"
import { EventV2Bridge } from "@/event-v2-bridge"
Expand Down Expand Up @@ -902,7 +902,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
const prompt = sessionPrompt
const result = yield* prompt.prompt({
sessionID: session.id,
messageID: MessageID.ascending(),
variant,
model: {
providerID,
Expand Down Expand Up @@ -950,7 +949,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
console.log("Requesting summary from agent...")
const summary = yield* prompt.prompt({
sessionID: session.id,
messageID: MessageID.ascending(),
variant,
model: {
providerID,
Expand Down
23 changes: 13 additions & 10 deletions packages/opencode/src/session/compaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SessionV1 } from "@opencode-ai/core/v1/session"
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
import { Session } from "./session"
import { SessionID, MessageID, PartID } from "./schema"
import { Identifier } from "@/id/id"
import { Provider } from "@/provider/provider"
import { MessageV2 } from "./message-v2"
import { Token } from "@/util/token"
Expand Down Expand Up @@ -390,8 +391,9 @@ const layer = Layer.effect(
.filter(Boolean)
.join("\n\n")
const ctx = yield* InstanceState.context
const created = Date.now()
const msg: SessionV1.Assistant = {
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "assistant",
parentID: input.parentID,
sessionID: input.sessionID,
Expand All @@ -412,9 +414,7 @@ const layer = Layer.effect(
},
modelID: model.id,
providerID: model.providerID,
time: {
created: Date.now(),
},
time: { created },
}
yield* session.updateMessage(msg)
const processor = yield* processors.create({
Expand Down Expand Up @@ -468,11 +468,12 @@ const layer = Layer.effect(
if (result === "continue" && input.auto) {
if (replay) {
const original = replay.info
const created = Date.now()
const replayMsg = yield* session.updateMessage({
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "user",
sessionID: input.sessionID,
time: { created: Date.now() },
time: { created },
agent: original.agent,
model: original.model,
format: original.format,
Expand Down Expand Up @@ -516,11 +517,12 @@ const layer = Layer.effect(
{ enabled: true },
)).enabled
) {
const created = Date.now()
const continueMsg = yield* session.updateMessage({
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "user",
sessionID: input.sessionID,
time: { created: Date.now() },
time: { created },
agent: userMessage.agent,
model: userMessage.model,
})
Expand Down Expand Up @@ -563,13 +565,14 @@ const layer = Layer.effect(
auto: boolean
overflow?: boolean
}) {
const created = Date.now()
const msg = yield* session.updateMessage({
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "user",
model: input.model,
sessionID: input.sessionID,
agent: input.agent,
time: { created: Date.now() },
time: { created },
})
yield* session.updatePart({
id: PartID.ascending(),
Expand Down
31 changes: 19 additions & 12 deletions packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from "path"
import { SessionV1 } from "@opencode-ai/core/v1/session"
import os from "os"
import { SessionID, MessageID, PartID } from "./schema"
import { Identifier } from "@/id/id"
import { MessageV2 } from "./message-v2"
import { SessionRevert } from "./revert"
import { Session } from "./session"
Expand Down Expand Up @@ -265,8 +266,9 @@ const layer = Layer.effect(
const promptOps = yield* ops()
const { task: taskTool } = yield* registry.named()
const taskModel = task.model ? yield* getModel(task.model.providerID, task.model.modelID, sessionID) : model
const created = Date.now()
const assistantMessage: SessionV1.Assistant = yield* sessions.updateMessage({
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "assistant",
parentID: lastUser.id,
sessionID,
Expand All @@ -278,7 +280,7 @@ const layer = Layer.effect(
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
modelID: taskModel.id,
providerID: taskModel.providerID,
time: { created: Date.now() },
time: { created },
})
let part: SessionV1.ToolPart = yield* sessions.updatePart({
id: PartID.ascending(),
Expand Down Expand Up @@ -429,11 +431,12 @@ const layer = Layer.effect(

if (!task.command) return

const summaryCreated = Date.now()
const summaryUserMsg: SessionV1.User = {
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", summaryCreated)),
sessionID,
role: "user",
time: { created: Date.now() },
time: { created: summaryCreated },
agent: lastUser.agent,
model: lastUser.model,
}
Expand Down Expand Up @@ -467,10 +470,11 @@ const layer = Layer.effect(
throw error
}
const model = input.model ?? agent.model ?? (yield* currentModel(input.sessionID))
const userCreated = Date.now()
const userMsg: SessionV1.User = {
id: input.messageID ?? MessageID.ascending(),
id: input.messageID ?? MessageID.ascending(Identifier.create("msg", "ascending", userCreated)),
sessionID: input.sessionID,
time: { created: Date.now() },
time: { created: userCreated },
role: "user",
agent: input.agent,
model: { providerID: model.providerID, modelID: model.modelID },
Expand All @@ -486,15 +490,16 @@ const layer = Layer.effect(
}
yield* sessions.updatePart(userPart)

const assistantCreated = Date.now()
const msg: SessionV1.Assistant = {
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", assistantCreated)),
sessionID: input.sessionID,
parentID: userMsg.id,
mode: input.agent,
agent: input.agent,
cost: 0,
path: { cwd: ctx.directory, root: ctx.worktree },
time: { created: Date.now() },
time: { created: assistantCreated },
role: "assistant",
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
modelID: model.modelID,
Expand Down Expand Up @@ -653,11 +658,12 @@ const layer = Layer.effect(
: undefined
const variant = input.variant ?? (ag.variant && full?.variants?.[ag.variant] ? ag.variant : undefined)

const created = Date.now()
const info: SessionV1.User = {
id: input.messageID ?? MessageID.ascending(),
id: input.messageID ?? MessageID.ascending(Identifier.create("msg", "ascending", created)),
role: "user",
sessionID: input.sessionID,
time: { created: Date.now() },
time: { created },
tools: input.tools,
agent: ag.name,
model: {
Expand Down Expand Up @@ -1183,8 +1189,9 @@ const layer = Layer.effect(
Effect.provideService(Session.Service, sessions),
)

const created = Date.now()
const msg: SessionV1.Assistant = {
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
parentID: lastUser.id,
role: "assistant",
mode: agent.name,
Expand All @@ -1195,7 +1202,7 @@ const layer = Layer.effect(
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
modelID: model.id,
providerID: model.providerID,
time: { created: Date.now() },
time: { created },
sessionID,
}
yield* sessions.updateMessage(msg)
Expand Down
6 changes: 4 additions & 2 deletions packages/opencode/src/tool/plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Session } from "@/session/session"
import { MessageV2 } from "../session/message-v2"
import { Provider } from "@/provider/provider"
import { InstanceState } from "@/effect/instance-state"
import { Identifier } from "@/id/id"
import { MessageID, PartID } from "../session/schema"
import EXIT_DESCRIPTION from "./plan-exit.txt"

Expand Down Expand Up @@ -50,11 +51,12 @@ export const PlanExitTool = Tool.define(
const model =
lastUser?.info.role === "user" && lastUser.info.model ? lastUser.info.model : yield* provider.defaultModel()

const created = Date.now()
const msg: SessionV1.User = {
id: MessageID.ascending(),
id: MessageID.ascending(Identifier.create("msg", "ascending", created)),
sessionID: ctx.sessionID,
role: "user",
time: { created: Date.now() },
time: { created },
agent: "build",
model,
}
Expand Down
3 changes: 1 addition & 2 deletions packages/opencode/src/tool/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ToolJsonSchema } from "./json-schema"
import { SessionV1 } from "@opencode-ai/core/v1/session"
import { BackgroundJob } from "@/background/job"
import { Session } from "@/session/session"
import { SessionID, MessageID } from "../session/schema"
import { SessionID } from "../session/schema"
import { MessageV2 } from "../session/message-v2"
import { Agent } from "../agent/agent"
import { deriveSubagentSessionPermission } from "../agent/subagent-permissions"
Expand Down Expand Up @@ -200,7 +200,6 @@ export const TaskTool = Tool.define(
const runTask = Effect.fn("TaskTool.runTask")(function* () {
const parts = yield* ops.resolvePromptParts(params.prompt)
const result = yield* ops.prompt({
messageID: MessageID.ascending(),
sessionID: nextSession.id,
model: {
modelID: model.modelID,
Expand Down
29 changes: 29 additions & 0 deletions packages/opencode/test/session/prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { SessionProjector } from "@opencode-ai/core/session/projector"
import { eq } from "drizzle-orm"
import { EventV2Bridge } from "@/event-v2-bridge"
import { Identifier } from "@/id/id"
import { expect } from "bun:test"
import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer } from "effect"
import path from "path"
Expand Down Expand Up @@ -442,6 +443,34 @@ const boot = Effect.fn("test.boot")(function* (input?: { title?: string }) {
return { prompt, run, sessions, chat }
})

it.instance("prompt persists the timestamp embedded in its freshly minted message ID", () =>
Effect.acquireUseRelease(
Effect.sync(() => {
const original = Date.now
let reads = 0
Date.now = () => 1_000 + reads++
return original
}),
() =>
Effect.gen(function* () {
const { prompt, chat } = yield* boot()
const message = yield* prompt.prompt({
sessionID: chat.id,
agent: "build",
model: ref,
noReply: true,
parts: [{ type: "text", text: "timestamp invariant" }],
})

expect(Identifier.timestamp(message.info.id)).toBe(message.info.time.created)
}),
(original) =>
Effect.sync(() => {
Date.now = original
}),
),
)

// Loop semantics

noLLMServer.instance(
Expand Down
Loading