| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- /**
- * Durable projection state for dynamic runtime context.
- * @module @deepseek-ai/dsh-agent-loop/runtime-context
- */
- import { createUserMessage } from '@deepseek-ai/dsh-llm'
- import type { ContextSnapshotSection } from '@deepseek-ai/dsh-llm'
- import type { Session, UserMessage } from '@deepseek-ai/dsh-session'
- import { isReplacementSurfaceEvent } from '@deepseek-ai/dsh-session'
- import type { Context } from 'cordis'
- const SOURCE = '@deepseek-ai/dsh-system-prompt'
- const CLEARED = 'Current runtime context: none. Earlier runtime-context snapshots no longer apply.'
- function isOwned(message: UserMessage): boolean {
- return message.source.kind === 'plugin' && message.source.plugin === SOURCE
- }
- function textOf(message: UserMessage): string | undefined {
- const [block] = message.content
- return message.content.length === 1 && block?.type === 'text' ? block.text : undefined
- }
- /** Tracks the last retained runtime-context snapshot without owning its commit. */
- export class RuntimeContextProjection {
- /** `undefined` means no snapshot ever existed; `null` means none is retained. */
- private retained: { seq: number; text: string | undefined } | null | undefined
- /**
- * Restore projection state once, then follow authoritative session events.
- * @param ctx - agent-scoped event context.
- * @param session - session receiving projected messages.
- */
- constructor(ctx: Context, session: Session) {
- const surface = new Set(session.surface.nodes)
- for (let index = session.events.length - 1; index >= 0; index -= 1) {
- const event = session.events[index]
- if (event?.type !== 'user/message' || !isOwned(event.data)) continue
- this.retained ??= null
- if (surface.has(event.seq)) {
- this.retained = { seq: event.seq, text: textOf(event.data) }
- break
- }
- }
- ctx.on('session/event', (subject, event) => {
- if (subject !== session) return
- if (event.type === 'user/message' && isOwned(event.data)) {
- this.retained = { seq: event.seq, text: textOf(event.data) }
- } else if (this.retained
- && isReplacementSurfaceEvent(event)
- && event.sourceEventSeqs?.includes(this.retained.seq) === true) {
- this.retained = null
- }
- })
- }
- /**
- * Create an uncommitted snapshot only when the retained value differs.
- * @param current - fully rendered dynamic context.
- * @param sections - named contributions that formed the current snapshot.
- * @returns a candidate user message, or `undefined` when no update is needed.
- */
- project(current: string, sections: readonly ContextSnapshotSection[]): UserMessage | undefined {
- if (this.retained === undefined && current.length === 0) return
- const snapshot = current.length === 0 ? CLEARED : current
- if (this.retained?.text === snapshot) return
- return createUserMessage({
- content: [{ type: 'text', text: snapshot }],
- // The cleared marker has no contributions left to attribute.
- source: sections.length === 0
- ? { kind: 'plugin', plugin: SOURCE }
- : { kind: 'plugin', plugin: SOURCE, form: 'snapshot', sections },
- })
- }
- }
|