@maudecode/openclaw-cowtail 0.12.3 → 0.14.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 +4 -0
- package/dist/index.js +429 -46
- package/dist/setup-entry.js +429 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13801,6 +13801,7 @@ var openclawThreadRecordSchema = exports_external.object({
|
|
|
13801
13801
|
var openclawMessageRecordBaseSchema = exports_external.object({
|
|
13802
13802
|
id: nonEmptyStringSchema,
|
|
13803
13803
|
threadId: nonEmptyStringSchema,
|
|
13804
|
+
streamId: nonEmptyStringSchema.optional(),
|
|
13804
13805
|
direction: openclawMessageDirectionSchema,
|
|
13805
13806
|
authorLabel: nonEmptyStringSchema.optional(),
|
|
13806
13807
|
text: openclawMessageTextSchema,
|
|
@@ -13855,13 +13856,16 @@ var openclawPluginMessageCommandSchema = requireOpenClawRenderableContent(export
|
|
|
13855
13856
|
requestId: openclawRequestIdSchema,
|
|
13856
13857
|
idempotencyKey: openclawIdempotencyKeySchema,
|
|
13857
13858
|
sessionKey: nonEmptyStringSchema,
|
|
13859
|
+
threadId: nonEmptyStringSchema.optional(),
|
|
13860
|
+
threadHint: nonEmptyStringSchema.optional(),
|
|
13858
13861
|
title: nonEmptyStringSchema.optional(),
|
|
13859
13862
|
text: openclawMessageTextSchema,
|
|
13860
13863
|
authorLabel: nonEmptyStringSchema.optional(),
|
|
13861
13864
|
links: exports_external.array(openclawLinkSchema).default([]),
|
|
13862
13865
|
toolCalls: exports_external.array(openclawToolCallRecordSchema).default([]),
|
|
13863
13866
|
actions: exports_external.array(openclawActionDraftSchema).default([]),
|
|
13864
|
-
deliveryState: openclawDeliveryStateSchema.optional()
|
|
13867
|
+
deliveryState: openclawDeliveryStateSchema.optional(),
|
|
13868
|
+
streamId: nonEmptyStringSchema
|
|
13865
13869
|
}));
|
|
13866
13870
|
var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(exports_external.object({
|
|
13867
13871
|
type: exports_external.literal("openclaw_message_update"),
|
|
@@ -13872,8 +13876,24 @@ var openclawPluginMessageUpdateCommandSchema = requireOpenClawRenderableContent(
|
|
|
13872
13876
|
links: exports_external.array(openclawLinkSchema).optional(),
|
|
13873
13877
|
toolCalls: exports_external.array(openclawToolCallRecordSchema).optional(),
|
|
13874
13878
|
actions: exports_external.array(openclawActionDraftSchema).optional(),
|
|
13875
|
-
deliveryState: openclawDeliveryStateSchema.optional()
|
|
13879
|
+
deliveryState: openclawDeliveryStateSchema.optional(),
|
|
13880
|
+
streamId: nonEmptyStringSchema
|
|
13876
13881
|
}));
|
|
13882
|
+
var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
13883
|
+
type: exports_external.literal("openclaw_message_stream_snapshot"),
|
|
13884
|
+
requestId: openclawRequestIdSchema,
|
|
13885
|
+
streamId: nonEmptyStringSchema,
|
|
13886
|
+
sessionKey: nonEmptyStringSchema,
|
|
13887
|
+
threadId: nonEmptyStringSchema,
|
|
13888
|
+
text: openclawMessageTextSchema,
|
|
13889
|
+
links: exports_external.array(openclawLinkSchema).default([]),
|
|
13890
|
+
toolCalls: exports_external.array(openclawToolCallRecordSchema).default([]),
|
|
13891
|
+
isFinal: exports_external.boolean(),
|
|
13892
|
+
snapshotSequence: exports_external.number().int().nonnegative(),
|
|
13893
|
+
updatedAt: timestampSchema
|
|
13894
|
+
});
|
|
13895
|
+
var openclawMessageStreamSnapshotCommandSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema);
|
|
13896
|
+
var openclawMessageStreamSnapshotServerMessageSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema.omit({ requestId: true }));
|
|
13877
13897
|
var openclawIosNewThreadCommandSchema = exports_external.object({
|
|
13878
13898
|
type: exports_external.literal("ios_new_thread"),
|
|
13879
13899
|
requestId: openclawRequestIdSchema,
|
|
@@ -13932,6 +13952,7 @@ var openclawActionResultCommandSchema = exports_external.object({
|
|
|
13932
13952
|
var openclawRealtimeClientMessageSchema = exports_external.union([
|
|
13933
13953
|
openclawPluginMessageCommandSchema,
|
|
13934
13954
|
openclawPluginMessageUpdateCommandSchema,
|
|
13955
|
+
openclawMessageStreamSnapshotCommandSchema,
|
|
13935
13956
|
openclawIosNewThreadCommandSchema,
|
|
13936
13957
|
openclawIosReplyCommandSchema,
|
|
13937
13958
|
openclawIosActionCommandSchema,
|
|
@@ -13941,11 +13962,18 @@ var openclawRealtimeClientMessageSchema = exports_external.union([
|
|
|
13941
13962
|
openclawSessionBoundCommandSchema,
|
|
13942
13963
|
openclawActionResultCommandSchema
|
|
13943
13964
|
]);
|
|
13965
|
+
var openclawRealtimeAckPayloadSchema = exports_external.object({
|
|
13966
|
+
threadId: nonEmptyStringSchema.optional(),
|
|
13967
|
+
messageId: nonEmptyStringSchema.optional(),
|
|
13968
|
+
dropped: exports_external.literal(true).optional(),
|
|
13969
|
+
duplicate: exports_external.literal(true).optional(),
|
|
13970
|
+
reason: nonEmptyStringSchema.optional()
|
|
13971
|
+
});
|
|
13944
13972
|
var openclawRealtimeAckSchema = exports_external.object({
|
|
13945
13973
|
type: exports_external.literal("ack"),
|
|
13946
13974
|
requestId: openclawRequestIdSchema,
|
|
13947
13975
|
sequence: openclawSequenceSchema.optional(),
|
|
13948
|
-
payload:
|
|
13976
|
+
payload: openclawRealtimeAckPayloadSchema.optional()
|
|
13949
13977
|
});
|
|
13950
13978
|
var openclawRealtimeErrorSchema = exports_external.object({
|
|
13951
13979
|
type: exports_external.literal("realtime_error"),
|
|
@@ -13954,6 +13982,7 @@ var openclawRealtimeErrorSchema = exports_external.object({
|
|
|
13954
13982
|
});
|
|
13955
13983
|
var openclawRealtimeServerMessageSchema = exports_external.union([
|
|
13956
13984
|
openclawEventEnvelopeSchema,
|
|
13985
|
+
openclawMessageStreamSnapshotServerMessageSchema,
|
|
13957
13986
|
openclawRealtimeAckSchema,
|
|
13958
13987
|
openclawRealtimeErrorSchema
|
|
13959
13988
|
]);
|
|
@@ -13993,6 +14022,13 @@ var openclawEventReplayResponseSchema = exports_external.object({
|
|
|
13993
14022
|
ok: exports_external.literal(true),
|
|
13994
14023
|
events: exports_external.array(openclawEventEnvelopeSchema)
|
|
13995
14024
|
});
|
|
14025
|
+
var openclawPushNotificationPayloadSchema = exports_external.object({
|
|
14026
|
+
kind: exports_external.literal("openclaw"),
|
|
14027
|
+
version: exports_external.literal(1),
|
|
14028
|
+
threadId: nonEmptyStringSchema,
|
|
14029
|
+
messageId: nonEmptyStringSchema,
|
|
14030
|
+
url: nonEmptyStringSchema.optional()
|
|
14031
|
+
});
|
|
13996
14032
|
// ../protocol/src/fixes.ts
|
|
13997
14033
|
var fixScopeSchema = exports_external.enum(fixScopes);
|
|
13998
14034
|
var fixCreateRequestSchema = exports_external.object({
|
|
@@ -14048,11 +14084,12 @@ var healthResponseSchema = exports_external.object({
|
|
|
14048
14084
|
storageUnit: nonEmptyStringSchema
|
|
14049
14085
|
});
|
|
14050
14086
|
// ../protocol/src/push.ts
|
|
14087
|
+
var pushEnvironmentSchema = exports_external.enum(["development", "production"]);
|
|
14051
14088
|
var pushRegisterRequestSchema = exports_external.object({
|
|
14052
14089
|
identityToken: nonEmptyStringSchema,
|
|
14053
14090
|
deviceToken: nonEmptyStringSchema,
|
|
14054
14091
|
platform: nonEmptyStringSchema.optional(),
|
|
14055
|
-
environment:
|
|
14092
|
+
environment: pushEnvironmentSchema.optional(),
|
|
14056
14093
|
deviceName: nonEmptyStringSchema.optional()
|
|
14057
14094
|
});
|
|
14058
14095
|
var pushRegisterResponseSchema = exports_external.object({
|
|
@@ -14061,6 +14098,7 @@ var pushRegisterResponseSchema = exports_external.object({
|
|
|
14061
14098
|
id: nonEmptyStringSchema
|
|
14062
14099
|
});
|
|
14063
14100
|
var pushUnregisterRequestSchema = exports_external.object({
|
|
14101
|
+
identityToken: nonEmptyStringSchema,
|
|
14064
14102
|
deviceToken: nonEmptyStringSchema
|
|
14065
14103
|
});
|
|
14066
14104
|
var pushUnregisterResponseSchema = exports_external.object({
|
|
@@ -14084,6 +14122,7 @@ var pushResultSchema = exports_external.object({
|
|
|
14084
14122
|
userId: nonEmptyStringSchema,
|
|
14085
14123
|
sent: exports_external.number().int().nonnegative(),
|
|
14086
14124
|
failed: exports_external.number().int().nonnegative(),
|
|
14125
|
+
skipped: exports_external.number().int().nonnegative().default(0),
|
|
14087
14126
|
results: exports_external.array(jsonObjectSchema)
|
|
14088
14127
|
});
|
|
14089
14128
|
// ../protocol/src/responses.ts
|
|
@@ -14104,7 +14143,8 @@ var usersListEntrySchema = exports_external.object({
|
|
|
14104
14143
|
enabledDeviceCount: exports_external.number().int().nonnegative()
|
|
14105
14144
|
});
|
|
14106
14145
|
var userDeviceSchema = exports_external.object({
|
|
14107
|
-
|
|
14146
|
+
id: nonEmptyStringSchema,
|
|
14147
|
+
deviceTokenPreview: nonEmptyStringSchema,
|
|
14108
14148
|
platform: nonEmptyStringSchema,
|
|
14109
14149
|
environment: nonEmptyStringSchema,
|
|
14110
14150
|
enabled: exports_external.boolean(),
|
|
@@ -14176,10 +14216,12 @@ class CowtailRealtimeClient {
|
|
|
14176
14216
|
}
|
|
14177
14217
|
sendOpenClawMessage(command) {
|
|
14178
14218
|
const requestId = this.#requestIdFactory();
|
|
14219
|
+
const idempotencyKey = command.idempotencyKey ?? `cowtail:request:${requestId}`;
|
|
14179
14220
|
return this.#sendCommand({
|
|
14180
14221
|
...command,
|
|
14181
14222
|
requestId,
|
|
14182
|
-
idempotencyKey
|
|
14223
|
+
idempotencyKey,
|
|
14224
|
+
streamId: command.streamId ?? idempotencyKey,
|
|
14183
14225
|
links: command.links ?? [],
|
|
14184
14226
|
toolCalls: command.toolCalls ?? [],
|
|
14185
14227
|
actions: command.actions ?? []
|
|
@@ -14212,6 +14254,12 @@ class CowtailRealtimeClient {
|
|
|
14212
14254
|
idempotencyKey: command.idempotencyKey ?? `cowtail:request:${requestId}`
|
|
14213
14255
|
}).then((result) => result.sequence);
|
|
14214
14256
|
}
|
|
14257
|
+
sendOpenClawStreamSnapshot(command) {
|
|
14258
|
+
return this.#sendTransientCommand({
|
|
14259
|
+
...command,
|
|
14260
|
+
requestId: this.#requestIdFactory()
|
|
14261
|
+
});
|
|
14262
|
+
}
|
|
14215
14263
|
#connect() {
|
|
14216
14264
|
if (!this.#started || this.#socket) {
|
|
14217
14265
|
return;
|
|
@@ -14311,6 +14359,9 @@ class CowtailRealtimeClient {
|
|
|
14311
14359
|
this.#rejectPendingRequest(message);
|
|
14312
14360
|
return;
|
|
14313
14361
|
}
|
|
14362
|
+
if (message.type === "openclaw_message_stream_snapshot") {
|
|
14363
|
+
return;
|
|
14364
|
+
}
|
|
14314
14365
|
await this.#onEvent(message);
|
|
14315
14366
|
await this.#stateStore.writeLastSeenSequence(message.sequence);
|
|
14316
14367
|
}
|
|
@@ -14387,6 +14438,19 @@ class CowtailRealtimeClient {
|
|
|
14387
14438
|
}
|
|
14388
14439
|
});
|
|
14389
14440
|
}
|
|
14441
|
+
async#sendTransientCommand(command) {
|
|
14442
|
+
const socket = this.#socket;
|
|
14443
|
+
const handshake = this.#handshake;
|
|
14444
|
+
if (!socket || !handshake) {
|
|
14445
|
+
throw new Error("Cowtail websocket is disconnected");
|
|
14446
|
+
}
|
|
14447
|
+
await handshake.promise;
|
|
14448
|
+
const currentSocket = this.#socket;
|
|
14449
|
+
if (!currentSocket || socket !== currentSocket || handshake !== this.#handshake || !this.#isSocketOpen(currentSocket)) {
|
|
14450
|
+
throw new Error("Cowtail websocket is disconnected");
|
|
14451
|
+
}
|
|
14452
|
+
currentSocket.send(JSON.stringify(command));
|
|
14453
|
+
}
|
|
14390
14454
|
#resolvePendingRequest(requestId, sequence, payload) {
|
|
14391
14455
|
const pending = this.#pendingRequests.get(requestId);
|
|
14392
14456
|
if (!pending) {
|
|
@@ -14491,6 +14555,8 @@ var CHANNEL_LABEL = "Cowtail";
|
|
|
14491
14555
|
var SENDER_LABEL = "Cowtail iOS";
|
|
14492
14556
|
var SENDER_ID = "cowtail-ios";
|
|
14493
14557
|
var SENDER_ADDRESS = "cowtail:ios";
|
|
14558
|
+
var STREAM_MIN_INTERVAL_MS = 45;
|
|
14559
|
+
var STREAM_MIN_CHARS_DELTA = 3;
|
|
14494
14560
|
async function handleCowtailEvent(params) {
|
|
14495
14561
|
const { event, account, client, runtime, logger } = params;
|
|
14496
14562
|
switch (event.type) {
|
|
@@ -14626,7 +14692,11 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14626
14692
|
});
|
|
14627
14693
|
const streamState = {
|
|
14628
14694
|
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14695
|
+
streamId: `cowtail:stream:${message.id}`,
|
|
14629
14696
|
updateIndex: 0,
|
|
14697
|
+
snapshotSequence: 0,
|
|
14698
|
+
toolFallbackIndex: 0,
|
|
14699
|
+
toolFallbackIds: {},
|
|
14630
14700
|
text: "",
|
|
14631
14701
|
links: [],
|
|
14632
14702
|
toolCalls: []
|
|
@@ -14636,12 +14706,17 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14636
14706
|
channel: CHANNEL_ID,
|
|
14637
14707
|
accountId: account.accountId,
|
|
14638
14708
|
agentId: route.agentId,
|
|
14709
|
+
client,
|
|
14710
|
+
logger,
|
|
14639
14711
|
route,
|
|
14712
|
+
thread,
|
|
14640
14713
|
storePath,
|
|
14641
14714
|
ctxPayload,
|
|
14642
14715
|
runtime,
|
|
14716
|
+
streamState,
|
|
14643
14717
|
deliver: async (payload, info, rawPayload) => deliverCowtailReply({
|
|
14644
14718
|
client,
|
|
14719
|
+
logger,
|
|
14645
14720
|
route,
|
|
14646
14721
|
thread,
|
|
14647
14722
|
payload,
|
|
@@ -14658,6 +14733,9 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14658
14733
|
});
|
|
14659
14734
|
await finalizeCowtailStreamedReply({
|
|
14660
14735
|
client,
|
|
14736
|
+
logger,
|
|
14737
|
+
route,
|
|
14738
|
+
thread,
|
|
14661
14739
|
streamState
|
|
14662
14740
|
});
|
|
14663
14741
|
}
|
|
@@ -14688,7 +14766,11 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14688
14766
|
let dispatchFailed = false;
|
|
14689
14767
|
const streamState = {
|
|
14690
14768
|
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14769
|
+
streamId: `cowtail:action-stream:${action.id}`,
|
|
14691
14770
|
updateIndex: 0,
|
|
14771
|
+
snapshotSequence: 0,
|
|
14772
|
+
toolFallbackIndex: 0,
|
|
14773
|
+
toolFallbackIds: {},
|
|
14692
14774
|
text: "",
|
|
14693
14775
|
links: [],
|
|
14694
14776
|
toolCalls: []
|
|
@@ -14698,12 +14780,17 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14698
14780
|
channel: CHANNEL_ID,
|
|
14699
14781
|
accountId: account.accountId,
|
|
14700
14782
|
agentId: route.agentId,
|
|
14783
|
+
client,
|
|
14784
|
+
logger,
|
|
14701
14785
|
route,
|
|
14786
|
+
thread,
|
|
14702
14787
|
storePath,
|
|
14703
14788
|
ctxPayload,
|
|
14704
14789
|
runtime,
|
|
14790
|
+
streamState,
|
|
14705
14791
|
deliver: async (replyPayload, info, rawPayload) => deliverCowtailReply({
|
|
14706
14792
|
client,
|
|
14793
|
+
logger,
|
|
14707
14794
|
route,
|
|
14708
14795
|
thread,
|
|
14709
14796
|
payload: replyPayload,
|
|
@@ -14721,6 +14808,9 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14721
14808
|
});
|
|
14722
14809
|
await finalizeCowtailStreamedReply({
|
|
14723
14810
|
client,
|
|
14811
|
+
logger,
|
|
14812
|
+
route,
|
|
14813
|
+
thread,
|
|
14724
14814
|
streamState
|
|
14725
14815
|
});
|
|
14726
14816
|
return !dispatchFailed;
|
|
@@ -14754,7 +14844,79 @@ async function recordCowtailInboundSessionAndDispatchReply(params) {
|
|
|
14754
14844
|
},
|
|
14755
14845
|
replyOptions: {
|
|
14756
14846
|
disableBlockStreaming: false,
|
|
14757
|
-
onModelSelected
|
|
14847
|
+
onModelSelected,
|
|
14848
|
+
onPartialReply: (payload) => {
|
|
14849
|
+
deliverCowtailPartialReply({
|
|
14850
|
+
client: params.client,
|
|
14851
|
+
logger: params.logger,
|
|
14852
|
+
route: params.route,
|
|
14853
|
+
thread: params.thread,
|
|
14854
|
+
payload: normalizeCowtailReplyPayload(payload),
|
|
14855
|
+
streamState: params.streamState
|
|
14856
|
+
});
|
|
14857
|
+
},
|
|
14858
|
+
onToolStart: (payload) => {
|
|
14859
|
+
deliverCowtailToolProgress({
|
|
14860
|
+
client: params.client,
|
|
14861
|
+
logger: params.logger,
|
|
14862
|
+
route: params.route,
|
|
14863
|
+
thread: params.thread,
|
|
14864
|
+
streamState: params.streamState,
|
|
14865
|
+
payload,
|
|
14866
|
+
requireStableId: true
|
|
14867
|
+
});
|
|
14868
|
+
},
|
|
14869
|
+
onItemEvent: (payload) => {
|
|
14870
|
+
deliverCowtailToolProgress({
|
|
14871
|
+
client: params.client,
|
|
14872
|
+
logger: params.logger,
|
|
14873
|
+
route: params.route,
|
|
14874
|
+
thread: params.thread,
|
|
14875
|
+
streamState: params.streamState,
|
|
14876
|
+
payload
|
|
14877
|
+
});
|
|
14878
|
+
},
|
|
14879
|
+
onCommandOutput: (payload) => {
|
|
14880
|
+
deliverCowtailToolProgress({
|
|
14881
|
+
client: params.client,
|
|
14882
|
+
logger: params.logger,
|
|
14883
|
+
route: params.route,
|
|
14884
|
+
thread: params.thread,
|
|
14885
|
+
streamState: params.streamState,
|
|
14886
|
+
payload
|
|
14887
|
+
});
|
|
14888
|
+
},
|
|
14889
|
+
onPatchSummary: (payload) => {
|
|
14890
|
+
deliverCowtailToolProgress({
|
|
14891
|
+
client: params.client,
|
|
14892
|
+
logger: params.logger,
|
|
14893
|
+
route: params.route,
|
|
14894
|
+
thread: params.thread,
|
|
14895
|
+
streamState: params.streamState,
|
|
14896
|
+
payload
|
|
14897
|
+
});
|
|
14898
|
+
},
|
|
14899
|
+
onApprovalEvent: (payload) => {
|
|
14900
|
+
deliverCowtailToolProgress({
|
|
14901
|
+
client: params.client,
|
|
14902
|
+
logger: params.logger,
|
|
14903
|
+
route: params.route,
|
|
14904
|
+
thread: params.thread,
|
|
14905
|
+
streamState: params.streamState,
|
|
14906
|
+
payload
|
|
14907
|
+
});
|
|
14908
|
+
},
|
|
14909
|
+
onToolResult: (payload) => {
|
|
14910
|
+
deliverCowtailToolProgress({
|
|
14911
|
+
client: params.client,
|
|
14912
|
+
logger: params.logger,
|
|
14913
|
+
route: params.route,
|
|
14914
|
+
thread: params.thread,
|
|
14915
|
+
streamState: params.streamState,
|
|
14916
|
+
payload,
|
|
14917
|
+
status: "complete"
|
|
14918
|
+
});
|
|
14919
|
+
}
|
|
14758
14920
|
}
|
|
14759
14921
|
});
|
|
14760
14922
|
}
|
|
@@ -14774,31 +14936,30 @@ async function deliverCowtailReply(params) {
|
|
|
14774
14936
|
rawPayload: params.rawPayload,
|
|
14775
14937
|
streamState: params.streamState
|
|
14776
14938
|
});
|
|
14777
|
-
params.streamState
|
|
14939
|
+
upsertCowtailToolCall(params.streamState, toolCall);
|
|
14778
14940
|
const messageText = params.streamState.text;
|
|
14941
|
+
emitCowtailStreamSnapshot({
|
|
14942
|
+
client: params.client,
|
|
14943
|
+
logger: params.logger,
|
|
14944
|
+
route: params.route,
|
|
14945
|
+
thread: params.thread,
|
|
14946
|
+
streamState: params.streamState,
|
|
14947
|
+
text: currentLiveCowtailStreamText(params.streamState),
|
|
14948
|
+
isFinal: false,
|
|
14949
|
+
updatedAt: Date.now()
|
|
14950
|
+
});
|
|
14779
14951
|
if (!params.streamState.messageId) {
|
|
14780
|
-
|
|
14781
|
-
type: "openclaw_message",
|
|
14782
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14783
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14784
|
-
title: params.thread.title,
|
|
14952
|
+
await createDurableCowtailReply(params, {
|
|
14785
14953
|
text: messageText,
|
|
14786
|
-
authorLabel: "OpenClaw",
|
|
14787
14954
|
links,
|
|
14788
|
-
toolCalls: params.streamState.toolCalls,
|
|
14789
|
-
actions: [],
|
|
14790
14955
|
deliveryState: "pending"
|
|
14791
14956
|
});
|
|
14792
|
-
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
14793
|
-
if (!messageId) {
|
|
14794
|
-
return;
|
|
14795
|
-
}
|
|
14796
|
-
params.streamState.messageId = messageId;
|
|
14797
14957
|
return;
|
|
14798
14958
|
}
|
|
14799
14959
|
await params.client.sendOpenClawMessageUpdate({
|
|
14800
14960
|
type: "openclaw_message_update",
|
|
14801
14961
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14962
|
+
streamId: params.streamState.streamId,
|
|
14802
14963
|
messageId: params.streamState.messageId,
|
|
14803
14964
|
text: messageText,
|
|
14804
14965
|
links,
|
|
@@ -14812,29 +14973,28 @@ async function deliverCowtailReply(params) {
|
|
|
14812
14973
|
}
|
|
14813
14974
|
if (kind === "block") {
|
|
14814
14975
|
params.streamState.text = appendReplyBlock(params.streamState.text, text);
|
|
14976
|
+
emitCowtailStreamSnapshot({
|
|
14977
|
+
client: params.client,
|
|
14978
|
+
logger: params.logger,
|
|
14979
|
+
route: params.route,
|
|
14980
|
+
thread: params.thread,
|
|
14981
|
+
streamState: params.streamState,
|
|
14982
|
+
text: params.streamState.text,
|
|
14983
|
+
isFinal: false,
|
|
14984
|
+
updatedAt: Date.now()
|
|
14985
|
+
});
|
|
14815
14986
|
if (!params.streamState.messageId) {
|
|
14816
|
-
|
|
14817
|
-
type: "openclaw_message",
|
|
14818
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14819
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14820
|
-
title: params.thread.title,
|
|
14987
|
+
await createDurableCowtailReply(params, {
|
|
14821
14988
|
text: params.streamState.text,
|
|
14822
|
-
authorLabel: "OpenClaw",
|
|
14823
14989
|
links,
|
|
14824
|
-
toolCalls: params.streamState.toolCalls,
|
|
14825
|
-
actions: [],
|
|
14826
14990
|
deliveryState: "pending"
|
|
14827
14991
|
});
|
|
14828
|
-
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
14829
|
-
if (!messageId) {
|
|
14830
|
-
return;
|
|
14831
|
-
}
|
|
14832
|
-
params.streamState.messageId = messageId;
|
|
14833
14992
|
return;
|
|
14834
14993
|
}
|
|
14835
14994
|
await params.client.sendOpenClawMessageUpdate({
|
|
14836
14995
|
type: "openclaw_message_update",
|
|
14837
14996
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14997
|
+
streamId: params.streamState.streamId,
|
|
14838
14998
|
messageId: params.streamState.messageId,
|
|
14839
14999
|
text: params.streamState.text,
|
|
14840
15000
|
links,
|
|
@@ -14848,6 +15008,7 @@ async function deliverCowtailReply(params) {
|
|
|
14848
15008
|
await params.client.sendOpenClawMessageUpdate({
|
|
14849
15009
|
type: "openclaw_message_update",
|
|
14850
15010
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15011
|
+
streamId: params.streamState.streamId,
|
|
14851
15012
|
messageId: params.streamState.messageId,
|
|
14852
15013
|
text,
|
|
14853
15014
|
links,
|
|
@@ -14855,23 +15016,67 @@ async function deliverCowtailReply(params) {
|
|
|
14855
15016
|
actions: [],
|
|
14856
15017
|
deliveryState: "sent"
|
|
14857
15018
|
});
|
|
15019
|
+
emitCowtailStreamSnapshot({
|
|
15020
|
+
client: params.client,
|
|
15021
|
+
logger: params.logger,
|
|
15022
|
+
route: params.route,
|
|
15023
|
+
thread: params.thread,
|
|
15024
|
+
streamState: params.streamState,
|
|
15025
|
+
text,
|
|
15026
|
+
isFinal: true,
|
|
15027
|
+
updatedAt: Date.now()
|
|
15028
|
+
});
|
|
14858
15029
|
params.streamState.completed = true;
|
|
14859
15030
|
return;
|
|
14860
15031
|
}
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14864
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14865
|
-
title: params.thread.title,
|
|
15032
|
+
params.streamState.text = text;
|
|
15033
|
+
const messageId = await createDurableCowtailReply(params, {
|
|
14866
15034
|
text,
|
|
14867
|
-
authorLabel: "OpenClaw",
|
|
14868
15035
|
links,
|
|
14869
|
-
toolCalls: params.streamState.toolCalls,
|
|
14870
|
-
actions: [],
|
|
14871
15036
|
deliveryState: "sent"
|
|
14872
15037
|
});
|
|
15038
|
+
if (!messageId) {
|
|
15039
|
+
return;
|
|
15040
|
+
}
|
|
15041
|
+
emitCowtailStreamSnapshot({
|
|
15042
|
+
client: params.client,
|
|
15043
|
+
logger: params.logger,
|
|
15044
|
+
route: params.route,
|
|
15045
|
+
thread: params.thread,
|
|
15046
|
+
streamState: params.streamState,
|
|
15047
|
+
text,
|
|
15048
|
+
isFinal: true,
|
|
15049
|
+
updatedAt: Date.now()
|
|
15050
|
+
});
|
|
14873
15051
|
params.streamState.completed = true;
|
|
14874
15052
|
}
|
|
15053
|
+
async function createDurableCowtailReply(params, message) {
|
|
15054
|
+
try {
|
|
15055
|
+
const result = await params.client.sendOpenClawMessage({
|
|
15056
|
+
type: "openclaw_message",
|
|
15057
|
+
idempotencyKey: params.streamState.idempotencyKey,
|
|
15058
|
+
streamId: params.streamState.streamId,
|
|
15059
|
+
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
15060
|
+
title: params.thread.title,
|
|
15061
|
+
text: message.text,
|
|
15062
|
+
authorLabel: "OpenClaw",
|
|
15063
|
+
links: message.links,
|
|
15064
|
+
toolCalls: params.streamState.toolCalls,
|
|
15065
|
+
actions: [],
|
|
15066
|
+
deliveryState: message.deliveryState
|
|
15067
|
+
});
|
|
15068
|
+
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
15069
|
+
if (!messageId) {
|
|
15070
|
+
failCowtailStreamBeforeDurableCreate(params);
|
|
15071
|
+
return;
|
|
15072
|
+
}
|
|
15073
|
+
params.streamState.messageId = messageId;
|
|
15074
|
+
return messageId;
|
|
15075
|
+
} catch (error48) {
|
|
15076
|
+
failCowtailStreamBeforeDurableCreate(params);
|
|
15077
|
+
throw error48;
|
|
15078
|
+
}
|
|
15079
|
+
}
|
|
14875
15080
|
async function finalizeCowtailStreamedReply(params) {
|
|
14876
15081
|
if (params.streamState.failed || params.streamState.completed || !params.streamState.messageId || !params.streamState.text.trim() && params.streamState.toolCalls.length === 0) {
|
|
14877
15082
|
return;
|
|
@@ -14879,6 +15084,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14879
15084
|
await params.client.sendOpenClawMessageUpdate({
|
|
14880
15085
|
type: "openclaw_message_update",
|
|
14881
15086
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15087
|
+
streamId: params.streamState.streamId,
|
|
14882
15088
|
messageId: params.streamState.messageId,
|
|
14883
15089
|
text: params.streamState.text,
|
|
14884
15090
|
links: params.streamState.links,
|
|
@@ -14886,8 +15092,137 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
14886
15092
|
actions: [],
|
|
14887
15093
|
deliveryState: "sent"
|
|
14888
15094
|
});
|
|
15095
|
+
emitCowtailStreamSnapshot({
|
|
15096
|
+
client: params.client,
|
|
15097
|
+
logger: params.logger,
|
|
15098
|
+
route: params.route,
|
|
15099
|
+
thread: params.thread,
|
|
15100
|
+
streamState: params.streamState,
|
|
15101
|
+
text: params.streamState.text,
|
|
15102
|
+
isFinal: true,
|
|
15103
|
+
updatedAt: Date.now()
|
|
15104
|
+
});
|
|
14889
15105
|
params.streamState.completed = true;
|
|
14890
15106
|
}
|
|
15107
|
+
function deliverCowtailPartialReply(params) {
|
|
15108
|
+
const text = params.payload.text;
|
|
15109
|
+
if (params.streamState.failed || typeof text !== "string" || !text.trim()) {
|
|
15110
|
+
return;
|
|
15111
|
+
}
|
|
15112
|
+
const now = Date.now();
|
|
15113
|
+
const previous = params.streamState.lastSnapshotText ?? "";
|
|
15114
|
+
const changedChars = Math.abs(text.length - previous.length);
|
|
15115
|
+
const sentRecently = params.streamState.lastSnapshotSentAt !== undefined && now - params.streamState.lastSnapshotSentAt < STREAM_MIN_INTERVAL_MS;
|
|
15116
|
+
if (text === previous || sentRecently && changedChars < STREAM_MIN_CHARS_DELTA) {
|
|
15117
|
+
return;
|
|
15118
|
+
}
|
|
15119
|
+
emitCowtailStreamSnapshot({
|
|
15120
|
+
client: params.client,
|
|
15121
|
+
logger: params.logger,
|
|
15122
|
+
route: params.route,
|
|
15123
|
+
thread: params.thread,
|
|
15124
|
+
streamState: params.streamState,
|
|
15125
|
+
text,
|
|
15126
|
+
isFinal: false,
|
|
15127
|
+
updatedAt: now
|
|
15128
|
+
});
|
|
15129
|
+
}
|
|
15130
|
+
function deliverCowtailToolProgress(params) {
|
|
15131
|
+
if (params.streamState.failed) {
|
|
15132
|
+
return;
|
|
15133
|
+
}
|
|
15134
|
+
const payload = readRecord(params.payload) ?? {};
|
|
15135
|
+
const stableId = readString(payload.itemId) ?? readString(payload.toolCallId) ?? readString(payload.id);
|
|
15136
|
+
if (params.requireStableId && !stableId) {
|
|
15137
|
+
return;
|
|
15138
|
+
}
|
|
15139
|
+
const id = stableId ?? fallbackCowtailToolCallId(params.streamState, payload);
|
|
15140
|
+
const name = readString(payload.name) ?? readString(payload.title) ?? readString(payload.command) ?? "tool_result";
|
|
15141
|
+
const status = params.status ?? normalizeCowtailToolCallStatus(payload.status) ?? normalizeCowtailToolCallStatus(payload.phase) ?? "running";
|
|
15142
|
+
const result = readCowtailToolProgressResult(payload);
|
|
15143
|
+
const args = readRecord(payload.args) ?? readRecord(payload.input);
|
|
15144
|
+
const now = Date.now();
|
|
15145
|
+
const currentText = currentLiveCowtailStreamText(params.streamState);
|
|
15146
|
+
const nextToolCall = {
|
|
15147
|
+
id,
|
|
15148
|
+
name,
|
|
15149
|
+
...args ? { args } : {},
|
|
15150
|
+
...result !== undefined ? { result } : {},
|
|
15151
|
+
status,
|
|
15152
|
+
...status === "complete" || status === "error" ? { completedAt: now } : {},
|
|
15153
|
+
insertedAtContentLength: currentText.length,
|
|
15154
|
+
contentSnapshotAtStart: currentText
|
|
15155
|
+
};
|
|
15156
|
+
upsertCowtailToolCall(params.streamState, nextToolCall);
|
|
15157
|
+
emitCowtailStreamSnapshot({
|
|
15158
|
+
client: params.client,
|
|
15159
|
+
logger: params.logger,
|
|
15160
|
+
route: params.route,
|
|
15161
|
+
thread: params.thread,
|
|
15162
|
+
streamState: params.streamState,
|
|
15163
|
+
text: currentText,
|
|
15164
|
+
isFinal: false,
|
|
15165
|
+
updatedAt: now
|
|
15166
|
+
});
|
|
15167
|
+
}
|
|
15168
|
+
function emitCowtailStreamSnapshot(params) {
|
|
15169
|
+
if (params.streamState.failed && params.allowFailed !== true || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15170
|
+
return;
|
|
15171
|
+
}
|
|
15172
|
+
params.streamState.liveText = params.text;
|
|
15173
|
+
params.streamState.lastSnapshotText = params.text;
|
|
15174
|
+
params.streamState.lastSnapshotSentAt = params.updatedAt;
|
|
15175
|
+
params.streamState.snapshotSequence += 1;
|
|
15176
|
+
params.client.sendOpenClawStreamSnapshot({
|
|
15177
|
+
type: "openclaw_message_stream_snapshot",
|
|
15178
|
+
streamId: params.streamState.streamId,
|
|
15179
|
+
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
15180
|
+
threadId: params.thread.id,
|
|
15181
|
+
text: params.text,
|
|
15182
|
+
links: params.streamState.links.map((link) => ({ ...link })),
|
|
15183
|
+
toolCalls: structuredClone(params.streamState.toolCalls),
|
|
15184
|
+
isFinal: params.isFinal,
|
|
15185
|
+
snapshotSequence: params.streamState.snapshotSequence,
|
|
15186
|
+
updatedAt: params.updatedAt
|
|
15187
|
+
}).catch((error48) => {
|
|
15188
|
+
params.logger?.warn?.(`Cowtail stream snapshot send failed: ${errorMessage(error48)}`);
|
|
15189
|
+
});
|
|
15190
|
+
}
|
|
15191
|
+
function failCowtailStreamBeforeDurableCreate(params) {
|
|
15192
|
+
if (!params.streamState.messageId && params.streamState.snapshotSequence > 0) {
|
|
15193
|
+
const text = params.streamState.text.trim() ? params.streamState.text : currentLiveCowtailStreamText(params.streamState);
|
|
15194
|
+
emitCowtailStreamSnapshot({
|
|
15195
|
+
client: params.client,
|
|
15196
|
+
logger: params.logger,
|
|
15197
|
+
route: params.route,
|
|
15198
|
+
thread: params.thread,
|
|
15199
|
+
streamState: params.streamState,
|
|
15200
|
+
text,
|
|
15201
|
+
isFinal: true,
|
|
15202
|
+
updatedAt: Date.now(),
|
|
15203
|
+
allowFailed: true
|
|
15204
|
+
});
|
|
15205
|
+
}
|
|
15206
|
+
params.streamState.failed = true;
|
|
15207
|
+
params.streamState.completed = true;
|
|
15208
|
+
}
|
|
15209
|
+
function currentLiveCowtailStreamText(streamState) {
|
|
15210
|
+
return streamState.liveText ?? streamState.text;
|
|
15211
|
+
}
|
|
15212
|
+
function upsertCowtailToolCall(streamState, toolCall) {
|
|
15213
|
+
const index = streamState.toolCalls.findIndex((candidate) => candidate.id === toolCall.id);
|
|
15214
|
+
if (index < 0) {
|
|
15215
|
+
streamState.toolCalls = [...streamState.toolCalls, toolCall];
|
|
15216
|
+
return;
|
|
15217
|
+
}
|
|
15218
|
+
const existing = streamState.toolCalls[index];
|
|
15219
|
+
streamState.toolCalls[index] = {
|
|
15220
|
+
...existing,
|
|
15221
|
+
...toolCall,
|
|
15222
|
+
insertedAtContentLength: existing.insertedAtContentLength ?? toolCall.insertedAtContentLength,
|
|
15223
|
+
contentSnapshotAtStart: existing.contentSnapshotAtStart ?? toolCall.contentSnapshotAtStart
|
|
15224
|
+
};
|
|
15225
|
+
}
|
|
14891
15226
|
function recordCreatedOpenClawMessageId(streamState, result) {
|
|
14892
15227
|
if (result.payload?.dropped === true) {
|
|
14893
15228
|
if (result.payload.duplicate === true) {
|
|
@@ -14983,6 +15318,48 @@ function readRecord(value) {
|
|
|
14983
15318
|
function readToolCallStatus(value) {
|
|
14984
15319
|
return value === "pending" || value === "running" || value === "complete" || value === "error" ? value : undefined;
|
|
14985
15320
|
}
|
|
15321
|
+
function normalizeCowtailToolCallStatus(value) {
|
|
15322
|
+
const status = readToolCallStatus(value);
|
|
15323
|
+
if (status) {
|
|
15324
|
+
return status;
|
|
15325
|
+
}
|
|
15326
|
+
if (value === "start" || value === "started" || value === "working") {
|
|
15327
|
+
return "running";
|
|
15328
|
+
}
|
|
15329
|
+
if (value === "end" || value === "done" || value === "completed" || value === "success") {
|
|
15330
|
+
return "complete";
|
|
15331
|
+
}
|
|
15332
|
+
if (value === "failed" || value === "failure") {
|
|
15333
|
+
return "error";
|
|
15334
|
+
}
|
|
15335
|
+
return;
|
|
15336
|
+
}
|
|
15337
|
+
function readCowtailToolProgressResult(payload) {
|
|
15338
|
+
const stringResult = readString(payload.output) ?? readString(payload.summary) ?? readString(payload.message) ?? readString(payload.progressText) ?? readString(payload.text);
|
|
15339
|
+
if (stringResult !== undefined) {
|
|
15340
|
+
return stringResult;
|
|
15341
|
+
}
|
|
15342
|
+
if (payload.result !== undefined) {
|
|
15343
|
+
return payload.result;
|
|
15344
|
+
}
|
|
15345
|
+
const structuredPatch = {
|
|
15346
|
+
...Array.isArray(payload.added) ? { added: payload.added } : {},
|
|
15347
|
+
...Array.isArray(payload.modified) ? { modified: payload.modified } : {},
|
|
15348
|
+
...Array.isArray(payload.deleted) ? { deleted: payload.deleted } : {}
|
|
15349
|
+
};
|
|
15350
|
+
return Object.keys(structuredPatch).length > 0 ? structuredPatch : undefined;
|
|
15351
|
+
}
|
|
15352
|
+
function fallbackCowtailToolCallId(streamState, payload) {
|
|
15353
|
+
const key = readString(payload.name) ?? readString(payload.title) ?? readString(payload.command) ?? JSON.stringify(Object.keys(payload).sort());
|
|
15354
|
+
const existing = streamState.toolFallbackIds[key];
|
|
15355
|
+
if (existing) {
|
|
15356
|
+
return existing;
|
|
15357
|
+
}
|
|
15358
|
+
streamState.toolFallbackIndex += 1;
|
|
15359
|
+
const next = `tool-${streamState.toolFallbackIndex}`;
|
|
15360
|
+
streamState.toolFallbackIds[key] = next;
|
|
15361
|
+
return next;
|
|
15362
|
+
}
|
|
14986
15363
|
function readTimestamp(value) {
|
|
14987
15364
|
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
14988
15365
|
}
|
|
@@ -15105,23 +15482,29 @@ function resolveCowtailTarget(to) {
|
|
|
15105
15482
|
if (!normalizedTarget) {
|
|
15106
15483
|
throw new Error("Cowtail target must not be blank");
|
|
15107
15484
|
}
|
|
15108
|
-
return
|
|
15485
|
+
return normalizedTarget;
|
|
15109
15486
|
}
|
|
15110
15487
|
async function sendCowtailText(params) {
|
|
15111
15488
|
const { client, to } = params;
|
|
15112
15489
|
const text = ensureNonBlankText(params.text);
|
|
15113
15490
|
const target = resolveCowtailTarget(to);
|
|
15491
|
+
const sessionKey = buildCowtailTarget(target);
|
|
15114
15492
|
const result = await client.sendOpenClawMessage({
|
|
15115
15493
|
type: "openclaw_message",
|
|
15116
|
-
sessionKey
|
|
15494
|
+
sessionKey,
|
|
15495
|
+
threadHint: target,
|
|
15117
15496
|
text,
|
|
15118
15497
|
links: [],
|
|
15119
15498
|
actions: []
|
|
15120
15499
|
});
|
|
15500
|
+
const messageId = result.payload?.messageId;
|
|
15501
|
+
if (typeof messageId !== "string" || messageId.trim() === "") {
|
|
15502
|
+
throw new Error("Cowtail did not acknowledge a durable message id");
|
|
15503
|
+
}
|
|
15121
15504
|
return {
|
|
15122
15505
|
channel: "cowtail",
|
|
15123
|
-
messageId
|
|
15124
|
-
to: target
|
|
15506
|
+
messageId,
|
|
15507
|
+
to: buildCowtailTarget(target)
|
|
15125
15508
|
};
|
|
15126
15509
|
}
|
|
15127
15510
|
|