feat: add persistent desktop assistant workspace
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent
698a15ad14
commit
6ef1795b81
@@ -4,7 +4,7 @@ import type {
|
||||
AgentRequest,
|
||||
AgentRuntimeStatus
|
||||
} from '../../shared/contracts'
|
||||
import type { AgentRuntime } from './runtime'
|
||||
import type { AgentRuntime, RuntimeAuthorizer } from './runtime'
|
||||
import { AgentRuntimeController } from './runtime-controller'
|
||||
|
||||
class TestRuntime implements AgentRuntime {
|
||||
@@ -15,7 +15,8 @@ class TestRuntime implements AgentRuntime {
|
||||
|
||||
constructor(
|
||||
private readonly delayed = false,
|
||||
readonly requiresToolApproval = false
|
||||
readonly requiresToolApproval = false,
|
||||
private readonly invokeToolAuthorization = false
|
||||
) {
|
||||
this.started = new Promise((resolve) => {
|
||||
this.markStarted = resolve
|
||||
@@ -24,7 +25,7 @@ class TestRuntime implements AgentRuntime {
|
||||
|
||||
getStatus(): Promise<AgentRuntimeStatus> {
|
||||
return Promise.resolve({
|
||||
id: 'demo',
|
||||
id: 'model',
|
||||
label: 'Test',
|
||||
available: true,
|
||||
detail: 'Test runtime'
|
||||
@@ -32,9 +33,21 @@ class TestRuntime implements AgentRuntime {
|
||||
}
|
||||
|
||||
async *run(
|
||||
request: AgentRequest
|
||||
request: AgentRequest,
|
||||
_signal: AbortSignal,
|
||||
authorize?: RuntimeAuthorizer
|
||||
): AsyncGenerator<AgentEvent, void, void> {
|
||||
this.markStarted()
|
||||
if (this.invokeToolAuthorization && authorize) {
|
||||
const decision = await authorize({
|
||||
scopeKey: 'test:tool',
|
||||
title: 'Test tool',
|
||||
description: 'Test tool request'
|
||||
})
|
||||
if (decision === 'deny') {
|
||||
throw new Error('tool denied')
|
||||
}
|
||||
}
|
||||
if (this.delayed) {
|
||||
await new Promise<void>((resolve) => {
|
||||
this.release = resolve
|
||||
@@ -57,19 +70,24 @@ describe('AgentRuntimeController', () => {
|
||||
const previous = new TestRuntime(true, true)
|
||||
const next = new TestRuntime()
|
||||
const controller = new AgentRuntimeController(previous)
|
||||
const authorize = vi.fn(async () => {})
|
||||
const authorize = vi.fn(async () => 'once' as const)
|
||||
const approvedStream = controller.run(
|
||||
{
|
||||
requestId: '1c608898-ecb7-4081-8174-2b6a52f53b08',
|
||||
conversationId: 'conversation-2',
|
||||
prompt: 'test'
|
||||
prompt: 'test',
|
||||
workMode: 'execute'
|
||||
},
|
||||
new AbortController().signal,
|
||||
authorize
|
||||
)
|
||||
const pendingEvent = approvedStream.next()
|
||||
await previous.started
|
||||
expect(authorize).toHaveBeenCalledWith(true)
|
||||
expect(authorize).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
scopeKey: 'runtime:whole-run'
|
||||
})
|
||||
)
|
||||
|
||||
const replacement = controller.replace(next)
|
||||
previous.finish()
|
||||
@@ -81,4 +99,26 @@ describe('AgentRuntimeController', () => {
|
||||
label: 'Test'
|
||||
})
|
||||
})
|
||||
|
||||
it.each(['ask', 'plan'] as const)(
|
||||
'denies tool authorization in %s mode without prompting the user',
|
||||
async (workMode) => {
|
||||
const runtime = new TestRuntime(false, false, true)
|
||||
const controller = new AgentRuntimeController(runtime)
|
||||
const authorize = vi.fn(async () => 'once' as const)
|
||||
const stream = controller.run(
|
||||
{
|
||||
requestId: '1c608898-ecb7-4081-8174-2b6a52f53b09',
|
||||
conversationId: 'conversation-3',
|
||||
prompt: 'test',
|
||||
workMode
|
||||
},
|
||||
new AbortController().signal,
|
||||
authorize
|
||||
)
|
||||
|
||||
await expect(stream.next()).rejects.toThrow('tool denied')
|
||||
expect(authorize).not.toHaveBeenCalled()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user