@maudecode/openclaw-cowtail 0.12.1 → 0.12.3
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 +57 -6
- package/dist/setup-entry.js +57 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13844,6 +13844,7 @@ var openclawActionSubmittedEventSchema = openclawEventEnvelopeSchema.extend({
|
|
|
13844
13844
|
payload: jsonObjectSchema
|
|
13845
13845
|
});
|
|
13846
13846
|
var openclawRequestIdSchema = nonEmptyStringSchema;
|
|
13847
|
+
var openclawIdempotencyKeySchema = nonEmptyStringSchema;
|
|
13847
13848
|
var openclawActionDraftSchema = exports_external.object({
|
|
13848
13849
|
label: nonEmptyStringSchema,
|
|
13849
13850
|
kind: nonEmptyStringSchema,
|
|
@@ -13852,6 +13853,7 @@ var openclawActionDraftSchema = exports_external.object({
|
|
|
13852
13853
|
var openclawPluginMessageCommandSchema = requireOpenClawRenderableContent(exports_external.object({
|
|
13853
13854
|
type: exports_external.literal("openclaw_message"),
|
|
13854
13855
|
requestId: openclawRequestIdSchema,
|
|
13856
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13855
13857
|
sessionKey: nonEmptyStringSchema,
|
|
13856
13858
|
title: nonEmptyStringSchema.optional(),
|
|
13857
13859
|
text: openclawMessageTextSchema,
|
|
@@ -13864,6 +13866,7 @@ var openclawPluginMessageCommandSchema = requireOpenClawRenderableContent(export
|
|
|
13864
13866
|
var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(exports_external.object({
|
|
13865
13867
|
type: exports_external.literal("openclaw_message_update"),
|
|
13866
13868
|
requestId: openclawRequestIdSchema,
|
|
13869
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13867
13870
|
messageId: nonEmptyStringSchema,
|
|
13868
13871
|
text: openclawMessageTextSchema,
|
|
13869
13872
|
links: exports_external.array(openclawLinkSchema).optional(),
|
|
@@ -13874,46 +13877,54 @@ var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(
|
|
|
13874
13877
|
var openclawIosNewThreadCommandSchema = exports_external.object({
|
|
13875
13878
|
type: exports_external.literal("ios_new_thread"),
|
|
13876
13879
|
requestId: openclawRequestIdSchema,
|
|
13880
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13877
13881
|
title: nonEmptyStringSchema.optional(),
|
|
13878
13882
|
text: nonEmptyStringSchema
|
|
13879
13883
|
});
|
|
13880
13884
|
var openclawIosReplyCommandSchema = exports_external.object({
|
|
13881
13885
|
type: exports_external.literal("ios_reply"),
|
|
13882
13886
|
requestId: openclawRequestIdSchema,
|
|
13887
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13883
13888
|
threadId: nonEmptyStringSchema,
|
|
13884
13889
|
text: nonEmptyStringSchema
|
|
13885
13890
|
});
|
|
13886
13891
|
var openclawIosActionCommandSchema = exports_external.object({
|
|
13887
13892
|
type: exports_external.literal("ios_action"),
|
|
13888
13893
|
requestId: openclawRequestIdSchema,
|
|
13894
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13889
13895
|
actionId: nonEmptyStringSchema,
|
|
13890
13896
|
payload: jsonObjectSchema
|
|
13891
13897
|
});
|
|
13892
13898
|
var openclawIosMarkThreadReadCommandSchema = exports_external.object({
|
|
13893
13899
|
type: exports_external.literal("ios_mark_thread_read"),
|
|
13894
13900
|
requestId: openclawRequestIdSchema,
|
|
13901
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13895
13902
|
threadId: nonEmptyStringSchema
|
|
13896
13903
|
});
|
|
13897
13904
|
var openclawIosRenameThreadCommandSchema = exports_external.object({
|
|
13898
13905
|
type: exports_external.literal("ios_rename_thread"),
|
|
13899
13906
|
requestId: openclawRequestIdSchema,
|
|
13907
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13900
13908
|
threadId: nonEmptyStringSchema,
|
|
13901
13909
|
title: nonEmptyStringSchema
|
|
13902
13910
|
});
|
|
13903
13911
|
var openclawIosDeleteThreadCommandSchema = exports_external.object({
|
|
13904
13912
|
type: exports_external.literal("ios_delete_thread"),
|
|
13905
13913
|
requestId: openclawRequestIdSchema,
|
|
13914
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13906
13915
|
threadId: nonEmptyStringSchema
|
|
13907
13916
|
});
|
|
13908
13917
|
var openclawSessionBoundCommandSchema = exports_external.object({
|
|
13909
13918
|
type: exports_external.literal("openclaw_session_bound"),
|
|
13910
13919
|
requestId: openclawRequestIdSchema,
|
|
13920
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13911
13921
|
threadId: nonEmptyStringSchema,
|
|
13912
13922
|
sessionKey: nonEmptyStringSchema
|
|
13913
13923
|
});
|
|
13914
13924
|
var openclawActionResultCommandSchema = exports_external.object({
|
|
13915
13925
|
type: exports_external.literal("openclaw_action_result"),
|
|
13916
13926
|
requestId: openclawRequestIdSchema,
|
|
13927
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13917
13928
|
actionId: nonEmptyStringSchema,
|
|
13918
13929
|
state: exports_external.enum(["submitted", "failed", "expired"]),
|
|
13919
13930
|
resultMetadata: jsonObjectSchema.optional()
|
|
@@ -14164,33 +14175,41 @@ class CowtailRealtimeClient {
|
|
|
14164
14175
|
this.#closeSocket();
|
|
14165
14176
|
}
|
|
14166
14177
|
sendOpenClawMessage(command) {
|
|
14178
|
+
const requestId = this.#requestIdFactory();
|
|
14167
14179
|
return this.#sendCommand({
|
|
14168
14180
|
...command,
|
|
14169
|
-
requestId
|
|
14181
|
+
requestId,
|
|
14182
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14170
14183
|
links: command.links ?? [],
|
|
14171
14184
|
toolCalls: command.toolCalls ?? [],
|
|
14172
14185
|
actions: command.actions ?? []
|
|
14173
14186
|
});
|
|
14174
14187
|
}
|
|
14175
14188
|
sendOpenClawMessageUpdate(command) {
|
|
14189
|
+
const requestId = this.#requestIdFactory();
|
|
14176
14190
|
return this.#sendCommand({
|
|
14177
14191
|
...command,
|
|
14178
|
-
requestId
|
|
14192
|
+
requestId,
|
|
14193
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14179
14194
|
...command.links ? { links: command.links } : {},
|
|
14180
14195
|
...command.toolCalls ? { toolCalls: command.toolCalls } : {},
|
|
14181
14196
|
...command.actions ? { actions: command.actions } : {}
|
|
14182
14197
|
});
|
|
14183
14198
|
}
|
|
14184
14199
|
sendSessionBound(command) {
|
|
14200
|
+
const requestId = this.#requestIdFactory();
|
|
14185
14201
|
return this.#sendCommand({
|
|
14186
14202
|
...command,
|
|
14187
|
-
requestId
|
|
14203
|
+
requestId,
|
|
14204
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14188
14205
|
}).then((result) => result.sequence);
|
|
14189
14206
|
}
|
|
14190
14207
|
sendActionResult(command) {
|
|
14208
|
+
const requestId = this.#requestIdFactory();
|
|
14191
14209
|
return this.#sendCommand({
|
|
14192
14210
|
...command,
|
|
14193
|
-
requestId
|
|
14211
|
+
requestId,
|
|
14212
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14194
14213
|
}).then((result) => result.sequence);
|
|
14195
14214
|
}
|
|
14196
14215
|
#connect() {
|
|
@@ -14498,6 +14517,7 @@ async function handleCowtailEvent(params) {
|
|
|
14498
14517
|
if (!thread.sessionKey) {
|
|
14499
14518
|
await client.sendSessionBound({
|
|
14500
14519
|
type: "openclaw_session_bound",
|
|
14520
|
+
idempotencyKey: `cowtail:session-bound:${thread.id}`,
|
|
14501
14521
|
threadId: thread.id,
|
|
14502
14522
|
sessionKey: route.sessionKey
|
|
14503
14523
|
});
|
|
@@ -14566,6 +14586,7 @@ async function handleCowtailEvent(params) {
|
|
|
14566
14586
|
});
|
|
14567
14587
|
await client.sendActionResult({
|
|
14568
14588
|
type: "openclaw_action_result",
|
|
14589
|
+
idempotencyKey: `cowtail:action-result:${action.id}:${dispatchSucceeded ? "submitted" : "failed"}`,
|
|
14569
14590
|
actionId: action.id,
|
|
14570
14591
|
state: dispatchSucceeded ? "submitted" : "failed"
|
|
14571
14592
|
});
|
|
@@ -14573,6 +14594,7 @@ async function handleCowtailEvent(params) {
|
|
|
14573
14594
|
logger?.error?.(`Cowtail action dispatch failed: ${errorMessage(error48)}`);
|
|
14574
14595
|
await client.sendActionResult({
|
|
14575
14596
|
type: "openclaw_action_result",
|
|
14597
|
+
idempotencyKey: `cowtail:action-result:${action.id}:failed`,
|
|
14576
14598
|
actionId: action.id,
|
|
14577
14599
|
state: "failed"
|
|
14578
14600
|
});
|
|
@@ -14602,7 +14624,13 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14602
14624
|
body,
|
|
14603
14625
|
timestamp: message.createdAt
|
|
14604
14626
|
});
|
|
14605
|
-
const streamState = {
|
|
14627
|
+
const streamState = {
|
|
14628
|
+
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14629
|
+
updateIndex: 0,
|
|
14630
|
+
text: "",
|
|
14631
|
+
links: [],
|
|
14632
|
+
toolCalls: []
|
|
14633
|
+
};
|
|
14606
14634
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14607
14635
|
cfg: runtime.config.loadConfig(),
|
|
14608
14636
|
channel: CHANNEL_ID,
|
|
@@ -14658,7 +14686,13 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14658
14686
|
timestamp
|
|
14659
14687
|
});
|
|
14660
14688
|
let dispatchFailed = false;
|
|
14661
|
-
const streamState = {
|
|
14689
|
+
const streamState = {
|
|
14690
|
+
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14691
|
+
updateIndex: 0,
|
|
14692
|
+
text: "",
|
|
14693
|
+
links: [],
|
|
14694
|
+
toolCalls: []
|
|
14695
|
+
};
|
|
14662
14696
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14663
14697
|
cfg: runtime.config.loadConfig(),
|
|
14664
14698
|
channel: CHANNEL_ID,
|
|
@@ -14745,6 +14779,7 @@ async function deliverCowtailReply(params) {
|
|
|
14745
14779
|
if (!params.streamState.messageId) {
|
|
14746
14780
|
const result = await params.client.sendOpenClawMessage({
|
|
14747
14781
|
type: "openclaw_message",
|
|
14782
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14748
14783
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14749
14784
|
title: params.thread.title,
|
|
14750
14785
|
text: messageText,
|
|
@@ -14763,6 +14798,7 @@ async function deliverCowtailReply(params) {
|
|
|
14763
14798
|
}
|
|
14764
14799
|
await params.client.sendOpenClawMessageUpdate({
|
|
14765
14800
|
type: "openclaw_message_update",
|
|
14801
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14766
14802
|
messageId: params.streamState.messageId,
|
|
14767
14803
|
text: messageText,
|
|
14768
14804
|
links,
|
|
@@ -14779,6 +14815,7 @@ async function deliverCowtailReply(params) {
|
|
|
14779
14815
|
if (!params.streamState.messageId) {
|
|
14780
14816
|
const result = await params.client.sendOpenClawMessage({
|
|
14781
14817
|
type: "openclaw_message",
|
|
14818
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14782
14819
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14783
14820
|
title: params.thread.title,
|
|
14784
14821
|
text: params.streamState.text,
|
|
@@ -14797,6 +14834,7 @@ async function deliverCowtailReply(params) {
|
|
|
14797
14834
|
}
|
|
14798
14835
|
await params.client.sendOpenClawMessageUpdate({
|
|
14799
14836
|
type: "openclaw_message_update",
|
|
14837
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14800
14838
|
messageId: params.streamState.messageId,
|
|
14801
14839
|
text: params.streamState.text,
|
|
14802
14840
|
links,
|
|
@@ -14809,6 +14847,7 @@ async function deliverCowtailReply(params) {
|
|
|
14809
14847
|
params.streamState.text = text;
|
|
14810
14848
|
await params.client.sendOpenClawMessageUpdate({
|
|
14811
14849
|
type: "openclaw_message_update",
|
|
14850
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14812
14851
|
messageId: params.streamState.messageId,
|
|
14813
14852
|
text,
|
|
14814
14853
|
links,
|
|
@@ -14821,6 +14860,7 @@ async function deliverCowtailReply(params) {
|
|
|
14821
14860
|
}
|
|
14822
14861
|
await params.client.sendOpenClawMessage({
|
|
14823
14862
|
type: "openclaw_message",
|
|
14863
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14824
14864
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14825
14865
|
title: params.thread.title,
|
|
14826
14866
|
text,
|
|
@@ -14838,6 +14878,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14838
14878
|
}
|
|
14839
14879
|
await params.client.sendOpenClawMessageUpdate({
|
|
14840
14880
|
type: "openclaw_message_update",
|
|
14881
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14841
14882
|
messageId: params.streamState.messageId,
|
|
14842
14883
|
text: params.streamState.text,
|
|
14843
14884
|
links: params.streamState.links,
|
|
@@ -14849,6 +14890,12 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14849
14890
|
}
|
|
14850
14891
|
function recordCreatedOpenClawMessageId(streamState, result) {
|
|
14851
14892
|
if (result.payload?.dropped === true) {
|
|
14893
|
+
if (result.payload.duplicate === true) {
|
|
14894
|
+
const duplicateMessageId = result.payload.messageId;
|
|
14895
|
+
if (typeof duplicateMessageId === "string" && duplicateMessageId.trim()) {
|
|
14896
|
+
return duplicateMessageId;
|
|
14897
|
+
}
|
|
14898
|
+
}
|
|
14852
14899
|
streamState.failed = true;
|
|
14853
14900
|
streamState.completed = true;
|
|
14854
14901
|
return;
|
|
@@ -14860,6 +14907,10 @@ function recordCreatedOpenClawMessageId(streamState, result) {
|
|
|
14860
14907
|
streamState.failed = true;
|
|
14861
14908
|
throw new Error("Cowtail realtime ack missing messageId for streamed OpenClaw reply");
|
|
14862
14909
|
}
|
|
14910
|
+
function nextStreamUpdateIdempotencyKey(streamState) {
|
|
14911
|
+
streamState.updateIndex += 1;
|
|
14912
|
+
return `${streamState.idempotencyKey}:update:${streamState.updateIndex}`;
|
|
14913
|
+
}
|
|
14863
14914
|
function resolveCowtailReplyLinks(payload) {
|
|
14864
14915
|
const urls = [
|
|
14865
14916
|
...Array.isArray(payload.mediaUrls) ? payload.mediaUrls : [],
|
package/dist/setup-entry.js
CHANGED
|
@@ -13844,6 +13844,7 @@ var openclawActionSubmittedEventSchema = openclawEventEnvelopeSchema.extend({
|
|
|
13844
13844
|
payload: jsonObjectSchema
|
|
13845
13845
|
});
|
|
13846
13846
|
var openclawRequestIdSchema = nonEmptyStringSchema;
|
|
13847
|
+
var openclawIdempotencyKeySchema = nonEmptyStringSchema;
|
|
13847
13848
|
var openclawActionDraftSchema = exports_external.object({
|
|
13848
13849
|
label: nonEmptyStringSchema,
|
|
13849
13850
|
kind: nonEmptyStringSchema,
|
|
@@ -13852,6 +13853,7 @@ var openclawActionDraftSchema = exports_external.object({
|
|
|
13852
13853
|
var openclawPluginMessageCommandSchema = requireOpenClawRenderableContent(exports_external.object({
|
|
13853
13854
|
type: exports_external.literal("openclaw_message"),
|
|
13854
13855
|
requestId: openclawRequestIdSchema,
|
|
13856
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13855
13857
|
sessionKey: nonEmptyStringSchema,
|
|
13856
13858
|
title: nonEmptyStringSchema.optional(),
|
|
13857
13859
|
text: openclawMessageTextSchema,
|
|
@@ -13864,6 +13866,7 @@ var openclawPluginMessageCommandSchema = requireOpenClawRenderableContent(export
|
|
|
13864
13866
|
var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(exports_external.object({
|
|
13865
13867
|
type: exports_external.literal("openclaw_message_update"),
|
|
13866
13868
|
requestId: openclawRequestIdSchema,
|
|
13869
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13867
13870
|
messageId: nonEmptyStringSchema,
|
|
13868
13871
|
text: openclawMessageTextSchema,
|
|
13869
13872
|
links: exports_external.array(openclawLinkSchema).optional(),
|
|
@@ -13874,46 +13877,54 @@ var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(
|
|
|
13874
13877
|
var openclawIosNewThreadCommandSchema = exports_external.object({
|
|
13875
13878
|
type: exports_external.literal("ios_new_thread"),
|
|
13876
13879
|
requestId: openclawRequestIdSchema,
|
|
13880
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13877
13881
|
title: nonEmptyStringSchema.optional(),
|
|
13878
13882
|
text: nonEmptyStringSchema
|
|
13879
13883
|
});
|
|
13880
13884
|
var openclawIosReplyCommandSchema = exports_external.object({
|
|
13881
13885
|
type: exports_external.literal("ios_reply"),
|
|
13882
13886
|
requestId: openclawRequestIdSchema,
|
|
13887
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13883
13888
|
threadId: nonEmptyStringSchema,
|
|
13884
13889
|
text: nonEmptyStringSchema
|
|
13885
13890
|
});
|
|
13886
13891
|
var openclawIosActionCommandSchema = exports_external.object({
|
|
13887
13892
|
type: exports_external.literal("ios_action"),
|
|
13888
13893
|
requestId: openclawRequestIdSchema,
|
|
13894
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13889
13895
|
actionId: nonEmptyStringSchema,
|
|
13890
13896
|
payload: jsonObjectSchema
|
|
13891
13897
|
});
|
|
13892
13898
|
var openclawIosMarkThreadReadCommandSchema = exports_external.object({
|
|
13893
13899
|
type: exports_external.literal("ios_mark_thread_read"),
|
|
13894
13900
|
requestId: openclawRequestIdSchema,
|
|
13901
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13895
13902
|
threadId: nonEmptyStringSchema
|
|
13896
13903
|
});
|
|
13897
13904
|
var openclawIosRenameThreadCommandSchema = exports_external.object({
|
|
13898
13905
|
type: exports_external.literal("ios_rename_thread"),
|
|
13899
13906
|
requestId: openclawRequestIdSchema,
|
|
13907
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13900
13908
|
threadId: nonEmptyStringSchema,
|
|
13901
13909
|
title: nonEmptyStringSchema
|
|
13902
13910
|
});
|
|
13903
13911
|
var openclawIosDeleteThreadCommandSchema = exports_external.object({
|
|
13904
13912
|
type: exports_external.literal("ios_delete_thread"),
|
|
13905
13913
|
requestId: openclawRequestIdSchema,
|
|
13914
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13906
13915
|
threadId: nonEmptyStringSchema
|
|
13907
13916
|
});
|
|
13908
13917
|
var openclawSessionBoundCommandSchema = exports_external.object({
|
|
13909
13918
|
type: exports_external.literal("openclaw_session_bound"),
|
|
13910
13919
|
requestId: openclawRequestIdSchema,
|
|
13920
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13911
13921
|
threadId: nonEmptyStringSchema,
|
|
13912
13922
|
sessionKey: nonEmptyStringSchema
|
|
13913
13923
|
});
|
|
13914
13924
|
var openclawActionResultCommandSchema = exports_external.object({
|
|
13915
13925
|
type: exports_external.literal("openclaw_action_result"),
|
|
13916
13926
|
requestId: openclawRequestIdSchema,
|
|
13927
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13917
13928
|
actionId: nonEmptyStringSchema,
|
|
13918
13929
|
state: exports_external.enum(["submitted", "failed", "expired"]),
|
|
13919
13930
|
resultMetadata: jsonObjectSchema.optional()
|
|
@@ -14164,33 +14175,41 @@ class CowtailRealtimeClient {
|
|
|
14164
14175
|
this.#closeSocket();
|
|
14165
14176
|
}
|
|
14166
14177
|
sendOpenClawMessage(command) {
|
|
14178
|
+
const requestId = this.#requestIdFactory();
|
|
14167
14179
|
return this.#sendCommand({
|
|
14168
14180
|
...command,
|
|
14169
|
-
requestId
|
|
14181
|
+
requestId,
|
|
14182
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14170
14183
|
links: command.links ?? [],
|
|
14171
14184
|
toolCalls: command.toolCalls ?? [],
|
|
14172
14185
|
actions: command.actions ?? []
|
|
14173
14186
|
});
|
|
14174
14187
|
}
|
|
14175
14188
|
sendOpenClawMessageUpdate(command) {
|
|
14189
|
+
const requestId = this.#requestIdFactory();
|
|
14176
14190
|
return this.#sendCommand({
|
|
14177
14191
|
...command,
|
|
14178
|
-
requestId
|
|
14192
|
+
requestId,
|
|
14193
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14179
14194
|
...command.links ? { links: command.links } : {},
|
|
14180
14195
|
...command.toolCalls ? { toolCalls: command.toolCalls } : {},
|
|
14181
14196
|
...command.actions ? { actions: command.actions } : {}
|
|
14182
14197
|
});
|
|
14183
14198
|
}
|
|
14184
14199
|
sendSessionBound(command) {
|
|
14200
|
+
const requestId = this.#requestIdFactory();
|
|
14185
14201
|
return this.#sendCommand({
|
|
14186
14202
|
...command,
|
|
14187
|
-
requestId
|
|
14203
|
+
requestId,
|
|
14204
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14188
14205
|
}).then((result) => result.sequence);
|
|
14189
14206
|
}
|
|
14190
14207
|
sendActionResult(command) {
|
|
14208
|
+
const requestId = this.#requestIdFactory();
|
|
14191
14209
|
return this.#sendCommand({
|
|
14192
14210
|
...command,
|
|
14193
|
-
requestId
|
|
14211
|
+
requestId,
|
|
14212
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14194
14213
|
}).then((result) => result.sequence);
|
|
14195
14214
|
}
|
|
14196
14215
|
#connect() {
|
|
@@ -14498,6 +14517,7 @@ async function handleCowtailEvent(params) {
|
|
|
14498
14517
|
if (!thread.sessionKey) {
|
|
14499
14518
|
await client.sendSessionBound({
|
|
14500
14519
|
type: "openclaw_session_bound",
|
|
14520
|
+
idempotencyKey: `cowtail:session-bound:${thread.id}`,
|
|
14501
14521
|
threadId: thread.id,
|
|
14502
14522
|
sessionKey: route.sessionKey
|
|
14503
14523
|
});
|
|
@@ -14566,6 +14586,7 @@ async function handleCowtailEvent(params) {
|
|
|
14566
14586
|
});
|
|
14567
14587
|
await client.sendActionResult({
|
|
14568
14588
|
type: "openclaw_action_result",
|
|
14589
|
+
idempotencyKey: `cowtail:action-result:${action.id}:${dispatchSucceeded ? "submitted" : "failed"}`,
|
|
14569
14590
|
actionId: action.id,
|
|
14570
14591
|
state: dispatchSucceeded ? "submitted" : "failed"
|
|
14571
14592
|
});
|
|
@@ -14573,6 +14594,7 @@ async function handleCowtailEvent(params) {
|
|
|
14573
14594
|
logger?.error?.(`Cowtail action dispatch failed: ${errorMessage(error48)}`);
|
|
14574
14595
|
await client.sendActionResult({
|
|
14575
14596
|
type: "openclaw_action_result",
|
|
14597
|
+
idempotencyKey: `cowtail:action-result:${action.id}:failed`,
|
|
14576
14598
|
actionId: action.id,
|
|
14577
14599
|
state: "failed"
|
|
14578
14600
|
});
|
|
@@ -14602,7 +14624,13 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14602
14624
|
body,
|
|
14603
14625
|
timestamp: message.createdAt
|
|
14604
14626
|
});
|
|
14605
|
-
const streamState = {
|
|
14627
|
+
const streamState = {
|
|
14628
|
+
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14629
|
+
updateIndex: 0,
|
|
14630
|
+
text: "",
|
|
14631
|
+
links: [],
|
|
14632
|
+
toolCalls: []
|
|
14633
|
+
};
|
|
14606
14634
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14607
14635
|
cfg: runtime.config.loadConfig(),
|
|
14608
14636
|
channel: CHANNEL_ID,
|
|
@@ -14658,7 +14686,13 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14658
14686
|
timestamp
|
|
14659
14687
|
});
|
|
14660
14688
|
let dispatchFailed = false;
|
|
14661
|
-
const streamState = {
|
|
14689
|
+
const streamState = {
|
|
14690
|
+
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14691
|
+
updateIndex: 0,
|
|
14692
|
+
text: "",
|
|
14693
|
+
links: [],
|
|
14694
|
+
toolCalls: []
|
|
14695
|
+
};
|
|
14662
14696
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14663
14697
|
cfg: runtime.config.loadConfig(),
|
|
14664
14698
|
channel: CHANNEL_ID,
|
|
@@ -14745,6 +14779,7 @@ async function deliverCowtailReply(params) {
|
|
|
14745
14779
|
if (!params.streamState.messageId) {
|
|
14746
14780
|
const result = await params.client.sendOpenClawMessage({
|
|
14747
14781
|
type: "openclaw_message",
|
|
14782
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14748
14783
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14749
14784
|
title: params.thread.title,
|
|
14750
14785
|
text: messageText,
|
|
@@ -14763,6 +14798,7 @@ async function deliverCowtailReply(params) {
|
|
|
14763
14798
|
}
|
|
14764
14799
|
await params.client.sendOpenClawMessageUpdate({
|
|
14765
14800
|
type: "openclaw_message_update",
|
|
14801
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14766
14802
|
messageId: params.streamState.messageId,
|
|
14767
14803
|
text: messageText,
|
|
14768
14804
|
links,
|
|
@@ -14779,6 +14815,7 @@ async function deliverCowtailReply(params) {
|
|
|
14779
14815
|
if (!params.streamState.messageId) {
|
|
14780
14816
|
const result = await params.client.sendOpenClawMessage({
|
|
14781
14817
|
type: "openclaw_message",
|
|
14818
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14782
14819
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14783
14820
|
title: params.thread.title,
|
|
14784
14821
|
text: params.streamState.text,
|
|
@@ -14797,6 +14834,7 @@ async function deliverCowtailReply(params) {
|
|
|
14797
14834
|
}
|
|
14798
14835
|
await params.client.sendOpenClawMessageUpdate({
|
|
14799
14836
|
type: "openclaw_message_update",
|
|
14837
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14800
14838
|
messageId: params.streamState.messageId,
|
|
14801
14839
|
text: params.streamState.text,
|
|
14802
14840
|
links,
|
|
@@ -14809,6 +14847,7 @@ async function deliverCowtailReply(params) {
|
|
|
14809
14847
|
params.streamState.text = text;
|
|
14810
14848
|
await params.client.sendOpenClawMessageUpdate({
|
|
14811
14849
|
type: "openclaw_message_update",
|
|
14850
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14812
14851
|
messageId: params.streamState.messageId,
|
|
14813
14852
|
text,
|
|
14814
14853
|
links,
|
|
@@ -14821,6 +14860,7 @@ async function deliverCowtailReply(params) {
|
|
|
14821
14860
|
}
|
|
14822
14861
|
await params.client.sendOpenClawMessage({
|
|
14823
14862
|
type: "openclaw_message",
|
|
14863
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14824
14864
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14825
14865
|
title: params.thread.title,
|
|
14826
14866
|
text,
|
|
@@ -14838,6 +14878,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14838
14878
|
}
|
|
14839
14879
|
await params.client.sendOpenClawMessageUpdate({
|
|
14840
14880
|
type: "openclaw_message_update",
|
|
14881
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14841
14882
|
messageId: params.streamState.messageId,
|
|
14842
14883
|
text: params.streamState.text,
|
|
14843
14884
|
links: params.streamState.links,
|
|
@@ -14849,6 +14890,12 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14849
14890
|
}
|
|
14850
14891
|
function recordCreatedOpenClawMessageId(streamState, result) {
|
|
14851
14892
|
if (result.payload?.dropped === true) {
|
|
14893
|
+
if (result.payload.duplicate === true) {
|
|
14894
|
+
const duplicateMessageId = result.payload.messageId;
|
|
14895
|
+
if (typeof duplicateMessageId === "string" && duplicateMessageId.trim()) {
|
|
14896
|
+
return duplicateMessageId;
|
|
14897
|
+
}
|
|
14898
|
+
}
|
|
14852
14899
|
streamState.failed = true;
|
|
14853
14900
|
streamState.completed = true;
|
|
14854
14901
|
return;
|
|
@@ -14860,6 +14907,10 @@ function recordCreatedOpenClawMessageId(streamState, result) {
|
|
|
14860
14907
|
streamState.failed = true;
|
|
14861
14908
|
throw new Error("Cowtail realtime ack missing messageId for streamed OpenClaw reply");
|
|
14862
14909
|
}
|
|
14910
|
+
function nextStreamUpdateIdempotencyKey(streamState) {
|
|
14911
|
+
streamState.updateIndex += 1;
|
|
14912
|
+
return `${streamState.idempotencyKey}:update:${streamState.updateIndex}`;
|
|
14913
|
+
}
|
|
14863
14914
|
function resolveCowtailReplyLinks(payload) {
|
|
14864
14915
|
const urls = [
|
|
14865
14916
|
...Array.isArray(payload.mediaUrls) ? payload.mediaUrls : [],
|