Fix chat.send metadata regression across gateway clients

This commit is contained in:
Haitao Pan 2026-04-06 13:53:25 +08:00
parent 2210b5f7f1
commit de6f4677ca
4 changed files with 86 additions and 6 deletions

View File

@ -146,7 +146,6 @@ extension GatewayRuntimeApiInternal on GatewayRuntime {
'idempotencyKey': runId,
if (agentId != null && agentId.trim().isNotEmpty)
'agentId': agentId.trim(),
if (metadata != null && metadata.isNotEmpty) 'metadata': metadata,
if (attachments.isNotEmpty)
'attachments': attachments
.map((attachment) => attachment.toJson())

View File

@ -294,10 +294,6 @@ class WebRelayGatewayClient {
Map<String, dynamic> metadata = const <String, dynamic>{},
}) async {
final runId = randomIdInternal();
final normalizedMetadata = <String, dynamic>{
for (final entry in metadata.entries)
if (entry.key.trim().isNotEmpty) entry.key: entry.value,
};
final payload = asMapInternal(
await request(
'chat.send',
@ -309,7 +305,6 @@ class WebRelayGatewayClient {
'attachments': attachments
.map((item) => item.toJson())
.toList(growable: false),
if (normalizedMetadata.isNotEmpty) 'metadata': normalizedMetadata,
'timeoutMs': 30000,
'idempotencyKey': runId,
},

View File

@ -34,6 +34,24 @@ void main() {
);
});
test('GatewayRuntime omits metadata from chat.send payloads', () async {
SharedPreferences.setMockInitialValues(<String, Object>{});
final store = createIsolatedTestStore();
final runtime = _FakeGatewayRuntimeForSendChat(store: store);
final runId = await runtime.sendChat(
sessionKey: 'thread-1',
message: 'hello',
thinking: 'medium',
metadata: const <String, dynamic>{'threadMode': 'test'},
);
expect(runId, 'run-send-chat');
expect(runtime.lastMethod, 'chat.send');
expect(runtime.lastParams, isNotNull);
expect(runtime.lastParams, isNot(contains('metadata')));
});
test(
'GatewayRuntime uses explicit shared token override for the initial connect handshake',
() async {
@ -669,6 +687,25 @@ class _FakeGatewayRuntimeForChatController extends GatewayRuntime {
}
}
class _FakeGatewayRuntimeForSendChat extends GatewayRuntime {
_FakeGatewayRuntimeForSendChat({required super.store})
: super(identityStore: DeviceIdentityStore(store));
String? lastMethod;
Map<String, dynamic>? lastParams;
@override
Future<dynamic> request(
String method, {
Map<String, dynamic>? params,
Duration timeout = const Duration(seconds: 15),
}) async {
lastMethod = method;
lastParams = params == null ? null : Map<String, dynamic>.from(params);
return const <String, dynamic>{'runId': 'run-send-chat'};
}
}
class FakeGatewayRuntimeServerInternal {
FakeGatewayRuntimeServerInternal._(
this.serverInternal, {

View File

@ -0,0 +1,49 @@
@TestOn('vm')
library;
import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:xworkmate/runtime/runtime_models.dart';
import 'package:xworkmate/web/web_relay_gateway_client.dart';
import 'package:xworkmate/web/web_store.dart';
class _FakeWebRelayGatewayClient extends WebRelayGatewayClient {
_FakeWebRelayGatewayClient() : super(WebStore());
String? lastMethod;
Map<String, dynamic>? lastParams;
@override
bool get isConnected => true;
@override
Future<dynamic> request(
String method, {
Map<String, dynamic>? params,
Duration timeout = const Duration(seconds: 15),
}) async {
lastMethod = method;
lastParams = params == null ? null : Map<String, dynamic>.from(params);
return const <String, dynamic>{'runId': 'relay-run'};
}
}
void main() {
test('WebRelayGatewayClient omits metadata from chat.send payloads', () async {
SharedPreferences.setMockInitialValues(<String, Object>{});
final client = _FakeWebRelayGatewayClient();
final runId = await client.sendChat(
sessionKey: 'thread-1',
message: 'hello',
thinking: 'medium',
metadata: const <String, dynamic>{'threadMode': 'test'},
attachments: const <GatewayChatAttachmentPayload>[],
);
expect(runId, 'relay-run');
expect(client.lastMethod, 'chat.send');
expect(client.lastParams, isNotNull);
expect(client.lastParams, isNot(contains('metadata')));
});
}