fix: align OpenClaw task key flow

This commit is contained in:
Haitao Pan 2026-06-06 13:56:03 +08:00
parent 481190f7b3
commit 4f25126d4f
5 changed files with 37 additions and 8 deletions

View File

@ -227,7 +227,7 @@ App → Bridge → Gateway: device.pair.approve / device.pair.reject
| `xworkmate.artifacts.collect-and-snapshot` | `{sessionKey, runId, artifactScope?, sinceUnixMs?, expectedArtifactDirs?}` | `{artifacts[], warnings[]}` |
| `xworkmate.artifacts.list` | `{sessionKey, runId, ...}` | `{artifacts[] (不含内容), manifestMarkdown}` |
| `xworkmate.artifacts.read` | `{sessionKey, runId, artifactScope?, relativePath?, artifactRef?}` | `{artifacts[0], manifestMarkdown}` |
| `xworkmate.tasks.get` | `{sessionKey, runId}` | `{taskStatus, status, artifacts[], warnings[]}` |
| `xworkmate.tasks.get` | `{appThreadKey, openclawSessionKey, runId/taskId}` | `{taskStatus, status, artifacts[], warnings[]}` |
`expectedArtifactDirs` has a single upstream source:
`session.start.metadata.xworkmateTaskArtifactContract.expectedArtifactDirs`.

View File

@ -43,6 +43,7 @@ xworkmate-app
│ ├─ params: sessionId, threadId, prompt, workingDirectory
│ ├─ routing: executionTarget=gateway, preferredGatewayProviderId=openclaw
│ └─ metadata: xworkmateTaskArtifactContract
│ └─ appThreadKey only; no prefilled openclawSessionKey
└─ Listen for SSE session.update events
├─ status=running → poll xworkmate.tasks.get
├─ terminal snapshot → applyGatewayChatResult()
@ -198,6 +199,8 @@ now copied into tasks/<session>/<run>/artifacts/ before export.
xworkmate.tasks.get:
Bridge forwards typed lookup to the plugin/native task-registry.
The request uses the persisted association:
{appThreadKey, openclawSessionKey, runId/taskId}
Terminal state comes from native task records only. Missing native records
return structured errors such as no_native_task_record instead of inferring
success from artifacts or reconstructing a Bridge task dictionary.

View File

@ -16,14 +16,15 @@ session identity boundary.
Rules:
- App code may keep `sessionKey` for local TaskThread and UI session APIs.
- XWorkmate OpenClaw integration payloads must use `appThreadKey` and
`openclawSessionKey`.
- Bridge may send `sessionKey` only when calling OpenClaw native APIs that
require that field, such as `chat.send`.
- App `session.start` only carries `appThreadKey` in typed metadata; it does
not preemptively choose the OpenClaw native session key.
- Bridge resolves or reuses `openclawSessionKey`, persists the mapping, and
then uses that key for OpenClaw native APIs such as `chat.send`.
- Plugin lookup must read `appThreadKey -> openclawSessionKey` from
`SessionEntry.pluginExtensions`, not from string replace or reverse parsing.
- Legacy `sessionKey` aliases are not accepted from App or Bridge as mapping
inputs.
- `xworkmate.tasks.get` must be invoked with the persisted association
(`appThreadKey`, `openclawSessionKey`, `runId/taskId`), not with a legacy
`sessionKey` alias.
## State Graph

View File

@ -328,7 +328,6 @@ class GoTaskServiceRequest {
if (_usesGatewaySessionMode(acpMode)) ...<String, dynamic>{
'executionTarget': normalizedTarget.promptValue,
'appThreadKey': threadId,
'openclawSessionKey': threadId,
if (agentId.trim().isNotEmpty) 'agentId': agentId.trim(),
if (metadata.isNotEmpty) 'metadata': metadata,
},

View File

@ -94,6 +94,32 @@ void main() {
expect(params, isNot(contains('artifactScope')));
});
test(
'gateway ACP params expose appThreadKey without preempting the OpenClaw session key',
() {
const request = GoTaskServiceRequest(
sessionId: 'draft:1780718661814229-2',
threadId: 'draft:1780718661814229-2',
target: AssistantExecutionTarget.gateway,
prompt: 'collect latest AI news',
workingDirectory: '/tmp/xworkmate-thread',
model: '',
thinking: 'low',
selectedSkills: <String>[],
inlineAttachments: <GatewayChatAttachmentPayload>[],
localAttachments: <CollaborationAttachment>[],
agentId: '',
metadata: <String, dynamic>{},
provider: SingleAgentProvider.openclaw,
);
final params = request.toExternalAcpParams();
expect(params['appThreadKey'], 'draft:1780718661814229-2');
expect(params, isNot(contains('openclawSessionKey')));
},
);
test('recognizes openclaw as the canonical gateway provider', () {
final provider = SingleAgentProvider.fromJsonValue('openclaw');