Initial commit: omp-advisor DSH plugin (oh-my-pi port) with docs and tests
This commit is contained in:
commit
fccf5fc6d2
8 files changed
+340
No files matched your search
@@ -0,0 +1,84 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import * as plugin from '../index.js'
|
||||
|
||||
function harness(replies, config = {}) {
|
||||
const listeners = new Map()
|
||||
const on = (n, f) => { listeners.set(n, [...(listeners.get(n) ?? []), f]); return () => listeners.set(n, listeners.get(n).filter((x) => x !== f)) }
|
||||
const prompts = []
|
||||
const llm = {
|
||||
async *stream(opts) {
|
||||
prompts.push(opts)
|
||||
const r = replies.shift() ?? '{"verdict":"ok","message":""}'
|
||||
yield { type: 'text-delta', text: r }
|
||||
yield { type: 'finish', reason: { kind: 'stop' } }
|
||||
},
|
||||
}
|
||||
const events = []
|
||||
const session = {
|
||||
header: { cwd: '/w' },
|
||||
requestHeader: () => ({ config: { provider: 'omni', model: 'main-model' } }),
|
||||
surface: { get nodes() { return events.map((_, i) => i) } },
|
||||
eventAt: (i) => events[i],
|
||||
deriveEventMessage: (e) => e.msg,
|
||||
}
|
||||
const steered = []
|
||||
const agent = { session, ctx: { on }, steer: (m) => steered.push(m) }
|
||||
const ctx = { agents: { list: () => [] }, llm, on, effect() {} }
|
||||
plugin.apply(ctx, { minLevel: 'note', blocking: true, ...config })
|
||||
for (const f of listeners.get('agent/created') ?? []) f({ agent })
|
||||
const preStep = async (step) => {
|
||||
let out
|
||||
for (const f of listeners.get('agent/pre-step') ?? []) out = await f({ agent, messages: [], step, turn: 1 }, async () => ({ kind: 'enter', messages: [] }))
|
||||
return out
|
||||
}
|
||||
const stopTurn = async () => { for (const f of listeners.get('agent/turn-stopping') ?? []) await f({ agent, turn: 1 }) }
|
||||
const add = (role, content) => events.push({ msg: { role, content } })
|
||||
return { preStep, stopTurn, add, steered, prompts }
|
||||
}
|
||||
|
||||
test('parseVerdict', () => {
|
||||
assert.deepEqual(plugin.parseVerdict('x {"verdict":"Concern","message":"m"} y'), { verdict: 'concern', message: 'm' })
|
||||
assert.equal(plugin.parseVerdict('nope'), null)
|
||||
assert.equal(plugin.parseVerdict('{"verdict":"maybe"}'), null)
|
||||
})
|
||||
|
||||
test('a concern is injected into the next step as a system reminder', async () => {
|
||||
const h = harness(['{"verdict":"concern","message":"You deleted tests/ without asking."}'])
|
||||
h.add('user', [{ type: 'text', text: 'clean up the repo' }])
|
||||
h.add('assistant', [{ type: 'tool-call', name: 'bash', arguments: { command: 'rm -rf tests/' } }])
|
||||
h.add('tool', [{ type: 'text', text: '' }])
|
||||
const d = await h.preStep(2)
|
||||
assert.equal(d.kind, 'enter')
|
||||
const text = d.messages.at(-1).content[0].text
|
||||
assert.match(text, /Advisor concern\] You deleted tests\/ without asking/)
|
||||
assert.equal(h.prompts[0].model, 'main-model')
|
||||
assert.match(h.prompts[0].messages[0].content[0].text, /rm -rf tests/)
|
||||
})
|
||||
|
||||
test('ok verdicts inject nothing; first step is never reviewed', async () => {
|
||||
const h = harness(['{"verdict":"ok","message":""}'])
|
||||
h.add('user', [{ type: 'text', text: 'hi' }])
|
||||
assert.equal((await h.preStep(1)).messages.length, 0)
|
||||
assert.equal(h.prompts.length, 0)
|
||||
assert.equal((await h.preStep(2)).messages.length, 0)
|
||||
})
|
||||
|
||||
test('blocker at turn end steers the agent', async () => {
|
||||
const h = harness(['{"verdict":"blocker","message":"Do not push: tests are failing."}'], { blocking: false })
|
||||
h.add('user', [{ type: 'text', text: 'ship it' }])
|
||||
h.add('assistant', [{ type: 'tool-call', name: 'forge_push', arguments: {} }])
|
||||
await h.preStep(2) // review starts in background
|
||||
await new Promise((r) => setTimeout(r, 50))
|
||||
await h.stopTurn()
|
||||
assert.equal(h.steered.length, 1)
|
||||
assert.match(h.steered[0].content[0].text, /ADVISOR BLOCKER.*Do not push/s)
|
||||
})
|
||||
|
||||
test('minLevel filters notes and duplicates are suppressed', async () => {
|
||||
const h = harness(['{"verdict":"note","message":"tiny"}', '{"verdict":"concern","message":"same"}', '{"verdict":"concern","message":"same"}'], { minLevel: 'concern' })
|
||||
h.add('user', [{ type: 'text', text: 'x' }])
|
||||
assert.equal((await h.preStep(2)).messages.length, 0) // note < minLevel: dropped
|
||||
assert.equal((await h.preStep(3)).messages.length, 1) // concern (blocking review) delivered
|
||||
assert.equal((await h.preStep(4)).messages.length, 0) // identical concern suppressed
|
||||
})
|
||||
Reference in new issue
Block a user