chore: user modifications
Some checks failed
Release Binaries / release (push) Has been cancelled

This commit is contained in:
Gemini AI
2025-12-28 01:03:54 +04:00
Unverified
parent 74001c7c3e
commit babce0e0a9
7 changed files with 157 additions and 17 deletions

View File

@@ -192,6 +192,16 @@ export interface InstanceData {
agentModelSelections: AgentModelSelection agentModelSelections: AgentModelSelection
sessionTasks?: SessionTasks // Multi-task chat support: tasks per session sessionTasks?: SessionTasks // Multi-task chat support: tasks per session
sessionSkills?: Record<string, SkillSelection[]> // Selected skills per session sessionSkills?: Record<string, SkillSelection[]> // Selected skills per session
sessionMessages?: Record<
string,
Array<{
id: string
role: "user" | "assistant" | "system" | "tool"
content?: string
createdAt?: number
updatedAt?: number
}>
>
customAgents?: Array<{ customAgents?: Array<{
name: string name: string
description?: string description?: string

View File

@@ -26,6 +26,20 @@ const InstanceDataSchema = z.object({
messageHistory: z.array(z.string()).default([]), messageHistory: z.array(z.string()).default([]),
agentModelSelections: z.record(z.string(), ModelPreferenceSchema).default({}), agentModelSelections: z.record(z.string(), ModelPreferenceSchema).default({}),
sessionTasks: z.record(z.string(), z.array(TaskSchema)).optional(), sessionTasks: z.record(z.string(), z.array(TaskSchema)).optional(),
sessionMessages: z
.record(
z.string(),
z.array(
z.object({
id: z.string(),
role: z.enum(["user", "assistant", "system", "tool"]),
content: z.string().optional(),
createdAt: z.number().optional(),
updatedAt: z.number().optional(),
}),
),
)
.optional(),
sessionSkills: z sessionSkills: z
.record( .record(
z.string(), z.string(),
@@ -47,6 +61,7 @@ const EMPTY_INSTANCE_DATA: InstanceData = {
messageHistory: [], messageHistory: [],
agentModelSelections: {}, agentModelSelections: {},
sessionTasks: {}, sessionTasks: {},
sessionMessages: {},
sessionSkills: {}, sessionSkills: {},
customAgents: [], customAgents: [],
} }

View File

@@ -8,6 +8,7 @@ const DEFAULT_INSTANCE_DATA: InstanceData = {
messageHistory: [], messageHistory: [],
agentModelSelections: {}, agentModelSelections: {},
sessionTasks: {}, sessionTasks: {},
sessionMessages: {},
} }
export class InstanceStore { export class InstanceStore {

View File

@@ -11,6 +11,7 @@ const DEFAULT_INSTANCE_DATA: InstanceData = {
messageHistory: [], messageHistory: [],
agentModelSelections: {}, agentModelSelections: {},
sessionTasks: {}, sessionTasks: {},
sessionMessages: {},
} }
function isDeepEqual(a: unknown, b: unknown): boolean { function isDeepEqual(a: unknown, b: unknown): boolean {
@@ -157,11 +158,13 @@ export class ServerStorage {
const messageHistory = Array.isArray(source.messageHistory) ? [...source.messageHistory] : [] const messageHistory = Array.isArray(source.messageHistory) ? [...source.messageHistory] : []
const agentModelSelections = { ...(source.agentModelSelections ?? {}) } const agentModelSelections = { ...(source.agentModelSelections ?? {}) }
const sessionTasks = { ...(source.sessionTasks ?? {}) } const sessionTasks = { ...(source.sessionTasks ?? {}) }
const sessionMessages = { ...(source.sessionMessages ?? {}) }
return { return {
...source, ...source,
messageHistory, messageHistory,
agentModelSelections, agentModelSelections,
sessionTasks, sessionTasks,
sessionMessages,
} }
} }

View File

@@ -10,6 +10,7 @@ const DEFAULT_INSTANCE_DATA: InstanceData = {
agentModelSelections: {}, agentModelSelections: {},
sessionTasks: {}, sessionTasks: {},
sessionSkills: {}, sessionSkills: {},
sessionMessages: {},
customAgents: [], customAgents: [],
} }
@@ -25,6 +26,7 @@ function cloneInstanceData(data?: InstanceData | null): InstanceData {
agentModelSelections: { ...(source.agentModelSelections ?? {}) }, agentModelSelections: { ...(source.agentModelSelections ?? {}) },
sessionTasks: { ...(source.sessionTasks ?? {}) }, sessionTasks: { ...(source.sessionTasks ?? {}) },
sessionSkills: { ...(source.sessionSkills ?? {}) }, sessionSkills: { ...(source.sessionSkills ?? {}) },
sessionMessages: { ...(source.sessionMessages ?? {}) },
customAgents: Array.isArray(source.customAgents) ? [...source.customAgents] : [], customAgents: Array.isArray(source.customAgents) ? [...source.customAgents] : [],
} }
} }

View File

@@ -26,6 +26,7 @@ import { getUserScopedKey } from "../lib/user-storage"
import { loadSkillDetails } from "./skills" import { loadSkillDetails } from "./skills"
import { serverApi } from "../lib/api-client" import { serverApi } from "../lib/api-client"
import { nativeSessionApi } from "../lib/lite-mode" import { nativeSessionApi } from "../lib/lite-mode"
import { ensureInstanceConfigLoaded, updateInstanceConfig, getInstanceConfig } from "./instance-config"
import type { Session } from "../types/session" import type { Session } from "../types/session"
const log = getLogger("actions") const log = getLogger("actions")
@@ -1284,6 +1285,37 @@ async function persistNativeMessages(
} }
} }
async function persistSdkMessages(
instanceId: string,
sessionId: string,
messages: Array<{
id: string
role: "user" | "assistant" | "system" | "tool"
content?: string
createdAt?: number
updatedAt?: number
}>,
): Promise<void> {
try {
await ensureInstanceConfigLoaded(instanceId)
const existing = getInstanceConfig(instanceId).sessionMessages ?? {}
const current = existing[sessionId] ?? []
const merged = [...current]
for (const message of messages) {
if (!merged.some((entry) => entry.id === message.id)) {
merged.push(message)
}
}
merged.sort((a, b) => (a.createdAt ?? 0) - (b.createdAt ?? 0))
const trimmed = merged.length > 200 ? merged.slice(-200) : merged
await updateInstanceConfig(instanceId, (draft) => {
draft.sessionMessages = { ...(draft.sessionMessages ?? {}), [sessionId]: trimmed }
})
} catch (error) {
log.warn("Failed to persist SDK messages", { instanceId, sessionId, error })
}
}
async function sendMessage( async function sendMessage(
instanceId: string, instanceId: string,
sessionId: string, sessionId: string,
@@ -1296,6 +1328,7 @@ async function sendMessage(
throw new Error("Instance not ready") throw new Error("Instance not ready")
} }
const isNative = instance.binaryPath === "__nomadarch_native__" const isNative = instance.binaryPath === "__nomadarch_native__"
const isSdk = !isNative
const instanceSessions = sessions().get(instanceId) const instanceSessions = sessions().get(instanceId)
const session = instanceSessions?.get(sessionId) const session = instanceSessions?.get(sessionId)
@@ -1587,6 +1620,24 @@ async function sendMessage(
updatedAt: completedAt, updatedAt: completedAt,
}, },
]) ])
} else if (isSdk) {
const completedAt = Date.now()
await persistSdkMessages(instanceId, sessionId, [
{
id: messageId,
role: "user",
content: resolvedPrompt,
createdAt: now,
updatedAt: now,
},
{
id: assistantMessageId,
role: "assistant",
content: assistantText,
createdAt: now,
updatedAt: completedAt,
},
])
} }
return messageId return messageId
} catch (error: any) { } catch (error: any) {

View File

@@ -486,7 +486,6 @@ async function fetchSessions(instanceId: string): Promise<void> {
}) })
} }
if (isNative) {
const updates: Promise<unknown>[] = [] const updates: Promise<unknown>[] = []
for (const [parentId, tasks] of Object.entries(sessionTasks)) { for (const [parentId, tasks] of Object.entries(sessionTasks)) {
if (!Array.isArray(tasks)) continue if (!Array.isArray(tasks)) continue
@@ -500,12 +499,32 @@ async function fetchSessions(instanceId: string): Promise<void> {
...childSession, ...childSession,
parentId, parentId,
}) })
if (isNative) {
updates.push(nativeSessionApi.updateSession(instanceId, childId, { parentId }).catch(() => undefined)) updates.push(nativeSessionApi.updateSession(instanceId, childId, { parentId }).catch(() => undefined))
} }
} }
}
if (updates.length > 0) { if (updates.length > 0) {
await Promise.allSettled(updates) await Promise.allSettled(updates)
} }
for (const [sessionId, tasks] of Object.entries(sessionTasks)) {
if (sessionMap.has(sessionId)) continue
if (!Array.isArray(tasks) || tasks.length === 0) continue
const existingSession = existingSessions?.get(sessionId)
sessionMap.set(sessionId, {
id: sessionId,
instanceId,
title: existingSession?.title ?? "Untitled",
parentId: existingSession?.parentId ?? null,
agent: existingSession?.agent ?? "",
model: existingSession?.model ?? { providerId: "", modelId: "" },
skills: existingSession?.skills ?? [],
version: existingSession?.version ?? "0",
time: existingSession?.time ?? { created: Date.now(), updated: Date.now() },
revert: existingSession?.revert,
tasks: tasks as any[],
})
} }
const validSessionIds = new Set(sessionMap.keys()) const validSessionIds = new Set(sessionMap.keys())
@@ -1069,6 +1088,45 @@ async function loadMessages(instanceId: string, sessionId: string, force = false
apiMessagesInfo = (response as any).info || {} // Assuming 'info' might be on the response object itself for some cases apiMessagesInfo = (response as any).info || {} // Assuming 'info' might be on the response object itself for some cases
} }
if (!isNative) {
await ensureInstanceConfigLoaded(instanceId)
const cachedMessages = getInstanceConfig(instanceId).sessionMessages?.[sessionId] ?? []
if (cachedMessages.length > 0) {
const existingIds = new Set<string>()
for (const apiMessage of apiMessages) {
const info = apiMessage.info || apiMessage
if (info?.id) {
existingIds.add(info.id)
}
}
for (const cached of cachedMessages) {
if (!cached?.id || existingIds.has(cached.id)) continue
apiMessages.push({
id: cached.id,
role: cached.role,
content: cached.content,
createdAt: cached.createdAt,
info: {
id: cached.id,
role: cached.role,
time: { created: cached.createdAt ?? Date.now() },
},
parts: cached.content
? [{ id: `part-${cached.id}`, type: "text", text: cached.content }]
: [],
})
existingIds.add(cached.id)
}
apiMessages.sort((a, b) => {
const aInfo = a.info || a
const bInfo = b.info || b
const aTime = aInfo.time?.created ?? aInfo.createdAt ?? 0
const bTime = bInfo.time?.created ?? bInfo.createdAt ?? 0
return aTime - bTime
})
}
}
const messagesInfo = new Map<string, any>() const messagesInfo = new Map<string, any>()
const messages: Message[] = apiMessages.map((apiMessage: any) => { const messages: Message[] = apiMessages.map((apiMessage: any) => {
const info = apiMessage.info || apiMessage const info = apiMessage.info || apiMessage