ocuclaw 1.2.4 → 1.3.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 +18 -5
- package/dist/config/runtime-config.js +81 -3
- package/dist/domain/activity-status-adapter.js +138 -605
- package/dist/domain/activity-status-arbiter.js +109 -0
- package/dist/domain/activity-status-labels.js +906 -0
- package/dist/domain/code-span-regions.js +103 -0
- package/dist/domain/conversation-state.js +14 -1
- package/dist/domain/debug-store.js +38 -182
- package/dist/domain/glasses-ui-content-summary.js +62 -0
- package/dist/domain/glasses-ui-system-prompt.js +28 -0
- package/dist/domain/message-emoji-allowlist.js +16 -0
- package/dist/domain/message-emoji-filter.js +33 -55
- package/dist/domain/neural-emoji-reactor-system-prompt.js +43 -0
- package/dist/domain/neural-emoji-reactor-tag-config.js +56 -0
- package/dist/domain/neural-pace-modulator-system-prompt.js +32 -0
- package/dist/domain/neural-pace-modulator-tag-config.js +51 -0
- package/dist/domain/tagged-span-parser.js +121 -0
- package/dist/domain/tagged-span-strip.js +38 -0
- package/dist/even-ai/even-ai-endpoint.js +91 -0
- package/dist/even-ai/even-ai-run-waiter.js +14 -0
- package/dist/even-ai/even-ai-settings-store.js +14 -0
- package/dist/gateway/gateway-bridge.js +14 -2
- package/dist/gateway/gateway-timing-ledger.js +457 -0
- package/dist/gateway/openclaw-client.js +462 -38
- package/dist/index.js +28 -1
- package/dist/runtime/downstream-handler.js +754 -83
- package/dist/runtime/downstream-server.js +700 -534
- package/dist/runtime/ocuclaw-settings-store.js +74 -31
- package/dist/runtime/plugin-update-service.js +216 -0
- package/dist/runtime/protocol-adapter.js +9 -0
- package/dist/runtime/provider-usage-select.js +168 -0
- package/dist/runtime/relay-client-nudge-controller.js +553 -0
- package/dist/runtime/relay-core.js +1209 -204
- package/dist/runtime/relay-health-monitor.js +172 -0
- package/dist/runtime/relay-operation-registry.js +263 -0
- package/dist/runtime/relay-service.js +201 -1
- package/dist/runtime/relay-worker-approval-replay-cache.js +68 -0
- package/dist/runtime/relay-worker-entry.js +32 -0
- package/dist/runtime/relay-worker-health.js +272 -0
- package/dist/runtime/relay-worker-protocol.js +285 -0
- package/dist/runtime/relay-worker-queue.js +202 -0
- package/dist/runtime/relay-worker-supervisor.js +1081 -0
- package/dist/runtime/relay-worker-transport.js +1051 -0
- package/dist/runtime/session-context-service.js +189 -0
- package/dist/runtime/session-service.js +615 -24
- package/dist/runtime/upstream-runtime.js +1167 -60
- package/dist/tools/device-info-tool.js +242 -0
- package/dist/tools/glasses-ui-cron.js +427 -0
- package/dist/tools/glasses-ui-descriptors.js +261 -0
- package/dist/tools/glasses-ui-limits.js +21 -0
- package/dist/tools/glasses-ui-paint-floor.js +99 -0
- package/dist/tools/glasses-ui-recipes.js +746 -0
- package/dist/tools/glasses-ui-surfaces.js +278 -0
- package/dist/tools/glasses-ui-template.js +182 -0
- package/dist/tools/glasses-ui-tool.js +1147 -0
- package/dist/tools/session-title-tool.js +209 -0
- package/dist/version.js +2 -0
- package/openclaw.plugin.json +163 -15
- package/package.json +12 -4
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
export const SESSION_TITLE_LIMITS = {
|
|
2
|
+
titleMax: 55, // 64 SDK list-item cap minus ~9 chars headroom for "<time> - " prefix
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export const sessionTitleParametersSchema = {
|
|
6
|
+
type: "object",
|
|
7
|
+
required: ["title"],
|
|
8
|
+
properties: {
|
|
9
|
+
title: {
|
|
10
|
+
type: "string",
|
|
11
|
+
minLength: 1,
|
|
12
|
+
maxLength: SESSION_TITLE_LIMITS.titleMax,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function validateSessionTitleInput(input) {
|
|
19
|
+
if (!input || typeof input !== "object") {
|
|
20
|
+
return { ok: false, code: "missing_field", message: "input must be an object with a title field" };
|
|
21
|
+
}
|
|
22
|
+
if (!("title" in input)) {
|
|
23
|
+
return { ok: false, code: "missing_field", message: "title field is required" };
|
|
24
|
+
}
|
|
25
|
+
if (typeof input.title !== "string") {
|
|
26
|
+
return { ok: false, code: "invalid_type", message: "title must be a string" };
|
|
27
|
+
}
|
|
28
|
+
const trimmed = input.title.trim();
|
|
29
|
+
if (trimmed.length === 0) {
|
|
30
|
+
return { ok: false, code: "title_empty", message: "title cannot be empty or whitespace-only" };
|
|
31
|
+
}
|
|
32
|
+
if (trimmed.length > SESSION_TITLE_LIMITS.titleMax) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
code: "title_too_long",
|
|
36
|
+
message: `title is ${trimmed.length} chars; max ${SESSION_TITLE_LIMITS.titleMax}`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return { ok: true, spec: { title: trimmed } };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const EVEN_AI_DEDICATED_KEY_PREFIX = "ocuclaw:even-ai";
|
|
43
|
+
|
|
44
|
+
function isEvenAiDedicatedKey(sessionKey) {
|
|
45
|
+
if (typeof sessionKey !== "string") return false;
|
|
46
|
+
const normalized = sessionKey.trim().toLowerCase();
|
|
47
|
+
return (
|
|
48
|
+
normalized === EVEN_AI_DEDICATED_KEY_PREFIX ||
|
|
49
|
+
normalized.startsWith(`${EVEN_AI_DEDICATED_KEY_PREFIX}:`)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function gateReason(sessionKey, deps) {
|
|
54
|
+
if (typeof deps.isSessionUserLocked === "function" && deps.isSessionUserLocked(sessionKey)) {
|
|
55
|
+
return "session_user_locked";
|
|
56
|
+
}
|
|
57
|
+
if (
|
|
58
|
+
typeof deps.isNeuralSessionNamesEnabled === "function" &&
|
|
59
|
+
!deps.isNeuralSessionNamesEnabled(sessionKey)
|
|
60
|
+
) {
|
|
61
|
+
return "feature_disabled";
|
|
62
|
+
}
|
|
63
|
+
// Hard guard against the agent titling a session before the user has sent
|
|
64
|
+
// their first real message. The synthetic session-starter prompt the agent
|
|
65
|
+
// sees on /new + the proactive prompt-hook nudge can otherwise tempt the
|
|
66
|
+
// model into titling from a non-user input (observed: titles like "New
|
|
67
|
+
// session"). Real user sends are recorded via dispatchOcuClawUserSend ->
|
|
68
|
+
// sessionService.recordFirstSentUserMessage; the synthetic starter never is.
|
|
69
|
+
if (
|
|
70
|
+
typeof deps.hasRecordedUserMessage === "function" &&
|
|
71
|
+
!deps.hasRecordedUserMessage(sessionKey)
|
|
72
|
+
) {
|
|
73
|
+
return "no_user_message_yet";
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createSessionTitleToolHandler(deps) {
|
|
79
|
+
async function setSessionTitle(params) {
|
|
80
|
+
const validation = validateSessionTitleInput(params);
|
|
81
|
+
if (!validation.ok) {
|
|
82
|
+
const err = new Error(`${validation.code}: ${validation.message}`);
|
|
83
|
+
err.code = validation.code;
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
const sessionKey = deps.peekSessionKey();
|
|
87
|
+
if (typeof sessionKey !== "string" || !sessionKey.trim()) {
|
|
88
|
+
const err = new Error(
|
|
89
|
+
"no_active_session: no OcuClaw session is currently active",
|
|
90
|
+
);
|
|
91
|
+
err.code = "no_active_session";
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
if (isEvenAiDedicatedKey(sessionKey)) {
|
|
95
|
+
const err = new Error(
|
|
96
|
+
"session_not_renamable: the persistent EvenAI session cannot be retitled",
|
|
97
|
+
);
|
|
98
|
+
err.code = "session_not_renamable";
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
const blockedReason = gateReason(sessionKey, deps);
|
|
102
|
+
if (blockedReason) {
|
|
103
|
+
const err = new Error(`${blockedReason}: tool unavailable for this session`);
|
|
104
|
+
err.code = blockedReason;
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
const result = await deps.setSessionTitle(sessionKey, validation.spec.title);
|
|
108
|
+
if (result && result.ok === false) {
|
|
109
|
+
const err = new Error(`${result.code}: ${result.message || "set rejected"}`);
|
|
110
|
+
err.code = result.code;
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
return result || { ok: true };
|
|
114
|
+
}
|
|
115
|
+
return { setSessionTitle };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const TOOL_DESCRIPTION = [
|
|
119
|
+
"Set a short title for the current chat session (shown in the user's glasses session list).",
|
|
120
|
+
"",
|
|
121
|
+
"When: first user turn that names any concrete topic — call eagerly. Later, only when the topic has clearly shifted. Skip greetings, acknowledgments, and no-topic messages.",
|
|
122
|
+
"",
|
|
123
|
+
"Title: 2-5 word noun phrase, ≤55 chars, no trailing punctuation or surrounding quotes.",
|
|
124
|
+
"",
|
|
125
|
+
"Do not announce the rename unless the user explicitly asked to retitle.",
|
|
126
|
+
].join("\n");
|
|
127
|
+
|
|
128
|
+
export function createSessionTitlePromptHook(deps) {
|
|
129
|
+
return function sessionTitleBeforePromptBuild(_event, ctx) {
|
|
130
|
+
const sessionKey = ctx && typeof ctx.sessionKey === "string" ? ctx.sessionKey : null;
|
|
131
|
+
if (!sessionKey) return undefined;
|
|
132
|
+
const title = typeof deps.getSessionTitle === "function" ? deps.getSessionTitle(sessionKey) : null;
|
|
133
|
+
const userLocked =
|
|
134
|
+
typeof deps.isSessionUserLocked === "function" && deps.isSessionUserLocked(sessionKey);
|
|
135
|
+
const featureEnabled =
|
|
136
|
+
typeof deps.isNeuralSessionNamesEnabled === "function"
|
|
137
|
+
? deps.isNeuralSessionNamesEnabled(sessionKey)
|
|
138
|
+
: true;
|
|
139
|
+
|
|
140
|
+
const fragments = [];
|
|
141
|
+
if (title) {
|
|
142
|
+
fragments.push(`Current session title: "${title}".`);
|
|
143
|
+
}
|
|
144
|
+
if (userLocked) {
|
|
145
|
+
fragments.push(
|
|
146
|
+
"The user has set a custom title; do not call set_session_title.",
|
|
147
|
+
);
|
|
148
|
+
} else if (!featureEnabled) {
|
|
149
|
+
fragments.push(
|
|
150
|
+
"Neural Topic Distiller is disabled; do not call set_session_title.",
|
|
151
|
+
);
|
|
152
|
+
} else if (title) {
|
|
153
|
+
fragments.push(
|
|
154
|
+
"Call set_session_title only if the topic has clearly shifted.",
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
const hasUserMessage =
|
|
158
|
+
typeof deps.hasRecordedUserMessage !== "function" ||
|
|
159
|
+
deps.hasRecordedUserMessage(sessionKey);
|
|
160
|
+
if (hasUserMessage) {
|
|
161
|
+
fragments.push(
|
|
162
|
+
"No session title is set yet. Call set_session_title now if the user's latest message names any concrete topic.",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (fragments.length === 0) return undefined;
|
|
168
|
+
return { appendSystemContext: fragments.join(" ") };
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function registerSessionTitleTool(api, service) {
|
|
173
|
+
if (!api || typeof api.registerTool !== "function") {
|
|
174
|
+
throw new Error("registerSessionTitleTool requires api.registerTool");
|
|
175
|
+
}
|
|
176
|
+
if (!service) {
|
|
177
|
+
throw new Error("registerSessionTitleTool requires the OcuClaw relay service");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const handler = createSessionTitleToolHandler({
|
|
181
|
+
peekSessionKey: () => service.peekSessionKey(),
|
|
182
|
+
setSessionTitle: (sessionKey, title, opts) => service.setSessionTitle(sessionKey, title, opts),
|
|
183
|
+
isSessionUserLocked: (sessionKey) => service.isSessionUserLocked(sessionKey),
|
|
184
|
+
isNeuralSessionNamesEnabled: (sessionKey) => service.isNeuralSessionNamesEnabled(sessionKey),
|
|
185
|
+
hasRecordedUserMessage: (sessionKey) => service.hasRecordedUserMessage(sessionKey),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
api.registerTool({
|
|
189
|
+
name: "set_session_title",
|
|
190
|
+
description: TOOL_DESCRIPTION,
|
|
191
|
+
parameters: sessionTitleParametersSchema,
|
|
192
|
+
async execute(_toolCallId, params) {
|
|
193
|
+
await handler.setSessionTitle(params);
|
|
194
|
+
return {
|
|
195
|
+
content: [{ type: "text", text: JSON.stringify({ status: "accepted" }) }],
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
if (typeof api.on === "function") {
|
|
201
|
+
const hook = createSessionTitlePromptHook({
|
|
202
|
+
getSessionTitle: (sessionKey) => service.getSessionTitle(sessionKey),
|
|
203
|
+
isSessionUserLocked: (sessionKey) => service.isSessionUserLocked(sessionKey),
|
|
204
|
+
isNeuralSessionNamesEnabled: (sessionKey) => service.isNeuralSessionNamesEnabled(sessionKey),
|
|
205
|
+
hasRecordedUserMessage: (sessionKey) => service.hasRecordedUserMessage(sessionKey),
|
|
206
|
+
});
|
|
207
|
+
api.on("before_prompt_build", hook);
|
|
208
|
+
}
|
|
209
|
+
}
|
package/dist/version.js
ADDED
package/openclaw.plugin.json
CHANGED
|
@@ -1,34 +1,144 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "ocuclaw",
|
|
3
|
+
"activation": {
|
|
4
|
+
"onStartup": true
|
|
5
|
+
},
|
|
3
6
|
"name": "OcuClaw",
|
|
4
|
-
"description": "OcuClaw for Even G2 smart glasses
|
|
7
|
+
"description": "OcuClaw for Even Realities G2 smart glasses.",
|
|
8
|
+
"contracts": {
|
|
9
|
+
"tools": [
|
|
10
|
+
"render_glasses_ui",
|
|
11
|
+
"set_session_title",
|
|
12
|
+
"get_evenrealities_device_info"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"skills": ["skills/glasses-ui"],
|
|
16
|
+
"hooks": {
|
|
17
|
+
"allowConversationAccess": true
|
|
18
|
+
},
|
|
19
|
+
"uiHints": {
|
|
20
|
+
"relayToken": {
|
|
21
|
+
"label": "Relay token",
|
|
22
|
+
"help": "Shared secret. Must match the relay server token set in the OcuClaw app inside Even Hub.",
|
|
23
|
+
"placeholder": "user-defined password",
|
|
24
|
+
"sensitive": true
|
|
25
|
+
},
|
|
26
|
+
"sonioxApiKey": {
|
|
27
|
+
"label": "Soniox API key",
|
|
28
|
+
"help": "Optional. Enables Soniox speech-to-text for voice input.",
|
|
29
|
+
"sensitive": true
|
|
30
|
+
},
|
|
31
|
+
"evenAiEnabled": {
|
|
32
|
+
"label": "Enable Even AI",
|
|
33
|
+
"help": "Routes Even AI agent requests through OcuClaw. Requires evenAiToken when enabled."
|
|
34
|
+
},
|
|
35
|
+
"evenAiToken": {
|
|
36
|
+
"label": "Even AI token",
|
|
37
|
+
"help": "Shared secret. Must match the password set in the Even AI Agent Configure section of the Even Realities app. Required when evenAiEnabled is true.",
|
|
38
|
+
"placeholder": "user-defined password",
|
|
39
|
+
"sensitive": true
|
|
40
|
+
},
|
|
41
|
+
"evenAiSystemPrompt": {
|
|
42
|
+
"label": "Even AI system prompt",
|
|
43
|
+
"help": "Optional extra system prompt appended to Even AI runs only.",
|
|
44
|
+
"advanced": true
|
|
45
|
+
},
|
|
46
|
+
"evenAiRoutingMode": {
|
|
47
|
+
"label": "Even AI routing mode",
|
|
48
|
+
"help": "active = current session; background = dedicated background session; background_new = fresh background session per request.",
|
|
49
|
+
"advanced": true
|
|
50
|
+
},
|
|
51
|
+
"wsBind": {
|
|
52
|
+
"label": "WebSocket bind address",
|
|
53
|
+
"help": "Local interface the OcuClaw relay listens on.",
|
|
54
|
+
"advanced": true
|
|
55
|
+
},
|
|
56
|
+
"wsPort": {
|
|
57
|
+
"label": "WebSocket port",
|
|
58
|
+
"help": "Local port the OcuClaw relay listens on.",
|
|
59
|
+
"advanced": true
|
|
60
|
+
},
|
|
61
|
+
"sessionLimit": {
|
|
62
|
+
"label": "Concurrent session limit",
|
|
63
|
+
"help": "Maximum simultaneous client sessions accepted by the relay.",
|
|
64
|
+
"advanced": true
|
|
65
|
+
},
|
|
66
|
+
"debugPayloadMaxBytes": {
|
|
67
|
+
"label": "Debug payload size limit",
|
|
68
|
+
"help": "Maximum byte size for debug payloads recorded for debugctl.",
|
|
69
|
+
"advanced": true
|
|
70
|
+
},
|
|
71
|
+
"debugNoisyPolicies": {
|
|
72
|
+
"label": "Debug noise policies",
|
|
73
|
+
"help": "Per-channel filters that suppress or sample noisy debug events.",
|
|
74
|
+
"advanced": true
|
|
75
|
+
},
|
|
76
|
+
"externalDebugToolsEnabled": {
|
|
77
|
+
"label": "External debug tools",
|
|
78
|
+
"help": "Allow debugctl-style external tools to call debug-set, debug-dump, and remote-control.",
|
|
79
|
+
"advanced": true
|
|
80
|
+
},
|
|
81
|
+
"evenAiRequestTimeoutMs": {
|
|
82
|
+
"label": "Even AI request timeout (ms) (deprecated)",
|
|
83
|
+
"advanced": true
|
|
84
|
+
},
|
|
85
|
+
"evenAiMaxBodyBytes": {
|
|
86
|
+
"label": "Even AI max body size (bytes) (deprecated)",
|
|
87
|
+
"advanced": true
|
|
88
|
+
},
|
|
89
|
+
"evenAiDedupWindowMs": {
|
|
90
|
+
"label": "Even AI dedup window (ms) (deprecated)",
|
|
91
|
+
"advanced": true
|
|
92
|
+
},
|
|
93
|
+
"evenAiDedicatedSessionKey": {
|
|
94
|
+
"label": "Even AI dedicated session key (deprecated)",
|
|
95
|
+
"help": "Deprecated — scheduled for removal in a future release. Internal session key prefix for background routing. Must start with 'ocuclaw:'.",
|
|
96
|
+
"advanced": true
|
|
97
|
+
},
|
|
98
|
+
"renderGlassesUiTimeoutMs": {
|
|
99
|
+
"label": "render_glasses_ui timeout (ms)",
|
|
100
|
+
"help": "How long a render_glasses_ui call waits for a user pick before resolving with { result: \"timeout\" }. Bounds the orphan tool_use corruption window if the gateway dies mid-render. Default 1800000 (30 minutes). Set 0 to disable (infinite wait — pre-2026-05-23 behaviour).",
|
|
101
|
+
"advanced": true
|
|
102
|
+
},
|
|
103
|
+
"freshnessWindowMs": {
|
|
104
|
+
"label": "Activity summary freshness window",
|
|
105
|
+
"help": "Milliseconds an agent summary outranks a tool label (3000-8000).",
|
|
106
|
+
"advanced": true
|
|
107
|
+
}
|
|
108
|
+
},
|
|
5
109
|
"configSchema": {
|
|
6
110
|
"type": "object",
|
|
7
111
|
"additionalProperties": false,
|
|
112
|
+
"required": ["relayToken"],
|
|
8
113
|
"properties": {
|
|
9
114
|
"relayToken": {
|
|
10
115
|
"type": "string",
|
|
11
|
-
"minLength": 1
|
|
116
|
+
"minLength": 1,
|
|
117
|
+
"description": "Shared secret matching the OcuClaw relay token in the Even Hub app. Required."
|
|
12
118
|
},
|
|
13
119
|
"wsBind": {
|
|
14
120
|
"type": "string",
|
|
15
|
-
"default": "127.0.0.1"
|
|
121
|
+
"default": "127.0.0.1",
|
|
122
|
+
"description": "Local interface the relay WebSocket listens on."
|
|
16
123
|
},
|
|
17
124
|
"wsPort": {
|
|
18
125
|
"type": "integer",
|
|
19
126
|
"minimum": 1,
|
|
20
127
|
"maximum": 65535,
|
|
21
|
-
"default": 9000
|
|
128
|
+
"default": 9000,
|
|
129
|
+
"description": "Local port the relay WebSocket listens on."
|
|
22
130
|
},
|
|
23
131
|
"sessionLimit": {
|
|
24
132
|
"type": "integer",
|
|
25
133
|
"minimum": 1,
|
|
26
|
-
"default": 10
|
|
134
|
+
"default": 10,
|
|
135
|
+
"description": "Maximum concurrent client sessions accepted by the relay."
|
|
27
136
|
},
|
|
28
137
|
"debugPayloadMaxBytes": {
|
|
29
138
|
"type": "integer",
|
|
30
139
|
"minimum": 1,
|
|
31
|
-
"default": 2048
|
|
140
|
+
"default": 2048,
|
|
141
|
+
"description": "Maximum byte size for individual debug payloads recorded for debugctl."
|
|
32
142
|
},
|
|
33
143
|
"debugNoisyPolicies": {
|
|
34
144
|
"anyOf": [
|
|
@@ -41,7 +151,8 @@
|
|
|
41
151
|
{
|
|
42
152
|
"type": "null"
|
|
43
153
|
}
|
|
44
|
-
]
|
|
154
|
+
],
|
|
155
|
+
"description": "Per-channel filters that suppress or sample noisy debug events."
|
|
45
156
|
},
|
|
46
157
|
"externalDebugToolsEnabled": {
|
|
47
158
|
"type": "boolean",
|
|
@@ -49,14 +160,18 @@
|
|
|
49
160
|
"description": "Allow debugctl-style external debug tools to use debug-set, debug-dump, and remote-control."
|
|
50
161
|
},
|
|
51
162
|
"sonioxApiKey": {
|
|
52
|
-
"type": "string"
|
|
163
|
+
"type": "string",
|
|
164
|
+
"description": "Optional Soniox API key. Enables Soniox speech-to-text for voice input."
|
|
53
165
|
},
|
|
54
166
|
"evenAiEnabled": {
|
|
55
167
|
"type": "boolean",
|
|
56
|
-
"default": false
|
|
168
|
+
"default": false,
|
|
169
|
+
"description": "Route Even AI agent requests through OcuClaw. When true, evenAiToken is required."
|
|
57
170
|
},
|
|
58
171
|
"evenAiToken": {
|
|
59
|
-
"type": "string"
|
|
172
|
+
"type": "string",
|
|
173
|
+
"minLength": 1,
|
|
174
|
+
"description": "Shared secret matching the password set in the Even AI Agent Configure section of the Even Realities app. Required when evenAiEnabled is true."
|
|
60
175
|
},
|
|
61
176
|
"evenAiSystemPrompt": {
|
|
62
177
|
"type": "string",
|
|
@@ -65,17 +180,23 @@
|
|
|
65
180
|
"evenAiRequestTimeoutMs": {
|
|
66
181
|
"type": "integer",
|
|
67
182
|
"minimum": 1,
|
|
68
|
-
"default": 60000
|
|
183
|
+
"default": 60000,
|
|
184
|
+
"deprecated": true,
|
|
185
|
+
"description": "Deprecated — scheduled for removal in a future release. The built-in default is used when this key is absent. Timeout (ms) for Even AI upstream requests."
|
|
69
186
|
},
|
|
70
187
|
"evenAiMaxBodyBytes": {
|
|
71
188
|
"type": "integer",
|
|
72
189
|
"minimum": 1,
|
|
73
|
-
"default": 65536
|
|
190
|
+
"default": 65536,
|
|
191
|
+
"deprecated": true,
|
|
192
|
+
"description": "Deprecated — scheduled for removal in a future release. The built-in default is used when this key is absent. Maximum response body size (bytes) accepted from the Even AI upstream."
|
|
74
193
|
},
|
|
75
194
|
"evenAiDedupWindowMs": {
|
|
76
195
|
"type": "integer",
|
|
77
196
|
"minimum": 0,
|
|
78
|
-
"default": 500
|
|
197
|
+
"default": 500,
|
|
198
|
+
"deprecated": true,
|
|
199
|
+
"description": "Deprecated — scheduled for removal in a future release. The built-in default is used when this key is absent. Dedup window (ms) for collapsing repeated Even AI requests."
|
|
79
200
|
},
|
|
80
201
|
"evenAiRoutingMode": {
|
|
81
202
|
"type": "string",
|
|
@@ -84,12 +205,39 @@
|
|
|
84
205
|
"background",
|
|
85
206
|
"background_new"
|
|
86
207
|
],
|
|
87
|
-
"default": "active"
|
|
208
|
+
"default": "active",
|
|
209
|
+
"description": "Even AI session routing: active uses the current session, background reuses a dedicated session, background_new starts a fresh session per request."
|
|
88
210
|
},
|
|
89
211
|
"evenAiDedicatedSessionKey": {
|
|
90
212
|
"type": "string",
|
|
91
|
-
"default": "ocuclaw:even-ai"
|
|
213
|
+
"default": "ocuclaw:even-ai",
|
|
214
|
+
"deprecated": true,
|
|
215
|
+
"description": "Deprecated — scheduled for removal in a future release. The built-in default is used when this key is absent. Internal session key prefix for background Even AI routing. Must start with 'ocuclaw:'."
|
|
216
|
+
},
|
|
217
|
+
"renderGlassesUiTimeoutMs": {
|
|
218
|
+
"type": "integer",
|
|
219
|
+
"minimum": 0,
|
|
220
|
+
"default": 1800000,
|
|
221
|
+
"description": "How long render_glasses_ui waits for user interaction before resolving as { result: \"timeout\" }. Bounds the orphan tool_use corruption window if the gateway dies during a pending render. Default 1800000 (30 minutes). 0 disables the timeout (infinite wait)."
|
|
222
|
+
},
|
|
223
|
+
"freshnessWindowMs": {
|
|
224
|
+
"type": "integer",
|
|
225
|
+
"minimum": 3000,
|
|
226
|
+
"maximum": 8000,
|
|
227
|
+
"default": 5000,
|
|
228
|
+
"description": "How long (ms) a fresh agent summary stays preferred over a tool label in the glasses activity status. Clamped 3000-8000."
|
|
92
229
|
}
|
|
230
|
+
},
|
|
231
|
+
"if": {
|
|
232
|
+
"properties": {
|
|
233
|
+
"evenAiEnabled": {
|
|
234
|
+
"const": true
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
"required": ["evenAiEnabled"]
|
|
238
|
+
},
|
|
239
|
+
"then": {
|
|
240
|
+
"required": ["evenAiToken"]
|
|
93
241
|
}
|
|
94
242
|
}
|
|
95
243
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocuclaw",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"requiresClientVersion": "1.3.0",
|
|
5
|
+
"description": "OcuClaw for Even Realities G2 smart glasses.",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"files": [
|
|
@@ -24,13 +25,20 @@
|
|
|
24
25
|
"openclaw": {
|
|
25
26
|
"extensions": [
|
|
26
27
|
"./dist/index.js"
|
|
27
|
-
]
|
|
28
|
+
],
|
|
29
|
+
"install": {
|
|
30
|
+
"npmSpec": "ocuclaw",
|
|
31
|
+
"defaultChoice": "npm",
|
|
32
|
+
"minHostVersion": ">=2026.5.20"
|
|
33
|
+
}
|
|
28
34
|
},
|
|
29
35
|
"dependencies": {
|
|
30
36
|
"marked": "^17.0.2",
|
|
37
|
+
"undici": "^6.26.0",
|
|
31
38
|
"ws": "^8.19.0"
|
|
32
39
|
},
|
|
33
40
|
"scripts": {
|
|
34
|
-
"build": "node ./scripts/build.mjs"
|
|
41
|
+
"build": "node ./scripts/build.mjs",
|
|
42
|
+
"prepare": "node ./scripts/build.mjs"
|
|
35
43
|
}
|
|
36
44
|
}
|