Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qjclaw-dmg
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
AI-甘富林
qjclaw-dmg
Commits
a38906e4
Commit
a38906e4
authored
May 20, 2026
by
edy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(desktop): restrict automation research sources
parent
ef2f3d16
Pipeline
#18477
failed
Changes
2
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
62 additions
and
5 deletions
+62
-5
ipc.ts
apps/desktop/src/main/ipc.ts
+23
-5
automationTaskIpcSource.test.ts
apps/desktop/test/automationTaskIpcSource.test.ts
+39
-0
No files found.
apps/desktop/src/main/ipc.ts
View file @
a38906e4
...
...
@@ -167,6 +167,23 @@ const SUPPORTED_ATTACHMENT_EXTENSIONS = new Set([
...DOCUMENT_ATTACHMENT_EXTENSIONS
]);
const BUILTIN_HOME_PROJECT_ID = "
home
-
chat
";
const AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT_MARKER = "
自动化联网资料源限制:
";
const AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT = [
AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT_MARKER,
"
-
只允许搜索、打开、引用中国境内网站资料;按域名和来源机构判断,不按服务器物理
IP
判断。
",
"
-
禁止使用
Google
、
Wikipedia
、
YouTube
、
Twitter
/
X
、
Reddit
、海外媒体、海外
SaaS
文档等非国内资料源。
",
"
-
优先使用
.
cn
、政府、央媒、行业协会、国内平台资料;可使用
baidu
.
com
、
qq
.
com
、
163
.
com
、
sina
.
com
.
cn
、
sohu
.
com
、
people
.
com
.
cn
、
xinhuanet
.
com
、
cctv
.
com
等国内来源。
",
"
-
如果搜索工具支持
domain
allowlist
,只使用国内域名
allowlist
;不支持时,用
site
:.
cn
或国内域名
site
:
范围搜索并过滤结果。
",
"
-
最终回复不得引用非国内来源;找不到足够国内资料时,明确回复“未找到可用国内资料”。
"
].join("
\
n
");
function withAutomationDomesticSourceConstraint(prompt: string): string {
const trimmed = prompt.trim();
if (trimmed.endsWith(AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT)) {
return trimmed;
}
return [trimmed, AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT].filter(Boolean).join("
\
n
\
n
");
}
function inferAttachmentMimeType(localPath: string, name?: string): string {
const extension = path.extname(name || localPath).toLowerCase();
...
...
@@ -2057,6 +2074,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
};
const executeAutomationPrompt = async (sessionId: string, projectId: string, prompt: string) => {
const automationPrompt = withAutomationDomesticSourceConstraint(prompt);
const project = await projectStore.getProjectSummary(projectId);
const projectRoot = await projectStore.getProjectRoot(project.id);
const projectConfig = await projectStore.getProjectPackageConfig(project.id);
...
...
@@ -2065,7 +2083,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
sessionId,
projectId: project.id,
projectRoot,
userPrompt:
p
rompt,
userPrompt:
automationP
rompt,
context: snapshot,
selectedSkillId: null,
attachments: [],
...
...
@@ -2088,7 +2106,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
sessionId,
projectId: project.id,
projectRoot,
userPrompt:
p
rompt,
userPrompt:
automationP
rompt,
context: snapshot,
selectedSkillId: resolvedSkillRoute.skillId,
attachments: [],
...
...
@@ -2109,7 +2127,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
sessionId,
projectRoot,
prompt: decision.preparedPrompt,
userPrompt:
p
rompt,
userPrompt:
automationP
rompt,
attachments: [],
extraEnv: {
...projectModelEnv,
...
...
@@ -2120,7 +2138,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
const fallbackExecutionPolicy = await resolveExecutionPolicy(project.id, undefined, "
chat
-
fallback
");
const fallbackResult = await runGatewayChatRequestWithRecovery(chatGatewayRecoveryCoordinator, {
reason: "
automation
-
task
",
execute: () => gatewayClient.sendPrompt(sessionId,
result.handoff.content
)
execute: () => gatewayClient.sendPrompt(sessionId,
withAutomationDomesticSourceConstraint(result.handoff.content)
)
});
runtimeCloudSupervisor.noteMessageSent(
fallbackResult.sessionId,
...
...
@@ -2141,7 +2159,7 @@ export function registerDesktopIpc(services: MainServices): RegisteredDesktopIpc
const result = await runGatewayChatRequestWithRecovery(chatGatewayRecoveryCoordinator, {
reason: "
automation
-
task
",
execute: () => gatewayClient.sendPrompt(sessionId, gatewayPrompt ??
p
rompt)
execute: () => gatewayClient.sendPrompt(sessionId, gatewayPrompt ??
automationP
rompt)
});
runtimeCloudSupervisor.noteMessageSent(result.sessionId, result.reply.content, executionPolicy.modelId, executionSkillId);
return { ...result, executionPolicy, artifacts: [] };
...
...
apps/desktop/test/automationTaskIpcSource.test.ts
View file @
a38906e4
...
...
@@ -19,6 +19,18 @@ function getExecuteAutomationPromptBody(): string {
return
bodyMatch
.
groups
.
body
}
function
getSendPromptBody
():
string
{
const
bodyMatch
=
ipcSource
.
match
(
/const sendPrompt = async
\(
sessionId: string, prompt: string, skillId
\?
: string, attachments
\?
: ChatAttachment
\[\]\)
=>
\{(?<
body>
[\s\S]
*
?)\n
\}
;
\n\n
const executeAutomationPrompt = async/
)
assert
.
ok
(
bodyMatch
?.
groups
?.
body
)
return
bodyMatch
.
groups
.
body
}
function
getStreamPromptBody
():
string
{
const
bodyMatch
=
ipcSource
.
match
(
/const streamPrompt = async
\(
sessionId: string, prompt: string, skillId
\?
: string, attachments
\?
: ChatAttachment
\[\]
, sender
\?
: WebContents
\)
=>
\{(?<
body>
[\s\S]
*
?)\n
\}
;
\n
const cancelStream = async/
)
assert
.
ok
(
bodyMatch
?.
groups
?.
body
)
return
bodyMatch
.
groups
.
body
}
test
(
"shared automation task channels and desktop API are declared"
,
()
=>
{
assert
.
match
(
sharedTypesSource
,
/automationTasksList:
\s
*"automation-tasks:list"/
)
assert
.
match
(
sharedTypesSource
,
/automationTasksCreate:
\s
*"automation-tasks:create"/
)
...
...
@@ -88,3 +100,30 @@ test("automation prompt execution refreshes project context after completion wit
assert
.
match
(
refreshCallMatch
.
groups
.
args
,
/projectStore/
)
assert
.
doesNotMatch
(
refreshCallMatch
.
groups
.
args
,
/sessionId/
)
})
test
(
"automation prompts restrict online research to domestic China sources"
,
()
=>
{
const
automationPromptBody
=
getExecuteAutomationPromptBody
()
assert
.
match
(
ipcSource
,
/AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT/
)
assert
.
match
(
ipcSource
,
/中国境内网站资料/
)
assert
.
match
(
ipcSource
,
/未找到可用国内资料/
)
assert
.
match
(
ipcSource
,
/Google、Wikipedia、YouTube、Twitter
\/
X、Reddit/
)
assert
.
match
(
ipcSource
,
/baidu
\.
com、qq
\.
com、163
\.
com、sina
\.
com
\.
cn、sohu
\.
com、people
\.
com
\.
cn、xinhuanet
\.
com、cctv
\.
com/
)
assert
.
match
(
automationPromptBody
,
/const automationPrompt = withAutomationDomesticSourceConstraint
\(
prompt
\)
/
)
assert
.
match
(
automationPromptBody
,
/userPrompt: automationPrompt/
)
assert
.
match
(
automationPromptBody
,
/projectSkillRouter
\.
resolve
\(
project
\.
id, prompt
\)
/
)
assert
.
match
(
automationPromptBody
,
/userPrompt: automationPrompt/
)
assert
.
match
(
automationPromptBody
,
/userPrompt: automationPrompt,
\n\s
+attachments:
\[\]
/
)
assert
.
match
(
automationPromptBody
,
/gatewayClient
\.
sendPrompt
\(
sessionId, withAutomationDomesticSourceConstraint
\(
result
\.
handoff
\.
content
\)\)
/
)
assert
.
match
(
automationPromptBody
,
/gatewayClient
\.
sendPrompt
\(
sessionId, gatewayPrompt
\?\?
automationPrompt
\)
/
)
})
test
(
"automation domestic source guard cannot be bypassed by marker text alone"
,
()
=>
{
assert
.
doesNotMatch
(
ipcSource
,
/trimmed
\.
includes
\(
AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT_MARKER
\)
/
)
assert
.
match
(
ipcSource
,
/trimmed
\.
endsWith
\(
AUTOMATION_DOMESTIC_SOURCE_CONSTRAINT
\)
/
)
})
test
(
"ordinary chat prompts do not receive automation domestic source constraints"
,
()
=>
{
assert
.
doesNotMatch
(
getSendPromptBody
(),
/withAutomationDomesticSourceConstraint/
)
assert
.
doesNotMatch
(
getStreamPromptBody
(),
/withAutomationDomesticSourceConstraint/
)
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment