@maudecode/openclaw-cowtail 0.12.1 → 0.13.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 +399 -17
- package/dist/setup-entry.js +399 -17
- package/package.json +1 -1
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(),
|
|
@@ -13871,49 +13874,71 @@ var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(
|
|
|
13871
13874
|
actions: exports_external.array(openclawActionDraftSchema).optional(),
|
|
13872
13875
|
deliveryState: openclawDeliveryStateSchema.optional()
|
|
13873
13876
|
}));
|
|
13877
|
+
var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
13878
|
+
type: exports_external.literal("openclaw_message_stream_snapshot"),
|
|
13879
|
+
requestId: openclawRequestIdSchema,
|
|
13880
|
+
streamId: nonEmptyStringSchema,
|
|
13881
|
+
sessionKey: nonEmptyStringSchema,
|
|
13882
|
+
threadId: nonEmptyStringSchema,
|
|
13883
|
+
text: openclawMessageTextSchema,
|
|
13884
|
+
links: exports_external.array(openclawLinkSchema).default([]),
|
|
13885
|
+
toolCalls: exports_external.array(openclawToolCallRecordSchema).default([]),
|
|
13886
|
+
isFinal: exports_external.boolean(),
|
|
13887
|
+
updatedAt: timestampSchema
|
|
13888
|
+
});
|
|
13889
|
+
var openclawMessageStreamSnapshotCommandSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema);
|
|
13890
|
+
var openclawMessageStreamSnapshotServerMessageSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema.omit({ requestId: true }));
|
|
13874
13891
|
var openclawIosNewThreadCommandSchema = exports_external.object({
|
|
13875
13892
|
type: exports_external.literal("ios_new_thread"),
|
|
13876
13893
|
requestId: openclawRequestIdSchema,
|
|
13894
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13877
13895
|
title: nonEmptyStringSchema.optional(),
|
|
13878
13896
|
text: nonEmptyStringSchema
|
|
13879
13897
|
});
|
|
13880
13898
|
var openclawIosReplyCommandSchema = exports_external.object({
|
|
13881
13899
|
type: exports_external.literal("ios_reply"),
|
|
13882
13900
|
requestId: openclawRequestIdSchema,
|
|
13901
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13883
13902
|
threadId: nonEmptyStringSchema,
|
|
13884
13903
|
text: nonEmptyStringSchema
|
|
13885
13904
|
});
|
|
13886
13905
|
var openclawIosActionCommandSchema = exports_external.object({
|
|
13887
13906
|
type: exports_external.literal("ios_action"),
|
|
13888
13907
|
requestId: openclawRequestIdSchema,
|
|
13908
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13889
13909
|
actionId: nonEmptyStringSchema,
|
|
13890
13910
|
payload: jsonObjectSchema
|
|
13891
13911
|
});
|
|
13892
13912
|
var openclawIosMarkThreadReadCommandSchema = exports_external.object({
|
|
13893
13913
|
type: exports_external.literal("ios_mark_thread_read"),
|
|
13894
13914
|
requestId: openclawRequestIdSchema,
|
|
13915
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13895
13916
|
threadId: nonEmptyStringSchema
|
|
13896
13917
|
});
|
|
13897
13918
|
var openclawIosRenameThreadCommandSchema = exports_external.object({
|
|
13898
13919
|
type: exports_external.literal("ios_rename_thread"),
|
|
13899
13920
|
requestId: openclawRequestIdSchema,
|
|
13921
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13900
13922
|
threadId: nonEmptyStringSchema,
|
|
13901
13923
|
title: nonEmptyStringSchema
|
|
13902
13924
|
});
|
|
13903
13925
|
var openclawIosDeleteThreadCommandSchema = exports_external.object({
|
|
13904
13926
|
type: exports_external.literal("ios_delete_thread"),
|
|
13905
13927
|
requestId: openclawRequestIdSchema,
|
|
13928
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13906
13929
|
threadId: nonEmptyStringSchema
|
|
13907
13930
|
});
|
|
13908
13931
|
var openclawSessionBoundCommandSchema = exports_external.object({
|
|
13909
13932
|
type: exports_external.literal("openclaw_session_bound"),
|
|
13910
13933
|
requestId: openclawRequestIdSchema,
|
|
13934
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13911
13935
|
threadId: nonEmptyStringSchema,
|
|
13912
13936
|
sessionKey: nonEmptyStringSchema
|
|
13913
13937
|
});
|
|
13914
13938
|
var openclawActionResultCommandSchema = exports_external.object({
|
|
13915
13939
|
type: exports_external.literal("openclaw_action_result"),
|
|
13916
13940
|
requestId: openclawRequestIdSchema,
|
|
13941
|
+
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13917
13942
|
actionId: nonEmptyStringSchema,
|
|
13918
13943
|
state: exports_external.enum(["submitted", "failed", "expired"]),
|
|
13919
13944
|
resultMetadata: jsonObjectSchema.optional()
|
|
@@ -13921,6 +13946,7 @@ var openclawActionResultCommandSchema = exports_external.object({
|
|
|
13921
13946
|
var openclawRealtimeClientMessageSchema = exports_external.union([
|
|
13922
13947
|
openclawPluginMessageCommandSchema,
|
|
13923
13948
|
openclawPluginMessageUpdateCommandSchema,
|
|
13949
|
+
openclawMessageStreamSnapshotCommandSchema,
|
|
13924
13950
|
openclawIosNewThreadCommandSchema,
|
|
13925
13951
|
openclawIosReplyCommandSchema,
|
|
13926
13952
|
openclawIosActionCommandSchema,
|
|
@@ -13943,6 +13969,7 @@ var openclawRealtimeErrorSchema = exports_external.object({
|
|
|
13943
13969
|
});
|
|
13944
13970
|
var openclawRealtimeServerMessageSchema = exports_external.union([
|
|
13945
13971
|
openclawEventEnvelopeSchema,
|
|
13972
|
+
openclawMessageStreamSnapshotServerMessageSchema,
|
|
13946
13973
|
openclawRealtimeAckSchema,
|
|
13947
13974
|
openclawRealtimeErrorSchema
|
|
13948
13975
|
]);
|
|
@@ -14164,35 +14191,49 @@ class CowtailRealtimeClient {
|
|
|
14164
14191
|
this.#closeSocket();
|
|
14165
14192
|
}
|
|
14166
14193
|
sendOpenClawMessage(command) {
|
|
14194
|
+
const requestId = this.#requestIdFactory();
|
|
14167
14195
|
return this.#sendCommand({
|
|
14168
14196
|
...command,
|
|
14169
|
-
requestId
|
|
14197
|
+
requestId,
|
|
14198
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14170
14199
|
links: command.links ?? [],
|
|
14171
14200
|
toolCalls: command.toolCalls ?? [],
|
|
14172
14201
|
actions: command.actions ?? []
|
|
14173
14202
|
});
|
|
14174
14203
|
}
|
|
14175
14204
|
sendOpenClawMessageUpdate(command) {
|
|
14205
|
+
const requestId = this.#requestIdFactory();
|
|
14176
14206
|
return this.#sendCommand({
|
|
14177
14207
|
...command,
|
|
14178
|
-
requestId
|
|
14208
|
+
requestId,
|
|
14209
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`,
|
|
14179
14210
|
...command.links ? { links: command.links } : {},
|
|
14180
14211
|
...command.toolCalls ? { toolCalls: command.toolCalls } : {},
|
|
14181
14212
|
...command.actions ? { actions: command.actions } : {}
|
|
14182
14213
|
});
|
|
14183
14214
|
}
|
|
14184
14215
|
sendSessionBound(command) {
|
|
14216
|
+
const requestId = this.#requestIdFactory();
|
|
14185
14217
|
return this.#sendCommand({
|
|
14186
14218
|
...command,
|
|
14187
|
-
requestId
|
|
14219
|
+
requestId,
|
|
14220
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14188
14221
|
}).then((result) => result.sequence);
|
|
14189
14222
|
}
|
|
14190
14223
|
sendActionResult(command) {
|
|
14224
|
+
const requestId = this.#requestIdFactory();
|
|
14191
14225
|
return this.#sendCommand({
|
|
14192
14226
|
...command,
|
|
14193
|
-
requestId
|
|
14227
|
+
requestId,
|
|
14228
|
+
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14194
14229
|
}).then((result) => result.sequence);
|
|
14195
14230
|
}
|
|
14231
|
+
sendOpenClawStreamSnapshot(command) {
|
|
14232
|
+
return this.#sendTransientCommand({
|
|
14233
|
+
...command,
|
|
14234
|
+
requestId: this.#requestIdFactory()
|
|
14235
|
+
});
|
|
14236
|
+
}
|
|
14196
14237
|
#connect() {
|
|
14197
14238
|
if (!this.#started || this.#socket) {
|
|
14198
14239
|
return;
|
|
@@ -14292,6 +14333,9 @@ class CowtailRealtimeClient {
|
|
|
14292
14333
|
this.#rejectPendingRequest(message);
|
|
14293
14334
|
return;
|
|
14294
14335
|
}
|
|
14336
|
+
if (message.type === "openclaw_message_stream_snapshot") {
|
|
14337
|
+
return;
|
|
14338
|
+
}
|
|
14295
14339
|
await this.#onEvent(message);
|
|
14296
14340
|
await this.#stateStore.writeLastSeenSequence(message.sequence);
|
|
14297
14341
|
}
|
|
@@ -14368,6 +14412,19 @@ class CowtailRealtimeClient {
|
|
|
14368
14412
|
}
|
|
14369
14413
|
});
|
|
14370
14414
|
}
|
|
14415
|
+
async#sendTransientCommand(command) {
|
|
14416
|
+
const socket = this.#socket;
|
|
14417
|
+
const handshake = this.#handshake;
|
|
14418
|
+
if (!socket || !handshake) {
|
|
14419
|
+
throw new Error("Cowtail websocket is disconnected");
|
|
14420
|
+
}
|
|
14421
|
+
await handshake.promise;
|
|
14422
|
+
const currentSocket = this.#socket;
|
|
14423
|
+
if (!currentSocket || socket !== currentSocket || handshake !== this.#handshake || !this.#isSocketOpen(currentSocket)) {
|
|
14424
|
+
throw new Error("Cowtail websocket is disconnected");
|
|
14425
|
+
}
|
|
14426
|
+
currentSocket.send(JSON.stringify(command));
|
|
14427
|
+
}
|
|
14371
14428
|
#resolvePendingRequest(requestId, sequence, payload) {
|
|
14372
14429
|
const pending = this.#pendingRequests.get(requestId);
|
|
14373
14430
|
if (!pending) {
|
|
@@ -14472,6 +14529,8 @@ var CHANNEL_LABEL = "Cowtail";
|
|
|
14472
14529
|
var SENDER_LABEL = "Cowtail iOS";
|
|
14473
14530
|
var SENDER_ID = "cowtail-ios";
|
|
14474
14531
|
var SENDER_ADDRESS = "cowtail:ios";
|
|
14532
|
+
var STREAM_MIN_INTERVAL_MS = 45;
|
|
14533
|
+
var STREAM_MIN_CHARS_DELTA = 3;
|
|
14475
14534
|
async function handleCowtailEvent(params) {
|
|
14476
14535
|
const { event, account, client, runtime, logger } = params;
|
|
14477
14536
|
switch (event.type) {
|
|
@@ -14498,6 +14557,7 @@ async function handleCowtailEvent(params) {
|
|
|
14498
14557
|
if (!thread.sessionKey) {
|
|
14499
14558
|
await client.sendSessionBound({
|
|
14500
14559
|
type: "openclaw_session_bound",
|
|
14560
|
+
idempotencyKey: `cowtail:session-bound:${thread.id}`,
|
|
14501
14561
|
threadId: thread.id,
|
|
14502
14562
|
sessionKey: route.sessionKey
|
|
14503
14563
|
});
|
|
@@ -14566,6 +14626,7 @@ async function handleCowtailEvent(params) {
|
|
|
14566
14626
|
});
|
|
14567
14627
|
await client.sendActionResult({
|
|
14568
14628
|
type: "openclaw_action_result",
|
|
14629
|
+
idempotencyKey: `cowtail:action-result:${action.id}:${dispatchSucceeded ? "submitted" : "failed"}`,
|
|
14569
14630
|
actionId: action.id,
|
|
14570
14631
|
state: dispatchSucceeded ? "submitted" : "failed"
|
|
14571
14632
|
});
|
|
@@ -14573,6 +14634,7 @@ async function handleCowtailEvent(params) {
|
|
|
14573
14634
|
logger?.error?.(`Cowtail action dispatch failed: ${errorMessage(error48)}`);
|
|
14574
14635
|
await client.sendActionResult({
|
|
14575
14636
|
type: "openclaw_action_result",
|
|
14637
|
+
idempotencyKey: `cowtail:action-result:${action.id}:failed`,
|
|
14576
14638
|
actionId: action.id,
|
|
14577
14639
|
state: "failed"
|
|
14578
14640
|
});
|
|
@@ -14602,18 +14664,32 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14602
14664
|
body,
|
|
14603
14665
|
timestamp: message.createdAt
|
|
14604
14666
|
});
|
|
14605
|
-
const streamState = {
|
|
14667
|
+
const streamState = {
|
|
14668
|
+
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14669
|
+
streamId: `cowtail:stream:${message.id}`,
|
|
14670
|
+
updateIndex: 0,
|
|
14671
|
+
toolFallbackIndex: 0,
|
|
14672
|
+
toolFallbackIds: {},
|
|
14673
|
+
text: "",
|
|
14674
|
+
links: [],
|
|
14675
|
+
toolCalls: []
|
|
14676
|
+
};
|
|
14606
14677
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14607
14678
|
cfg: runtime.config.loadConfig(),
|
|
14608
14679
|
channel: CHANNEL_ID,
|
|
14609
14680
|
accountId: account.accountId,
|
|
14610
14681
|
agentId: route.agentId,
|
|
14682
|
+
client,
|
|
14683
|
+
logger,
|
|
14611
14684
|
route,
|
|
14685
|
+
thread,
|
|
14612
14686
|
storePath,
|
|
14613
14687
|
ctxPayload,
|
|
14614
14688
|
runtime,
|
|
14689
|
+
streamState,
|
|
14615
14690
|
deliver: async (payload, info, rawPayload) => deliverCowtailReply({
|
|
14616
14691
|
client,
|
|
14692
|
+
logger,
|
|
14617
14693
|
route,
|
|
14618
14694
|
thread,
|
|
14619
14695
|
payload,
|
|
@@ -14630,6 +14706,9 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14630
14706
|
});
|
|
14631
14707
|
await finalizeCowtailStreamedReply({
|
|
14632
14708
|
client,
|
|
14709
|
+
logger,
|
|
14710
|
+
route,
|
|
14711
|
+
thread,
|
|
14633
14712
|
streamState
|
|
14634
14713
|
});
|
|
14635
14714
|
}
|
|
@@ -14658,18 +14737,32 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14658
14737
|
timestamp
|
|
14659
14738
|
});
|
|
14660
14739
|
let dispatchFailed = false;
|
|
14661
|
-
const streamState = {
|
|
14740
|
+
const streamState = {
|
|
14741
|
+
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14742
|
+
streamId: `cowtail:action-stream:${action.id}`,
|
|
14743
|
+
updateIndex: 0,
|
|
14744
|
+
toolFallbackIndex: 0,
|
|
14745
|
+
toolFallbackIds: {},
|
|
14746
|
+
text: "",
|
|
14747
|
+
links: [],
|
|
14748
|
+
toolCalls: []
|
|
14749
|
+
};
|
|
14662
14750
|
await recordCowtailInboundSessionAndDispatchReply({
|
|
14663
14751
|
cfg: runtime.config.loadConfig(),
|
|
14664
14752
|
channel: CHANNEL_ID,
|
|
14665
14753
|
accountId: account.accountId,
|
|
14666
14754
|
agentId: route.agentId,
|
|
14755
|
+
client,
|
|
14756
|
+
logger,
|
|
14667
14757
|
route,
|
|
14758
|
+
thread,
|
|
14668
14759
|
storePath,
|
|
14669
14760
|
ctxPayload,
|
|
14670
14761
|
runtime,
|
|
14762
|
+
streamState,
|
|
14671
14763
|
deliver: async (replyPayload, info, rawPayload) => deliverCowtailReply({
|
|
14672
14764
|
client,
|
|
14765
|
+
logger,
|
|
14673
14766
|
route,
|
|
14674
14767
|
thread,
|
|
14675
14768
|
payload: replyPayload,
|
|
@@ -14687,6 +14780,9 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14687
14780
|
});
|
|
14688
14781
|
await finalizeCowtailStreamedReply({
|
|
14689
14782
|
client,
|
|
14783
|
+
logger,
|
|
14784
|
+
route,
|
|
14785
|
+
thread,
|
|
14690
14786
|
streamState
|
|
14691
14787
|
});
|
|
14692
14788
|
return !dispatchFailed;
|
|
@@ -14720,7 +14816,79 @@ async function recordCowtailInboundSessionAndDispatchReply(params) {
|
|
|
14720
14816
|
},
|
|
14721
14817
|
replyOptions: {
|
|
14722
14818
|
disableBlockStreaming: false,
|
|
14723
|
-
onModelSelected
|
|
14819
|
+
onModelSelected,
|
|
14820
|
+
onPartialReply: (payload) => {
|
|
14821
|
+
deliverCowtailPartialReply({
|
|
14822
|
+
client: params.client,
|
|
14823
|
+
logger: params.logger,
|
|
14824
|
+
route: params.route,
|
|
14825
|
+
thread: params.thread,
|
|
14826
|
+
payload: normalizeCowtailReplyPayload(payload),
|
|
14827
|
+
streamState: params.streamState
|
|
14828
|
+
});
|
|
14829
|
+
},
|
|
14830
|
+
onToolStart: (payload) => {
|
|
14831
|
+
deliverCowtailToolProgress({
|
|
14832
|
+
client: params.client,
|
|
14833
|
+
logger: params.logger,
|
|
14834
|
+
route: params.route,
|
|
14835
|
+
thread: params.thread,
|
|
14836
|
+
streamState: params.streamState,
|
|
14837
|
+
payload,
|
|
14838
|
+
requireStableId: true
|
|
14839
|
+
});
|
|
14840
|
+
},
|
|
14841
|
+
onItemEvent: (payload) => {
|
|
14842
|
+
deliverCowtailToolProgress({
|
|
14843
|
+
client: params.client,
|
|
14844
|
+
logger: params.logger,
|
|
14845
|
+
route: params.route,
|
|
14846
|
+
thread: params.thread,
|
|
14847
|
+
streamState: params.streamState,
|
|
14848
|
+
payload
|
|
14849
|
+
});
|
|
14850
|
+
},
|
|
14851
|
+
onCommandOutput: (payload) => {
|
|
14852
|
+
deliverCowtailToolProgress({
|
|
14853
|
+
client: params.client,
|
|
14854
|
+
logger: params.logger,
|
|
14855
|
+
route: params.route,
|
|
14856
|
+
thread: params.thread,
|
|
14857
|
+
streamState: params.streamState,
|
|
14858
|
+
payload
|
|
14859
|
+
});
|
|
14860
|
+
},
|
|
14861
|
+
onPatchSummary: (payload) => {
|
|
14862
|
+
deliverCowtailToolProgress({
|
|
14863
|
+
client: params.client,
|
|
14864
|
+
logger: params.logger,
|
|
14865
|
+
route: params.route,
|
|
14866
|
+
thread: params.thread,
|
|
14867
|
+
streamState: params.streamState,
|
|
14868
|
+
payload
|
|
14869
|
+
});
|
|
14870
|
+
},
|
|
14871
|
+
onApprovalEvent: (payload) => {
|
|
14872
|
+
deliverCowtailToolProgress({
|
|
14873
|
+
client: params.client,
|
|
14874
|
+
logger: params.logger,
|
|
14875
|
+
route: params.route,
|
|
14876
|
+
thread: params.thread,
|
|
14877
|
+
streamState: params.streamState,
|
|
14878
|
+
payload
|
|
14879
|
+
});
|
|
14880
|
+
},
|
|
14881
|
+
onToolResult: (payload) => {
|
|
14882
|
+
deliverCowtailToolProgress({
|
|
14883
|
+
client: params.client,
|
|
14884
|
+
logger: params.logger,
|
|
14885
|
+
route: params.route,
|
|
14886
|
+
thread: params.thread,
|
|
14887
|
+
streamState: params.streamState,
|
|
14888
|
+
payload,
|
|
14889
|
+
status: "complete"
|
|
14890
|
+
});
|
|
14891
|
+
}
|
|
14724
14892
|
}
|
|
14725
14893
|
});
|
|
14726
14894
|
}
|
|
@@ -14740,11 +14908,22 @@ async function deliverCowtailReply(params) {
|
|
|
14740
14908
|
rawPayload: params.rawPayload,
|
|
14741
14909
|
streamState: params.streamState
|
|
14742
14910
|
});
|
|
14743
|
-
params.streamState
|
|
14911
|
+
upsertCowtailToolCall(params.streamState, toolCall);
|
|
14744
14912
|
const messageText = params.streamState.text;
|
|
14913
|
+
emitCowtailStreamSnapshot({
|
|
14914
|
+
client: params.client,
|
|
14915
|
+
logger: params.logger,
|
|
14916
|
+
route: params.route,
|
|
14917
|
+
thread: params.thread,
|
|
14918
|
+
streamState: params.streamState,
|
|
14919
|
+
text: currentLiveCowtailStreamText(params.streamState),
|
|
14920
|
+
isFinal: false,
|
|
14921
|
+
updatedAt: Date.now()
|
|
14922
|
+
});
|
|
14745
14923
|
if (!params.streamState.messageId) {
|
|
14746
|
-
const
|
|
14924
|
+
const result2 = await params.client.sendOpenClawMessage({
|
|
14747
14925
|
type: "openclaw_message",
|
|
14926
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14748
14927
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14749
14928
|
title: params.thread.title,
|
|
14750
14929
|
text: messageText,
|
|
@@ -14754,15 +14933,16 @@ async function deliverCowtailReply(params) {
|
|
|
14754
14933
|
actions: [],
|
|
14755
14934
|
deliveryState: "pending"
|
|
14756
14935
|
});
|
|
14757
|
-
const
|
|
14758
|
-
if (!
|
|
14936
|
+
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14937
|
+
if (!messageId2) {
|
|
14759
14938
|
return;
|
|
14760
14939
|
}
|
|
14761
|
-
params.streamState.messageId =
|
|
14940
|
+
params.streamState.messageId = messageId2;
|
|
14762
14941
|
return;
|
|
14763
14942
|
}
|
|
14764
14943
|
await params.client.sendOpenClawMessageUpdate({
|
|
14765
14944
|
type: "openclaw_message_update",
|
|
14945
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14766
14946
|
messageId: params.streamState.messageId,
|
|
14767
14947
|
text: messageText,
|
|
14768
14948
|
links,
|
|
@@ -14776,9 +14956,20 @@ async function deliverCowtailReply(params) {
|
|
|
14776
14956
|
}
|
|
14777
14957
|
if (kind === "block") {
|
|
14778
14958
|
params.streamState.text = appendReplyBlock(params.streamState.text, text);
|
|
14959
|
+
emitCowtailStreamSnapshot({
|
|
14960
|
+
client: params.client,
|
|
14961
|
+
logger: params.logger,
|
|
14962
|
+
route: params.route,
|
|
14963
|
+
thread: params.thread,
|
|
14964
|
+
streamState: params.streamState,
|
|
14965
|
+
text: params.streamState.text,
|
|
14966
|
+
isFinal: false,
|
|
14967
|
+
updatedAt: Date.now()
|
|
14968
|
+
});
|
|
14779
14969
|
if (!params.streamState.messageId) {
|
|
14780
|
-
const
|
|
14970
|
+
const result2 = await params.client.sendOpenClawMessage({
|
|
14781
14971
|
type: "openclaw_message",
|
|
14972
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14782
14973
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14783
14974
|
title: params.thread.title,
|
|
14784
14975
|
text: params.streamState.text,
|
|
@@ -14788,15 +14979,16 @@ async function deliverCowtailReply(params) {
|
|
|
14788
14979
|
actions: [],
|
|
14789
14980
|
deliveryState: "pending"
|
|
14790
14981
|
});
|
|
14791
|
-
const
|
|
14792
|
-
if (!
|
|
14982
|
+
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14983
|
+
if (!messageId2) {
|
|
14793
14984
|
return;
|
|
14794
14985
|
}
|
|
14795
|
-
params.streamState.messageId =
|
|
14986
|
+
params.streamState.messageId = messageId2;
|
|
14796
14987
|
return;
|
|
14797
14988
|
}
|
|
14798
14989
|
await params.client.sendOpenClawMessageUpdate({
|
|
14799
14990
|
type: "openclaw_message_update",
|
|
14991
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14800
14992
|
messageId: params.streamState.messageId,
|
|
14801
14993
|
text: params.streamState.text,
|
|
14802
14994
|
links,
|
|
@@ -14809,6 +15001,7 @@ async function deliverCowtailReply(params) {
|
|
|
14809
15001
|
params.streamState.text = text;
|
|
14810
15002
|
await params.client.sendOpenClawMessageUpdate({
|
|
14811
15003
|
type: "openclaw_message_update",
|
|
15004
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14812
15005
|
messageId: params.streamState.messageId,
|
|
14813
15006
|
text,
|
|
14814
15007
|
links,
|
|
@@ -14816,11 +15009,23 @@ async function deliverCowtailReply(params) {
|
|
|
14816
15009
|
actions: [],
|
|
14817
15010
|
deliveryState: "sent"
|
|
14818
15011
|
});
|
|
15012
|
+
emitCowtailStreamSnapshot({
|
|
15013
|
+
client: params.client,
|
|
15014
|
+
logger: params.logger,
|
|
15015
|
+
route: params.route,
|
|
15016
|
+
thread: params.thread,
|
|
15017
|
+
streamState: params.streamState,
|
|
15018
|
+
text,
|
|
15019
|
+
isFinal: true,
|
|
15020
|
+
updatedAt: Date.now()
|
|
15021
|
+
});
|
|
14819
15022
|
params.streamState.completed = true;
|
|
14820
15023
|
return;
|
|
14821
15024
|
}
|
|
14822
|
-
|
|
15025
|
+
params.streamState.text = text;
|
|
15026
|
+
const result = await params.client.sendOpenClawMessage({
|
|
14823
15027
|
type: "openclaw_message",
|
|
15028
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
14824
15029
|
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14825
15030
|
title: params.thread.title,
|
|
14826
15031
|
text,
|
|
@@ -14830,6 +15035,21 @@ async function deliverCowtailReply(params) {
|
|
|
14830
15035
|
actions: [],
|
|
14831
15036
|
deliveryState: "sent"
|
|
14832
15037
|
});
|
|
15038
|
+
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
15039
|
+
if (!messageId) {
|
|
15040
|
+
return;
|
|
15041
|
+
}
|
|
15042
|
+
params.streamState.messageId = messageId;
|
|
15043
|
+
emitCowtailStreamSnapshot({
|
|
15044
|
+
client: params.client,
|
|
15045
|
+
logger: params.logger,
|
|
15046
|
+
route: params.route,
|
|
15047
|
+
thread: params.thread,
|
|
15048
|
+
streamState: params.streamState,
|
|
15049
|
+
text,
|
|
15050
|
+
isFinal: true,
|
|
15051
|
+
updatedAt: Date.now()
|
|
15052
|
+
});
|
|
14833
15053
|
params.streamState.completed = true;
|
|
14834
15054
|
}
|
|
14835
15055
|
async function finalizeCowtailStreamedReply(params) {
|
|
@@ -14838,6 +15058,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14838
15058
|
}
|
|
14839
15059
|
await params.client.sendOpenClawMessageUpdate({
|
|
14840
15060
|
type: "openclaw_message_update",
|
|
15061
|
+
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14841
15062
|
messageId: params.streamState.messageId,
|
|
14842
15063
|
text: params.streamState.text,
|
|
14843
15064
|
links: params.streamState.links,
|
|
@@ -14845,10 +15066,125 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14845
15066
|
actions: [],
|
|
14846
15067
|
deliveryState: "sent"
|
|
14847
15068
|
});
|
|
15069
|
+
emitCowtailStreamSnapshot({
|
|
15070
|
+
client: params.client,
|
|
15071
|
+
logger: params.logger,
|
|
15072
|
+
route: params.route,
|
|
15073
|
+
thread: params.thread,
|
|
15074
|
+
streamState: params.streamState,
|
|
15075
|
+
text: params.streamState.text,
|
|
15076
|
+
isFinal: true,
|
|
15077
|
+
updatedAt: Date.now()
|
|
15078
|
+
});
|
|
14848
15079
|
params.streamState.completed = true;
|
|
14849
15080
|
}
|
|
15081
|
+
function deliverCowtailPartialReply(params) {
|
|
15082
|
+
const text = params.payload.text;
|
|
15083
|
+
if (params.streamState.failed || typeof text !== "string" || !text.trim()) {
|
|
15084
|
+
return;
|
|
15085
|
+
}
|
|
15086
|
+
const now = Date.now();
|
|
15087
|
+
const previous = params.streamState.lastSnapshotText ?? "";
|
|
15088
|
+
const changedChars = Math.abs(text.length - previous.length);
|
|
15089
|
+
const sentRecently = params.streamState.lastSnapshotSentAt !== undefined && now - params.streamState.lastSnapshotSentAt < STREAM_MIN_INTERVAL_MS;
|
|
15090
|
+
if (text === previous || sentRecently && changedChars < STREAM_MIN_CHARS_DELTA) {
|
|
15091
|
+
return;
|
|
15092
|
+
}
|
|
15093
|
+
emitCowtailStreamSnapshot({
|
|
15094
|
+
client: params.client,
|
|
15095
|
+
logger: params.logger,
|
|
15096
|
+
route: params.route,
|
|
15097
|
+
thread: params.thread,
|
|
15098
|
+
streamState: params.streamState,
|
|
15099
|
+
text,
|
|
15100
|
+
isFinal: false,
|
|
15101
|
+
updatedAt: now
|
|
15102
|
+
});
|
|
15103
|
+
}
|
|
15104
|
+
function deliverCowtailToolProgress(params) {
|
|
15105
|
+
if (params.streamState.failed) {
|
|
15106
|
+
return;
|
|
15107
|
+
}
|
|
15108
|
+
const payload = readRecord(params.payload) ?? {};
|
|
15109
|
+
const stableId = readString(payload.itemId) ?? readString(payload.toolCallId) ?? readString(payload.id);
|
|
15110
|
+
if (params.requireStableId && !stableId) {
|
|
15111
|
+
return;
|
|
15112
|
+
}
|
|
15113
|
+
const id = stableId ?? fallbackCowtailToolCallId(params.streamState, payload);
|
|
15114
|
+
const name = readString(payload.name) ?? readString(payload.title) ?? readString(payload.command) ?? "tool_result";
|
|
15115
|
+
const status = params.status ?? normalizeCowtailToolCallStatus(payload.status) ?? normalizeCowtailToolCallStatus(payload.phase) ?? "running";
|
|
15116
|
+
const result = readCowtailToolProgressResult(payload);
|
|
15117
|
+
const args = readRecord(payload.args) ?? readRecord(payload.input);
|
|
15118
|
+
const now = Date.now();
|
|
15119
|
+
const currentText = currentLiveCowtailStreamText(params.streamState);
|
|
15120
|
+
const nextToolCall = {
|
|
15121
|
+
id,
|
|
15122
|
+
name,
|
|
15123
|
+
...args ? { args } : {},
|
|
15124
|
+
...result !== undefined ? { result } : {},
|
|
15125
|
+
status,
|
|
15126
|
+
...status === "complete" || status === "error" ? { completedAt: now } : {},
|
|
15127
|
+
insertedAtContentLength: currentText.length,
|
|
15128
|
+
contentSnapshotAtStart: currentText
|
|
15129
|
+
};
|
|
15130
|
+
upsertCowtailToolCall(params.streamState, nextToolCall);
|
|
15131
|
+
emitCowtailStreamSnapshot({
|
|
15132
|
+
client: params.client,
|
|
15133
|
+
logger: params.logger,
|
|
15134
|
+
route: params.route,
|
|
15135
|
+
thread: params.thread,
|
|
15136
|
+
streamState: params.streamState,
|
|
15137
|
+
text: currentText,
|
|
15138
|
+
isFinal: false,
|
|
15139
|
+
updatedAt: now
|
|
15140
|
+
});
|
|
15141
|
+
}
|
|
15142
|
+
function emitCowtailStreamSnapshot(params) {
|
|
15143
|
+
if (params.streamState.failed || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15144
|
+
return;
|
|
15145
|
+
}
|
|
15146
|
+
params.streamState.liveText = params.text;
|
|
15147
|
+
params.streamState.lastSnapshotText = params.text;
|
|
15148
|
+
params.streamState.lastSnapshotSentAt = params.updatedAt;
|
|
15149
|
+
params.client.sendOpenClawStreamSnapshot({
|
|
15150
|
+
type: "openclaw_message_stream_snapshot",
|
|
15151
|
+
streamId: params.streamState.streamId,
|
|
15152
|
+
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
15153
|
+
threadId: params.thread.id,
|
|
15154
|
+
text: params.text,
|
|
15155
|
+
links: params.streamState.links.map((link) => ({ ...link })),
|
|
15156
|
+
toolCalls: structuredClone(params.streamState.toolCalls),
|
|
15157
|
+
isFinal: params.isFinal,
|
|
15158
|
+
updatedAt: params.updatedAt
|
|
15159
|
+
}).catch((error48) => {
|
|
15160
|
+
params.logger?.warn?.(`Cowtail stream snapshot send failed: ${errorMessage(error48)}`);
|
|
15161
|
+
});
|
|
15162
|
+
}
|
|
15163
|
+
function currentLiveCowtailStreamText(streamState) {
|
|
15164
|
+
return streamState.liveText ?? streamState.text;
|
|
15165
|
+
}
|
|
15166
|
+
function upsertCowtailToolCall(streamState, toolCall) {
|
|
15167
|
+
const index = streamState.toolCalls.findIndex((candidate) => candidate.id === toolCall.id);
|
|
15168
|
+
if (index < 0) {
|
|
15169
|
+
streamState.toolCalls = [...streamState.toolCalls, toolCall];
|
|
15170
|
+
return;
|
|
15171
|
+
}
|
|
15172
|
+
const existing = streamState.toolCalls[index];
|
|
15173
|
+
streamState.toolCalls[index] = {
|
|
15174
|
+
...existing,
|
|
15175
|
+
...toolCall,
|
|
15176
|
+
insertedAtContentLength: existing.insertedAtContentLength ?? toolCall.insertedAtContentLength,
|
|
15177
|
+
contentSnapshotAtStart: existing.contentSnapshotAtStart ?? toolCall.contentSnapshotAtStart
|
|
15178
|
+
};
|
|
15179
|
+
}
|
|
14850
15180
|
function recordCreatedOpenClawMessageId(streamState, result) {
|
|
14851
15181
|
if (result.payload?.dropped === true) {
|
|
15182
|
+
if (result.payload.duplicate === true) {
|
|
15183
|
+
const duplicateMessageId = result.payload.messageId;
|
|
15184
|
+
if (typeof duplicateMessageId === "string" && duplicateMessageId.trim()) {
|
|
15185
|
+
return duplicateMessageId;
|
|
15186
|
+
}
|
|
15187
|
+
}
|
|
14852
15188
|
streamState.failed = true;
|
|
14853
15189
|
streamState.completed = true;
|
|
14854
15190
|
return;
|
|
@@ -14860,6 +15196,10 @@ function recordCreatedOpenClawMessageId(streamState, result) {
|
|
|
14860
15196
|
streamState.failed = true;
|
|
14861
15197
|
throw new Error("Cowtail realtime ack missing messageId for streamed OpenClaw reply");
|
|
14862
15198
|
}
|
|
15199
|
+
function nextStreamUpdateIdempotencyKey(streamState) {
|
|
15200
|
+
streamState.updateIndex += 1;
|
|
15201
|
+
return `${streamState.idempotencyKey}:update:${streamState.updateIndex}`;
|
|
15202
|
+
}
|
|
14863
15203
|
function resolveCowtailReplyLinks(payload) {
|
|
14864
15204
|
const urls = [
|
|
14865
15205
|
...Array.isArray(payload.mediaUrls) ? payload.mediaUrls : [],
|
|
@@ -14932,6 +15272,48 @@ function readRecord(value) {
|
|
|
14932
15272
|
function readToolCallStatus(value) {
|
|
14933
15273
|
return value === "pending" || value === "running" || value === "complete" || value === "error" ? value : undefined;
|
|
14934
15274
|
}
|
|
15275
|
+
function normalizeCowtailToolCallStatus(value) {
|
|
15276
|
+
const status = readToolCallStatus(value);
|
|
15277
|
+
if (status) {
|
|
15278
|
+
return status;
|
|
15279
|
+
}
|
|
15280
|
+
if (value === "start" || value === "started" || value === "working") {
|
|
15281
|
+
return "running";
|
|
15282
|
+
}
|
|
15283
|
+
if (value === "end" || value === "done" || value === "completed" || value === "success") {
|
|
15284
|
+
return "complete";
|
|
15285
|
+
}
|
|
15286
|
+
if (value === "failed" || value === "failure") {
|
|
15287
|
+
return "error";
|
|
15288
|
+
}
|
|
15289
|
+
return;
|
|
15290
|
+
}
|
|
15291
|
+
function readCowtailToolProgressResult(payload) {
|
|
15292
|
+
const stringResult = readString(payload.output) ?? readString(payload.summary) ?? readString(payload.message) ?? readString(payload.progressText) ?? readString(payload.text);
|
|
15293
|
+
if (stringResult !== undefined) {
|
|
15294
|
+
return stringResult;
|
|
15295
|
+
}
|
|
15296
|
+
if (payload.result !== undefined) {
|
|
15297
|
+
return payload.result;
|
|
15298
|
+
}
|
|
15299
|
+
const structuredPatch = {
|
|
15300
|
+
...Array.isArray(payload.added) ? { added: payload.added } : {},
|
|
15301
|
+
...Array.isArray(payload.modified) ? { modified: payload.modified } : {},
|
|
15302
|
+
...Array.isArray(payload.deleted) ? { deleted: payload.deleted } : {}
|
|
15303
|
+
};
|
|
15304
|
+
return Object.keys(structuredPatch).length > 0 ? structuredPatch : undefined;
|
|
15305
|
+
}
|
|
15306
|
+
function fallbackCowtailToolCallId(streamState, payload) {
|
|
15307
|
+
const key = readString(payload.name) ?? readString(payload.title) ?? readString(payload.command) ?? JSON.stringify(Object.keys(payload).sort());
|
|
15308
|
+
const existing = streamState.toolFallbackIds[key];
|
|
15309
|
+
if (existing) {
|
|
15310
|
+
return existing;
|
|
15311
|
+
}
|
|
15312
|
+
streamState.toolFallbackIndex += 1;
|
|
15313
|
+
const next = `tool-${streamState.toolFallbackIndex}`;
|
|
15314
|
+
streamState.toolFallbackIds[key] = next;
|
|
15315
|
+
return next;
|
|
15316
|
+
}
|
|
14935
15317
|
function readTimestamp(value) {
|
|
14936
15318
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
14937
15319
|
}
|