A preset is a directory holding one `agent.cordis.yml`. Mounting it under an agent's scope context during `setup(agentCtx)` gives that one session its own tools and prompt sections while every other live session keeps its own. No registry gains a tier. `dsh-tools` and `dsh-system-prompt` already file registrations into the calling context's scope layer, and entry contexts chain to the context a subtree was plugged into, so a composition mounted under `agent.ctx` is that agent's alone and unwinds with it. The mount audits itself because a directly-plugged subtree is absent from `ctx.loader.entries()` and no boot audit covers it. It rejects an unscoped target, a row that never became usable, and a row that published a service into the root service realm — that last one is process-global rather than per-session, and its collision with the next session surfaces as an unhandled rejection `setup` never observes, leaving a half-composed agent that looks healthy. The package invariant re-checks that rule on every service notification, since a row publishing from a timer would escape a one-shot audit. Raises the `packages/README.md` word ceiling from 920 to 980: the group table must enumerate every group, and the new `preset/` row is necessary content. Design: .agents/notes/implemented/architecture/2026-08-03-per-session-agent-presets.md
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
/**
|
|
* Package-owned invariant companion for `@deepseek-ai/dsh-agent-presets`.
|
|
* @module @deepseek-ai/dsh-agent-presets/invariant
|
|
*/
|
|
|
|
import type { Context } from 'cordis'
|
|
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
|
// Imported through the package name, not `./mount.ts`: a module shared between
|
|
// the two build entry points becomes a third chunk that the published `files`
|
|
// list does not carry, which `verify-built-package-invariants` rejects.
|
|
import { leakedServices, livePresetMounts } from '@deepseek-ai/dsh-agent-presets'
|
|
|
|
const PACKAGE_NAME = '@deepseek-ai/dsh-agent-presets'
|
|
|
|
/** Cordis companion plugin name. */
|
|
export const name = 'agent-presets-invariant'
|
|
/** Service required before the companion can reserve package ownership. */
|
|
export const inject = ['invariants']
|
|
|
|
/**
|
|
* Assert that no installed preset composition reaches the root service realm.
|
|
*
|
|
* `mountPreset` proves this once, when the subtree settles. A row that
|
|
* publishes later — from a timer, or an asynchronous continuation after its
|
|
* plugin returned — would escape that one-shot audit, so re-check every live
|
|
* mount whenever a service registration changes.
|
|
*/
|
|
const install: InvariantInstaller = (ctx, fail) => {
|
|
ctx.on('internal/service', function (this: Context, name) {
|
|
for (const mount of livePresetMounts()) {
|
|
const leaked = leakedServices(ctx, mount.fiber)
|
|
if (leaked.length === 0) continue
|
|
fail(
|
|
`preset "${mount.presetId}" published process-global service(s) [${leaked.join(', ')}] `
|
|
+ `after its mount was audited (observed while notifying "${name}") — `
|
|
+ 'a preset service must sit behind an `isolate` realm or move to the host composition',
|
|
)
|
|
}
|
|
}, { global: true })
|
|
}
|
|
|
|
/**
|
|
* Register this package's invariant companion.
|
|
* @param ctx - Cordis context carrying the invariant service.
|
|
* @returns the installed registration's disposer after setup succeeds.
|
|
*/
|
|
export const apply = (ctx: Context): Promise<() => void> =>
|
|
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|