Download packages/agent-core-v2/src/session/sessionMetadata/sessionMetadataService.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/session/sessionMetadata/sessionMetadataService.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/agent-core-v2/src/session/sessionMetadata/sessionMetadataService.ts
-
curl -L -o sessionMetadataService.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/session/sessionMetadata/sessionMetadataService.ts
10.6 kB
| import { Service } from '#/_base/di/service'; | |
| import { LifecycleScope } from '#/app/scopes'; | |
| import { ScopeActivation, registerScopedService } from '#/_base/di/scope'; | |
| import { Emitter, type Event } from '#/_base/event'; | |
| import { ILogService } from '#/_base/log/log'; | |
| import { defineState } from '#/state/state'; | |
| import { ISessionIndexMirror } from '#/app/sessionIndex/sessionIndex'; | |
| import { buildSessionSummary } from '#/app/sessionIndex/sessionIndexSource'; | |
| import { IAtomicDocumentStore } from '#/persistence/interface/atomicDocumentStore'; | |
| import { ISessionContext } from '#/session/sessionContext/sessionContext'; | |
| import { ISessionStateService } from '#/session/state/sessionState'; | |
| import { | |
| ISessionMetadata, | |
| SESSION_META_VERSION, | |
| type AgentMeta, | |
| type SessionMeta, | |
| type SessionMetadataChangedEvent, | |
| type SessionMetaPatch, | |
| type SessionTitleKind, | |
| } from './sessionMetadata'; | |
| const META_KEY = 'state.json'; | |
| const pendingWrites = new Set<Promise<void>>(); | |
| export async function drainSessionMetadataWrites(): Promise<void> { | |
| await Promise.all(pendingWrites); | |
| } | |
| export const sessionMetadataDataKey = defineState<SessionMeta | undefined>( | |
| 'sessionMetadata.data', | |
| () => undefined, | |
| ); | |
| export class SessionMetadata extends Service implements ISessionMetadata { | |
| declare readonly _serviceBrand: undefined; | |
| private disposed = false; | |
| readonly ready: Promise<void>; | |
| readonly onDidChangeMetadata: Event<SessionMetadataChangedEvent>; | |
| private readonly _onDidChangeMetadata = this._register( | |
| new Emitter<SessionMetadataChangedEvent>(), | |
| ); | |
| private readonly scope: string; | |
| private updateQueue: Promise<void> = Promise.resolve(); | |
| constructor( | |
| private readonly states: ISessionStateService, | |
| private readonly ctx: ISessionContext, | |
| private readonly store: IAtomicDocumentStore, | |
| private readonly log: ILogService, | |
| private readonly mirror: ISessionIndexMirror, | |
| ) { | |
| super(); | |
| this._register({ | |
| dispose: () => { | |
| this.disposed = true; | |
| }, | |
| }); | |
| this.states.contributeState(sessionMetadataDataKey); | |
| this.scope = ctx.metaScope; | |
| this.onDidChangeMetadata = this._onDidChangeMetadata.event; | |
| this.ready = this.load(); | |
| } | |
| private get data(): SessionMeta { | |
| return this.states.get(sessionMetadataDataKey) as SessionMeta; | |
| } | |
| private set data(value: SessionMeta) { | |
| this.states.set(sessionMetadataDataKey, value); | |
| } | |
| async read(): Promise<SessionMeta> { | |
| await this.ready; | |
| return this.data; | |
| } | |
| async update( | |
| patch: SessionMetaPatch, | |
| opts?: { readonly touchUpdatedAt?: boolean }, | |
| ): Promise<void> { | |
| return this.enqueueUpdate(async () => { | |
| await this.applyUpdate(patch, opts); | |
| }); | |
| } | |
| private async applyUpdate( | |
| patch: SessionMetaPatch, | |
| opts?: { readonly touchUpdatedAt?: boolean }, | |
| ): Promise<boolean> { | |
| await this.ready; | |
| if (this.disposed) return false; | |
| const updatedAt = | |
| patch.updatedAt ?? (opts?.touchUpdatedAt === false ? this.data.updatedAt : Date.now()); | |
| this.data = { ...this.data, ...patch, updatedAt }; | |
| await this.store.set(this.scope, META_KEY, encodeSessionMeta(this.data)); | |
| if (this.disposed) return false; | |
| this.mirrorToReadModel(); | |
| this._onDidChangeMetadata.fire({ | |
| changed: Object.keys(patch) as (keyof SessionMeta)[], | |
| }); | |
| return true; | |
| } | |
| async setTitle(title: string): Promise<void> { | |
| await this.update({ title, titleKind: 'custom' }, { touchUpdatedAt: false }); | |
| } | |
| async setGeneratedTitleIfUncustomized( | |
| title: string, | |
| opts?: { force?: boolean }, | |
| ): Promise<boolean> { | |
| return this.enqueueUpdate(async () => { | |
| await this.ready; | |
| if (opts?.force !== true && this.data.titleKind === 'custom') return false; | |
| return this.applyUpdate({ title, titleKind: 'generated' }, { touchUpdatedAt: false }); | |
| }); | |
| } | |
| async setArchived(archived: boolean): Promise<void> { | |
| await this.update( | |
| archived ? { archived: true, archivedAt: Date.now() } : { archived: false, archivedAt: undefined }, | |
| { touchUpdatedAt: false }, | |
| ); | |
| } | |
| async registerAgent(agentId: string, meta: AgentMeta): Promise<void> { | |
| return this.enqueueUpdate(async () => { | |
| await this.ready; | |
| const existing = this.data.agents?.[agentId]; | |
| if (existing !== undefined && agentMetaEquals(existing, meta)) return; | |
| const agents = { ...this.data.agents, [agentId]: meta }; | |
| await this.applyUpdate({ agents }, { touchUpdatedAt: false }); | |
| }); | |
| } | |
| private enqueueUpdate<T>(work: () => Promise<T>): Promise<T> { | |
| const run = this.updateQueue.then(work, work); | |
| const tracked: Promise<void> = run.then( | |
| () => undefined, | |
| () => undefined, | |
| ); | |
| this.updateQueue = tracked; | |
| pendingWrites.add(tracked); | |
| void tracked.finally(() => pendingWrites.delete(tracked)); | |
| return run; | |
| } | |
| private mirrorToReadModel(): void { | |
| try { | |
| this.mirror.record( | |
| buildSessionSummary({ | |
| id: this.data.id, | |
| workspaceId: this.ctx.workspaceId, | |
| cwd: this.ctx.cwd, | |
| title: this.data.title, | |
| lastPrompt: this.data.lastPrompt, | |
| createdAt: this.data.createdAt, | |
| updatedAt: this.data.updatedAt, | |
| archived: this.data.archived === true, | |
| archivedAt: this.data.archivedAt, | |
| custom: this.data.custom, | |
| lastTurnReason: this.data.lastTurnReason, | |
| }), | |
| ); | |
| } catch (error) { | |
| this.log.warn('session index mirror record failed; the read model heals by reconciliation', { | |
| sessionId: this.ctx.sessionId, | |
| error: error instanceof Error ? error.message : String(error), | |
| }); | |
| } | |
| } | |
| private async load(): Promise<void> { | |
| const existing = await this.store.get<SessionMeta>(this.scope, META_KEY); | |
| if (existing !== undefined) { | |
| this.data = normalizeSessionMeta(existing, this.ctx.sessionId); | |
| if ( | |
| this.data.agents === undefined || | |
| this.data.custom === undefined || | |
| sessionMetaTitleNeedsMigration(existing, this.data) | |
| ) { | |
| this.data = { | |
| ...this.data, | |
| agents: this.data.agents ?? {}, | |
| custom: this.data.custom ?? {}, | |
| }; | |
| await this.store.set(this.scope, META_KEY, encodeSessionMeta(this.data)); | |
| } | |
| return; | |
| } | |
| const now = Date.now(); | |
| this.data = { | |
| id: this.ctx.sessionId, | |
| version: SESSION_META_VERSION, | |
| cwd: this.ctx.cwd, | |
| createdAt: now, | |
| updatedAt: now, | |
| archived: false, | |
| agents: {}, | |
| custom: {}, | |
| }; | |
| await this.store.set(this.scope, META_KEY, encodeSessionMeta(this.data)); | |
| this.mirrorToReadModel(); | |
| this.log.debug('session metadata created', { sessionId: this.ctx.sessionId }); | |
| } | |
| } | |
| function agentMetaEquals(a: AgentMeta, b: AgentMeta): boolean { | |
| return ( | |
| a.homedir === b.homedir && | |
| a.type === b.type && | |
| (a.parentAgentId ?? null) === (b.parentAgentId ?? null) && | |
| a.forkedFrom === b.forkedFrom && | |
| a.swarmItem === b.swarmItem && | |
| recordEquals(a.labels, b.labels) | |
| ); | |
| } | |
| function recordEquals(a: AgentMeta['labels'], b: AgentMeta['labels']): boolean { | |
| const entriesA = Object.entries(a ?? {}); | |
| const entriesB = Object.entries(b ?? {}); | |
| return ( | |
| entriesA.length === entriesB.length && entriesA.every(([key, value]) => b?.[key] === value) | |
| ); | |
| } | |
| export function normalizeSessionMeta(raw: SessionMeta, sessionId: string): SessionMeta { | |
| const legacy = raw as unknown as LegacySessionMeta; | |
| const normalizedTitle = normalizeSessionTitle(legacy); | |
| const { | |
| createdAt: legacyCreatedAt, | |
| updatedAt: legacyUpdatedAt, | |
| workDir: legacyWorkDir, | |
| titleSource: _legacyTitleSource, | |
| isCustomTitle: _legacyIsCustomTitle, | |
| customTitle: _legacyCustomTitle, | |
| ...clean | |
| } = legacy; | |
| const cwd = | |
| clean.cwd ?? (typeof legacyWorkDir === 'string' && legacyWorkDir.length > 0 | |
| ? legacyWorkDir | |
| : undefined); | |
| const { title, titleKind } = normalizedTitle; | |
| return { | |
| ...clean, | |
| id: clean.version === SESSION_META_VERSION ? clean.id : sessionId, | |
| version: SESSION_META_VERSION, | |
| cwd, | |
| title, | |
| titleKind, | |
| createdAt: toEpochMs(legacyCreatedAt), | |
| updatedAt: toEpochMs(legacyUpdatedAt), | |
| archived: clean.archived === true, | |
| }; | |
| } | |
| type LegacySessionMeta = Omit<SessionMeta, 'createdAt' | 'updatedAt'> & { | |
| readonly createdAt?: unknown; | |
| readonly updatedAt?: unknown; | |
| readonly workDir?: unknown; | |
| readonly titleSource?: unknown; | |
| readonly isCustomTitle?: unknown; | |
| readonly customTitle?: unknown; | |
| }; | |
| function normalizeSessionTitle( | |
| raw: LegacySessionMeta, | |
| ): Pick<SessionMeta, 'title' | 'titleKind'> { | |
| const title = typeof raw.title === 'string' ? raw.title : undefined; | |
| if (title !== undefined && raw.isCustomTitle === true) { | |
| return { title, titleKind: 'custom' }; | |
| } | |
| if (title !== undefined && isSessionTitleKind(raw.titleKind)) { | |
| return { title, titleKind: raw.titleKind }; | |
| } | |
| if (title !== undefined && raw.isCustomTitle === false) { | |
| return { title, titleKind: 'replaceable' }; | |
| } | |
| if (typeof raw.customTitle === 'string') { | |
| return { title: raw.customTitle, titleKind: 'custom' }; | |
| } | |
| return title === undefined ? {} : { title, titleKind: 'replaceable' }; | |
| } | |
| function isSessionTitleKind(value: unknown): value is SessionTitleKind { | |
| return value === 'replaceable' || value === 'generated' || value === 'custom'; | |
| } | |
| type PersistedSessionMeta = SessionMeta & { readonly isCustomTitle: boolean }; | |
| export function encodeSessionMeta(meta: SessionMeta): PersistedSessionMeta { | |
| return { ...meta, isCustomTitle: meta.titleKind === 'custom' }; | |
| } | |
| function sessionMetaTitleNeedsMigration(raw: SessionMeta, normalized: SessionMeta): boolean { | |
| const record = raw as unknown as Record<string, unknown>; | |
| return ( | |
| raw.title !== normalized.title || | |
| raw.titleKind !== normalized.titleKind || | |
| record['isCustomTitle'] !== (normalized.titleKind === 'custom') || | |
| Object.hasOwn(record, 'titleSource') || | |
| Object.hasOwn(record, 'customTitle') | |
| ); | |
| } | |
| export function toEpochMs(value: unknown): number { | |
| if (typeof value === 'number' && Number.isFinite(value)) return value; | |
| if (typeof value === 'string') { | |
| const parsed = Date.parse(value); | |
| if (!Number.isNaN(parsed)) return parsed; | |
| } | |
| return 0; | |
| } | |
| registerScopedService( | |
| LifecycleScope.Session, | |
| ISessionMetadata, | |
| SessionMetadata, | |
| ScopeActivation.OnScopeCreated, | |
| 'sessionMetadata', | |
| ); | |