cordis-plugin-sofagent-inject
启动注入企业约束——四层加载链(seam: agent/pre-step)——桥接 @sofagent/harness buildConstrainedSystemPrompt——DSH(DeepSeek Harness)cordis plugin。sofagent 约束层在 DeepSeek Harness 生态的插件形态。
Install
npx skills add https://github.com/KongFangXun/sofagent/tree/main/engine/dsh-plugins/cordis-plugin-sofagent-inject
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kongfangxun-sofagent@llmmart
git clone https://github.com/KongFangXun/sofagent.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole kongfangxun/sofagent collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
cordis-plugin-sofagent-inject
启动注入企业约束——四层加载链(seam: agent/pre-step)——桥接 @sofagent/inject buildConstrainedSystemPrompt
用途
装上之后:模型每次请求前带上企业铁律 / 反思 / 用户规则 / 知识库(四层加载链)。什么时候用:希望 Agent 一开口就带着公司的规矩,不必每次交代背景。
接入点(seam: agent/pre-step):桥接 @sofagent/inject,缺依赖时该能力静默跳过;接入形态(声明 / 实现)见 SEAMS.md。
本插件随 sofagent 主线版本发布(SkillHub 通道:skillhub install cordis-plugin-sofagent-inject 安装与检索;npm 通道未开通)。版本号与 sofagent 主线对齐。
相关链接
- sofagent 主仓:https://github.com/KongFangXun/sofagent
- 开发日志:docs/changelog/v1.4/v1.4.0.md(DSH 插件家族)
Files (sofagent)
-
src
-
index.test.ts 9 KB
// ============================================================ // cordis-plugin-inject · 插件单测(v1.4.0 交付五 · v1.5.0 章十补接线面) // ============================================================ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import pluginDefault, { pluginMeta, capability, invoke } from './index'; import { buildConstrainedSystemPrompt } from '@sofagent/inject'; import { createUserMessage } from '@deepseek-ai/dsh-llm'; // 章十:接线面断言需要可控的判定源与消息工厂——两条桥接面都打桩成确定性替身 // (真依赖是否装在当前环境与接线正确性无关;打桩后能对**透传参数**做逐字断言)。 vi.mock('@sofagent/inject', () => ({ buildConstrainedSystemPrompt: vi.fn(() => 'CONSTRAINT-PROMPT'), })); vi.mock('@deepseek-ai/dsh-llm', () => ({ createUserMessage: vi.fn((input: Record<string, unknown>) => ({ __fakeUserMessage: true, ...input })), })); describe('cordis-plugin-sofagent-inject', () => { it('插件元数据完整(id/version/description/seam)', () => { expect(pluginMeta.id).toBe('cordis-plugin-sofagent-inject'); expect(pluginMeta.version).toBe(require('../package.json').version); // SSOT 对齐:版本跟随主版本(读 package.json) expect(pluginMeta.description.length).toBeGreaterThan(10); expect(pluginMeta.seam.length).toBeGreaterThan(0); }); it('能力说明非空', () => { expect(capability.length).toBeGreaterThan(0); }); it('invoke 可调用(成功或降级,不挂死)', async () => { const r = await invoke().catch((e) => e); expect(r).toBeDefined(); }); }); // ───────────────────────────────────────────────────────────────────────────── // v1.5.0 章十 · seam 事件接线(seam 从声明到实现) // 断言面:① 订阅真实存在(ctx.on 的调用形态与事件名)② disposer 收进复合卸载契约 // ③ Turn 首步**真注入**(判定源 = @sofagent/inject.buildConstrainedSystemPrompt) // ④ 非首步 / reject / 判定源缺席 / 空文本 → 原样返回(fail-open,绝不误改本步输入) // ───────────────────────────────────────────────────────────────────────────── describe('章十 · seam 事件接线', () => { const MANIFEST = require('../../plugins.json') as { plugins: Array<{ id: string; seamHandlers?: string[] }>; }; const declared: string[] = MANIFEST.plugins.find((p) => p.id === 'cordis-plugin-sofagent-inject')?.seamHandlers ?? []; const ONE = ['agent/pre-step']; const errSpy = () => vi.spyOn(console, 'error').mockImplementation(() => {}); beforeEach(() => { vi.clearAllMocks(); vi.mocked(buildConstrainedSystemPrompt).mockImplementation(() => 'CONSTRAINT-PROMPT'); vi.mocked(createUserMessage).mockImplementation((input: Record<string, unknown>) => ({ __fakeUserMessage: true, ...input, })); }); afterEach(() => { vi.restoreAllMocks(); }); /** 宿主 ctx 替身:记录订阅名 + 保留 disposer(对齐 cordis `ctx.on(event, h) → disposer`) */ function hostCtx() { const subscribed = new Map<string, (...a: unknown[]) => unknown>(); const disposed: string[] = []; const on = vi.fn((event: string, handler: (...a: unknown[]) => unknown) => { subscribed.set(event, handler); return () => { disposed.push(event); }; }); return { ctx: { provide: vi.fn(() => () => undefined), on }, subscribed, disposed }; } /** 宿主 pre-step 载荷替身:`{ messages, turn, step, signal }`(waterfall listener 收 `(payload, next)`) */ function preStepPayload(step: number, cwd?: string) { return { messages: [{ role: 'user', content: [{ type: 'text', text: 'hi' }] }], turn: 1, step, signal: undefined, agent: cwd === undefined ? undefined : { session: { header: { cwd } } }, }; } it('seamHandlers 与 plugins.json 声明同集合(三处对账的插件侧)', () => { expect(declared.slice().sort()).toEqual([...ONE].sort()); }); it('apply 经 ctx.on 订阅 agent/pre-step;复合 disposer 逐个反注册', async () => { const spy = errSpy(); const { ctx, subscribed, disposed } = hostCtx(); const disposer = (pluginDefault.apply as (c: unknown) => unknown)(ctx) as | (() => Promise<void>) | undefined; expect([...subscribed.keys()].sort()).toEqual([...ONE].sort()); expect(typeof disposer).toBe('function'); await disposer!(); expect(disposed.slice().sort()).toEqual([...ONE].sort()); spy.mockRestore(); }); it('step === 1:注入一条约束消息(判定源 + 宿主消息工厂,宿主参数原样在前)', async () => { const spy = errSpy(); const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const hostDecision = { kind: 'enter', messages: [{ host: true }] }; const next = vi.fn(async () => hostDecision); const verdict = (await subscribed.get('agent/pre-step')!( preStepPayload(1, '/proj/root'), next, )) as { kind: string; messages: unknown[] }; expect(next).toHaveBeenCalledTimes(1); // 先取宿主默认决策,再在其上追加 expect(buildConstrainedSystemPrompt).toHaveBeenCalledWith('/proj/root'); // cwd 优先透传 expect(createUserMessage).toHaveBeenCalledWith({ content: [{ type: 'text', text: 'CONSTRAINT-PROMPT' }], source: { kind: 'plugin', plugin: 'sofagent-inject' }, }); expect(verdict.kind).toBe('enter'); // 宿主的 kind 保留 expect(verdict.messages).toHaveLength(2); expect(verdict.messages[0]).toEqual({ host: true }); // 宿主消息在前,注入消息追加在后 expect(verdict.messages[1]).toMatchObject({ __fakeUserMessage: true }); spy.mockRestore(); }); it('step !== 1:原样返回宿主决策(约束是常驻上下位,不逐步重复注入)', async () => { const spy = errSpy(); const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const hostDecision = { kind: 'enter', messages: [{ host: true }] }; const next = vi.fn(async () => hostDecision); const verdict = await subscribed.get('agent/pre-step')!(preStepPayload(2), next); expect(verdict).toBe(hostDecision); // 同一对象原样返回 expect(buildConstrainedSystemPrompt).not.toHaveBeenCalled(); expect(createUserMessage).not.toHaveBeenCalled(); spy.mockRestore(); }); it("kind === 'reject':原样返回,不做任何注入", async () => { const spy = errSpy(); const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const hostDecision = { kind: 'reject', messages: [] }; const next = vi.fn(async () => hostDecision); const verdict = await subscribed.get('agent/pre-step')!(preStepPayload(1), next); expect(verdict).toBe(hostDecision); expect(createUserMessage).not.toHaveBeenCalled(); spy.mockRestore(); }); it('判定源缺席(buildConstrainedSystemPrompt 抛错):原样返回宿主决策(fail-open)', async () => { const spy = errSpy(); vi.mocked(buildConstrainedSystemPrompt).mockImplementation(() => { throw new Error('约束源不可达'); }); const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const hostDecision = { kind: 'enter', messages: [{ host: true }] }; const next = vi.fn(async () => hostDecision); await expect( subscribed.get('agent/pre-step')!(preStepPayload(1), next), ).resolves.toBe(hostDecision); expect(createUserMessage).not.toHaveBeenCalled(); spy.mockRestore(); }); it('约束文本为空:不注入空消息(不污染本步输入)', async () => { const spy = errSpy(); vi.mocked(buildConstrainedSystemPrompt).mockImplementation(() => ' '); const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const hostDecision = { kind: 'enter', messages: [{ host: true }] }; const next = vi.fn(async () => hostDecision); await expect( subscribed.get('agent/pre-step')!(preStepPayload(1), next), ).resolves.toBe(hostDecision); expect(createUserMessage).not.toHaveBeenCalled(); spy.mockRestore(); }); it('项目根缺 session 面:回落到 SOFAGENT_PROJECT_ROOT(与 CLI/MCP 同口径)', async () => { const spy = errSpy(); process.env.SOFAGENT_PROJECT_ROOT = '/env/root'; const { ctx, subscribed } = hostCtx(); (pluginDefault.apply as (c: unknown) => unknown)(ctx); const next = vi.fn(async () => ({ kind: 'enter', messages: [] })); await subscribed.get('agent/pre-step')!(preStepPayload(1), next); expect(buildConstrainedSystemPrompt).toHaveBeenCalledWith('/env/root'); delete process.env.SOFAGENT_PROJECT_ROOT; spy.mockRestore(); }); }); -
index.ts 5 KB
// cordis-plugin-sofagent-inject · DSH 反向插件(v1.5.2:98 行样板收敛到 @sofagent/dsh-plugin-kit) // seam 挂载:agent/pre-step # 语义:模型看到输入前注入四层加载链约束(Turn 首步一条消息) // 清单生成源 = engine/dsh-plugins/plugins.json(生成 package.json 的 description/sofagent/dsh 段与 cordis.patch.yml);本文件的 seam 字面量由生成器 --check 与之对账。 import { createSofagentPlugin, seamHelpers, type SeamHandler, type SeamHelpers, } from '@sofagent/dsh-plugin-kit'; /** 一次性日志表(接线自证 / 降级提示只打一次) */ const logged = new Set<string>(); function logOnce(helpers: SeamHelpers, key: string, message: string): void { if (logged.has(key)) return; logged.add(key); helpers.log(message); } const errMsg = (err: unknown): string => (err instanceof Error ? err.message : String(err)); /** 项目根:宿主 session 的 cwd 优先(对齐宿主同类 listener 的取法),缺省进程工作目录 */ function projectRootOf(payload: unknown): string { const agent = (payload as { agent?: unknown } | null | undefined)?.agent as | { session?: { header?: { cwd?: unknown } } } | undefined; const cwd = agent?.session?.header?.cwd; if (typeof cwd === 'string' && cwd !== '') return cwd; return process.env.SOFAGENT_PROJECT_ROOT ?? process.cwd(); } /** * seam 事件处理器(v1.5.0 章十)——`agent/pre-step` 的**实现**(此前只有声明)。 * * 宿主契约(`dsh-agent-loop.preStep`):waterfall 派发,listener 约定 * `(payload, next)`,payload = `{ messages, turn, step, signal }`;`next()` 给出 * 宿主默认决策 `{ kind, messages }`,返回一个改过的决策即可改变本步交给模型的输入。 * * 🔴 判定逻辑零改动:约束文本来自既有 `@sofagent/inject.buildConstrainedSystemPrompt`, * 插件只负责把它作为一条消息挂进本步输入。 * 🔴 只在 Turn 首个 step 注入(对齐宿主同类 listener 的 `step === 1` 判据)—— * 约束是常驻上下位,逐步重复注入只会白烧 token。 * 🔴 失败一律 fail-open:约束源 / 消息工厂任一不可用即原样返回宿主决策。 */ const seamHandlers: Record<string, SeamHandler> = { 'agent/pre-step': async (...args: unknown[]) => { const helpers = seamHelpers(args); const [payload, next] = args; const decision = (typeof next === 'function' ? await (next as () => Promise<unknown>)() : undefined) as | { kind?: unknown; messages?: unknown } | undefined; if (decision === undefined || decision.kind === 'reject') return decision; const step = (payload as { step?: unknown } | null | undefined)?.step; if (step !== 1) return decision; if (!Array.isArray(decision.messages)) return decision; let text: unknown; try { text = await helpers.call( '@sofagent/inject', 'buildConstrainedSystemPrompt', projectRootOf(payload), ); } catch (err) { logOnce(helpers, 'pre-step-unavailable', `约束注入不可用(本次不注入):${errMsg(err)}`); return decision; } if (typeof text !== 'string' || text.trim() === '') return decision; try { // 消息构造走宿主自己的工厂(`@deepseek-ai/dsh-llm`)而非手搓形状—— // 插件保持零静态宿主 import,宿主面一律经 helpers.call 动态取。 const message = await helpers.call('@deepseek-ai/dsh-llm', 'createUserMessage', { content: [{ type: 'text', text }], source: { kind: 'plugin', plugin: 'sofagent-inject' }, }); logOnce(helpers, 'pre-step-injected', '四层加载链约束已在 Turn 首步注入(agent/pre-step)'); return { ...decision, messages: [...decision.messages, message] }; } catch (err) { logOnce(helpers, 'pre-step-message-failed', `约束消息构造失败(本次不注入):${errMsg(err)}`); return decision; } }, }; /** 插件声明(本文件唯一手写处;适配层红线由 kit 承担:ctx 鸭子类型 + 宿主 API 缺席降级不抛) */ const kit = createSofagentPlugin( { id: 'cordis-plugin-sofagent-inject', seam: 'agent/pre-step', seamSemantics: '模型看到输入前注入四层加载链约束(Turn 首步一条消息,判定源 = buildConstrainedSystemPrompt)', capability: '约束注入链(SKILL→fde→think→knowledge)', bridgePkg: '@sofagent/inject', bridgeApi: 'buildConstrainedSystemPrompt', description: '启动注入企业约束——四层加载链', seamHandlers, }, require('../package.json') as { version?: string }, ); export const pluginMeta = kit.pluginMeta; // 插件元数据(DSH profile/注册表消费) export const capability = kit.capability; // 依赖的 sofagent 能力说明(DSH skill 引导链展示) export const invoke = kit.invoke; // 桥接 @sofagent/* 公共 API(懒加载 + 降级不抛) export default kit.plugin; // DSH Cordis 插件契约(apply 三段式由 kit 提供)
-
-
cordis.patch.yml 611 B
# sofagent cordis-plugin-sofagent-inject bundle patch v1.5.2——注册为 DSH profile layer - insert: - id: sofagent-inject name: 'cordis-plugin-sofagent-inject' inject: [settings, dynamicCordisRunner] config: seam: "agent/pre-step" # 语义:模型看到输入前注入四层加载链约束(Turn 首步一条消息,判定源 = buildConstrainedSystemPrompt) description: "给宿主加上约束注入——每次请求模型前带上企业铁律 / 反思 / 用户规则 / 知识库(四层加载链)——桥接 @sofagent/inject buildConstrainedSystemPrompt" -
package.json 1.6 KB
{ "name": "cordis-plugin-sofagent-inject", "version": "1.5.2", "engines": { "node": ">=18" }, "description": "给宿主加上约束注入——每次请求模型前带上企业铁律 / 反思 / 用户规则 / 知识库(四层加载链)(seam: agent/pre-step)——桥接 @sofagent/inject buildConstrainedSystemPrompt", "license": "MIT", "author": "KongFangXun", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "test": "vitest run src/index.test.ts" }, "keywords": [ "sofagent", "dsh", "cordis-plugin" ], "sofagent": { "type": "dsh-plugin", "family": "cordis", "seam": "agent/pre-step", "seamSemantics": "模型看到输入前注入四层加载链约束(Turn 首步一条消息,判定源 = buildConstrainedSystemPrompt)", "seamHandlers": [ "agent/pre-step" ] }, "//optionalDependencies": "v1.4.5 T6 (R4):src/index.ts 惰性 await import(懒加载 + 缺依赖降级不抛;v1.4.8 起该样板由 @sofagent/dsh-plugin-kit 统一封装;v1.4.9 P2 起厚插件多包 bridges 按序解析、部分可用即部分成功),此前未声明任何依赖——对齐 root package.json F-18 optionalDependencies 先例。", "optionalDependencies": { "@sofagent/inject": "1.5.2" }, "devDependencies": { "typescript": "^7.0.2", "vitest": "^5.0.0" }, "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }, "files": [ "dist/", "cordis.patch.yml", "SKILL.md", "!dist/**/*.js.map", "!dist/**/*.d.ts.map", "!dist/**/*.test.*" ], "dependencies": { "@sofagent/dsh-plugin-kit": "1.5.2" } } -
SKILL.md 1.3 KB
--- name: cordis-plugin-sofagent-inject slug: cordis-plugin-sofagent-inject version: 1.5.2 displayName: cordis-plugin-sofagent-inject description: > 启动注入企业约束——四层加载链(seam: agent/pre-step)——桥接 @sofagent/inject buildConstrainedSystemPrompt——DSH(DeepSeek Harness)cordis plugin。sofagent 约束层在 DeepSeek Harness 生态的插件形态。 --- # cordis-plugin-sofagent-inject 启动注入企业约束——四层加载链(seam: agent/pre-step)——桥接 @sofagent/inject buildConstrainedSystemPrompt ## 用途 **装上之后**:模型每次请求前带上企业铁律 / 反思 / 用户规则 / 知识库(四层加载链)。**什么时候用**:希望 Agent 一开口就带着公司的规矩,不必每次交代背景。 **接入点**(seam: agent/pre-step):桥接 `@sofagent/inject`,缺依赖时该能力静默跳过;接入形态(声明 / 实现)见 [SEAMS.md](../SEAMS.md)。 本插件随 sofagent 主线版本发布(SkillHub 通道:`skillhub install cordis-plugin-sofagent-inject` 安装与检索;npm 通道未开通)。版本号与 sofagent 主线对齐。 ## 相关链接 - sofagent 主仓:https://github.com/KongFangXun/sofagent - 开发日志:docs/changelog/v1.4/v1.4.0.md(DSH 插件家族) -
tsconfig.json 185 B
{ "extends": "../tsconfig.base.json", "compilerOptions": { "rootDir": "src", "outDir": "dist" }, "include": [ "src" ], "exclude": [ "src/**/*.test.ts" ] }
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.