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
a6063e5b
Commit
a6063e5b
authored
May 09, 2026
by
edy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(desktop): pass ingress ownership flags to workspace agent
parent
d21ff2dd
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
277 additions
and
1 deletion
+277
-1
project-workspace-agent-runner.ts
apps/desktop/src/main/project-workspace-agent-runner.ts
+3
-1
workspace-agent-runner-smoke.mjs
build/scripts/workspace-agent-runner-smoke.mjs
+273
-0
package.json
package.json
+1
-0
No files found.
apps/desktop/src/main/project-workspace-agent-runner.ts
View file @
a6063e5b
...
...
@@ -332,7 +332,9 @@ async function main(): Promise<void> {
sessionId
:
runtimeSession
.
sessionId
,
sessionKey
:
runtimeSession
.
sessionKey
,
workspaceDir
:
input
.
projectRoot
,
runId
runId
,
senderIsOwner
:
true
,
allowModelOverride
:
true
},
silentRuntime
);
emit
({
...
...
build/scripts/workspace-agent-runner-smoke.mjs
0 → 100644
View file @
a6063e5b
#!/usr/bin/env node
import
{
execFileSync
,
spawnSync
}
from
"node:child_process"
import
{
existsSync
,
mkdirSync
,
rmSync
,
writeFileSync
}
from
"node:fs"
import
{
dirname
,
join
,
resolve
}
from
"node:path"
const
repoRoot
=
resolve
(
import
.
meta
.
dirname
,
".."
,
".."
)
const
tmpRoot
=
join
(
repoRoot
,
".tmp"
,
"workspace-agent-runner-smoke"
)
const
compileDir
=
join
(
tmpRoot
,
"compiled"
)
let
failures
=
0
function
check
(
label
,
condition
,
detail
)
{
if
(
condition
)
{
console
.
log
(
` PASS:
${
label
}
`
)
}
else
{
console
.
error
(
` FAIL:
${
label
}${
detail
?
` -
${
detail
}
`
:
""
}
`
)
failures
++
}
}
function
emitSummary
()
{
console
.
log
(
""
)
if
(
failures
===
0
)
{
console
.
log
(
"workspace-agent-runner-smoke: ALL PASSED"
)
}
else
{
console
.
error
(
`workspace-agent-runner-smoke:
${
failures
}
FAILURE(S)`
)
process
.
exit
(
1
)
}
}
function
writePackageFile
(
packageRoot
,
relativePath
,
content
)
{
const
filePath
=
join
(
packageRoot
,
relativePath
)
mkdirSync
(
dirname
(
filePath
),
{
recursive
:
true
})
writeFileSync
(
filePath
,
content
.
trimStart
(),
"utf8"
)
}
function
preparePackage
(
caseRoot
,
files
)
{
const
packageRoot
=
join
(
caseRoot
,
"openclaw-package"
)
mkdirSync
(
join
(
packageRoot
,
"dist"
),
{
recursive
:
true
})
mkdirSync
(
join
(
packageRoot
,
"node_modules"
),
{
recursive
:
true
})
writePackageFile
(
packageRoot
,
"package.json"
,
JSON
.
stringify
({
type
:
"module"
},
null
,
2
))
for
(
const
[
relativePath
,
content
]
of
Object
.
entries
(
files
))
{
writePackageFile
(
packageRoot
,
relativePath
,
content
)
}
return
packageRoot
}
function
parseEvents
(
stdout
)
{
return
stdout
.
split
(
/
\r?\n
/
)
.
filter
((
line
)
=>
line
.
startsWith
(
"QJC_WORKSPACE_EVENT
\
t"
))
.
map
((
line
)
=>
JSON
.
parse
(
line
.
slice
(
"QJC_WORKSPACE_EVENT
\
t"
.
length
)))
}
function
defaultAttachments
(
projectRoot
,
name
)
{
return
[{
id
:
`
${
name
}
-image`
,
kind
:
"image"
,
name
:
"sample.png"
,
projectPath
:
join
(
projectRoot
,
"inputs"
,
"images"
,
"main"
,
"sample.png"
),
relativeProjectPath
:
"inputs/images/main/sample.png"
,
sizeBytes
:
12
,
mimeType
:
"image/png"
,
}]
}
function
multiKindAttachments
(
projectRoot
,
name
)
{
return
[
...
defaultAttachments
(
projectRoot
,
name
),
{
id
:
`
${
name
}
-pdf`
,
kind
:
"pdf"
,
name
:
"brief.pdf"
,
projectPath
:
join
(
projectRoot
,
"inputs"
,
"documents"
,
"brief.pdf"
),
relativeProjectPath
:
"inputs/documents/brief.pdf"
,
sizeBytes
:
128
,
mimeType
:
"application/pdf"
,
},
{
id
:
`
${
name
}
-xlsx`
,
kind
:
"spreadsheet"
,
name
:
"metrics.xlsx"
,
projectPath
:
join
(
projectRoot
,
"inputs"
,
"spreadsheets"
,
"metrics.xlsx"
),
relativeProjectPath
:
"inputs/spreadsheets/metrics.xlsx"
,
sizeBytes
:
256
,
mimeType
:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
,
},
{
id
:
`
${
name
}
-ppt`
,
kind
:
"presentation"
,
name
:
"deck.pptx"
,
projectPath
:
join
(
projectRoot
,
"inputs"
,
"presentations"
,
"deck.pptx"
),
relativeProjectPath
:
"inputs/presentations/deck.pptx"
,
sizeBytes
:
512
,
mimeType
:
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
,
},
{
id
:
`
${
name
}
-mp3`
,
kind
:
"audio"
,
name
:
"clip.mp3"
,
projectPath
:
join
(
projectRoot
,
"inputs"
,
"audio"
,
"clip.mp3"
),
relativeProjectPath
:
"inputs/audio/clip.mp3"
,
sizeBytes
:
1024
,
mimeType
:
"audio/mpeg"
,
},
]
}
function
runCase
(
compiledRunner
,
name
,
files
,
expectedContentPart
,
options
=
{})
{
const
caseRoot
=
join
(
tmpRoot
,
name
)
const
projectRoot
=
join
(
caseRoot
,
"project"
)
const
instrumentationDir
=
join
(
caseRoot
,
"instrumented"
)
rmSync
(
caseRoot
,
{
recursive
:
true
,
force
:
true
})
mkdirSync
(
projectRoot
,
{
recursive
:
true
})
const
vendorPackageDir
=
preparePackage
(
caseRoot
,
files
)
const
attachments
=
options
.
attachments
?.(
projectRoot
,
name
)
||
defaultAttachments
(
projectRoot
,
name
)
const
expectedAttachmentPaths
=
options
.
expectedAttachmentPaths
||
attachments
.
map
((
attachment
)
=>
attachment
.
relativeProjectPath
)
const
result
=
spawnSync
(
process
.
execPath
,
[
compiledRunner
],
{
cwd
:
repoRoot
,
encoding
:
"utf8"
,
input
:
JSON
.
stringify
({
vendorPackageDir
,
instrumentationDir
,
projectRoot
,
sessionId
:
`
${
name
}
-session`
,
prompt
:
"Analyze this image"
,
attachments
,
runId
:
`
${
name
}
-run`
,
}),
})
const
events
=
parseEvents
(
result
.
stdout
)
const
errorEvent
=
events
.
find
((
event
)
=>
event
.
type
===
"error"
)
const
completedEvent
=
events
.
find
((
event
)
=>
event
.
type
===
"completed"
)
const
deltaEvents
=
events
.
filter
((
event
)
=>
event
.
type
===
"delta"
)
check
(
`
${
name
}
: runner exited successfully`
,
result
.
status
===
0
,
errorEvent
?.
message
||
result
.
stderr
||
`exit
${
result
.
status
}
`
)
check
(
`
${
name
}
: emitted delta`
,
deltaEvents
.
length
>
0
,
JSON
.
stringify
(
events
))
check
(
`
${
name
}
: completed`
,
Boolean
(
completedEvent
),
JSON
.
stringify
(
events
))
check
(
`
${
name
}
: reply content`
,
completedEvent
?.
content
?.
includes
(
expectedContentPart
),
completedEvent
?.
content
)
for
(
const
relativePath
of
expectedAttachmentPaths
)
{
check
(
`
${
name
}
: attachment prelude includes
${
relativePath
}
`
,
completedEvent
?.
content
?.
includes
(
relativePath
),
completedEvent
?.
content
)
}
}
async
function
main
()
{
console
.
log
(
"workspace-agent-runner-smoke: validating OpenClaw runner ingress options"
)
rmSync
(
tmpRoot
,
{
recursive
:
true
,
force
:
true
})
mkdirSync
(
compileDir
,
{
recursive
:
true
})
execFileSync
(
"corepack"
,
[
"pnpm"
,
"--dir"
,
join
(
repoRoot
,
"apps"
,
"desktop"
),
"exec"
,
"tsup"
,
"src/main/project-workspace-agent-runner.ts"
,
"--no-config"
,
"--format"
,
"cjs"
,
"--platform"
,
"node"
,
"--target"
,
"node20"
,
"--out-dir"
,
compileDir
,
],
{
cwd
:
repoRoot
,
stdio
:
"inherit"
,
})
const
compiledRunner
=
join
(
compileDir
,
"project-workspace-agent-runner.js"
)
check
(
"compiled workspace agent runner"
,
existsSync
(
compiledRunner
),
`not found:
${
compiledRunner
}
`
)
if
(
!
existsSync
(
compiledRunner
))
{
emitSummary
()
return
}
const
strictIngressOptionsSource
=
`
function assertIngressOptions(options) {
if (typeof options.senderIsOwner !== "boolean") {
throw new Error("senderIsOwner must be a boolean");
}
if (options.senderIsOwner !== true) {
throw new Error("senderIsOwner must be true");
}
if (typeof options.allowModelOverride !== "boolean") {
throw new Error("allowModelOverride must be a boolean");
}
if (options.allowModelOverride !== true) {
throw new Error("allowModelOverride must be true");
}
}
`
runCase
(
compiledRunner
,
"ingress-options"
,
{
"dist/agent-legacy.js"
:
`
import { emitAgentEvent, legacyModelMarker } from "./model-selection-legacy.js";
${
strictIngressOptionsSource
}
async function t(options) {
assertIngressOptions(options);
emitAgentEvent({ runId: options.runId, stream: "assistant", data: { delta: "leg" } });
return { payloads: [{ text: "legacy:" + legacyModelMarker() + ":" + options.message }] };
}
export { t };
`
,
"dist/model-selection-legacy.js"
:
`
const listeners = new Set();
function emitAgentEvent(event) {
for (const listener of listeners) {
listener(event);
}
}
function onAgentEvent(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
function legacyModelMarker() {
return "direct-model-selection";
}
export { emitAgentEvent, legacyModelMarker, onAgentEvent };
`
,
},
"legacy:direct-model-selection"
)
runCase
(
compiledRunner
,
"multi-attachment-prelude"
,
{
"dist/agent-multi.js"
:
`
import { emitAgentEvent, legacyModelMarker } from "./model-selection-multi.js";
${
strictIngressOptionsSource
}
async function t(options) {
assertIngressOptions(options);
emitAgentEvent({ runId: options.runId, stream: "assistant", data: { delta: "mul" } });
return { payloads: [{ text: "multi:" + legacyModelMarker() + ":" + options.message }] };
}
export { t };
`
,
"dist/model-selection-multi.js"
:
`
const listeners = new Set();
function emitAgentEvent(event) {
for (const listener of listeners) {
listener(event);
}
}
function onAgentEvent(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
function legacyModelMarker() {
return "direct-model-selection";
}
export { emitAgentEvent, legacyModelMarker, onAgentEvent };
`
,
},
"multi:direct-model-selection"
,
{
attachments
:
multiKindAttachments
,
expectedAttachmentPaths
:
[
"inputs/images/main/sample.png"
,
"inputs/documents/brief.pdf"
,
"inputs/spreadsheets/metrics.xlsx"
,
"inputs/presentations/deck.pptx"
,
"inputs/audio/clip.mp3"
,
],
})
rmSync
(
tmpRoot
,
{
recursive
:
true
,
force
:
true
})
emitSummary
()
}
main
().
catch
((
error
)
=>
{
console
.
error
(
error
instanceof
Error
?
error
.
stack
||
error
.
message
:
String
(
error
))
process
.
exit
(
1
)
})
package.json
View file @
a6063e5b
...
...
@@ -20,6 +20,7 @@
"smoke:mac:workspace-entry"
:
"node build/scripts/mac-workspace-entry-smoke.mjs"
,
"smoke:mac:workspace-service"
:
"node build/scripts/mac-workspace-service-smoke.mjs"
,
"smoke:mac:workspace-startup"
:
"node build/scripts/mac-workspace-startup-smoke.mjs"
,
"smoke:workspace-agent-runner"
:
"node build/scripts/workspace-agent-runner-smoke.mjs"
,
"smoke:bundled-runtime"
:
"powershell -ExecutionPolicy Bypass -File build/scripts/bundled-runtime-smoke.ps1"
,
"smoke:workspace-entry"
:
"powershell -ExecutionPolicy Bypass -File build/scripts/workspace-entry-smoke.ps1"
,
"smoke:cloud-bundle"
:
"powershell -ExecutionPolicy Bypass -File build/scripts/cloud-bundle-smoke.ps1"
,
...
...
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