v0.4.0: 工具与审批(业务工具骨架 + Approval Card)

This commit is contained in:
Rick Ye
2026-09-05 09:47:50 +08:00
parent fe70cb0f71
commit 807fab4f20
15 changed files with 472 additions and 16 deletions
+31 -8
View File
@@ -13,6 +13,8 @@ import {
type CreateAgentSessionRuntimeFactory,
type SessionInfo
} from '@earendil-works/pi-coding-agent'
import { ApprovalService, createApprovalExtension } from './approval'
import { demoTools, TOOLS_REQUIRING_APPROVAL } from '../tools/demo-tools'
import type {
AgentUiEvent,
AppSettings,
@@ -41,6 +43,7 @@ export class AgentService {
private attached: AgentSession | null = null
private unsubscribeAttached: (() => void) | null = null
private settings: AppSettings = { systemPrompt: '' }
readonly approvals = new ApprovalService()
private get cwd(): string {
return app.getPath('home')
@@ -74,6 +77,11 @@ export class AgentService {
return () => this.listeners.delete(fn)
}
/** 供 IPC 层主动广播事件(如审批结果同步到所有窗口) */
broadcastEvent(event: AgentUiEvent): void {
this.emit(event)
}
private emit(event: AgentUiEvent): void {
for (const fn of this.listeners) {
try {
@@ -110,13 +118,23 @@ export class AgentService {
const cwd = this.cwd
const agentDir = getAgentDir()
this.settings = this.loadSettings()
const initialServices = await createAgentSessionServices({
cwd,
agentDir,
resourceLoaderOptions: this.settings.systemPrompt.trim()
? { systemPrompt: this.settings.systemPrompt }
: undefined
// 审批拦截:TOOLS_REQUIRING_APPROVAL 名单内的工具调用需经渲染层 Approval Card 确认
this.approvals.onRequest((request) => {
this.emit({ type: 'approval_request', request })
})
this.approvals.onSettle((id, approved, timedOut) => {
this.emit({ type: 'approval_settled', id, approved, timedOut })
})
const buildServices = (targetCwd: string, targetAgentDir: string) =>
createAgentSessionServices({
cwd: targetCwd,
agentDir: targetAgentDir,
resourceLoaderOptions: {
...(this.settings.systemPrompt.trim() ? { systemPrompt: this.settings.systemPrompt } : {}),
extensionFactories: [createApprovalExtension(this.approvals, TOOLS_REQUIRING_APPROVAL)]
}
})
const initialServices = await buildServices(cwd, agentDir)
// 每次切换/新建时由 runtime 调用;cwd 变化时重建服务,否则复用
const factory: CreateAgentSessionRuntimeFactory = async ({
@@ -128,8 +146,13 @@ export class AgentService {
const services =
nextCwd === initialServices.cwd && nextAgentDir === initialServices.agentDir
? initialServices
: await createAgentSessionServices({ cwd: nextCwd, agentDir: nextAgentDir })
const result = await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })
: await buildServices(nextCwd, nextAgentDir)
const result = await createAgentSessionFromServices({
services,
sessionManager,
sessionStartEvent,
customTools: demoTools
})
return { ...result, services, diagnostics: services.diagnostics }
}