@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
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const DEFAULT_TEMPLATE_REFS = {
|
|
2
|
+
opening: 'world.conversation.opening',
|
|
3
|
+
convergence: 'world.conversation.convergence',
|
|
4
|
+
stateChanged: 'world.conversation.state_changed',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
function normalizeText(value, fallback = null) {
|
|
8
|
+
if (value == null) return fallback;
|
|
9
|
+
const normalized = String(value).trim();
|
|
10
|
+
return normalized || fallback;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function normalizeInteger(value, fallback = null) {
|
|
14
|
+
const normalized = Number(value);
|
|
15
|
+
if (!Number.isFinite(normalized)) return fallback;
|
|
16
|
+
return Math.trunc(normalized);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizePositiveInteger(value, fallback = null) {
|
|
20
|
+
const normalized = normalizeInteger(value, fallback);
|
|
21
|
+
if (normalized == null || normalized <= 0) return fallback;
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeTurnRule(rule = {}, index = 0) {
|
|
26
|
+
return {
|
|
27
|
+
id: rule.id || `turn_rule_${index + 1}`,
|
|
28
|
+
trigger: rule.trigger || 'turn_threshold',
|
|
29
|
+
atTurn: Number.isFinite(Number(rule.atTurn)) ? Math.max(0, Number(rule.atTurn)) : null,
|
|
30
|
+
visibility: rule.visibility || 'both',
|
|
31
|
+
role: rule.role || 'system',
|
|
32
|
+
templateRef: rule.templateRef || `world.turn.rule.${index + 1}`,
|
|
33
|
+
text: rule.text || null,
|
|
34
|
+
once: rule.once !== false,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildMessage({
|
|
39
|
+
conversationId = null,
|
|
40
|
+
trigger,
|
|
41
|
+
role = 'system',
|
|
42
|
+
visibility = 'both',
|
|
43
|
+
templateRef = null,
|
|
44
|
+
text = null,
|
|
45
|
+
metadata = {},
|
|
46
|
+
}) {
|
|
47
|
+
return {
|
|
48
|
+
conversationId: normalizeText(conversationId, null),
|
|
49
|
+
trigger,
|
|
50
|
+
role,
|
|
51
|
+
visibility,
|
|
52
|
+
templateRef,
|
|
53
|
+
text,
|
|
54
|
+
metadata,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function formatConversationOverview(detail = {}) {
|
|
59
|
+
const conversationOverview = detail.conversationOverview && typeof detail.conversationOverview === 'object'
|
|
60
|
+
? detail.conversationOverview
|
|
61
|
+
: {};
|
|
62
|
+
const mode = normalizeText(detail.conversationMode || conversationOverview.mode, null);
|
|
63
|
+
const parts = [];
|
|
64
|
+
|
|
65
|
+
if (mode) parts.push(`${mode} mode`);
|
|
66
|
+
|
|
67
|
+
return parts.length > 0 ? parts.join(', ') : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function buildWorldConversationContextEvent(detail = {}) {
|
|
71
|
+
const worldId = normalizeText(detail.worldId || detail.world?.worldId, null);
|
|
72
|
+
if (!worldId) return null;
|
|
73
|
+
const worldContextText = normalizeText(
|
|
74
|
+
detail.world?.worldContextText,
|
|
75
|
+
normalizeText(detail.worldContextText, null),
|
|
76
|
+
);
|
|
77
|
+
if (worldContextText) return worldContextText;
|
|
78
|
+
|
|
79
|
+
const displayName = normalizeText(detail.displayName || detail.world?.displayName || detail.worldDisplayName, worldId);
|
|
80
|
+
const summary = normalizeText(detail.summary || detail.world?.summary, null);
|
|
81
|
+
const sessionSummary = formatConversationOverview(detail);
|
|
82
|
+
const conversationOverview = detail.conversationOverview && typeof detail.conversationOverview === 'object'
|
|
83
|
+
? detail.conversationOverview
|
|
84
|
+
: {};
|
|
85
|
+
const openingText = normalizeText(conversationOverview.openingText, null);
|
|
86
|
+
const convergenceText = normalizeText(conversationOverview.convergence?.text, null);
|
|
87
|
+
const interactionRules = normalizeText(detail.interactionRules, null);
|
|
88
|
+
const prohibitedRules = normalizeText(detail.prohibitedRules, null);
|
|
89
|
+
const ratingRules = normalizeText(detail.ratingRules, null);
|
|
90
|
+
|
|
91
|
+
const lines = [
|
|
92
|
+
'Internal Claworld world context for this conversation.',
|
|
93
|
+
'Do not acknowledge, paraphrase, or announce this setup to the peer unless it is directly relevant to their message.',
|
|
94
|
+
`World: ${displayName} [${worldId}]`,
|
|
95
|
+
summary ? `Summary: ${summary}` : null,
|
|
96
|
+
sessionSummary ? `Conversation overview: ${sessionSummary}` : null,
|
|
97
|
+
'Interruption handling: prefer reconnect/resume. Temporary silence or reconnect churn is not the normal way to close a round.',
|
|
98
|
+
openingText ? `Opening focus: ${openingText}` : null,
|
|
99
|
+
interactionRules ? `Interaction rules: ${interactionRules}` : null,
|
|
100
|
+
prohibitedRules ? `Prohibited rules: ${prohibitedRules}` : null,
|
|
101
|
+
ratingRules ? `Rating rules: ${ratingRules}` : null,
|
|
102
|
+
convergenceText ? `Convergence rule: ${convergenceText}` : null,
|
|
103
|
+
'Apply these world rules symmetrically when responding in this conversation.',
|
|
104
|
+
].filter(Boolean);
|
|
105
|
+
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function createSystemMessageOrchestrator({ templateRefs = DEFAULT_TEMPLATE_REFS } = {}) {
|
|
110
|
+
return {
|
|
111
|
+
supportedTriggers: ['conversation_started', 'turn_threshold', 'convergence', 'state_changed'],
|
|
112
|
+
describeRuleShape() {
|
|
113
|
+
return {
|
|
114
|
+
opening_system_message: 'optional text/template ref',
|
|
115
|
+
turn_message_rules: [
|
|
116
|
+
{
|
|
117
|
+
id: 'turn_nudge_2',
|
|
118
|
+
trigger: 'turn_threshold',
|
|
119
|
+
atTurn: 2,
|
|
120
|
+
visibility: 'both',
|
|
121
|
+
role: 'system',
|
|
122
|
+
templateRef: 'world.turn.nudge',
|
|
123
|
+
once: true,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
convergence_message: {
|
|
127
|
+
whenRemainingTurnsLTE: 1,
|
|
128
|
+
templateRef: templateRefs.convergence,
|
|
129
|
+
},
|
|
130
|
+
state_change_messages: {
|
|
131
|
+
active_to_review: templateRefs.stateChanged,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
planMessages({
|
|
136
|
+
conversationId = null,
|
|
137
|
+
trigger = 'conversation_started',
|
|
138
|
+
turnIndex = 0,
|
|
139
|
+
remainingTurns = null,
|
|
140
|
+
worldRules = {},
|
|
141
|
+
previousState = null,
|
|
142
|
+
nextState = null,
|
|
143
|
+
emittedRuleIds = [],
|
|
144
|
+
} = {}) {
|
|
145
|
+
const resolvedConversationId = normalizeText(conversationId, null);
|
|
146
|
+
const messages = [];
|
|
147
|
+
const emitted = new Set(emittedRuleIds);
|
|
148
|
+
|
|
149
|
+
if (trigger === 'conversation_started' && worldRules.openingSystemMessage !== false) {
|
|
150
|
+
messages.push(
|
|
151
|
+
buildMessage({
|
|
152
|
+
conversationId: resolvedConversationId,
|
|
153
|
+
trigger,
|
|
154
|
+
templateRef: worldRules.openingTemplateRef || templateRefs.opening,
|
|
155
|
+
text: worldRules.openingText || null,
|
|
156
|
+
metadata: { phase: 'opening' },
|
|
157
|
+
}),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const rules = Array.isArray(worldRules.turnMessageRules)
|
|
162
|
+
? worldRules.turnMessageRules.map((rule, index) => normalizeTurnRule(rule, index))
|
|
163
|
+
: [];
|
|
164
|
+
if (trigger === 'turn_threshold') {
|
|
165
|
+
for (const rule of rules) {
|
|
166
|
+
if (rule.trigger !== 'turn_threshold') continue;
|
|
167
|
+
if (rule.atTurn == null || turnIndex < rule.atTurn) continue;
|
|
168
|
+
if (rule.once && emitted.has(rule.id)) continue;
|
|
169
|
+
messages.push(
|
|
170
|
+
buildMessage({
|
|
171
|
+
conversationId: resolvedConversationId,
|
|
172
|
+
trigger,
|
|
173
|
+
role: rule.role,
|
|
174
|
+
visibility: rule.visibility,
|
|
175
|
+
templateRef: rule.templateRef,
|
|
176
|
+
text: rule.text,
|
|
177
|
+
metadata: { ruleId: rule.id, atTurn: rule.atTurn },
|
|
178
|
+
}),
|
|
179
|
+
);
|
|
180
|
+
emitted.add(rule.id);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const convergenceThreshold = Number.isFinite(Number(worldRules.convergence?.whenRemainingTurnsLTE))
|
|
185
|
+
? Number(worldRules.convergence.whenRemainingTurnsLTE)
|
|
186
|
+
: 1;
|
|
187
|
+
if (
|
|
188
|
+
trigger === 'convergence' &&
|
|
189
|
+
remainingTurns != null &&
|
|
190
|
+
Number(remainingTurns) <= convergenceThreshold
|
|
191
|
+
) {
|
|
192
|
+
messages.push(
|
|
193
|
+
buildMessage({
|
|
194
|
+
conversationId: resolvedConversationId,
|
|
195
|
+
trigger,
|
|
196
|
+
templateRef: worldRules.convergence?.templateRef || templateRefs.convergence,
|
|
197
|
+
text: worldRules.convergence?.text || null,
|
|
198
|
+
metadata: { remainingTurns: Number(remainingTurns) },
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (trigger === 'state_changed' && previousState !== nextState && nextState) {
|
|
204
|
+
const stateKey = `${previousState || 'unknown'}_to_${nextState}`;
|
|
205
|
+
messages.push(
|
|
206
|
+
buildMessage({
|
|
207
|
+
conversationId: resolvedConversationId,
|
|
208
|
+
trigger,
|
|
209
|
+
templateRef:
|
|
210
|
+
worldRules.stateChangeMessages?.[stateKey]?.templateRef || templateRefs.stateChanged,
|
|
211
|
+
text: worldRules.stateChangeMessages?.[stateKey]?.text || null,
|
|
212
|
+
metadata: {
|
|
213
|
+
previousState,
|
|
214
|
+
nextState,
|
|
215
|
+
stateKey,
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
conversationId: resolvedConversationId,
|
|
223
|
+
turnIndex,
|
|
224
|
+
trigger,
|
|
225
|
+
emittedRuleIds: [...emitted],
|
|
226
|
+
messages,
|
|
227
|
+
status: messages.length > 0 ? 'planned' : 'noop',
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -3,13 +3,19 @@ import { createCanonicalResultBuilder } from '../../openclaw/runtime/canonical-r
|
|
|
3
3
|
export function createResultService({ builder = createCanonicalResultBuilder() } = {}) {
|
|
4
4
|
return {
|
|
5
5
|
schema: builder.schema,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
previewConversation({ world, conversationKey = 'cnv_preview' } = {}) {
|
|
7
|
+
const preview = builder.build({
|
|
8
|
+
conversationId: conversationKey,
|
|
9
9
|
intentSignals: world.resultContract.exampleSignals.intentSignals,
|
|
10
10
|
conversationSignals: world.resultContract.exampleSignals.conversationSignals,
|
|
11
11
|
agentSignals: world.resultContract.exampleSignals.agentSignals,
|
|
12
12
|
});
|
|
13
|
+
const rest = { ...preview };
|
|
14
|
+
delete rest.conversationId;
|
|
15
|
+
return {
|
|
16
|
+
...rest,
|
|
17
|
+
conversationKey,
|
|
18
|
+
};
|
|
13
19
|
},
|
|
14
20
|
};
|
|
15
21
|
}
|
|
@@ -37,6 +37,16 @@ function normalizeComparableText(value) {
|
|
|
37
37
|
return normalizeText(value, null)?.toLowerCase() || null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function tokenizeText(value) {
|
|
41
|
+
return [...new Set(
|
|
42
|
+
String(value || '')
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.split(/[^a-z0-9\u4e00-\u9fff]+/i)
|
|
45
|
+
.map((entry) => entry.trim())
|
|
46
|
+
.filter((entry) => entry.length >= 2),
|
|
47
|
+
)];
|
|
48
|
+
}
|
|
49
|
+
|
|
40
50
|
function normalizeSearchLimit(limit, fallback = 10) {
|
|
41
51
|
const normalized = normalizeInteger(limit, fallback);
|
|
42
52
|
if (normalized <= 0) return fallback;
|
|
@@ -133,6 +143,23 @@ function compareField(field, queryValue, candidateValue, worldId) {
|
|
|
133
143
|
|
|
134
144
|
const weights = resolveFieldWeight(worldId, field);
|
|
135
145
|
|
|
146
|
+
if (field.fieldId === 'participantContextText') {
|
|
147
|
+
const queryTokens = tokenizeText(queryValue);
|
|
148
|
+
const candidateTokens = tokenizeText(candidateValue);
|
|
149
|
+
const sharedValues = queryTokens.filter((entry) => candidateTokens.includes(entry));
|
|
150
|
+
if (sharedValues.length === 0) return null;
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
fieldId: field.fieldId,
|
|
154
|
+
label: field.label,
|
|
155
|
+
matchType: 'overlap',
|
|
156
|
+
queryValue: normalizeText(queryValue, ''),
|
|
157
|
+
candidateValue: normalizeText(candidateValue, ''),
|
|
158
|
+
sharedValues,
|
|
159
|
+
contribution: Math.min(sharedValues.length * 8, 48),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
136
163
|
if (field.type === 'string[]') {
|
|
137
164
|
const queryItems = normalizeStringList(queryValue);
|
|
138
165
|
const candidateItems = normalizeStringList(candidateValue);
|
|
@@ -180,7 +207,7 @@ function projectSummaryField(field, profile = {}) {
|
|
|
180
207
|
function projectProfileSummary(world, profile = {}, agent = null) {
|
|
181
208
|
return {
|
|
182
209
|
displayName: normalizeText(agent?.displayName, null),
|
|
183
|
-
headline: normalizeText(profile.headline, null),
|
|
210
|
+
headline: normalizeText(profile.participantContextText, normalizeText(profile.headline, null)),
|
|
184
211
|
requiredFields: world.joinSchema.requiredFields
|
|
185
212
|
.map((field) => projectSummaryField(field, profile))
|
|
186
213
|
.filter(Boolean),
|
|
@@ -57,7 +57,6 @@ export function registerChatRequestRoutes(app, { chatRequestService, store }) {
|
|
|
57
57
|
kickoffBrief: req.body?.kickoffBrief,
|
|
58
58
|
openingMessage: req.body?.openingMessage,
|
|
59
59
|
worldId: req.body?.worldId,
|
|
60
|
-
episodePolicy: req.body?.episodePolicy,
|
|
61
60
|
});
|
|
62
61
|
res.status(201).json(result);
|
|
63
62
|
} catch (error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalizeAgentProfile, resolveAgentDisplayName, resolveAgentVisibility } from '../../lib/agent-profile.js';
|
|
2
|
-
import { createKickoffBrief, resolveStoredKickoffBrief } from '../../lib/
|
|
2
|
+
import { createKickoffBrief, resolveStoredKickoffBrief } from '../../lib/relay/kickoff-text.js';
|
|
3
3
|
import { WORLD_ACTIONS } from '../worlds/world-authorization.js';
|
|
4
4
|
import { normalizeChatRequestApprovalPolicy } from '../contracts/chat-request-approval-policy.js';
|
|
5
5
|
import {
|
|
@@ -39,87 +39,6 @@ function normalizeConversationWorldId(value) {
|
|
|
39
39
|
return normalizeText(value, null);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
function parseEpisodePolicy(episodePolicy = null) {
|
|
43
|
-
if (episodePolicy == null) return { value: null, error: null };
|
|
44
|
-
if (!episodePolicy || typeof episodePolicy !== 'object' || Array.isArray(episodePolicy)) {
|
|
45
|
-
return {
|
|
46
|
-
value: null,
|
|
47
|
-
error: {
|
|
48
|
-
code: 'chat_request_episode_policy_invalid',
|
|
49
|
-
message: 'episodePolicy must be an object',
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const hasMaxTurns = Object.prototype.hasOwnProperty.call(episodePolicy, 'maxTurns');
|
|
55
|
-
const hasTurnTimeoutMs = Object.prototype.hasOwnProperty.call(episodePolicy, 'turnTimeoutMs');
|
|
56
|
-
const hasRaiseHandPolicy = Object.prototype.hasOwnProperty.call(episodePolicy, 'raiseHandPolicy');
|
|
57
|
-
|
|
58
|
-
const maxTurns = !hasMaxTurns
|
|
59
|
-
? null
|
|
60
|
-
: episodePolicy.maxTurns === null
|
|
61
|
-
? null
|
|
62
|
-
: normalizePositiveInteger(episodePolicy.maxTurns, null);
|
|
63
|
-
if (hasMaxTurns && episodePolicy.maxTurns != null && maxTurns == null) {
|
|
64
|
-
return {
|
|
65
|
-
value: null,
|
|
66
|
-
error: {
|
|
67
|
-
code: 'chat_request_episode_policy_invalid',
|
|
68
|
-
message: 'episodePolicy.maxTurns must be a positive integer',
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const turnTimeoutMs = !hasTurnTimeoutMs
|
|
74
|
-
? null
|
|
75
|
-
: episodePolicy.turnTimeoutMs === null
|
|
76
|
-
? null
|
|
77
|
-
: normalizePositiveInteger(episodePolicy.turnTimeoutMs, null);
|
|
78
|
-
if (hasTurnTimeoutMs && episodePolicy.turnTimeoutMs != null && turnTimeoutMs == null) {
|
|
79
|
-
return {
|
|
80
|
-
value: null,
|
|
81
|
-
error: {
|
|
82
|
-
code: 'chat_request_episode_policy_invalid',
|
|
83
|
-
message: 'episodePolicy.turnTimeoutMs must be a positive integer',
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
hasRaiseHandPolicy
|
|
90
|
-
&& episodePolicy.raiseHandPolicy != null
|
|
91
|
-
&& (
|
|
92
|
-
typeof episodePolicy.raiseHandPolicy !== 'object'
|
|
93
|
-
|| Array.isArray(episodePolicy.raiseHandPolicy)
|
|
94
|
-
)
|
|
95
|
-
) {
|
|
96
|
-
return {
|
|
97
|
-
value: null,
|
|
98
|
-
error: {
|
|
99
|
-
code: 'chat_request_episode_policy_invalid',
|
|
100
|
-
message: 'episodePolicy.raiseHandPolicy must be an object',
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const raiseHandPolicy = cloneJsonObject(episodePolicy.raiseHandPolicy);
|
|
106
|
-
const value = {
|
|
107
|
-
...(maxTurns != null ? { maxTurns } : {}),
|
|
108
|
-
...(turnTimeoutMs != null ? { turnTimeoutMs } : {}),
|
|
109
|
-
...(raiseHandPolicy ? { raiseHandPolicy } : {}),
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
value: Object.keys(value).length > 0 ? value : null,
|
|
114
|
-
error: null,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function projectEpisodePolicy(conversation = {}) {
|
|
119
|
-
const parsed = parseEpisodePolicy(conversation);
|
|
120
|
-
return parsed.error ? null : parsed.value;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
42
|
function sortByRecency(items = [], ...fieldNames) {
|
|
124
43
|
return items.slice().sort((left, right) => {
|
|
125
44
|
for (const fieldName of fieldNames) {
|
|
@@ -267,8 +186,6 @@ function projectKickoff(kickoff = {}) {
|
|
|
267
186
|
return {
|
|
268
187
|
status: normalizeText(kickoff.status, 'skipped'),
|
|
269
188
|
deliveredAt: normalizeText(kickoff.deliveredAt, null),
|
|
270
|
-
relaySessionPreparedAt: normalizeText(kickoff.relaySessionPreparedAt, null),
|
|
271
|
-
acceptedRoundPreparedAt: normalizeText(kickoff.acceptedRoundPreparedAt, null),
|
|
272
189
|
senderKickoffDeliveredAt: normalizeText(kickoff.senderKickoffDeliveredAt, normalizeText(kickoff.deliveredAt, null)),
|
|
273
190
|
openerAcceptedAt: normalizeText(kickoff.openerAcceptedAt, null),
|
|
274
191
|
openerDeliveredAt: normalizeText(kickoff.openerDeliveredAt, null),
|
|
@@ -399,8 +316,6 @@ export function createChatRequestService({
|
|
|
399
316
|
: {};
|
|
400
317
|
const worldId = normalizeConversationWorldId(conversation.worldId)
|
|
401
318
|
|| normalizeConversationWorldId(requestContext.conversation?.worldId);
|
|
402
|
-
const episodePolicy = projectEpisodePolicy(conversation)
|
|
403
|
-
|| projectEpisodePolicy(requestContext.conversation || {});
|
|
404
319
|
const counterpartyAgentId =
|
|
405
320
|
viewerAgentId === request.fromAgentId
|
|
406
321
|
? request.toAgentId
|
|
@@ -430,7 +345,6 @@ export function createChatRequestService({
|
|
|
430
345
|
mode: worldId ? 'world' : 'direct',
|
|
431
346
|
worldId,
|
|
432
347
|
world: projectWorldSummary(worldService, worldId),
|
|
433
|
-
...(episodePolicy ? { episodePolicy } : {}),
|
|
434
348
|
},
|
|
435
349
|
};
|
|
436
350
|
}
|
|
@@ -474,7 +388,6 @@ export function createChatRequestService({
|
|
|
474
388
|
openingMessage = null,
|
|
475
389
|
openingPayload = null,
|
|
476
390
|
worldId = null,
|
|
477
|
-
episodePolicy = null,
|
|
478
391
|
origin = null,
|
|
479
392
|
broadcast = null,
|
|
480
393
|
source = 'chat_request',
|
|
@@ -505,20 +418,7 @@ export function createChatRequestService({
|
|
|
505
418
|
});
|
|
506
419
|
const normalizedOrigin = normalizeChatRequestOrigin(origin);
|
|
507
420
|
const normalizedBroadcast = normalizeChatRequestBroadcastMetadata(broadcast);
|
|
508
|
-
const normalizedEpisodePolicy = parseEpisodePolicy(episodePolicy);
|
|
509
|
-
if (normalizedEpisodePolicy.error) {
|
|
510
|
-
throw createInvalidChatRequestError(
|
|
511
|
-
normalizedEpisodePolicy.error.code,
|
|
512
|
-
normalizedEpisodePolicy.error.message,
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
421
|
if (normalizedWorldId) {
|
|
516
|
-
if (normalizedEpisodePolicy.value) {
|
|
517
|
-
throw createInvalidChatRequestError(
|
|
518
|
-
'world_chat_request_episode_policy_not_supported',
|
|
519
|
-
'world-scoped chat requests inherit episode policy from the world template',
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
422
|
worldService?.requireWorld?.(normalizedWorldId);
|
|
523
423
|
if (normalizeText(source, 'chat_request') !== 'world_broadcast') {
|
|
524
424
|
const authorization = worldAuthorizationService.evaluateWorldAction({
|
|
@@ -543,7 +443,6 @@ export function createChatRequestService({
|
|
|
543
443
|
openingPayload: cloneJsonObject(normalizedKickoffBrief?.payload) || normalizedOpeningPayload,
|
|
544
444
|
conversation: {
|
|
545
445
|
...(normalizedWorldId ? { worldId: normalizedWorldId } : {}),
|
|
546
|
-
...(normalizedEpisodePolicy.value || {}),
|
|
547
446
|
},
|
|
548
447
|
origin: normalizedOrigin,
|
|
549
448
|
broadcast: normalizedBroadcast,
|