Files
deepseek-harness/packages/context/harness-dev-context/src/index.ts
T

159 lines
8.4 KiB
TypeScript

/**
* @deepseek-ai/dsh-harness-dev-context — model context for an agent that can
* inspect and extend the DeepSeek Harness serving its Web GUI. It registers
* path- and URL-free prompt sections and states the current implementation
* checkout and Web GUI URL as runtime context, so a process started from
* another checkout, port, or installation leaves the system prompt unchanged.
* A Session whose admitted prompt holds the paragraphs that embedded those
* values keeps them verbatim, so resuming it never rewrites its logged prompt.
* @module @deepseek-ai/dsh-harness-dev-context
*/
import { fileURLToPath } from 'node:url'
import type { Context } from '@deepseek-ai/cordis'
import { z as zod } from 'zod'
import type {} from '@deepseek-ai/dsh-agent'
import type {} from '@deepseek-ai/dsh-web-app'
import type { SessionEvent } from '@deepseek-ai/dsh-session'
import type {} from '@deepseek-ai/dsh-session-projection'
import type { AssembleContext } from '@deepseek-ai/dsh-system-prompt'
/** Stable Cordis plugin name. */
export const name = 'harness-dev-context'
/** Prompt registries, the projection registry, and the Web GUI whose URL the model learns. */
export const inject = ['systemPrompt', 'sessionProjections', 'webApp']
/** This installation's root, four directories above this package's source or built entry. */
const SOURCE_ROOT = fileURLToPath(new URL('../../../..', import.meta.url))
/** Prompt-section and runtime-context name for the implementation checkout. */
const HARNESS_SOURCE = 'harness:source'
/** Prompt-section and runtime-context name for the Web GUI orientation and its URL. */
const WEB_SURFACE = 'app:web-surface'
const HARNESS_SOURCE_GUIDANCE = 'The checkout location and current working directory are separate values and may differ; '
+ 'never infer the working directory from the checkout path. Use pwd to determine the current working directory. '
+ 'Use this checkout only to inspect or extend DSH itself.'
const HARNESS_SOURCE_PROMPT = `The runtime context names the DeepSeek Harness implementation checkout. ${HARNESS_SOURCE_GUIDANCE}`
const WEB_SURFACE_GUIDANCE = 'When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. '
+ 'The browser provides no implicit DOM, route, or screenshot context. '
+ 'The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while '
+ '`pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. '
+ 'Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. '
+ 'Starting another server does not update this GUI. '
+ 'The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. '
+ 'Do not start a replacement server unless the user asks; if one is needed, use a managed background job and verify its exact URL.'
const WEB_SURFACE_PROMPT = `You are interacting with the user through the DeepSeek Harness Web GUI whose URL the runtime context names. ${WEB_SURFACE_GUIDANCE}`
/**
* Fixed text around the value in each paragraph that embedded it, frozen as
* those releases rendered it: never edit these together with the current
* guidance, or Sessions holding the earlier paragraphs stop matching and
* rewrite their logged prompt.
*/
const LEGACY_SOURCE = {
prefix: 'The DeepSeek Harness implementation checkout is at ',
suffix: '. The checkout location and current working directory are separate values and may differ; '
+ 'never infer the working directory from this path. Use pwd to determine the current working directory. '
+ 'Use this checkout only to inspect or extend DSH itself.',
}
// The frozen copy repeats today's guidance on purpose; the two may diverge.
/* jscpd:ignore-start */
const LEGACY_WEB_SURFACE = {
prefix: 'You are interacting with the user through the DeepSeek Harness Web GUI at ',
suffix: '. When the user refers to "this page", "this GUI", or "this app" without naming another target, they mean this GUI. '
+ 'The browser provides no implicit DOM, route, or screenshot context. '
+ 'The client-plugin HMR receiver is active, but client-plugin changes reload without a refresh only while '
+ '`pnpm run dev:web` is also running from this same checkout to rebuild their bundles; verify that watcher before promising automatic updates. '
+ 'Every other change — the apps/web shell and plain packages — requires rebuilding the affected Web artifacts and verifying this existing URL after a page refresh. '
+ 'Starting another server does not update this GUI. '
+ 'The apps/web Vite entry builds the shell but is not a standalone application because only dsh web injects window.__DSH_BOOT__. '
+ 'Do not start a replacement server unless the user asks; if one is needed, use a managed background job and verify its exact URL.',
}
/* jscpd:ignore-end */
/** Host-only projection key of the value-bearing paragraphs a Session admitted. */
const LEGACY_PROMPT = 'harnessDevLegacyPrompt'
const legacyPromptSchema = zod.object({ source: zod.string().nullable(), web: zod.string().nullable() })
/** Value-bearing paragraphs of the latest nonempty system prompt a Session committed; `null` where it has none. */
type LegacyPrompt = zod.infer<typeof legacyPromptSchema>
/** The complete single-line paragraph between `prefix` and `suffix`, or `null` when the prompt has none. */
function legacyParagraph(prompt: string, { prefix, suffix }: { prefix: string; suffix: string }): string | null {
const start = prompt.indexOf(prefix)
if (start < 0) return null
const end = prompt.indexOf(suffix, start + prefix.length)
if (end < 0) return null
const paragraph = prompt.slice(start, end + suffix.length)
return paragraph.includes('\n') ? null : paragraph
}
/**
* Fold one committed event into the admitted paragraphs. Like the loop's own
* prompt-version reading, only a single nonempty text block is a prompt
* version; an emptied or other version keeps the previous state, because a
* series consolidation can log only the emptied later version.
*/
function foldLegacyPrompt(state: LegacyPrompt, event: SessionEvent): LegacyPrompt {
if (event.type !== 'system/message') return state
const { content } = event.data.message
const [block] = content
if (content.length !== 1 || block?.type !== 'text' || block.text === '') return state
const source = legacyParagraph(block.text, LEGACY_SOURCE)
const web = legacyParagraph(block.text, LEGACY_WEB_SURFACE)
return source === state.source && web === state.web ? state : { source, web }
}
const ADMITS_NOTHING: LegacyPrompt = { source: null, web: null }
/**
* Register the two sections, their runtime-context values, and the
* projection that keeps a Session's admitted paragraphs.
* @param ctx - plugin context with every {@link inject} service.
* @returns after the projection reader and prompt registrations are ready.
*/
export async function apply(ctx: Context): Promise<void> {
const legacyPromptProjectionHandle = await ctx.sessionProjections.register({
key: LEGACY_PROMPT,
stateVersion: 1,
stateSchema: legacyPromptSchema,
init: () => ADMITS_NOTHING,
apply: foldLegacyPrompt,
})
const admitted = (context: AssembleContext): LegacyPrompt => {
const session = context.agent?.session
return session === undefined ? ADMITS_NOTHING : legacyPromptProjectionHandle.stateOf(session)
}
ctx.systemPrompt.section({
name: HARNESS_SOURCE,
order: ctx.systemPrompt.getSectionOrder('HARNESS_SOURCE'),
interpolate: false,
text: context => admitted(context).source ?? HARNESS_SOURCE_PROMPT,
})
ctx.systemPrompt.context({
name: HARNESS_SOURCE,
order: ctx.systemPrompt.getContextOrder('HARNESS_SOURCE'),
interpolate: false,
text: `Current DeepSeek Harness implementation checkout: ${JSON.stringify(SOURCE_ROOT)}.`,
})
ctx.systemPrompt.section({
name: WEB_SURFACE,
order: ctx.systemPrompt.getSectionOrder('WEB_SURFACE'),
interpolate: false,
text: context => admitted(context).web ?? WEB_SURFACE_PROMPT,
})
ctx.systemPrompt.context({
name: WEB_SURFACE,
order: ctx.systemPrompt.getContextOrder('WEB_SURFACE'),
interpolate: false,
text: () => `Current DeepSeek Harness Web GUI URL: ${JSON.stringify(ctx.webApp.getAdvertisedUrl())}.`,
})
}