fix(user-questions): bridge scoped request events

This commit is contained in:
imccyu
2026-08-23 16:16:03 +08:00
parent 016be7d533
commit 9eb3747ffc
3 changed files with 32 additions and 4 deletions
@@ -34,6 +34,7 @@ const scopedSubjectResolvers: Readonly<Record<string, ScopedSubjectResolver | nu
'tools/post-execute': args => (args[0] as Record<string, unknown>)['agent'],
'tools/pre-execute': args => (args[0] as Record<string, unknown>)['agent'],
'tools/result': args => (args[0] as Record<string, unknown>)['agent'],
'user-questions/request': args => (args[0] as Record<string, unknown>)['agent'],
})
/**
@@ -10,6 +10,7 @@
import { Context, Service } from '@deepseek-ai/cordis'
import type { Agent } from '@deepseek-ai/dsh-agent'
import { HarnessError } from '@deepseek-ai/dsh-llm'
import { scopeTarget } from '@deepseek-ai/dsh-scope'
declare module '@deepseek-ai/cordis' {
interface Context {
@@ -144,11 +145,18 @@ export class UserQuestionService extends Service {
'BAD_INTENT')
}
}
if (this.provider === undefined) {
throw new UserQuestionError('no user-questions provider is registered', 'NO_PROVIDER')
}
const askProvider = () => this.provider === undefined
? Promise.reject(new UserQuestionError('no user-questions provider is registered', 'NO_PROVIDER'))
: this.provider.ask(request)
try {
return await this.provider.ask(request)
return await (agent === undefined
? askProvider()
: this.ctx.waterfall(
scopeTarget(agent, agent),
'user-questions/request',
{ ...request, agent },
askProvider,
))
} catch (error) {
if (request.signal?.aborted && !(error instanceof UserQuestionError)) {
throw abortedQuestion(error)
@@ -171,6 +171,25 @@ describe('UserQuestionService', () => {
expect(result).toEqual({ answers: [{ id: 'confirm', selected: ['yes'] }] })
})
it('offers an Agent-scoped waterfall before the provider fallback', async () => {
const ctx = new Context()
await ctx.plugin(AgentRegistry)
await ctx.plugin(UserQuestionService)
const p = provider('fallback')
ctx.userQuestions.registerProvider(p)
const agent = stubAgent('root')
ctx.agents.enter(agent, undefined)
ctx.on('user-questions/request', request => Promise.resolve({
answers: request.questions.map(question => ({ id: question.id, selected: ['remote'] })),
}))
await expect(ctx.userQuestions.ask({
questions: [{ id: 'confirm', question: 'Proceed?' }],
agent,
})).resolves.toEqual({ answers: [{ id: 'confirm', selected: ['remote'] }] })
expect(p.seen).toEqual([])
})
it('rejects a supplied agent when no live registry can attest it', async () => {
const ctx = new Context()
await ctx.plugin(UserQuestionService)