ocuclaw 0.1.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 +25 -0
- package/dist/config/runtime-config.js +165 -0
- package/dist/domain/activity-status-adapter.js +1041 -0
- package/dist/domain/conversation-state.js +516 -0
- package/dist/domain/debug-store.js +700 -0
- package/dist/domain/message-emoji-filter.js +249 -0
- package/dist/domain/readability-system-prompt.js +17 -0
- package/dist/even-ai/even-ai-endpoint.js +938 -0
- package/dist/even-ai/even-ai-model-hook.js +80 -0
- package/dist/even-ai/even-ai-router.js +98 -0
- package/dist/even-ai/even-ai-run-waiter.js +265 -0
- package/dist/even-ai/even-ai-settings-store.js +365 -0
- package/dist/gateway/gateway-bridge.js +175 -0
- package/dist/gateway/openclaw-client.js +1570 -0
- package/dist/index.js +38 -0
- package/dist/runtime/downstream-handler.js +2747 -0
- package/dist/runtime/downstream-server.js +1565 -0
- package/dist/runtime/ocuclaw-settings-store.js +237 -0
- package/dist/runtime/protocol-adapter.js +378 -0
- package/dist/runtime/relay-core.js +1977 -0
- package/dist/runtime/relay-service.js +146 -0
- package/dist/runtime/session-service.js +1026 -0
- package/dist/runtime/upstream-runtime.js +931 -0
- package/openclaw.plugin.json +95 -0
- package/package.json +36 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
|
|
4
|
+
const STORE_VERSION = 1;
|
|
5
|
+
const STORE_FILENAME = "ocuclaw-settings.json";
|
|
6
|
+
|
|
7
|
+
function normalizeLogger(logger) {
|
|
8
|
+
if (!logger || typeof logger !== "object") {
|
|
9
|
+
return console;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
info: typeof logger.info === "function" ? logger.info.bind(logger) : console.log,
|
|
13
|
+
warn: typeof logger.warn === "function" ? logger.warn.bind(logger) : console.warn,
|
|
14
|
+
error: typeof logger.error === "function" ? logger.error.bind(logger) : console.error,
|
|
15
|
+
debug:
|
|
16
|
+
typeof logger.debug === "function" ? logger.debug.bind(logger) : console.debug,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeTrimmedString(value) {
|
|
21
|
+
if (typeof value !== "string") {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
return value.trim();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function normalizeOcuClawSystemPrompt(value) {
|
|
28
|
+
return normalizeTrimmedString(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function normalizeOcuClawDefaultModel(value) {
|
|
32
|
+
return normalizeTrimmedString(value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function normalizeOcuClawDefaultThinking(value) {
|
|
36
|
+
const normalized = normalizeTrimmedString(value).toLowerCase();
|
|
37
|
+
if (
|
|
38
|
+
normalized === "" ||
|
|
39
|
+
normalized === "off" ||
|
|
40
|
+
normalized === "minimal" ||
|
|
41
|
+
normalized === "low" ||
|
|
42
|
+
normalized === "medium" ||
|
|
43
|
+
normalized === "high" ||
|
|
44
|
+
normalized === "xhigh"
|
|
45
|
+
) {
|
|
46
|
+
return normalized;
|
|
47
|
+
}
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isStoredSnapshotCanonical(value, snapshot) {
|
|
52
|
+
if (!value || typeof value !== "object") {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
normalizeTrimmedString(value.systemPrompt) === snapshot.systemPrompt &&
|
|
57
|
+
normalizeTrimmedString(value.defaultModel) === snapshot.defaultModel &&
|
|
58
|
+
normalizeOcuClawDefaultThinking(value.defaultThinking) === snapshot.defaultThinking
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function normalizeOcuClawSettingsSnapshot(value = {}) {
|
|
63
|
+
return {
|
|
64
|
+
systemPrompt: normalizeOcuClawSystemPrompt(value.systemPrompt),
|
|
65
|
+
defaultModel: normalizeOcuClawDefaultModel(value.defaultModel),
|
|
66
|
+
defaultThinking: normalizeOcuClawDefaultThinking(value.defaultThinking),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasOwn(obj, key) {
|
|
71
|
+
return !!obj && Object.prototype.hasOwnProperty.call(obj, key);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function createOcuClawSettingsStore(opts = {}) {
|
|
75
|
+
const logger = normalizeLogger(opts.logger);
|
|
76
|
+
const emitDebug = typeof opts.emitDebug === "function" ? opts.emitDebug : () => {};
|
|
77
|
+
const now = typeof opts.now === "function" ? opts.now : () => Date.now();
|
|
78
|
+
const defaults = normalizeOcuClawSettingsSnapshot(opts.defaults || {});
|
|
79
|
+
const statePath =
|
|
80
|
+
typeof opts.statePath === "string" && opts.statePath.trim()
|
|
81
|
+
? opts.statePath.trim()
|
|
82
|
+
: typeof opts.stateDir === "string" && opts.stateDir.trim()
|
|
83
|
+
? path.join(opts.stateDir.trim(), STORE_FILENAME)
|
|
84
|
+
: null;
|
|
85
|
+
|
|
86
|
+
function persistSnapshot(snapshot, reason) {
|
|
87
|
+
if (!statePath) {
|
|
88
|
+
emitDebug(
|
|
89
|
+
"settings.loadsave",
|
|
90
|
+
"ocuclaw_settings_persist_skipped",
|
|
91
|
+
"debug",
|
|
92
|
+
null,
|
|
93
|
+
() => ({
|
|
94
|
+
reason,
|
|
95
|
+
systemPromptChars: snapshot.systemPrompt.length,
|
|
96
|
+
defaultModel: snapshot.defaultModel,
|
|
97
|
+
defaultThinking: snapshot.defaultThinking,
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
105
|
+
fs.writeFileSync(
|
|
106
|
+
statePath,
|
|
107
|
+
JSON.stringify(
|
|
108
|
+
{
|
|
109
|
+
version: STORE_VERSION,
|
|
110
|
+
updatedAtMs: now(),
|
|
111
|
+
settings: snapshot,
|
|
112
|
+
},
|
|
113
|
+
null,
|
|
114
|
+
2,
|
|
115
|
+
) + "\n",
|
|
116
|
+
);
|
|
117
|
+
emitDebug(
|
|
118
|
+
"settings.loadsave",
|
|
119
|
+
"ocuclaw_settings_persisted",
|
|
120
|
+
"info",
|
|
121
|
+
null,
|
|
122
|
+
() => ({
|
|
123
|
+
reason,
|
|
124
|
+
statePath,
|
|
125
|
+
systemPromptChars: snapshot.systemPrompt.length,
|
|
126
|
+
defaultModel: snapshot.defaultModel,
|
|
127
|
+
defaultThinking: snapshot.defaultThinking,
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
logger.error(
|
|
132
|
+
`[ocuclaw] failed to persist OcuClaw settings: ${err && err.message ? err.message : err}`,
|
|
133
|
+
);
|
|
134
|
+
emitDebug(
|
|
135
|
+
"settings.loadsave",
|
|
136
|
+
"ocuclaw_settings_persist_failed",
|
|
137
|
+
"warn",
|
|
138
|
+
null,
|
|
139
|
+
() => ({
|
|
140
|
+
reason,
|
|
141
|
+
statePath,
|
|
142
|
+
message: err && err.message ? err.message : String(err),
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function loadInitialSnapshot() {
|
|
150
|
+
if (!statePath || !fs.existsSync(statePath)) {
|
|
151
|
+
persistSnapshot(defaults, "seed_defaults");
|
|
152
|
+
return { ...defaults };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const raw = fs.readFileSync(statePath, "utf8");
|
|
157
|
+
const parsed = JSON.parse(raw);
|
|
158
|
+
const storedSettings =
|
|
159
|
+
parsed && parsed.settings && typeof parsed.settings === "object"
|
|
160
|
+
? parsed.settings
|
|
161
|
+
: null;
|
|
162
|
+
const loaded =
|
|
163
|
+
parsed && parsed.version === STORE_VERSION && storedSettings
|
|
164
|
+
? normalizeOcuClawSettingsSnapshot(storedSettings)
|
|
165
|
+
: defaults;
|
|
166
|
+
emitDebug(
|
|
167
|
+
"settings.loadsave",
|
|
168
|
+
"ocuclaw_settings_loaded",
|
|
169
|
+
"info",
|
|
170
|
+
null,
|
|
171
|
+
() => ({
|
|
172
|
+
statePath,
|
|
173
|
+
systemPromptChars: loaded.systemPrompt.length,
|
|
174
|
+
defaultModel: loaded.defaultModel,
|
|
175
|
+
defaultThinking: loaded.defaultThinking,
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
if (
|
|
179
|
+
parsed.version !== STORE_VERSION ||
|
|
180
|
+
!isStoredSnapshotCanonical(storedSettings, loaded)
|
|
181
|
+
) {
|
|
182
|
+
persistSnapshot(loaded, "normalize_loaded_settings");
|
|
183
|
+
}
|
|
184
|
+
return loaded;
|
|
185
|
+
} catch (err) {
|
|
186
|
+
logger.warn(
|
|
187
|
+
`[ocuclaw] failed to load OcuClaw settings, falling back to defaults: ${err && err.message ? err.message : err}`,
|
|
188
|
+
);
|
|
189
|
+
emitDebug(
|
|
190
|
+
"settings.loadsave",
|
|
191
|
+
"ocuclaw_settings_load_failed",
|
|
192
|
+
"warn",
|
|
193
|
+
null,
|
|
194
|
+
() => ({
|
|
195
|
+
statePath,
|
|
196
|
+
message: err && err.message ? err.message : String(err),
|
|
197
|
+
}),
|
|
198
|
+
);
|
|
199
|
+
persistSnapshot(defaults, "rewrite_after_load_failure");
|
|
200
|
+
return { ...defaults };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let snapshot = loadInitialSnapshot();
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
getStatePath() {
|
|
208
|
+
return statePath;
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
getSnapshot() {
|
|
212
|
+
return { ...snapshot };
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
async setSettings(patch = {}) {
|
|
216
|
+
const next = {
|
|
217
|
+
systemPrompt: hasOwn(patch, "systemPrompt")
|
|
218
|
+
? normalizeOcuClawSystemPrompt(patch.systemPrompt)
|
|
219
|
+
: snapshot.systemPrompt,
|
|
220
|
+
defaultModel: hasOwn(patch, "defaultModel")
|
|
221
|
+
? normalizeOcuClawDefaultModel(patch.defaultModel)
|
|
222
|
+
: snapshot.defaultModel,
|
|
223
|
+
defaultThinking: hasOwn(patch, "defaultThinking")
|
|
224
|
+
? normalizeOcuClawDefaultThinking(patch.defaultThinking)
|
|
225
|
+
: snapshot.defaultThinking,
|
|
226
|
+
};
|
|
227
|
+
snapshot = next;
|
|
228
|
+
persistSnapshot(snapshot, "set_settings");
|
|
229
|
+
return {
|
|
230
|
+
status: "accepted",
|
|
231
|
+
settings: { ...snapshot },
|
|
232
|
+
};
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export default createOcuClawSettingsStore;
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
const V1_TO_INTERNAL = {
|
|
2
|
+
send: "ocuclaw.message.send",
|
|
3
|
+
newSession: "ocuclaw.session.create",
|
|
4
|
+
switchSession: "ocuclaw.session.switch",
|
|
5
|
+
newChat: "ocuclaw.session.reset",
|
|
6
|
+
getSessions: "ocuclaw.session.list",
|
|
7
|
+
getStatus: "ocuclaw.runtime.status.get",
|
|
8
|
+
getModelsCatalog: "ocuclaw.model.catalog.get",
|
|
9
|
+
getSkills: "ocuclaw.skills.catalog.get",
|
|
10
|
+
getSonioxModels: "ocuclaw.voice.soniox.models.get",
|
|
11
|
+
getSessionModelConfig: "ocuclaw.session.config.get",
|
|
12
|
+
setSessionModelConfig: "ocuclaw.session.config.set",
|
|
13
|
+
getEvenAiSettings: "ocuclaw.evenai.settings.get",
|
|
14
|
+
getEvenAiSessions: "ocuclaw.evenai.session.list",
|
|
15
|
+
setEvenAiSettings: "ocuclaw.evenai.settings.set",
|
|
16
|
+
getOcuClawSettings: "ocuclaw.settings.get",
|
|
17
|
+
setOcuClawSettings: "ocuclaw.settings.set",
|
|
18
|
+
slashCommand: "ocuclaw.command.slash",
|
|
19
|
+
approvalResponse: "ocuclaw.approval.resolve",
|
|
20
|
+
subscribeProtocol: "ocuclaw.protocol.tap.subscribe",
|
|
21
|
+
eventDebug: "ocuclaw.debug.event",
|
|
22
|
+
"debug-set": "ocuclaw.debug.config.set",
|
|
23
|
+
"debug-dump": "ocuclaw.debug.events.query",
|
|
24
|
+
resume: "ocuclaw.sync.resume",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const RESULT_TO_V1 = {
|
|
28
|
+
"ocuclaw.message.send": "sendAck",
|
|
29
|
+
"ocuclaw.message.send.ack": "sendAck",
|
|
30
|
+
"ocuclaw.session.list.result": "sessions",
|
|
31
|
+
"ocuclaw.session.config.snapshot": "sessionModelConfig",
|
|
32
|
+
"ocuclaw.session.config.set.ack": "sessionModelConfigAck",
|
|
33
|
+
"ocuclaw.evenai.settings.snapshot": "evenAiSettings",
|
|
34
|
+
"ocuclaw.evenai.session.list.result": "evenAiSessions",
|
|
35
|
+
"ocuclaw.evenai.settings.set.ack": "evenAiSettingsAck",
|
|
36
|
+
"ocuclaw.settings.snapshot": "ocuClawSettings",
|
|
37
|
+
"ocuclaw.settings.set.ack": "ocuClawSettingsAck",
|
|
38
|
+
"ocuclaw.model.catalog.snapshot": "modelsCatalog",
|
|
39
|
+
"ocuclaw.skills.catalog.snapshot": "skillsCatalog",
|
|
40
|
+
"ocuclaw.voice.soniox.models.snapshot": "sonioxModels",
|
|
41
|
+
"ocuclaw.approval.resolve.ack": "approvalResponseAck",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const EVENT_TO_V1 = {
|
|
45
|
+
"ocuclaw.view.pages.snapshot": "pages",
|
|
46
|
+
"ocuclaw.runtime.status": "status",
|
|
47
|
+
"ocuclaw.activity.update": "activity",
|
|
48
|
+
"ocuclaw.message.stream.delta": "streaming",
|
|
49
|
+
"ocuclaw.session.switch.applied": "sessionSwitched",
|
|
50
|
+
"ocuclaw.sync.resume.ack": "resume-ack",
|
|
51
|
+
"ocuclaw.approval.request": "approval",
|
|
52
|
+
"ocuclaw.approval.resolved": "approvalResolved",
|
|
53
|
+
"ocuclaw.remote.control": "remote-control",
|
|
54
|
+
"ocuclaw.protocol.tap.frame": "protocol",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const INTERNAL_TO_V1 = Object.fromEntries(
|
|
58
|
+
Object.entries(V1_TO_INTERNAL).map(([type, op]) => [op, type]),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const V1_TO_RESULT = Object.fromEntries(
|
|
62
|
+
Object.entries(RESULT_TO_V1).map(([op, type]) => [type, op]),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const V1_TO_EVENT = Object.fromEntries(
|
|
66
|
+
Object.entries(EVENT_TO_V1).map(([event, type]) => [type, event]),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
function asRecord(value) {
|
|
70
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function frameRequestId(frame) {
|
|
77
|
+
const value = frame.requestId ?? frame.id;
|
|
78
|
+
return typeof value === "string" ? value : null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function framePayload(frame) {
|
|
82
|
+
const { type: _type, ...payload } = frame;
|
|
83
|
+
return payload;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function clonePayload(value) {
|
|
87
|
+
return { ...value };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function internalOpPayload(op) {
|
|
91
|
+
const payload = clonePayload(op.payload || {});
|
|
92
|
+
delete payload.requestId;
|
|
93
|
+
delete payload.idempotencyKey;
|
|
94
|
+
return payload;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function parseV1Inbound(raw) {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = asRecord(JSON.parse(raw));
|
|
100
|
+
if (!parsed || typeof parsed.type !== "string") {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return parsed;
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function serializeV1Outbound(frame) {
|
|
110
|
+
return JSON.stringify(frame);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parseV2Inbound(raw) {
|
|
114
|
+
try {
|
|
115
|
+
const parsed = asRecord(JSON.parse(raw));
|
|
116
|
+
if (!parsed || typeof parsed.type !== "string") {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (!parsed.type.startsWith("ocuclaw.")) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const requestId =
|
|
123
|
+
typeof parsed.requestId === "string" && parsed.requestId.trim()
|
|
124
|
+
? parsed.requestId.trim()
|
|
125
|
+
: null;
|
|
126
|
+
const idempotencyKey =
|
|
127
|
+
typeof parsed.idempotencyKey === "string" && parsed.idempotencyKey.trim()
|
|
128
|
+
? parsed.idempotencyKey.trim()
|
|
129
|
+
: null;
|
|
130
|
+
const { type: op, requestId: _requestId, idempotencyKey: _idempotencyKey, ...payload } = parsed;
|
|
131
|
+
return {
|
|
132
|
+
op,
|
|
133
|
+
requestId,
|
|
134
|
+
idempotencyKey,
|
|
135
|
+
payload,
|
|
136
|
+
};
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function mapV1InboundToInternalOps(frame, _ctx) {
|
|
143
|
+
const op = V1_TO_INTERNAL[frame.type];
|
|
144
|
+
if (!op) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
const idempotencyKey = typeof frame.idempotencyKey === "string" ? frame.idempotencyKey : null;
|
|
148
|
+
return [
|
|
149
|
+
{
|
|
150
|
+
op,
|
|
151
|
+
requestId: frameRequestId(frame),
|
|
152
|
+
idempotencyKey,
|
|
153
|
+
payload: framePayload(frame),
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function mapInternalOpToV1Inbound(op, _ctx) {
|
|
159
|
+
const type = INTERNAL_TO_V1[op.op];
|
|
160
|
+
if (!type) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const payload = internalOpPayload(op);
|
|
165
|
+
if (type === "send") {
|
|
166
|
+
const id =
|
|
167
|
+
op.requestId ||
|
|
168
|
+
(typeof payload.id === "string" && payload.id.trim() ? payload.id.trim() : null);
|
|
169
|
+
if (id) payload.id = id;
|
|
170
|
+
delete payload.requestId;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (type === "approvalResponse") {
|
|
174
|
+
if (op.requestId && !payload.requestId) {
|
|
175
|
+
payload.requestId = op.requestId;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return [{ type, ...payload }];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function mapInternalResultToV1Outbound(result, _ctx) {
|
|
183
|
+
const type = RESULT_TO_V1[result.op];
|
|
184
|
+
if (!type) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
if (type !== "sendAck") {
|
|
188
|
+
return [{ type, ...result.result }];
|
|
189
|
+
}
|
|
190
|
+
const payload = clonePayload(result.result || {});
|
|
191
|
+
const id =
|
|
192
|
+
result.requestId ||
|
|
193
|
+
(typeof payload.id === "string" && payload.id.trim() ? payload.id.trim() : null);
|
|
194
|
+
const status =
|
|
195
|
+
typeof payload.status === "string"
|
|
196
|
+
? payload.status
|
|
197
|
+
: result.ok
|
|
198
|
+
? "accepted"
|
|
199
|
+
: "rejected";
|
|
200
|
+
const error =
|
|
201
|
+
typeof payload.error === "string" && payload.error
|
|
202
|
+
? payload.error
|
|
203
|
+
: !result.ok && result.message
|
|
204
|
+
? result.message
|
|
205
|
+
: undefined;
|
|
206
|
+
const errorCode =
|
|
207
|
+
typeof payload.errorCode === "string" && payload.errorCode
|
|
208
|
+
? payload.errorCode
|
|
209
|
+
: !result.ok && result.code
|
|
210
|
+
? result.code
|
|
211
|
+
: undefined;
|
|
212
|
+
return [
|
|
213
|
+
{
|
|
214
|
+
type: "sendAck",
|
|
215
|
+
id,
|
|
216
|
+
status,
|
|
217
|
+
...(error ? { error } : {}),
|
|
218
|
+
...(errorCode ? { errorCode } : {}),
|
|
219
|
+
},
|
|
220
|
+
];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function mapInternalEventToV1Outbound(event, _ctx) {
|
|
224
|
+
const type = EVENT_TO_V1[event.event];
|
|
225
|
+
if (!type) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
return [{ type, ...event.payload }];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function mapV1OutboundToInternalResult(frame, _ctx) {
|
|
232
|
+
const op = V1_TO_RESULT[frame.type];
|
|
233
|
+
if (!op) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const payload = framePayload(frame);
|
|
238
|
+
if (frame.type === "sendAck") {
|
|
239
|
+
return {
|
|
240
|
+
op: "ocuclaw.message.send.ack",
|
|
241
|
+
requestId:
|
|
242
|
+
typeof frame.id === "string" && frame.id.trim() ? frame.id.trim() : null,
|
|
243
|
+
ok: frame.status === "accepted",
|
|
244
|
+
code:
|
|
245
|
+
typeof frame.errorCode === "string" && frame.errorCode.trim()
|
|
246
|
+
? frame.errorCode.trim()
|
|
247
|
+
: frame.status === "accepted"
|
|
248
|
+
? "ok"
|
|
249
|
+
: "request_rejected",
|
|
250
|
+
message:
|
|
251
|
+
typeof frame.error === "string" && frame.error.trim()
|
|
252
|
+
? frame.error.trim()
|
|
253
|
+
: null,
|
|
254
|
+
result: payload,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (frame.type === "approvalResponseAck") {
|
|
259
|
+
return {
|
|
260
|
+
op,
|
|
261
|
+
requestId:
|
|
262
|
+
typeof frame.requestId === "string" && frame.requestId.trim()
|
|
263
|
+
? frame.requestId.trim()
|
|
264
|
+
: null,
|
|
265
|
+
ok: frame.status === "accepted",
|
|
266
|
+
code:
|
|
267
|
+
typeof frame.code === "string" && frame.code.trim() ? frame.code.trim() : null,
|
|
268
|
+
message:
|
|
269
|
+
typeof frame.message === "string" && frame.message.trim()
|
|
270
|
+
? frame.message.trim()
|
|
271
|
+
: null,
|
|
272
|
+
result: payload,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
frame.type === "sessionModelConfigAck" ||
|
|
278
|
+
frame.type === "evenAiSettingsAck" ||
|
|
279
|
+
frame.type === "ocuClawSettingsAck"
|
|
280
|
+
) {
|
|
281
|
+
return {
|
|
282
|
+
op,
|
|
283
|
+
requestId: null,
|
|
284
|
+
ok: frame.status === "accepted",
|
|
285
|
+
code: frame.status === "accepted" ? "ok" : "request_rejected",
|
|
286
|
+
message:
|
|
287
|
+
typeof frame.error === "string" && frame.error.trim()
|
|
288
|
+
? frame.error.trim()
|
|
289
|
+
: null,
|
|
290
|
+
result: payload,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
op,
|
|
296
|
+
requestId:
|
|
297
|
+
typeof frame.requestId === "string" && frame.requestId.trim()
|
|
298
|
+
? frame.requestId.trim()
|
|
299
|
+
: typeof frame.id === "string" && frame.id.trim()
|
|
300
|
+
? frame.id.trim()
|
|
301
|
+
: null,
|
|
302
|
+
ok: true,
|
|
303
|
+
code: "ok",
|
|
304
|
+
message: null,
|
|
305
|
+
result: payload,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function mapV1OutboundToInternalEvent(frame, _ctx) {
|
|
310
|
+
const event = V1_TO_EVENT[frame.type];
|
|
311
|
+
if (!event) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
event,
|
|
316
|
+
requestId:
|
|
317
|
+
typeof frame.requestId === "string" && frame.requestId.trim()
|
|
318
|
+
? frame.requestId.trim()
|
|
319
|
+
: null,
|
|
320
|
+
payload: framePayload(frame),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function serializeInternalResultToV2Outbound(result) {
|
|
325
|
+
const payload = {
|
|
326
|
+
type: result.op,
|
|
327
|
+
...(result.requestId ? { requestId: result.requestId } : {}),
|
|
328
|
+
...(result.result || {}),
|
|
329
|
+
};
|
|
330
|
+
if (result.code && payload.code === undefined) {
|
|
331
|
+
payload.code = result.code;
|
|
332
|
+
}
|
|
333
|
+
if (result.message && payload.message === undefined) {
|
|
334
|
+
payload.message = result.message;
|
|
335
|
+
}
|
|
336
|
+
return JSON.stringify(payload);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function serializeInternalEventToV2Outbound(event) {
|
|
340
|
+
return JSON.stringify({
|
|
341
|
+
type: event.event,
|
|
342
|
+
...(event.requestId ? { requestId: event.requestId } : {}),
|
|
343
|
+
...(event.payload || {}),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function normalizeInternalError(input) {
|
|
348
|
+
if (input instanceof Error) {
|
|
349
|
+
return {
|
|
350
|
+
code: input.name || "internal_error",
|
|
351
|
+
message: input.message || "internal error",
|
|
352
|
+
retryable: false,
|
|
353
|
+
details: {},
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const value = asRecord(input);
|
|
357
|
+
return {
|
|
358
|
+
code: typeof value?.code === "string" ? value.code : "internal_error",
|
|
359
|
+
message: typeof value?.message === "string" ? value.message : "internal error",
|
|
360
|
+
retryable: value?.retryable === true,
|
|
361
|
+
details: asRecord(value?.details) ?? {},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export {
|
|
366
|
+
mapInternalEventToV1Outbound,
|
|
367
|
+
mapInternalOpToV1Inbound,
|
|
368
|
+
mapInternalResultToV1Outbound,
|
|
369
|
+
mapV1InboundToInternalOps,
|
|
370
|
+
mapV1OutboundToInternalEvent,
|
|
371
|
+
mapV1OutboundToInternalResult,
|
|
372
|
+
normalizeInternalError,
|
|
373
|
+
parseV1Inbound,
|
|
374
|
+
parseV2Inbound,
|
|
375
|
+
serializeInternalEventToV2Outbound,
|
|
376
|
+
serializeInternalResultToV2Outbound,
|
|
377
|
+
serializeV1Outbound,
|
|
378
|
+
};
|