omoclaw 3.1.1 → 3.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/dist/index.js +83 -101
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -995,6 +995,7 @@ function handleSessionStatusEvent(event, dedup, state, timers, webhookFn, notify
|
|
|
995
995
|
|
|
996
996
|
// src/handlers/user-events.ts
|
|
997
997
|
var PROMPT_PREVIEW_MAX = 200;
|
|
998
|
+
var PROMPT_FLUSH_DELAY_MS = 2000;
|
|
998
999
|
function shortSessionID3(sessionID) {
|
|
999
1000
|
return sessionID.slice(0, 12);
|
|
1000
1001
|
}
|
|
@@ -1007,86 +1008,43 @@ function asObject3(value) {
|
|
|
1007
1008
|
function asString(value) {
|
|
1008
1009
|
return typeof value === "string" ? value : "";
|
|
1009
1010
|
}
|
|
1010
|
-
function collectContentText(value, output) {
|
|
1011
|
-
if (typeof value === "string") {
|
|
1012
|
-
output.push(value);
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
if (Array.isArray(value)) {
|
|
1016
|
-
for (const item of value) {
|
|
1017
|
-
collectContentText(item, output);
|
|
1018
|
-
}
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
const record = asObject3(value);
|
|
1022
|
-
if (!record) {
|
|
1023
|
-
return;
|
|
1024
|
-
}
|
|
1025
|
-
if (typeof record.text === "string") {
|
|
1026
|
-
output.push(record.text);
|
|
1027
|
-
}
|
|
1028
|
-
if (typeof record.content === "string") {
|
|
1029
|
-
output.push(record.content);
|
|
1030
|
-
} else if (Array.isArray(record.content)) {
|
|
1031
|
-
collectContentText(record.content, output);
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
function collectPartsText(value, output) {
|
|
1035
|
-
if (!Array.isArray(value)) {
|
|
1036
|
-
return;
|
|
1037
|
-
}
|
|
1038
|
-
for (const item of value) {
|
|
1039
|
-
const part = asObject3(item);
|
|
1040
|
-
if (!part) {
|
|
1041
|
-
continue;
|
|
1042
|
-
}
|
|
1043
|
-
const partType = asString(part.type);
|
|
1044
|
-
if (partType === "text" && typeof part.text === "string") {
|
|
1045
|
-
output.push(part.text);
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if (typeof part.text === "string") {
|
|
1049
|
-
output.push(part.text);
|
|
1050
|
-
}
|
|
1051
|
-
if (typeof part.content === "string") {
|
|
1052
|
-
output.push(part.content);
|
|
1053
|
-
} else if (Array.isArray(part.content)) {
|
|
1054
|
-
collectContentText(part.content, output);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
1011
|
function normalizePreviewText(input) {
|
|
1059
1012
|
return input.replace(/\s+/g, " ").trim();
|
|
1060
1013
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1014
|
+
var seenMessageIDs = new Set;
|
|
1015
|
+
var SEEN_MAX = 5000;
|
|
1016
|
+
var pendingPrompts = new Map;
|
|
1017
|
+
function evictOldestSeen() {
|
|
1018
|
+
if (seenMessageIDs.size <= SEEN_MAX)
|
|
1019
|
+
return;
|
|
1020
|
+
const first = seenMessageIDs.values().next().value;
|
|
1021
|
+
if (first !== undefined)
|
|
1022
|
+
seenMessageIDs.delete(first);
|
|
1023
|
+
}
|
|
1024
|
+
function flushPendingPrompt(messageID, notify, debugLog) {
|
|
1025
|
+
const pending = pendingPrompts.get(messageID);
|
|
1026
|
+
if (!pending)
|
|
1027
|
+
return;
|
|
1028
|
+
clearTimeout(pending.timer);
|
|
1029
|
+
pendingPrompts.delete(messageID);
|
|
1030
|
+
seenMessageIDs.add(messageID);
|
|
1031
|
+
evictOldestSeen();
|
|
1032
|
+
const preview = normalizePreviewText(pending.text).slice(0, PROMPT_PREVIEW_MAX);
|
|
1033
|
+
if (!preview) {
|
|
1034
|
+
debugLog?.(`User prompt SKIPPED (no text after flush): session=${shortSessionID3(pending.sessionID)} msg=${messageID}`);
|
|
1035
|
+
return;
|
|
1074
1036
|
}
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
const merged = normalizePreviewText(candidates.join(" "));
|
|
1078
|
-
return merged.slice(0, PROMPT_PREVIEW_MAX);
|
|
1037
|
+
debugLog?.(`User prompt FLUSHED: session=${shortSessionID3(pending.sessionID)} msg=${messageID} text="${preview.slice(0, 60)}..."`);
|
|
1038
|
+
notify("user-prompt", `[OpenCode] User prompt submitted (${shortSessionID3(pending.sessionID)}): ${preview}`, pending.agent, { promptText: preview });
|
|
1079
1039
|
}
|
|
1080
1040
|
function handleUserEvent(event, dedup, state, notify, debugLog) {
|
|
1081
1041
|
if (event.type === "session.created" || event.type === "session.updated") {
|
|
1082
1042
|
const info2 = asObject3(event.properties.info);
|
|
1083
|
-
if (!info2)
|
|
1043
|
+
if (!info2)
|
|
1084
1044
|
return;
|
|
1085
|
-
}
|
|
1086
1045
|
const sessionID2 = asString(info2.id);
|
|
1087
|
-
if (!sessionID2)
|
|
1046
|
+
if (!sessionID2)
|
|
1088
1047
|
return;
|
|
1089
|
-
}
|
|
1090
1048
|
const parentID = asString(info2.parentID);
|
|
1091
1049
|
if (parentID) {
|
|
1092
1050
|
state.setParentID(sessionID2, parentID);
|
|
@@ -1096,61 +1054,85 @@ function handleUserEvent(event, dedup, state, notify, debugLog) {
|
|
|
1096
1054
|
}
|
|
1097
1055
|
if (event.type === "tui.command.execute") {
|
|
1098
1056
|
const command = event.properties.command;
|
|
1099
|
-
if (command !== "session.interrupt")
|
|
1057
|
+
if (command !== "session.interrupt")
|
|
1100
1058
|
return;
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
if (!dedup.shouldSend(dedupKey2)) {
|
|
1059
|
+
const dedupKey = "user-interrupt:tui-command";
|
|
1060
|
+
if (!dedup.shouldSend(dedupKey))
|
|
1104
1061
|
return;
|
|
1105
|
-
}
|
|
1106
1062
|
notify("user-interrupt", "[OpenCode] User interrupt requested");
|
|
1107
1063
|
return;
|
|
1108
1064
|
}
|
|
1109
1065
|
if (event.type === "session.error") {
|
|
1110
1066
|
const sessionID2 = event.properties.sessionID;
|
|
1111
|
-
const
|
|
1112
|
-
if (!sessionID2 ||
|
|
1067
|
+
const errorObj = event.properties.error;
|
|
1068
|
+
if (!sessionID2 || errorObj?.name !== "MessageAbortedError")
|
|
1113
1069
|
return;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
if (!dedup.shouldSend(dedupKey2)) {
|
|
1070
|
+
const dedupKey = `user-interrupt:session-error:${sessionID2}`;
|
|
1071
|
+
if (!dedup.shouldSend(dedupKey))
|
|
1117
1072
|
return;
|
|
1118
|
-
}
|
|
1119
1073
|
notify("user-interrupt", `[OpenCode] User interrupt (${shortSessionID3(sessionID2)})`, state.getAgent(sessionID2));
|
|
1120
1074
|
return;
|
|
1121
1075
|
}
|
|
1122
|
-
if (event.type
|
|
1076
|
+
if (event.type === "message.part.updated") {
|
|
1077
|
+
const part = asObject3(event.properties.part);
|
|
1078
|
+
if (!part)
|
|
1079
|
+
return;
|
|
1080
|
+
const messageID2 = asString(part.messageID);
|
|
1081
|
+
if (!messageID2)
|
|
1082
|
+
return;
|
|
1083
|
+
const pending = pendingPrompts.get(messageID2);
|
|
1084
|
+
if (!pending)
|
|
1085
|
+
return;
|
|
1086
|
+
if (asString(part.type) !== "text")
|
|
1087
|
+
return;
|
|
1088
|
+
if (part.synthetic === true) {
|
|
1089
|
+
debugLog?.(`User prompt part SKIPPED (synthetic): msg=${messageID2}`);
|
|
1090
|
+
seenMessageIDs.add(messageID2);
|
|
1091
|
+
evictOldestSeen();
|
|
1092
|
+
clearTimeout(pending.timer);
|
|
1093
|
+
pendingPrompts.delete(messageID2);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
const partText = asString(part.text);
|
|
1097
|
+
if (!partText)
|
|
1098
|
+
return;
|
|
1099
|
+
pending.text += (pending.text ? " " : "") + partText;
|
|
1100
|
+
flushPendingPrompt(messageID2, notify, debugLog);
|
|
1123
1101
|
return;
|
|
1124
1102
|
}
|
|
1103
|
+
if (event.type !== "message.updated")
|
|
1104
|
+
return;
|
|
1125
1105
|
const info = asObject3(event.properties.info);
|
|
1126
|
-
if (!info)
|
|
1106
|
+
if (!info)
|
|
1127
1107
|
return;
|
|
1128
|
-
|
|
1129
|
-
if (asString(info.role) !== "user") {
|
|
1108
|
+
if (asString(info.role) !== "user")
|
|
1130
1109
|
return;
|
|
1131
|
-
}
|
|
1132
1110
|
const sessionID = asString(info.sessionID);
|
|
1133
|
-
if (!sessionID)
|
|
1111
|
+
if (!sessionID)
|
|
1134
1112
|
return;
|
|
1135
|
-
|
|
1136
|
-
if (
|
|
1137
|
-
debugLog?.(`User prompt SKIPPED (sub-agent): session=${shortSessionID3(sessionID)} parent=${state.getState(sessionID)?.parentID ?? "?"}`);
|
|
1113
|
+
const messageID = asString(info.id);
|
|
1114
|
+
if (!messageID)
|
|
1138
1115
|
return;
|
|
1139
|
-
|
|
1140
|
-
const promptPreview = extractPromptPreview(info);
|
|
1141
|
-
if (!promptPreview) {
|
|
1142
|
-
debugLog?.(`User prompt SKIPPED (empty preview): session=${shortSessionID3(sessionID)}`);
|
|
1116
|
+
if (seenMessageIDs.has(messageID))
|
|
1143
1117
|
return;
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1118
|
+
if (pendingPrompts.has(messageID))
|
|
1119
|
+
return;
|
|
1120
|
+
if (state.hasParentID(sessionID)) {
|
|
1121
|
+
debugLog?.(`User prompt SKIPPED (sub-agent): session=${shortSessionID3(sessionID)} msg=${messageID}`);
|
|
1122
|
+
seenMessageIDs.add(messageID);
|
|
1123
|
+
evictOldestSeen();
|
|
1149
1124
|
return;
|
|
1150
1125
|
}
|
|
1151
|
-
debugLog?.(`User prompt
|
|
1152
|
-
|
|
1153
|
-
|
|
1126
|
+
debugLog?.(`User prompt PENDING: session=${shortSessionID3(sessionID)} msg=${messageID} (waiting for text parts)`);
|
|
1127
|
+
const timer = setTimeout(() => {
|
|
1128
|
+
flushPendingPrompt(messageID, notify, debugLog);
|
|
1129
|
+
}, PROMPT_FLUSH_DELAY_MS);
|
|
1130
|
+
pendingPrompts.set(messageID, {
|
|
1131
|
+
sessionID,
|
|
1132
|
+
messageID,
|
|
1133
|
+
agent: state.getAgent(sessionID),
|
|
1134
|
+
text: "",
|
|
1135
|
+
timer
|
|
1154
1136
|
});
|
|
1155
1137
|
}
|
|
1156
1138
|
|
package/package.json
CHANGED