mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-06 06:41:56 +00:00
refactor: extract permission handler base class for code reuse
This commit is contained in:
@@ -7,7 +7,11 @@
|
||||
|
||||
import { logger } from "@/ui/logger";
|
||||
import { ApiSessionClient } from "@/api/apiSession";
|
||||
import { AgentState } from "@/api/types";
|
||||
import {
|
||||
BasePermissionHandler,
|
||||
type PendingPermissionRequest,
|
||||
type PermissionCompletion
|
||||
} from "@/modules/common/permission/BasePermissionHandler";
|
||||
|
||||
interface PermissionResponse {
|
||||
id: string;
|
||||
@@ -16,25 +20,15 @@ interface PermissionResponse {
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
interface PendingRequest {
|
||||
resolve: (value: PermissionResult) => void;
|
||||
reject: (error: Error) => void;
|
||||
toolName: string;
|
||||
input: unknown;
|
||||
}
|
||||
|
||||
interface PermissionResult {
|
||||
decision: 'approved' | 'approved_for_session' | 'denied' | 'abort';
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export class CodexPermissionHandler {
|
||||
private pendingRequests = new Map<string, PendingRequest>();
|
||||
private session: ApiSessionClient;
|
||||
export class CodexPermissionHandler extends BasePermissionHandler<PermissionResponse, PermissionResult> {
|
||||
|
||||
constructor(session: ApiSessionClient) {
|
||||
this.session = session;
|
||||
this.setupRpcHandler();
|
||||
super(session);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,12 +45,7 @@ export class CodexPermissionHandler {
|
||||
): Promise<PermissionResult> {
|
||||
return new Promise<PermissionResult>((resolve, reject) => {
|
||||
// Store the pending request
|
||||
this.pendingRequests.set(toolCallId, {
|
||||
resolve,
|
||||
reject,
|
||||
toolName,
|
||||
input
|
||||
});
|
||||
this.addPendingRequest(toolCallId, toolName, input, { resolve, reject });
|
||||
|
||||
// Send push notification
|
||||
// this.session.api.push().sendToAllDevices(
|
||||
@@ -70,117 +59,49 @@ export class CodexPermissionHandler {
|
||||
// }
|
||||
// );
|
||||
|
||||
// Update agent state with pending request
|
||||
this.session.updateAgentState((currentState) => ({
|
||||
...currentState,
|
||||
requests: {
|
||||
...currentState.requests,
|
||||
[toolCallId]: {
|
||||
tool: toolName,
|
||||
arguments: input,
|
||||
createdAt: Date.now()
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
logger.debug(`[Codex] Permission request sent for tool: ${toolName} (${toolCallId})`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup RPC handler for permission responses
|
||||
* Handle permission responses
|
||||
*/
|
||||
private setupRpcHandler(): void {
|
||||
this.session.rpcHandlerManager.registerHandler<PermissionResponse, void>(
|
||||
'permission',
|
||||
async (response) => {
|
||||
// console.log(`[Codex] Permission response received:`, response);
|
||||
|
||||
const pending = this.pendingRequests.get(response.id);
|
||||
if (!pending) {
|
||||
logger.debug('[Codex] Permission request not found or already resolved');
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from pending
|
||||
this.pendingRequests.delete(response.id);
|
||||
|
||||
// Resolve the permission request
|
||||
const reason = typeof response.reason === 'string' ? response.reason : undefined;
|
||||
const result: PermissionResult = response.approved
|
||||
? {
|
||||
decision: response.decision === 'approved_for_session' ? 'approved_for_session' : 'approved',
|
||||
reason
|
||||
}
|
||||
: {
|
||||
decision: response.decision === 'denied' ? 'denied' : 'abort',
|
||||
reason
|
||||
};
|
||||
|
||||
pending.resolve(result);
|
||||
|
||||
// Move request to completed in agent state
|
||||
this.session.updateAgentState((currentState) => {
|
||||
const request = currentState.requests?.[response.id];
|
||||
if (!request) return currentState;
|
||||
|
||||
// console.log(`[Codex] Permission ${response.approved ? 'approved' : 'denied'} for ${pending.toolName}`);
|
||||
|
||||
const { [response.id]: _, ...remainingRequests } = currentState.requests || {};
|
||||
|
||||
let res = {
|
||||
...currentState,
|
||||
requests: remainingRequests,
|
||||
completedRequests: {
|
||||
...currentState.completedRequests,
|
||||
[response.id]: {
|
||||
...request,
|
||||
completedAt: Date.now(),
|
||||
status: response.approved ? 'approved' : 'denied',
|
||||
decision: result.decision,
|
||||
reason: result.reason
|
||||
}
|
||||
}
|
||||
} satisfies AgentState;
|
||||
// console.log(`[Codex] Updated agent state:`, res);
|
||||
return res;
|
||||
});
|
||||
|
||||
logger.debug(`[Codex] Permission ${response.approved ? 'approved' : 'denied'} for ${pending.toolName}`);
|
||||
protected handlePermissionResponse(
|
||||
response: PermissionResponse,
|
||||
pending: PendingPermissionRequest<PermissionResult>
|
||||
): PermissionCompletion {
|
||||
const reason = typeof response.reason === 'string' ? response.reason : undefined;
|
||||
const result: PermissionResult = response.approved
|
||||
? {
|
||||
decision: response.decision === 'approved_for_session' ? 'approved_for_session' : 'approved',
|
||||
reason
|
||||
}
|
||||
);
|
||||
: {
|
||||
decision: response.decision === 'denied' ? 'denied' : 'abort',
|
||||
reason
|
||||
};
|
||||
|
||||
pending.resolve(result);
|
||||
logger.debug(`[Codex] Permission ${response.approved ? 'approved' : 'denied'} for ${pending.toolName}`);
|
||||
|
||||
return {
|
||||
status: response.approved ? 'approved' : 'denied',
|
||||
decision: result.decision,
|
||||
reason: result.reason
|
||||
};
|
||||
}
|
||||
|
||||
protected handleMissingPendingResponse(_response: PermissionResponse): void {
|
||||
logger.debug('[Codex] Permission request not found or already resolved');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset state for new sessions
|
||||
*/
|
||||
reset(): void {
|
||||
// Reject all pending requests
|
||||
for (const [id, pending] of this.pendingRequests.entries()) {
|
||||
pending.reject(new Error('Session reset'));
|
||||
}
|
||||
this.pendingRequests.clear();
|
||||
|
||||
// Clear requests in agent state
|
||||
this.session.updateAgentState((currentState) => {
|
||||
const pendingRequests = currentState.requests || {};
|
||||
const completedRequests = { ...currentState.completedRequests };
|
||||
|
||||
// Move all pending to completed as canceled
|
||||
for (const [id, request] of Object.entries(pendingRequests)) {
|
||||
completedRequests[id] = {
|
||||
...request,
|
||||
completedAt: Date.now(),
|
||||
status: 'canceled',
|
||||
reason: 'Session reset'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...currentState,
|
||||
requests: {},
|
||||
completedRequests
|
||||
};
|
||||
this.cancelPendingRequests({
|
||||
completedReason: 'Session reset',
|
||||
rejectMessage: 'Session reset'
|
||||
});
|
||||
|
||||
logger.debug('[Codex] Permission handler reset');
|
||||
|
||||
Reference in New Issue
Block a user