mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-10-16 15:34:08 +08:00
fix: avoid stale oem routing metadata
This commit is contained in:
@@ -112,10 +112,11 @@ function printSummary(changedFiles, tasks) {
|
||||
|
||||
if (tasks.docsOnly) {
|
||||
console.log("[local-ci] 当前仅检测到文档改动,跳过本地代码校验。");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[local-ci] 计划执行:");
|
||||
if (!tasks.docsOnly) {
|
||||
console.log("[local-ci] 计划执行:");
|
||||
}
|
||||
if (tasks.integrity) {
|
||||
console.log("[local-ci] - 一致性校验");
|
||||
}
|
||||
|
||||
@@ -78,6 +78,22 @@ const I18N_PATCH_RETIREMENT_RECOMMENDED_COMMANDS = [
|
||||
"npm run i18n:patch-retirement-gate -- --check",
|
||||
];
|
||||
|
||||
const I18N_RELEASE_DOCS_WORKFLOW_RECOMMENDED_COMMANDS = [
|
||||
"npm run i18n:release-docs-report:json -- --output docs/roadmap/i18n/evidence/release-docs-workflow-inventory.json",
|
||||
];
|
||||
|
||||
const I18N_APP_METADATA_WORKFLOW_RECOMMENDED_COMMANDS = [
|
||||
"npm run i18n:app-metadata-report:json -- --output docs/roadmap/i18n/evidence/app-metadata-workflow-inventory.json",
|
||||
];
|
||||
|
||||
const I18N_RTL_READINESS_RECOMMENDED_COMMANDS = [
|
||||
"npm run i18n:rtl-readiness-report:json -- --output docs/roadmap/i18n/evidence/rtl-readiness-inventory.json",
|
||||
];
|
||||
|
||||
const I18N_RTL_SMOKE_RECOMMENDED_COMMANDS = [
|
||||
"npm run i18n:rtl-smoke",
|
||||
];
|
||||
|
||||
const I18N_PATCH_RETIREMENT_FILES = new Set([
|
||||
"scripts/i18n-patch-metrics-report.mjs",
|
||||
"scripts/i18n-patch-retirement-gate.mjs",
|
||||
@@ -87,6 +103,91 @@ const I18N_PATCH_RETIREMENT_FILES = new Set([
|
||||
"scripts/verify-gui-smoke.mjs",
|
||||
]);
|
||||
|
||||
const I18N_RELEASE_DOCS_WORKFLOW_FILES = new Set([
|
||||
"README.md",
|
||||
"README.en.md",
|
||||
"RELEASE_NOTES.md",
|
||||
"RELEASE_NOTES.en.md",
|
||||
"docs/README.md",
|
||||
"docs/nuxt.config.ts",
|
||||
"docs/package.json",
|
||||
"docs/roadmap/i18n/evidence/release-docs-workflow-inventory.json",
|
||||
"docs/roadmap/i18n/release-docs-workflow-evaluation.md",
|
||||
"scripts/i18n-release-docs-workflow-report.test.ts",
|
||||
"scripts/i18n-release-docs-workflow-report.ts",
|
||||
]);
|
||||
|
||||
const I18N_RELEASE_DOCS_WORKFLOW_PREFIXES = [
|
||||
"docs/bussniss/",
|
||||
"docs/content/",
|
||||
"docs/develop/",
|
||||
"docs/oem/",
|
||||
];
|
||||
|
||||
const I18N_APP_METADATA_WORKFLOW_FILES = new Set([
|
||||
"docs/roadmap/i18n/app-metadata-workflow-evaluation.md",
|
||||
"docs/roadmap/i18n/evidence/app-metadata-workflow-inventory.json",
|
||||
"package.json",
|
||||
"scripts/i18n-app-metadata-workflow-report.test.ts",
|
||||
"scripts/i18n-app-metadata-workflow-report.ts",
|
||||
"src-tauri/Cargo.toml",
|
||||
"src-tauri/capabilities/agent-app-shell.json",
|
||||
"src-tauri/tauri.conf.headless.json",
|
||||
"src-tauri/tauri.conf.json",
|
||||
]);
|
||||
|
||||
const I18N_RTL_READINESS_FILES = new Set([
|
||||
"docs/roadmap/i18n/evidence/rtl-readiness-inventory.json",
|
||||
"docs/roadmap/i18n/rtl-readiness-evaluation.md",
|
||||
"scripts/i18n-rtl-readiness-report.test.ts",
|
||||
"scripts/i18n-rtl-readiness-report.ts",
|
||||
"src/i18n/createI18n.ts",
|
||||
"src/i18n/locales.ts",
|
||||
]);
|
||||
|
||||
const I18N_RTL_SMOKE_FILES = new Set([
|
||||
"scripts/i18n-rtl-playwright-smoke.mjs",
|
||||
]);
|
||||
|
||||
const I18N_RTL_SURFACE_FILES = new Set([
|
||||
"src/App.tsx",
|
||||
"src/components/AppSidebar.tsx",
|
||||
"src/components/Modal.tsx",
|
||||
"src/components/agent/chat/components/team-workspace-board/TeamWorkspaceBoardHeader.tsx",
|
||||
"src/components/agent/chat/components/team-workspace-board/TeamWorkspaceBoardShell.tsx",
|
||||
"src/components/agent/chat/components/team-workspace-board/TeamWorkspaceCanvasLaneCard.tsx",
|
||||
"src/components/agent/chat/components/team-workspace-board/TeamWorkspaceCanvasStage.tsx",
|
||||
"src/components/agent/chat/components/team-workspace-board/TeamWorkspaceCanvasToolbar.tsx",
|
||||
"src/components/agent/chat/workspace/WorkspaceConversationScene.tsx",
|
||||
"src/components/agent/chat/workspace/WorkspaceGeneralWorkbenchSidebar.tsx",
|
||||
"src/components/agent/chat/workspace/WorkspaceHarnessDialogs.tsx",
|
||||
"src/components/agent/chat/workspace/WorkspaceMainArea.tsx",
|
||||
"src/components/agent/chat/workspace/WorkspaceShellScene.tsx",
|
||||
"src/components/api-key-provider/ImportExportDialog.tsx",
|
||||
"src/components/app-sidebar/AppSidebarConversationShelf.tsx",
|
||||
"src/components/channels/ImConfigPage.tsx",
|
||||
"src/components/connect/ConnectConfirmDialog.tsx",
|
||||
"src/components/settings-v2/_layout/SettingsSidebar.tsx",
|
||||
"src/components/settings-v2/_layout/index.tsx",
|
||||
"src/components/settings-v2/agent/providers/index.tsx",
|
||||
"src/components/settings-v2/general/appearance/index.tsx",
|
||||
"src/components/settings-v2/general/hotkeys/index.tsx",
|
||||
"src/components/settings-v2/general/memory/index.tsx",
|
||||
"src/components/settings-v2/system/about/index.tsx",
|
||||
"src/components/settings-v2/system/automation/index.tsx",
|
||||
"src/components/settings-v2/system/channels/ChannelLogTailPanel.tsx",
|
||||
"src/components/settings-v2/system/channels/ChannelsDebugWorkbench.tsx",
|
||||
"src/components/settings-v2/system/developer/index.tsx",
|
||||
"src/components/settings-v2/system/environment/index.tsx",
|
||||
"src/components/settings-v2/system/experimental/index.tsx",
|
||||
"src/components/settings-v2/system/web-search/index.tsx",
|
||||
"src/components/skills/SkillScaffoldDialog.tsx",
|
||||
"src/components/workspace/canvas/shared/CanvasBreadcrumbHeader.tsx",
|
||||
"src/components/workspace/document/DocumentToolbar.tsx",
|
||||
"src/components/workspace/video/VideoSidebar.tsx",
|
||||
"src/features/knowledge/KnowledgePage.tsx",
|
||||
]);
|
||||
|
||||
const I18N_HARDCODED_SCAN_PREFIXES = [
|
||||
"src/components/",
|
||||
"src/features/",
|
||||
@@ -358,6 +459,31 @@ function isI18nPatchRetirementChange(file) {
|
||||
return I18N_PATCH_RETIREMENT_FILES.has(file);
|
||||
}
|
||||
|
||||
function isI18nReleaseDocsWorkflowChange(file) {
|
||||
return (
|
||||
I18N_RELEASE_DOCS_WORKFLOW_FILES.has(file) ||
|
||||
I18N_RELEASE_DOCS_WORKFLOW_PREFIXES.some((prefix) =>
|
||||
file.startsWith(prefix),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function isI18nAppMetadataWorkflowChange(file) {
|
||||
return I18N_APP_METADATA_WORKFLOW_FILES.has(file);
|
||||
}
|
||||
|
||||
function isI18nRtlReadinessChange(file) {
|
||||
return (
|
||||
I18N_RTL_READINESS_FILES.has(file) ||
|
||||
I18N_RTL_SMOKE_FILES.has(file) ||
|
||||
I18N_RTL_SURFACE_FILES.has(file)
|
||||
);
|
||||
}
|
||||
|
||||
function isI18nRtlSmokeChange(file) {
|
||||
return I18N_RTL_SMOKE_FILES.has(file) || I18N_RTL_SURFACE_FILES.has(file);
|
||||
}
|
||||
|
||||
function isI18nHardcodedScanChange(file) {
|
||||
return (
|
||||
file === "src/App.tsx" ||
|
||||
@@ -456,6 +582,22 @@ function collectRecommendedCommands(changedFiles, { docsOnly = false } = {}) {
|
||||
commands.push(...I18N_BUNDLE_STRATEGY_RECOMMENDED_COMMANDS);
|
||||
}
|
||||
|
||||
if (changedFiles.some(isI18nReleaseDocsWorkflowChange)) {
|
||||
commands.push(...I18N_RELEASE_DOCS_WORKFLOW_RECOMMENDED_COMMANDS);
|
||||
}
|
||||
|
||||
if (changedFiles.some(isI18nAppMetadataWorkflowChange)) {
|
||||
commands.push(...I18N_APP_METADATA_WORKFLOW_RECOMMENDED_COMMANDS);
|
||||
}
|
||||
|
||||
if (changedFiles.some(isI18nRtlReadinessChange)) {
|
||||
commands.push(...I18N_RTL_READINESS_RECOMMENDED_COMMANDS);
|
||||
}
|
||||
|
||||
if (changedFiles.some(isI18nRtlSmokeChange)) {
|
||||
commands.push(...I18N_RTL_SMOKE_RECOMMENDED_COMMANDS);
|
||||
}
|
||||
|
||||
return Array.from(new Set(commands));
|
||||
}
|
||||
|
||||
@@ -545,7 +687,7 @@ function detectTasks(changedFiles, { full = false } = {}) {
|
||||
docs: true,
|
||||
docsOnly: true,
|
||||
fallback: false,
|
||||
recommendedCommands: [],
|
||||
recommendedCommands,
|
||||
workflow: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3834,6 +3834,7 @@ export function AgentChatWorkspace({
|
||||
sessionId,
|
||||
executionStrategy,
|
||||
accessMode,
|
||||
providerType,
|
||||
preferredTeamPresetId,
|
||||
selectedTeam,
|
||||
selectedTeamLabel,
|
||||
|
||||
@@ -207,6 +207,38 @@ describe("CodeReviewSummaryPanel", () => {
|
||||
expect(container.textContent).toContain("1 条输出需要处理");
|
||||
});
|
||||
|
||||
it("只有输出时主按钮应打开输出区块", () => {
|
||||
const { container, onOpenSection, onOpenFileCheckpoints } = renderPanel({
|
||||
harnessState: {
|
||||
...createEmptyHarnessState(),
|
||||
outputSignals: [
|
||||
{
|
||||
id: "signal-only",
|
||||
toolCallId: "tool-test",
|
||||
toolName: "bash",
|
||||
title: "类型检查",
|
||||
summary: "typecheck passed",
|
||||
preview: "tsc --noEmit",
|
||||
exitCode: 0,
|
||||
},
|
||||
],
|
||||
hasSignals: true,
|
||||
},
|
||||
fileCheckpointSummary: null,
|
||||
});
|
||||
|
||||
const primaryAction = container.querySelector(
|
||||
'[data-testid="code-review-summary-primary-action"]',
|
||||
) as HTMLButtonElement | null;
|
||||
|
||||
act(() => {
|
||||
primaryAction?.click();
|
||||
});
|
||||
|
||||
expect(onOpenSection).toHaveBeenCalledWith("outputs");
|
||||
expect(onOpenFileCheckpoints).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("没有快照时只展示空态入口", () => {
|
||||
const { container } = renderPanel({
|
||||
harnessState: {
|
||||
|
||||
@@ -1062,6 +1062,65 @@ Extract it into the Agent Skills directory.`,
|
||||
}
|
||||
});
|
||||
|
||||
it("切到非 OEM Provider 时不应继续透传 OEM 低额度路由", async () => {
|
||||
mockResolveOemCloudRuntimeContext.mockReturnValue({
|
||||
baseUrl: "https://lime.example.com",
|
||||
controlPlaneBaseUrl: "https://lime.example.com",
|
||||
sceneBaseUrl: "https://lime.example.com",
|
||||
gatewayBaseUrl: "https://gateway.example.com",
|
||||
tenantId: "tenant-1",
|
||||
sessionToken: "session-token",
|
||||
hubProviderName: "lime-hub",
|
||||
loginPath: "/login",
|
||||
desktopClientId: "desktop-client",
|
||||
desktopOauthRedirectUrl: "lime://oauth/callback",
|
||||
desktopOauthNextPath: "/welcome",
|
||||
});
|
||||
mockGetOemCloudBootstrapSnapshot.mockReturnValue({
|
||||
providerPreference: {
|
||||
tenantId: "tenant-1",
|
||||
userId: "user-1",
|
||||
providerSource: "oem_cloud",
|
||||
providerKey: "lime-hub",
|
||||
defaultModel: "gpt-5.5",
|
||||
needsValidation: false,
|
||||
updatedAt: "2026-04-24T00:00:00.000Z",
|
||||
},
|
||||
providerOffersSummary: [
|
||||
{
|
||||
providerKey: "lime-hub",
|
||||
source: "oem_cloud",
|
||||
state: "available_quota_low",
|
||||
defaultModel: "gpt-5.5",
|
||||
configMode: "managed",
|
||||
quotaStatus: "low",
|
||||
fallbackToLocalAllowed: false,
|
||||
canInvoke: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
const harness = mountHook({ providerType: "deepseek" });
|
||||
|
||||
try {
|
||||
await act(async () => {
|
||||
const started = await harness
|
||||
.getValue()
|
||||
.handleSend([], false, false, "继续处理当前话题", "react");
|
||||
expect(started).toBe(true);
|
||||
});
|
||||
|
||||
expect(mockSendMessage).toHaveBeenCalledTimes(1);
|
||||
const args = mockSendMessage.mock.calls[0] as Parameters<
|
||||
HookProps["sendMessage"]
|
||||
>;
|
||||
expect(args?.[8]?.requestMetadata?.harness).not.toHaveProperty(
|
||||
"oem_routing",
|
||||
);
|
||||
} finally {
|
||||
harness.unmount();
|
||||
}
|
||||
});
|
||||
|
||||
it("OEM bootstrap features 应透传为 tenant_feature_flags 策略输入", async () => {
|
||||
mockResolveOemCloudRuntimeContext.mockReturnValue({
|
||||
baseUrl: "https://lime.example.com",
|
||||
|
||||
@@ -2554,6 +2554,7 @@ interface UseWorkspaceSendActionsParams {
|
||||
sessionId?: string | null;
|
||||
executionStrategy: ExecutionStrategy;
|
||||
accessMode?: AgentAccessMode;
|
||||
providerType?: string | null;
|
||||
preferredTeamPresetId?: string | null;
|
||||
selectedTeam?: TeamDefinition | null;
|
||||
selectedTeamLabel?: string;
|
||||
@@ -2712,6 +2713,7 @@ export function useWorkspaceSendActions({
|
||||
sessionId,
|
||||
executionStrategy,
|
||||
accessMode: _accessMode,
|
||||
providerType,
|
||||
preferredTeamPresetId,
|
||||
selectedTeam,
|
||||
selectedTeamLabel,
|
||||
@@ -5216,6 +5218,7 @@ export function useWorkspaceSendActions({
|
||||
...(sendOptions || {}),
|
||||
toolPreferencesOverride: effectiveToolPreferences,
|
||||
},
|
||||
currentProviderType: providerType,
|
||||
effectiveToolPreferences,
|
||||
mappedTheme,
|
||||
isThemeWorkbench,
|
||||
@@ -5384,6 +5387,7 @@ export function useWorkspaceSendActions({
|
||||
messagesCount,
|
||||
mentionedCharacters,
|
||||
preferredTeamPresetId,
|
||||
providerType,
|
||||
rollbackAfterSendFailure,
|
||||
selectedTeam,
|
||||
selectedTeamLabel,
|
||||
|
||||
@@ -497,6 +497,25 @@ function buildOemRoutingRequestMetadata():
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeProviderSelection(value?: string | null): string {
|
||||
return value?.trim().toLowerCase() || "";
|
||||
}
|
||||
|
||||
function providerMatchesOemRouting(
|
||||
providerType: string | null | undefined,
|
||||
oemRouting: HarnessOemRoutingRequestMetadata | undefined,
|
||||
): boolean {
|
||||
const normalizedProvider = normalizeProviderSelection(providerType);
|
||||
const normalizedOemProvider = normalizeProviderSelection(
|
||||
oemRouting?.provider_key,
|
||||
);
|
||||
if (!normalizedProvider || !normalizedOemProvider) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return normalizedProvider === normalizedOemProvider;
|
||||
}
|
||||
|
||||
function buildTenantFeatureFlagsRequestMetadata():
|
||||
| HarnessTenantFeatureFlagsRequestMetadata
|
||||
| undefined {
|
||||
@@ -607,6 +626,7 @@ interface PrimeBrowserAssistBeforeSendOptions {
|
||||
interface BuildWorkspaceRequestMetadataOptions {
|
||||
workspaceRequestMetadataBase?: Record<string, unknown>;
|
||||
sendOptions?: HandleSendOptions;
|
||||
currentProviderType?: string | null;
|
||||
effectiveToolPreferences: ChatToolPreferences;
|
||||
mappedTheme: ThemeType;
|
||||
isThemeWorkbench: boolean;
|
||||
@@ -941,6 +961,7 @@ export function buildWorkspaceRequestMetadata(
|
||||
const {
|
||||
workspaceRequestMetadataBase,
|
||||
sendOptions,
|
||||
currentProviderType,
|
||||
effectiveToolPreferences,
|
||||
mappedTheme,
|
||||
isThemeWorkbench,
|
||||
@@ -1004,45 +1025,54 @@ export function buildWorkspaceRequestMetadata(
|
||||
const resolvedTenantFeatureFlags =
|
||||
buildTenantFeatureFlagsRequestMetadata() ||
|
||||
readExistingTenantFeatureFlags(existingHarnessMetadata);
|
||||
const oemRoutingMatchesCurrentProvider = providerMatchesOemRouting(
|
||||
currentProviderType,
|
||||
resolvedOemRouting,
|
||||
);
|
||||
const harnessMetadata = buildHarnessRequestMetadata({
|
||||
base: existingHarnessMetadata,
|
||||
theme: mappedTheme,
|
||||
turnPurpose: sendOptions?.purpose,
|
||||
preferences: {
|
||||
webSearch: effectiveToolPreferences.webSearch,
|
||||
thinking: effectiveToolPreferences.thinking,
|
||||
task: effectiveToolPreferences.task,
|
||||
subagent: effectiveToolPreferences.subagent,
|
||||
},
|
||||
sessionMode: isThemeWorkbench ? "general_workbench" : "default",
|
||||
gateKey: isThemeWorkbench ? currentGateKey : undefined,
|
||||
runTitle: themeWorkbenchActiveQueueTitle?.trim() || undefined,
|
||||
contentId: contentId || undefined,
|
||||
browserRequirement: resolvedBrowserRequirement,
|
||||
browserRequirementReason: resolvedBrowserRequirementReason,
|
||||
browserLaunchUrl: resolvedBrowserLaunchUrl,
|
||||
browserAssistProfileKey:
|
||||
mappedTheme === "general"
|
||||
? browserAssistProfileKey || GENERAL_BROWSER_ASSIST_PROFILE_KEY
|
||||
: undefined,
|
||||
browserAssistPreferredBackend,
|
||||
browserAssistAutoLaunch,
|
||||
preferredTeamPresetId: resolvedPreferredTeamPresetId,
|
||||
selectedTeamId: resolvedSelectedTeamId,
|
||||
selectedTeamSource: resolvedSelectedTeamSource,
|
||||
selectedTeamLabel: resolvedSelectedTeamLabel,
|
||||
selectedTeamDescription: resolvedSelectedTeamDescription,
|
||||
selectedTeamSummary: resolvedSelectedTeamSummary,
|
||||
selectedTeamRoles: resolvedSelectedTeamRoles,
|
||||
teamMemoryShadow: resolvedTeamMemoryShadow,
|
||||
agentResponseLanguage,
|
||||
oemRouting: oemRoutingMatchesCurrentProvider ? resolvedOemRouting : undefined,
|
||||
tenantFeatureFlags: resolvedTenantFeatureFlags,
|
||||
});
|
||||
if (!oemRoutingMatchesCurrentProvider) {
|
||||
delete harnessMetadata.oem_routing;
|
||||
delete harnessMetadata.oemRouting;
|
||||
}
|
||||
|
||||
return {
|
||||
...(workspaceRequestMetadataBase || {}),
|
||||
...(sendOptions?.requestMetadata || {}),
|
||||
harness: buildHarnessRequestMetadata({
|
||||
base: existingHarnessMetadata,
|
||||
theme: mappedTheme,
|
||||
turnPurpose: sendOptions?.purpose,
|
||||
preferences: {
|
||||
webSearch: effectiveToolPreferences.webSearch,
|
||||
thinking: effectiveToolPreferences.thinking,
|
||||
task: effectiveToolPreferences.task,
|
||||
subagent: effectiveToolPreferences.subagent,
|
||||
},
|
||||
sessionMode: isThemeWorkbench ? "general_workbench" : "default",
|
||||
gateKey: isThemeWorkbench ? currentGateKey : undefined,
|
||||
runTitle: themeWorkbenchActiveQueueTitle?.trim() || undefined,
|
||||
contentId: contentId || undefined,
|
||||
browserRequirement: resolvedBrowserRequirement,
|
||||
browserRequirementReason: resolvedBrowserRequirementReason,
|
||||
browserLaunchUrl: resolvedBrowserLaunchUrl,
|
||||
browserAssistProfileKey:
|
||||
mappedTheme === "general"
|
||||
? browserAssistProfileKey || GENERAL_BROWSER_ASSIST_PROFILE_KEY
|
||||
: undefined,
|
||||
browserAssistPreferredBackend,
|
||||
browserAssistAutoLaunch,
|
||||
preferredTeamPresetId: resolvedPreferredTeamPresetId,
|
||||
selectedTeamId: resolvedSelectedTeamId,
|
||||
selectedTeamSource: resolvedSelectedTeamSource,
|
||||
selectedTeamLabel: resolvedSelectedTeamLabel,
|
||||
selectedTeamDescription: resolvedSelectedTeamDescription,
|
||||
selectedTeamSummary: resolvedSelectedTeamSummary,
|
||||
selectedTeamRoles: resolvedSelectedTeamRoles,
|
||||
teamMemoryShadow: resolvedTeamMemoryShadow,
|
||||
agentResponseLanguage,
|
||||
oemRouting: resolvedOemRouting,
|
||||
tenantFeatureFlags: resolvedTenantFeatureFlags,
|
||||
}),
|
||||
harness: harnessMetadata,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user