@xfxstudio/claworld 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -29
- package/openclaw.plugin.json +9 -33
- package/package.json +2 -10
- package/skills/claworld-help/SKILL.md +86 -160
- package/skills/claworld-join-and-chat/SKILL.md +107 -203
- package/skills/claworld-manage-worlds/SKILL.md +75 -392
- package/src/lib/chat-request.js +347 -0
- package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
- package/src/openclaw/index.js +0 -5
- package/src/openclaw/installer/cli.js +14 -16
- package/src/openclaw/installer/core.js +13 -14
- package/src/openclaw/installer/doctor.js +69 -31
- package/src/openclaw/installer/workspace-contract.js +33 -9
- package/src/openclaw/plugin/claworld-channel-plugin.js +156 -625
- package/src/openclaw/plugin/config-schema.js +4 -16
- package/src/openclaw/plugin/managed-config.js +127 -75
- package/src/openclaw/plugin/onboarding.js +7 -3
- package/src/openclaw/plugin/register.js +40 -339
- package/src/openclaw/plugin/relay-client.js +112 -102
- package/src/openclaw/protocol/relay-event-protocol.js +34 -22
- package/src/openclaw/runtime/canonical-result-builder.js +15 -5
- package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
- package/src/openclaw/runtime/feedback-helper.js +3 -2
- package/src/openclaw/runtime/inbound-session-router.js +28 -20
- package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
- package/src/openclaw/runtime/product-shell-helper.js +45 -637
- package/src/openclaw/runtime/runtime-path.js +2 -2
- package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
- package/src/openclaw/runtime/tool-contracts.js +36 -258
- package/src/openclaw/runtime/world-moderation-helper.js +11 -65
- package/src/product-shell/catalog/default-world-catalog.js +15 -33
- package/src/product-shell/contracts/candidate-feed.js +40 -5
- package/src/product-shell/contracts/chat-request-approval-policy.js +3 -3
- package/src/product-shell/contracts/world-manifest.js +134 -161
- package/src/product-shell/contracts/world-orchestration.js +55 -326
- package/src/product-shell/feedback/feedback-routes.js +4 -3
- package/src/product-shell/feedback/feedback-service.js +11 -8
- package/src/product-shell/index.js +6 -7
- package/src/product-shell/matching/matchmaking-service.js +39 -5
- package/src/product-shell/membership/membership-service.js +125 -147
- package/src/product-shell/onboarding/onboarding-service.js +2 -2
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
- package/src/product-shell/orchestration/world-conversation-text.js +231 -0
- package/src/product-shell/results/result-service.js +9 -3
- package/src/product-shell/search/search-service.js +28 -1
- package/src/product-shell/social/chat-request-routes.js +0 -1
- package/src/product-shell/social/chat-request-service.js +1 -102
- package/src/product-shell/worlds/world-admin-service.js +86 -277
- package/src/product-shell/worlds/world-authorization.js +3 -5
- package/src/product-shell/worlds/world-routes.js +8 -38
- package/src/product-shell/worlds/world-service.js +3 -3
- package/src/product-shell/worlds/world-text.js +77 -0
- package/src/lib/runtime-guidance.js +0 -457
- package/src/openclaw/runtime/world-session-startup.js +0 -1
- package/src/product-shell/orchestration/session-orchestrator.js +0 -38
|
@@ -5,6 +5,7 @@ import { buildRuntimeAuthHeaders } from './account-identity.js';
|
|
|
5
5
|
import { createRelayEventProtocol } from '../protocol/relay-event-protocol.js';
|
|
6
6
|
import { createInboundSessionRouter } from '../runtime/inbound-session-router.js';
|
|
7
7
|
import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.js';
|
|
8
|
+
import { normalizeChatRequestInput } from '../../lib/chat-request.js';
|
|
8
9
|
import {
|
|
9
10
|
buildPublicErrorPayload,
|
|
10
11
|
createRuntimeBoundaryError,
|
|
@@ -33,61 +34,19 @@ function normalizeRelayWebSocketUrl(serverUrl) {
|
|
|
33
34
|
|
|
34
35
|
function buildInboundEnvelope(message = {}) {
|
|
35
36
|
const data = message.data || {};
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
session_id: sessionId,
|
|
51
|
-
event_id: eventId,
|
|
52
|
-
from_agent_id: data.fromAgentId || data.targetAgentId || null,
|
|
53
|
-
type: 'system_message',
|
|
54
|
-
payload: { kind: 'session.created', ...data },
|
|
55
|
-
};
|
|
56
|
-
case 'turn.deliver':
|
|
57
|
-
return {
|
|
58
|
-
session_id: sessionId,
|
|
59
|
-
event_id: eventId,
|
|
60
|
-
from_agent_id: data.fromAgentId || data.fromAgent?.agentId || null,
|
|
61
|
-
type: 'message',
|
|
62
|
-
payload: data.payload || {},
|
|
63
|
-
};
|
|
64
|
-
case 'turn.reply':
|
|
65
|
-
return {
|
|
66
|
-
session_id: sessionId,
|
|
67
|
-
event_id: eventId,
|
|
68
|
-
from_agent_id: data.fromAgentId || data.fromAgent?.agentId || null,
|
|
69
|
-
type: 'message',
|
|
70
|
-
payload: data.payload || {},
|
|
71
|
-
};
|
|
72
|
-
case 'turn.timeout':
|
|
73
|
-
return {
|
|
74
|
-
session_id: sessionId,
|
|
75
|
-
event_id: eventId,
|
|
76
|
-
from_agent_id: data.fromAgentId || null,
|
|
77
|
-
type: 'system_message',
|
|
78
|
-
payload: { kind: 'turn.timeout', ...data },
|
|
79
|
-
};
|
|
80
|
-
case 'session.terminated':
|
|
81
|
-
return {
|
|
82
|
-
session_id: sessionId,
|
|
83
|
-
event_id: eventId,
|
|
84
|
-
from_agent_id: data.actorAgentId || null,
|
|
85
|
-
type: 'session_end',
|
|
86
|
-
payload: { kind: 'session.terminated', ...data },
|
|
87
|
-
};
|
|
88
|
-
default:
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
37
|
+
if (message.event !== 'delivery') return null;
|
|
38
|
+
const metadata = data.metadata && typeof data.metadata === 'object' && !Array.isArray(data.metadata)
|
|
39
|
+
? { ...data.metadata }
|
|
40
|
+
: {};
|
|
41
|
+
return {
|
|
42
|
+
eventType: data.eventType || 'delivery',
|
|
43
|
+
deliveryId: data.deliveryId || null,
|
|
44
|
+
sessionKey: data.sessionKey || null,
|
|
45
|
+
payload: data.payload && typeof data.payload === 'object' && !Array.isArray(data.payload)
|
|
46
|
+
? { ...data.payload }
|
|
47
|
+
: {},
|
|
48
|
+
metadata,
|
|
49
|
+
};
|
|
91
50
|
}
|
|
92
51
|
|
|
93
52
|
export class ClaworldRelayClient extends EventEmitter {
|
|
@@ -118,6 +77,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
118
77
|
this.reconnectAttempts = 0;
|
|
119
78
|
this.manualClose = false;
|
|
120
79
|
this.lastDisconnectInfo = null;
|
|
80
|
+
this.acceptedChatRequests = new Map();
|
|
121
81
|
}
|
|
122
82
|
|
|
123
83
|
buildBoundaryContext(extra = null) {
|
|
@@ -176,9 +136,9 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
176
136
|
fallbackTarget: fallbackTarget || this.runtimeConfig.routing.fallbackTarget,
|
|
177
137
|
});
|
|
178
138
|
const runtimeEvent = {
|
|
179
|
-
|
|
139
|
+
eventType: inboundEnvelope.eventType,
|
|
180
140
|
protocol: described,
|
|
181
|
-
inboundEnvelope,
|
|
141
|
+
delivery: inboundEnvelope,
|
|
182
142
|
route,
|
|
183
143
|
raw: message,
|
|
184
144
|
};
|
|
@@ -325,12 +285,14 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
325
285
|
accountId: this.runtimeConfig.accountId,
|
|
326
286
|
agentId,
|
|
327
287
|
clientVersion,
|
|
288
|
+
bridgeProtocol: this.protocol.version,
|
|
328
289
|
});
|
|
329
290
|
this.send({
|
|
330
291
|
type: 'auth',
|
|
331
292
|
agentId,
|
|
332
293
|
credential,
|
|
333
294
|
clientVersion,
|
|
295
|
+
bridgeProtocol: this.protocol.version,
|
|
334
296
|
});
|
|
335
297
|
});
|
|
336
298
|
|
|
@@ -517,7 +479,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
517
479
|
config,
|
|
518
480
|
agentId,
|
|
519
481
|
credential = null,
|
|
520
|
-
clientVersion = 'claworld-plugin/0.1.
|
|
482
|
+
clientVersion = 'claworld-plugin/0.1.5',
|
|
521
483
|
sessionTarget,
|
|
522
484
|
fallbackTarget,
|
|
523
485
|
} = {}) {
|
|
@@ -608,47 +570,84 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
608
570
|
this.send({ type: 'heartbeat' });
|
|
609
571
|
}
|
|
610
572
|
|
|
611
|
-
|
|
612
|
-
const envelope = this.outbound.createReplyEnvelope({
|
|
573
|
+
sendReply({ deliveryId, sessionKey, replyText, source = 'subagent' } = {}) {
|
|
574
|
+
const envelope = this.outbound.createReplyEnvelope({
|
|
575
|
+
deliveryId,
|
|
576
|
+
sessionKey,
|
|
577
|
+
replyText,
|
|
578
|
+
source,
|
|
579
|
+
});
|
|
613
580
|
this.send({
|
|
614
|
-
type: '
|
|
615
|
-
|
|
581
|
+
type: 'reply',
|
|
582
|
+
deliveryId: envelope.deliveryId,
|
|
583
|
+
sessionKey: envelope.sessionKey,
|
|
616
584
|
payload: {
|
|
617
|
-
|
|
618
|
-
source: envelope.source,
|
|
619
|
-
trace: envelope.trace,
|
|
620
|
-
...(envelope.control ? { control: envelope.control } : {}),
|
|
585
|
+
...envelope.payload,
|
|
621
586
|
},
|
|
622
587
|
});
|
|
623
588
|
return envelope;
|
|
624
589
|
}
|
|
625
590
|
|
|
626
|
-
|
|
627
|
-
this.
|
|
591
|
+
replyToDelivery({ deliveryId, sessionKey, replyText, source = 'subagent' } = {}) {
|
|
592
|
+
return this.sendReply({
|
|
593
|
+
deliveryId,
|
|
594
|
+
sessionKey,
|
|
595
|
+
replyText,
|
|
596
|
+
source,
|
|
597
|
+
});
|
|
628
598
|
}
|
|
629
599
|
|
|
630
|
-
async
|
|
631
|
-
|
|
600
|
+
async createChatRequest({ fromAgentId, toAddress, requestContext = {} } = {}) {
|
|
601
|
+
const target = await this.requestJson(`/v1/agents/resolve?address=${encodeURIComponent(toAddress)}`, {
|
|
602
|
+
method: 'GET',
|
|
603
|
+
headers: buildRuntimeAuthHeaders(this.runtimeConfig),
|
|
604
|
+
}, {
|
|
605
|
+
code: 'relay_target_resolve_failed',
|
|
606
|
+
message: 'failed to resolve relay target',
|
|
607
|
+
publicMessage: 'failed to resolve relay target',
|
|
608
|
+
});
|
|
609
|
+
if (target.status >= 400) return target;
|
|
610
|
+
|
|
611
|
+
const normalized = normalizeChatRequestInput({ requestContext, source: 'direct_lookup' });
|
|
612
|
+
return await this.requestJson('/v1/chat-requests', {
|
|
632
613
|
method: 'POST',
|
|
633
614
|
headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
|
|
634
|
-
body: JSON.stringify({
|
|
615
|
+
body: JSON.stringify({
|
|
616
|
+
fromAgentId,
|
|
617
|
+
targetAgentId: target.body?.agentId || target.body?.id || null,
|
|
618
|
+
kickoffBrief: normalized.kickoffBrief || null,
|
|
619
|
+
openingMessage: normalized.openingMessage || null,
|
|
620
|
+
worldId: normalized.conversation?.worldId || null,
|
|
621
|
+
}),
|
|
635
622
|
}, {
|
|
636
623
|
code: 'relay_request_create_failed',
|
|
637
|
-
message: 'failed to create relay
|
|
638
|
-
publicMessage: 'failed to create relay
|
|
624
|
+
message: 'failed to create relay chat request',
|
|
625
|
+
publicMessage: 'failed to create relay chat request',
|
|
639
626
|
});
|
|
640
627
|
}
|
|
641
628
|
|
|
642
|
-
async
|
|
643
|
-
|
|
629
|
+
async acceptChatRequest(requestId, { actorAgentId, ...options } = {}) {
|
|
630
|
+
const result = await this.requestJson(`/v1/chat-requests/${requestId}/accept`, {
|
|
644
631
|
method: 'POST',
|
|
645
632
|
headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
|
|
646
633
|
body: JSON.stringify({ actorAgentId, ...options }),
|
|
647
634
|
}, {
|
|
648
635
|
code: 'relay_request_accept_failed',
|
|
649
|
-
message: 'failed to accept relay
|
|
650
|
-
publicMessage: 'failed to accept relay
|
|
636
|
+
message: 'failed to accept relay chat request',
|
|
637
|
+
publicMessage: 'failed to accept relay chat request',
|
|
651
638
|
});
|
|
639
|
+
if (result.status < 400 && requestId) {
|
|
640
|
+
const kickoff = result.body?.kickoff && typeof result.body.kickoff === 'object' && !Array.isArray(result.body.kickoff)
|
|
641
|
+
? { ...result.body.kickoff }
|
|
642
|
+
: null;
|
|
643
|
+
this.acceptedChatRequests.set(requestId, {
|
|
644
|
+
requestId,
|
|
645
|
+
sessionKey: kickoff?.sessionKey || null,
|
|
646
|
+
conversationKey: kickoff?.conversationKey || null,
|
|
647
|
+
kickoff,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
return result;
|
|
652
651
|
}
|
|
653
652
|
|
|
654
653
|
async deliverMessage({ fromAgentId, toAddress, payload = {}, conversation = {} } = {}) {
|
|
@@ -663,18 +662,6 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
663
662
|
});
|
|
664
663
|
}
|
|
665
664
|
|
|
666
|
-
async createTurn({ sessionId, fromAgentId, payload = {} } = {}) {
|
|
667
|
-
return await this.requestJson(`/v1/sessions/${sessionId}/turns`, {
|
|
668
|
-
method: 'POST',
|
|
669
|
-
headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
|
|
670
|
-
body: JSON.stringify({ fromAgentId, payload }),
|
|
671
|
-
}, {
|
|
672
|
-
code: 'relay_turn_create_failed',
|
|
673
|
-
message: 'failed to create relay turn',
|
|
674
|
-
publicMessage: 'failed to create relay turn',
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
|
|
678
665
|
waitFor(eventNameOrPredicate, timeoutMs = 8000) {
|
|
679
666
|
const isPredicate = typeof eventNameOrPredicate === 'function';
|
|
680
667
|
const predicate = isPredicate
|
|
@@ -700,7 +687,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
700
687
|
});
|
|
701
688
|
}
|
|
702
689
|
|
|
703
|
-
async
|
|
690
|
+
async establishConversation({ fromAgentId, toAddress, requestContext = {}, openingPayload = {} } = {}) {
|
|
704
691
|
const normalizedRequestContext = requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
|
|
705
692
|
? { ...requestContext }
|
|
706
693
|
: {};
|
|
@@ -714,32 +701,55 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
714
701
|
}
|
|
715
702
|
}
|
|
716
703
|
|
|
717
|
-
const requestResult = await this.
|
|
704
|
+
const requestResult = await this.createChatRequest({
|
|
718
705
|
fromAgentId,
|
|
719
706
|
toAddress,
|
|
720
707
|
requestContext: normalizedRequestContext,
|
|
721
708
|
});
|
|
722
709
|
if (requestResult.status !== 201) {
|
|
723
|
-
throw new Error(`failed to create
|
|
710
|
+
throw new Error(`failed to create chat request: ${JSON.stringify(requestResult.body)}`);
|
|
724
711
|
}
|
|
725
712
|
const requestId = requestResult.body.requestId;
|
|
726
713
|
return {
|
|
727
714
|
requestId,
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
715
|
+
sessionKey: null,
|
|
716
|
+
conversationKey: null,
|
|
717
|
+
openAcceptedConversation: async ({ timeoutMs = 15000 } = {}) => {
|
|
718
|
+
const acceptedRequest = this.acceptedChatRequests.get(requestId) || null;
|
|
719
|
+
if (acceptedRequest?.kickoff || acceptedRequest?.conversationKey || acceptedRequest?.sessionKey) {
|
|
720
|
+
return {
|
|
721
|
+
requestId,
|
|
722
|
+
sessionKey: acceptedRequest?.sessionKey || acceptedRequest?.kickoff?.sessionKey || null,
|
|
723
|
+
conversationKey: acceptedRequest?.conversationKey || acceptedRequest?.kickoff?.conversationKey || null,
|
|
724
|
+
kickoff: acceptedRequest?.kickoff || null,
|
|
725
|
+
delivery: null,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
const deliveryEvent = await this.waitFor(
|
|
729
|
+
(event) => event.event === 'delivery'
|
|
730
|
+
&& (
|
|
731
|
+
event.data?.metadata?.kickoffRequestId === requestId
|
|
732
|
+
),
|
|
734
733
|
timeoutMs,
|
|
735
734
|
);
|
|
736
|
-
const
|
|
737
|
-
?
|
|
738
|
-
:
|
|
735
|
+
const delivery = deliveryEvent?.data && typeof deliveryEvent.data === 'object' && !Array.isArray(deliveryEvent.data)
|
|
736
|
+
? deliveryEvent.data
|
|
737
|
+
: {};
|
|
738
|
+
const metadata = delivery.metadata && typeof delivery.metadata === 'object' && !Array.isArray(delivery.metadata)
|
|
739
|
+
? delivery.metadata
|
|
740
|
+
: {};
|
|
741
|
+
const kickoff = {
|
|
742
|
+
status: 'delivered',
|
|
743
|
+
deliveryId: delivery.deliveryId || null,
|
|
744
|
+
sessionKey: delivery.sessionKey || metadata.sessionKey || null,
|
|
745
|
+
conversationKey: delivery.conversationKey || null,
|
|
746
|
+
};
|
|
739
747
|
return {
|
|
740
748
|
requestId,
|
|
741
|
-
|
|
749
|
+
sessionKey: kickoff.sessionKey,
|
|
750
|
+
conversationKey: kickoff.conversationKey,
|
|
742
751
|
kickoff,
|
|
752
|
+
delivery: deliveryEvent,
|
|
743
753
|
};
|
|
744
754
|
},
|
|
745
755
|
};
|
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
export const CLAWORLD_PLUGIN_BRIDGE_PROTOCOL = 'claworld.delivery_reply.v1';
|
|
2
|
+
|
|
3
|
+
const DELIVERY_EVENT_TYPE = 'delivery';
|
|
4
|
+
|
|
5
|
+
function normalizeText(value, fallback = null) {
|
|
6
|
+
if (value == null) return fallback;
|
|
7
|
+
const normalized = String(value).trim();
|
|
8
|
+
return normalized || fallback;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function normalizePayload(payload = null) {
|
|
12
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return {};
|
|
13
|
+
return { ...payload };
|
|
14
|
+
}
|
|
9
15
|
|
|
10
16
|
export function createRelayEventProtocol() {
|
|
11
17
|
return {
|
|
12
|
-
version:
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
version: CLAWORLD_PLUGIN_BRIDGE_PROTOCOL,
|
|
19
|
+
eventTypes: [DELIVERY_EVENT_TYPE],
|
|
20
|
+
requiredEnvelopeFields: ['eventType', 'deliveryId', 'sessionKey', 'payload'],
|
|
15
21
|
describeEvent(event = {}) {
|
|
22
|
+
const payload = normalizePayload(event.payload);
|
|
23
|
+
const missing = [];
|
|
24
|
+
if (normalizeText(event.eventType, null) !== DELIVERY_EVENT_TYPE) {
|
|
25
|
+
missing.push('eventType');
|
|
26
|
+
}
|
|
27
|
+
if (!normalizeText(event.deliveryId, null)) {
|
|
28
|
+
missing.push('deliveryId');
|
|
29
|
+
}
|
|
30
|
+
if (!normalizeText(event.sessionKey, null)) {
|
|
31
|
+
missing.push('sessionKey');
|
|
32
|
+
}
|
|
33
|
+
if (!normalizeText(payload.text, null)) {
|
|
34
|
+
missing.push('payload.text');
|
|
35
|
+
}
|
|
16
36
|
return {
|
|
17
|
-
ok:
|
|
18
|
-
missing
|
|
19
|
-
role:
|
|
37
|
+
ok: missing.length === 0,
|
|
38
|
+
missing,
|
|
39
|
+
role: 'delivery',
|
|
20
40
|
};
|
|
21
41
|
},
|
|
22
42
|
};
|
|
23
43
|
}
|
|
24
|
-
|
|
25
|
-
function inferRoleFromType(type) {
|
|
26
|
-
if (type === 'system_message') return 'system';
|
|
27
|
-
if (type === 'raise_hand') return 'control';
|
|
28
|
-
if (type === 'message') return 'agent';
|
|
29
|
-
if (type === 'session_result_ready') return 'system';
|
|
30
|
-
return 'control';
|
|
31
|
-
}
|
|
@@ -34,12 +34,16 @@ function buildSummary({ matchScore, riskCount, intentCount, conversationCount, a
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function pickRecommendation({ matchScore, normalizedSignals, risks }) {
|
|
37
|
-
const
|
|
37
|
+
const readySignals = normalizedSignals.filter(
|
|
38
|
+
(signal) => signal.type === 'next_step_ready'
|
|
39
|
+
|| signal.type === 'human_handoff_ready'
|
|
40
|
+
|| signal.type === 'conversation_complete',
|
|
41
|
+
).length;
|
|
38
42
|
const hardBlock = normalizedSignals.some(
|
|
39
43
|
(signal) => signal.type === 'block' || signal.metadata?.hardBlock === true || signal.risk >= 0.85,
|
|
40
44
|
);
|
|
41
45
|
if (hardBlock) return 'pass';
|
|
42
|
-
if (
|
|
46
|
+
if (readySignals >= 2 && (matchScore == null || matchScore >= 0.45) && risks.length <= 1) {
|
|
43
47
|
return 'continue';
|
|
44
48
|
}
|
|
45
49
|
if (matchScore != null && matchScore >= 0.65 && risks.length === 0) {
|
|
@@ -58,9 +62,15 @@ export function createCanonicalResultBuilder() {
|
|
|
58
62
|
summary: 'string',
|
|
59
63
|
risks: 'string[]',
|
|
60
64
|
recommendation: 'continue|pass|review',
|
|
61
|
-
evidence: '
|
|
65
|
+
evidence: 'ConversationMessage[]',
|
|
62
66
|
},
|
|
63
|
-
build({
|
|
67
|
+
build({
|
|
68
|
+
conversationId = null,
|
|
69
|
+
intentSignals = [],
|
|
70
|
+
conversationSignals = [],
|
|
71
|
+
agentSignals = [],
|
|
72
|
+
} = {}) {
|
|
73
|
+
const resolvedConversationId = conversationId || null;
|
|
64
74
|
const normalizedIntentSignals = intentSignals.map((signal, index) =>
|
|
65
75
|
normalizeSignal(signal, index, 'intent'),
|
|
66
76
|
);
|
|
@@ -92,7 +102,7 @@ export function createCanonicalResultBuilder() {
|
|
|
92
102
|
}));
|
|
93
103
|
|
|
94
104
|
return {
|
|
95
|
-
|
|
105
|
+
conversationId: resolvedConversationId,
|
|
96
106
|
match_score: matchScore,
|
|
97
107
|
summary: buildSummary({
|
|
98
108
|
matchScore,
|
|
@@ -4,23 +4,19 @@ export function createDemoSessionBootstrap() {
|
|
|
4
4
|
users: ['demo-a', 'demo-b'],
|
|
5
5
|
world: 'dating-demo-world',
|
|
6
6
|
allowDemoToken: true,
|
|
7
|
-
maxTurns: 6,
|
|
8
7
|
},
|
|
9
8
|
createLaunchPlan({
|
|
10
9
|
sessionGoal = 'run one stable A2A demo loop',
|
|
11
10
|
users,
|
|
12
11
|
world,
|
|
13
|
-
maxTurns,
|
|
14
12
|
openingMessage = 'You are entering demo mode. Try to complete one stable match loop.',
|
|
15
13
|
} = {}) {
|
|
16
14
|
const resolvedUsers = Array.isArray(users) && users.length > 0 ? users : this.defaults.users;
|
|
17
15
|
const resolvedWorld = world || this.defaults.world;
|
|
18
|
-
const resolvedMaxTurns = Number.isFinite(Number(maxTurns)) ? Number(maxTurns) : this.defaults.maxTurns;
|
|
19
16
|
return {
|
|
20
17
|
sessionGoal,
|
|
21
18
|
world: resolvedWorld,
|
|
22
19
|
users: resolvedUsers,
|
|
23
|
-
maxTurns: resolvedMaxTurns,
|
|
24
20
|
openingMessage,
|
|
25
21
|
steps: [
|
|
26
22
|
'load demo users',
|
|
@@ -110,8 +110,9 @@ export async function submitFeedbackReport({
|
|
|
110
110
|
reproductionSteps,
|
|
111
111
|
context: {
|
|
112
112
|
worldId: normalizeText(normalizedContext.worldId, null),
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
conversationKey: normalizeText(normalizedContext.conversationKey, null),
|
|
114
|
+
turnId: normalizeText(normalizedContext.turnId, null),
|
|
115
|
+
deliveryId: normalizeText(normalizedContext.deliveryId, null),
|
|
115
116
|
targetAgentId: normalizeText(normalizedContext.targetAgentId, null),
|
|
116
117
|
targetAgentCode: normalizeText(normalizedContext.targetAgentCode, null),
|
|
117
118
|
tags: normalizeStringList(normalizedContext.tags),
|
|
@@ -1,35 +1,43 @@
|
|
|
1
1
|
import { OPENCLAW_RUNTIME_PATH, createRuntimePathTrace } from './runtime-path.js';
|
|
2
2
|
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
function normalizeText(value, fallback = null) {
|
|
4
|
+
if (value == null) return fallback;
|
|
5
|
+
const normalized = String(value).trim();
|
|
6
|
+
return normalized || fallback;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function normalizePayload(payload = null) {
|
|
10
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return {};
|
|
11
|
+
return { ...payload };
|
|
6
12
|
}
|
|
7
13
|
|
|
8
14
|
export function createInboundSessionRouter() {
|
|
9
15
|
return {
|
|
10
16
|
runtimePath: OPENCLAW_RUNTIME_PATH,
|
|
11
17
|
routeInboundEvent(event = {}, options = {}) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
18
|
+
const eventType = normalizeText(event.eventType || event.type, null);
|
|
19
|
+
const deliveryId = normalizeText(event.deliveryId || event.event_id || event.eventId, null);
|
|
20
|
+
const sessionKey = normalizeText(event.sessionKey, null);
|
|
21
|
+
const payload = normalizePayload(event.payload);
|
|
15
22
|
return {
|
|
16
|
-
action: '
|
|
17
|
-
target,
|
|
18
|
-
fallbackTarget,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
preserveFields: ['session_id', 'event_id', 'from_agent_id'],
|
|
23
|
+
action: 'route_delivery',
|
|
24
|
+
target: normalizeText(options.sessionTarget, 'mainagent'),
|
|
25
|
+
fallbackTarget: normalizeText(options.fallbackTarget, 'mainagent'),
|
|
26
|
+
eventType,
|
|
27
|
+
deliveryId,
|
|
28
|
+
sessionKey,
|
|
29
|
+
payload,
|
|
30
|
+
metadata: event.metadata && typeof event.metadata === 'object' && !Array.isArray(event.metadata)
|
|
31
|
+
? { ...event.metadata }
|
|
32
|
+
: {},
|
|
27
33
|
trace: createRuntimePathTrace({
|
|
28
|
-
|
|
29
|
-
eventId:
|
|
34
|
+
sessionKey,
|
|
35
|
+
eventId: deliveryId,
|
|
30
36
|
direction: 'inbound',
|
|
31
37
|
}),
|
|
32
|
-
status:
|
|
38
|
+
status: eventType === 'delivery' && deliveryId && sessionKey && normalizeText(payload.text, null)
|
|
39
|
+
? 'resolved'
|
|
40
|
+
: 'invalid',
|
|
33
41
|
};
|
|
34
42
|
},
|
|
35
43
|
};
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
function normalizeText(value, fallback = null) {
|
|
2
|
+
if (value == null) return fallback;
|
|
3
|
+
const normalized = String(value).trim();
|
|
4
|
+
return normalized || fallback;
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export function createOutboundSessionBridge() {
|
|
4
8
|
return {
|
|
5
|
-
createReplyEnvelope({
|
|
9
|
+
createReplyEnvelope({
|
|
10
|
+
deliveryId,
|
|
11
|
+
sessionKey,
|
|
12
|
+
replyText,
|
|
13
|
+
source = 'subagent',
|
|
14
|
+
} = {}) {
|
|
15
|
+
const normalizedReplyText = normalizeText(replyText, '');
|
|
16
|
+
const normalizedDeliveryId = normalizeText(deliveryId, null);
|
|
17
|
+
const normalizedSessionKey = normalizeText(sessionKey, null);
|
|
6
18
|
return {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
eventType: 'reply',
|
|
20
|
+
deliveryId: normalizedDeliveryId,
|
|
21
|
+
sessionKey: normalizedSessionKey,
|
|
22
|
+
payload: {
|
|
23
|
+
text: normalizedReplyText,
|
|
24
|
+
source: normalizeText(source, 'subagent'),
|
|
25
|
+
},
|
|
14
26
|
};
|
|
15
27
|
},
|
|
16
28
|
};
|