mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-20 09:14:22 +01:00
feat: add model management to ACP sessions (#3358)
This commit is contained in:
@@ -12,6 +12,8 @@ import type {
|
|||||||
NewSessionResponse,
|
NewSessionResponse,
|
||||||
PromptRequest,
|
PromptRequest,
|
||||||
PromptResponse,
|
PromptResponse,
|
||||||
|
SetSessionModelRequest,
|
||||||
|
SetSessionModelResponse,
|
||||||
} from "@agentclientprotocol/sdk"
|
} from "@agentclientprotocol/sdk"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { ACPSessionManager } from "./session"
|
import { ACPSessionManager } from "./session"
|
||||||
@@ -55,10 +57,16 @@ export class OpenCodeAgent implements Agent {
|
|||||||
async newSession(params: NewSessionRequest): Promise<NewSessionResponse> {
|
async newSession(params: NewSessionRequest): Promise<NewSessionResponse> {
|
||||||
this.log.info("newSession", { cwd: params.cwd, mcpServers: params.mcpServers.length })
|
this.log.info("newSession", { cwd: params.cwd, mcpServers: params.mcpServers.length })
|
||||||
|
|
||||||
const session = await this.sessionManager.create(params.cwd, params.mcpServers)
|
const model = await this.defaultModel()
|
||||||
|
const session = await this.sessionManager.create(params.cwd, params.mcpServers, model)
|
||||||
|
const availableModels = await this.availableModels()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sessionId: session.id,
|
sessionId: session.id,
|
||||||
|
models: {
|
||||||
|
currentModelId: `${model.providerID}/${model.modelID}`,
|
||||||
|
availableModels,
|
||||||
|
},
|
||||||
_meta: {},
|
_meta: {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,13 +74,64 @@ export class OpenCodeAgent implements Agent {
|
|||||||
async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {
|
async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {
|
||||||
this.log.info("loadSession", { sessionId: params.sessionId, cwd: params.cwd })
|
this.log.info("loadSession", { sessionId: params.sessionId, cwd: params.cwd })
|
||||||
|
|
||||||
await this.sessionManager.load(params.sessionId, params.cwd, params.mcpServers)
|
const defaultModel = await this.defaultModel()
|
||||||
|
const session = await this.sessionManager.load(params.sessionId, params.cwd, params.mcpServers, defaultModel)
|
||||||
|
const availableModels = await this.availableModels()
|
||||||
|
|
||||||
|
return {
|
||||||
|
models: {
|
||||||
|
currentModelId: `${session.model.providerID}/${session.model.modelID}`,
|
||||||
|
availableModels,
|
||||||
|
},
|
||||||
|
_meta: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async setSessionModel(params: SetSessionModelRequest): Promise<SetSessionModelResponse> {
|
||||||
|
this.log.info("setSessionModel", { sessionId: params.sessionId, modelId: params.modelId })
|
||||||
|
|
||||||
|
const session = this.sessionManager.get(params.sessionId)
|
||||||
|
if (!session) {
|
||||||
|
throw new Error(`Session not found: ${params.sessionId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = Provider.parseModel(params.modelId)
|
||||||
|
const model = await Provider.getModel(parsed.providerID, parsed.modelID)
|
||||||
|
|
||||||
|
this.sessionManager.setModel(session.id, {
|
||||||
|
providerID: model.providerID,
|
||||||
|
modelID: model.modelID,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_meta: {},
|
_meta: {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async defaultModel() {
|
||||||
|
const configured = this.config.defaultModel
|
||||||
|
if (configured) return configured
|
||||||
|
return Provider.defaultModel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async availableModels() {
|
||||||
|
const providers = await Provider.list()
|
||||||
|
const entries = Object.entries(providers).sort((a, b) => {
|
||||||
|
const nameA = a[1].info.name.toLowerCase()
|
||||||
|
const nameB = b[1].info.name.toLowerCase()
|
||||||
|
if (nameA < nameB) return -1
|
||||||
|
if (nameA > nameB) return 1
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
return entries.flatMap(([providerID, provider]) => {
|
||||||
|
const models = Provider.sort(Object.values(provider.info.models))
|
||||||
|
return models.map((model) => ({
|
||||||
|
modelId: `${providerID}/${model.id}`,
|
||||||
|
name: `${provider.info.name}/${model.name}`,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async prompt(params: PromptRequest): Promise<PromptResponse> {
|
async prompt(params: PromptRequest): Promise<PromptResponse> {
|
||||||
this.log.info("prompt", {
|
this.log.info("prompt", {
|
||||||
sessionId: params.sessionId,
|
sessionId: params.sessionId,
|
||||||
@@ -84,7 +143,11 @@ export class OpenCodeAgent implements Agent {
|
|||||||
throw new Error(`Session not found: ${params.sessionId}`)
|
throw new Error(`Session not found: ${params.sessionId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const model = this.config.defaultModel || (await Provider.defaultModel())
|
const current = acpSession.model
|
||||||
|
const model = current ?? (await this.defaultModel())
|
||||||
|
if (!current) {
|
||||||
|
this.sessionManager.setModel(acpSession.id, model)
|
||||||
|
}
|
||||||
|
|
||||||
const parts = params.prompt.map((content) => {
|
const parts = params.prompt.map((content) => {
|
||||||
if (content.type === "text") {
|
if (content.type === "text") {
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import type { McpServer } from "@agentclientprotocol/sdk"
|
import type { McpServer } from "@agentclientprotocol/sdk"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Session } from "../session"
|
import { Session } from "../session"
|
||||||
|
import { Provider } from "../provider/provider"
|
||||||
import type { ACPSessionState } from "./types"
|
import type { ACPSessionState } from "./types"
|
||||||
|
|
||||||
export class ACPSessionManager {
|
export class ACPSessionManager {
|
||||||
private sessions = new Map<string, ACPSessionState>()
|
private sessions = new Map<string, ACPSessionState>()
|
||||||
|
|
||||||
async create(cwd: string, mcpServers: McpServer[]): Promise<ACPSessionState> {
|
async create(
|
||||||
|
cwd: string,
|
||||||
|
mcpServers: McpServer[],
|
||||||
|
model?: ACPSessionState["model"],
|
||||||
|
): Promise<ACPSessionState> {
|
||||||
const sessionId = `acp_${Identifier.ascending("session")}`
|
const sessionId = `acp_${Identifier.ascending("session")}`
|
||||||
const openCodeSession = await Session.create({ title: `ACP Session ${sessionId}` })
|
const openCodeSession = await Session.create({ title: `ACP Session ${sessionId}` })
|
||||||
|
const resolvedModel = model ?? (await Provider.defaultModel())
|
||||||
|
|
||||||
const state: ACPSessionState = {
|
const state: ACPSessionState = {
|
||||||
id: sessionId,
|
id: sessionId,
|
||||||
@@ -16,6 +22,7 @@ export class ACPSessionManager {
|
|||||||
mcpServers,
|
mcpServers,
|
||||||
openCodeSessionId: openCodeSession.id,
|
openCodeSessionId: openCodeSession.id,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
model: resolvedModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sessions.set(sessionId, state)
|
this.sessions.set(sessionId, state)
|
||||||
@@ -38,13 +45,24 @@ export class ACPSessionManager {
|
|||||||
return this.sessions.has(sessionId)
|
return this.sessions.has(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(sessionId: string, cwd: string, mcpServers: McpServer[]): Promise<ACPSessionState> {
|
async load(
|
||||||
|
sessionId: string,
|
||||||
|
cwd: string,
|
||||||
|
mcpServers: McpServer[],
|
||||||
|
model?: ACPSessionState["model"],
|
||||||
|
): Promise<ACPSessionState> {
|
||||||
const existing = this.sessions.get(sessionId)
|
const existing = this.sessions.get(sessionId)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
if (!existing.model) {
|
||||||
|
const resolved = model ?? (await Provider.defaultModel())
|
||||||
|
existing.model = resolved
|
||||||
|
this.sessions.set(sessionId, existing)
|
||||||
|
}
|
||||||
return existing
|
return existing
|
||||||
}
|
}
|
||||||
|
|
||||||
const openCodeSession = await Session.create({ title: `ACP Session ${sessionId} (loaded)` })
|
const openCodeSession = await Session.create({ title: `ACP Session ${sessionId} (loaded)` })
|
||||||
|
const resolvedModel = model ?? (await Provider.defaultModel())
|
||||||
|
|
||||||
const state: ACPSessionState = {
|
const state: ACPSessionState = {
|
||||||
id: sessionId,
|
id: sessionId,
|
||||||
@@ -52,9 +70,24 @@ export class ACPSessionManager {
|
|||||||
mcpServers,
|
mcpServers,
|
||||||
openCodeSessionId: openCodeSession.id,
|
openCodeSessionId: openCodeSession.id,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
model: resolvedModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sessions.set(sessionId, state)
|
this.sessions.set(sessionId, state)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModel(sessionId: string) {
|
||||||
|
const session = this.sessions.get(sessionId)
|
||||||
|
if (!session) return
|
||||||
|
return session.model
|
||||||
|
}
|
||||||
|
|
||||||
|
setModel(sessionId: string, model: ACPSessionState["model"]) {
|
||||||
|
const session = this.sessions.get(sessionId)
|
||||||
|
if (!session) return
|
||||||
|
session.model = model
|
||||||
|
this.sessions.set(sessionId, session)
|
||||||
|
return session
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ export interface ACPSessionState {
|
|||||||
mcpServers: McpServer[]
|
mcpServers: McpServer[]
|
||||||
openCodeSessionId: string
|
openCodeSessionId: string
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
model: {
|
||||||
|
providerID: string
|
||||||
|
modelID: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ACPConfig {
|
export interface ACPConfig {
|
||||||
|
|||||||
Reference in New Issue
Block a user