mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-26 13:11:53 +08:00
60 lines
2.4 KiB
TypeScript
60 lines
2.4 KiB
TypeScript
import { browser } from 'wxt/browser';
|
|
import type { HandoffReason } from '@/types/models';
|
|
import type { CapabilityDomainHandler } from '../capability-context';
|
|
import { allowedTarget } from '../capability-context';
|
|
import { activateTab } from '@/platform/browser/targets';
|
|
import { getTab } from '@/platform/browser/targets';
|
|
import { getState, updateState } from '@/platform/storage/state';
|
|
import { setAgentRuntimeState } from '@/features/agent-runtime/service';
|
|
import { ExtensionError } from '@/shared/errors';
|
|
import { HANDOFF_CAPABILITY_DOMAIN } from '../capability-domains';
|
|
|
|
export const handoffCapabilityHandler: CapabilityDomainHandler = {
|
|
...HANDOFF_CAPABILITY_DOMAIN,
|
|
async handle({ method, input, grant }) {
|
|
if (method === 'browser.handoff.status') {
|
|
const handoff = (await getState()).handoff;
|
|
return handoff?.taskId === grant.taskId ? handoff : { state: 'idle' };
|
|
}
|
|
const resolvedTarget = await allowedTarget(grant, input);
|
|
const [tab, frame] = await Promise.all([
|
|
getTab(resolvedTarget.tabId),
|
|
browser.webNavigation.getFrame(resolvedTarget),
|
|
]);
|
|
if (!frame?.url || !/^https?:/i.test(frame.url)) {
|
|
throw new ExtensionError('target_unavailable', '目标 frame 不是可接管的 HTTP(S) 页面');
|
|
}
|
|
const grantTarget = {
|
|
...resolvedTarget,
|
|
isolationContextId: tab.isolationContextId || `browser-profile:tab-${tab.id}`,
|
|
cookieStoreId: tab.cookieStoreId,
|
|
origin: new URL(frame.url).origin,
|
|
grantedUrl: frame.url,
|
|
title: tab.title,
|
|
};
|
|
const now = Date.now();
|
|
const state = await updateState((current) => {
|
|
if (current.handoff?.state === 'waiting_for_user') {
|
|
throw new ExtensionError('handoff_in_progress', '已有人工接管请求正在等待处理');
|
|
}
|
|
return {
|
|
...current,
|
|
handoff: {
|
|
id: crypto.randomUUID(),
|
|
taskId: grant.taskId,
|
|
target: grantTarget,
|
|
reason: input.reason as HandoffReason,
|
|
message: typeof input.message === 'string' ? input.message : '',
|
|
state: 'waiting_for_user' as const,
|
|
requestedAt: now,
|
|
},
|
|
};
|
|
});
|
|
await activateTab(resolvedTarget.tabId);
|
|
await browser.action.setBadgeBackgroundColor({ color: '#ee7815' });
|
|
await browser.action.setBadgeText({ text: '待确认', tabId: resolvedTarget.tabId });
|
|
await setAgentRuntimeState('waiting_for_human', grant);
|
|
return state.handoff;
|
|
},
|
|
};
|