@maudecode/openclaw-cowtail 0.13.0 → 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 +99 -47
- package/dist/setup-entry.js +99 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,3 +7,7 @@ Load it from an OpenClaw config with `plugins.entries.cowtail.path` pointing at
|
|
|
7
7
|
Configure `channels.cowtail.url` with the Cowtail realtime WebSocket endpoint and `channels.cowtail.bridgeToken` with the same bridge token configured on the Cowtail realtime service.
|
|
8
8
|
|
|
9
9
|
V1 supports a single owner and OpenClaw's default `main` agent only.
|
|
10
|
+
|
|
11
|
+
## Realtime event scope
|
|
12
|
+
|
|
13
|
+
The plugin receives Cowtail events that require OpenClaw work: iOS-created threads, iOS replies, and submitted actions. Cowtail thread lifecycle updates such as read state, rename, and delete stay local to Cowtail/iOS because OpenClaw v1 has no channel-level state mutation contract for those operations.
|
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,7 +13876,8 @@ 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
|
}));
|
|
13877
13882
|
var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
13878
13883
|
type: exports_external.literal("openclaw_message_stream_snapshot"),
|
|
@@ -13884,6 +13889,7 @@ var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
|
13884
13889
|
links: exports_external.array(openclawLinkSchema).default([]),
|
|
13885
13890
|
toolCalls: exports_external.array(openclawToolCallRecordSchema).default([]),
|
|
13886
13891
|
isFinal: exports_external.boolean(),
|
|
13892
|
+
snapshotSequence: exports_external.number().int().nonnegative(),
|
|
13887
13893
|
updatedAt: timestampSchema
|
|
13888
13894
|
});
|
|
13889
13895
|
var openclawMessageStreamSnapshotCommandSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema);
|
|
@@ -13956,11 +13962,18 @@ var openclawRealtimeClientMessageSchema = exports_external.union([
|
|
|
13956
13962
|
openclawSessionBoundCommandSchema,
|
|
13957
13963
|
openclawActionResultCommandSchema
|
|
13958
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
|
+
});
|
|
13959
13972
|
var openclawRealtimeAckSchema = exports_external.object({
|
|
13960
13973
|
type: exports_external.literal("ack"),
|
|
13961
13974
|
requestId: openclawRequestIdSchema,
|
|
13962
13975
|
sequence: openclawSequenceSchema.optional(),
|
|
13963
|
-
payload:
|
|
13976
|
+
payload: openclawRealtimeAckPayloadSchema.optional()
|
|
13964
13977
|
});
|
|
13965
13978
|
var openclawRealtimeErrorSchema = exports_external.object({
|
|
13966
13979
|
type: exports_external.literal("realtime_error"),
|
|
@@ -14009,6 +14022,13 @@ var openclawEventReplayResponseSchema = exports_external.object({
|
|
|
14009
14022
|
ok: exports_external.literal(true),
|
|
14010
14023
|
events: exports_external.array(openclawEventEnvelopeSchema)
|
|
14011
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
|
+
});
|
|
14012
14032
|
// ../protocol/src/fixes.ts
|
|
14013
14033
|
var fixScopeSchema = exports_external.enum(fixScopes);
|
|
14014
14034
|
var fixCreateRequestSchema = exports_external.object({
|
|
@@ -14064,11 +14084,12 @@ var healthResponseSchema = exports_external.object({
|
|
|
14064
14084
|
storageUnit: nonEmptyStringSchema
|
|
14065
14085
|
});
|
|
14066
14086
|
// ../protocol/src/push.ts
|
|
14087
|
+
var pushEnvironmentSchema = exports_external.enum(["development", "production"]);
|
|
14067
14088
|
var pushRegisterRequestSchema = exports_external.object({
|
|
14068
14089
|
identityToken: nonEmptyStringSchema,
|
|
14069
14090
|
deviceToken: nonEmptyStringSchema,
|
|
14070
14091
|
platform: nonEmptyStringSchema.optional(),
|
|
14071
|
-
environment:
|
|
14092
|
+
environment: pushEnvironmentSchema.optional(),
|
|
14072
14093
|
deviceName: nonEmptyStringSchema.optional()
|
|
14073
14094
|
});
|
|
14074
14095
|
var pushRegisterResponseSchema = exports_external.object({
|
|
@@ -14077,6 +14098,7 @@ var pushRegisterResponseSchema = exports_external.object({
|
|
|
14077
14098
|
id: nonEmptyStringSchema
|
|
14078
14099
|
});
|
|
14079
14100
|
var pushUnregisterRequestSchema = exports_external.object({
|
|
14101
|
+
identityToken: nonEmptyStringSchema,
|
|
14080
14102
|
deviceToken: nonEmptyStringSchema
|
|
14081
14103
|
});
|
|
14082
14104
|
var pushUnregisterResponseSchema = exports_external.object({
|
|
@@ -14100,6 +14122,7 @@ var pushResultSchema = exports_external.object({
|
|
|
14100
14122
|
userId: nonEmptyStringSchema,
|
|
14101
14123
|
sent: exports_external.number().int().nonnegative(),
|
|
14102
14124
|
failed: exports_external.number().int().nonnegative(),
|
|
14125
|
+
skipped: exports_external.number().int().nonnegative().default(0),
|
|
14103
14126
|
results: exports_external.array(jsonObjectSchema)
|
|
14104
14127
|
});
|
|
14105
14128
|
// ../protocol/src/responses.ts
|
|
@@ -14120,7 +14143,8 @@ var usersListEntrySchema = exports_external.object({
|
|
|
14120
14143
|
enabledDeviceCount: exports_external.number().int().nonnegative()
|
|
14121
14144
|
});
|
|
14122
14145
|
var userDeviceSchema = exports_external.object({
|
|
14123
|
-
|
|
14146
|
+
id: nonEmptyStringSchema,
|
|
14147
|
+
deviceTokenPreview: nonEmptyStringSchema,
|
|
14124
14148
|
platform: nonEmptyStringSchema,
|
|
14125
14149
|
environment: nonEmptyStringSchema,
|
|
14126
14150
|
enabled: exports_external.boolean(),
|
|
@@ -14192,10 +14216,12 @@ class CowtailRealtimeClient {
|
|
|
14192
14216
|
}
|
|
14193
14217
|
sendOpenClawMessage(command) {
|
|
14194
14218
|
const requestId = this.#requestIdFactory();
|
|
14219
|
+
const idempotencyKey = command.idempotencyKey ?? `cowtail:request:${requestId}`;
|
|
14195
14220
|
return this.#sendCommand({
|
|
14196
14221
|
...command,
|
|
14197
14222
|
requestId,
|
|
14198
|
-
idempotencyKey
|
|
14223
|
+
idempotencyKey,
|
|
14224
|
+
streamId: command.streamId ?? idempotencyKey,
|
|
14199
14225
|
links: command.links ?? [],
|
|
14200
14226
|
toolCalls: command.toolCalls ?? [],
|
|
14201
14227
|
actions: command.actions ?? []
|
|
@@ -14668,6 +14694,7 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14668
14694
|
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14669
14695
|
streamId: `cowtail:stream:${message.id}`,
|
|
14670
14696
|
updateIndex: 0,
|
|
14697
|
+
snapshotSequence: 0,
|
|
14671
14698
|
toolFallbackIndex: 0,
|
|
14672
14699
|
toolFallbackIds: {},
|
|
14673
14700
|
text: "",
|
|
@@ -14741,6 +14768,7 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14741
14768
|
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14742
14769
|
streamId: `cowtail:action-stream:${action.id}`,
|
|
14743
14770
|
updateIndex: 0,
|
|
14771
|
+
snapshotSequence: 0,
|
|
14744
14772
|
toolFallbackIndex: 0,
|
|
14745
14773
|
toolFallbackIds: {},
|
|
14746
14774
|
text: "",
|
|
@@ -14921,28 +14949,17 @@ async function deliverCowtailReply(params) {
|
|
|
14921
14949
|
updatedAt: Date.now()
|
|
14922
14950
|
});
|
|
14923
14951
|
if (!params.streamState.messageId) {
|
|
14924
|
-
|
|
14925
|
-
type: "openclaw_message",
|
|
14926
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14927
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14928
|
-
title: params.thread.title,
|
|
14952
|
+
await createDurableCowtailReply(params, {
|
|
14929
14953
|
text: messageText,
|
|
14930
|
-
authorLabel: "OpenClaw",
|
|
14931
14954
|
links,
|
|
14932
|
-
toolCalls: params.streamState.toolCalls,
|
|
14933
|
-
actions: [],
|
|
14934
14955
|
deliveryState: "pending"
|
|
14935
14956
|
});
|
|
14936
|
-
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14937
|
-
if (!messageId2) {
|
|
14938
|
-
return;
|
|
14939
|
-
}
|
|
14940
|
-
params.streamState.messageId = messageId2;
|
|
14941
14957
|
return;
|
|
14942
14958
|
}
|
|
14943
14959
|
await params.client.sendOpenClawMessageUpdate({
|
|
14944
14960
|
type: "openclaw_message_update",
|
|
14945
14961
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14962
|
+
streamId: params.streamState.streamId,
|
|
14946
14963
|
messageId: params.streamState.messageId,
|
|
14947
14964
|
text: messageText,
|
|
14948
14965
|
links,
|
|
@@ -14967,28 +14984,17 @@ async function deliverCowtailReply(params) {
|
|
|
14967
14984
|
updatedAt: Date.now()
|
|
14968
14985
|
});
|
|
14969
14986
|
if (!params.streamState.messageId) {
|
|
14970
|
-
|
|
14971
|
-
type: "openclaw_message",
|
|
14972
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14973
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14974
|
-
title: params.thread.title,
|
|
14987
|
+
await createDurableCowtailReply(params, {
|
|
14975
14988
|
text: params.streamState.text,
|
|
14976
|
-
authorLabel: "OpenClaw",
|
|
14977
14989
|
links,
|
|
14978
|
-
toolCalls: params.streamState.toolCalls,
|
|
14979
|
-
actions: [],
|
|
14980
14990
|
deliveryState: "pending"
|
|
14981
14991
|
});
|
|
14982
|
-
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14983
|
-
if (!messageId2) {
|
|
14984
|
-
return;
|
|
14985
|
-
}
|
|
14986
|
-
params.streamState.messageId = messageId2;
|
|
14987
14992
|
return;
|
|
14988
14993
|
}
|
|
14989
14994
|
await params.client.sendOpenClawMessageUpdate({
|
|
14990
14995
|
type: "openclaw_message_update",
|
|
14991
14996
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14997
|
+
streamId: params.streamState.streamId,
|
|
14992
14998
|
messageId: params.streamState.messageId,
|
|
14993
14999
|
text: params.streamState.text,
|
|
14994
15000
|
links,
|
|
@@ -15002,6 +15008,7 @@ async function deliverCowtailReply(params) {
|
|
|
15002
15008
|
await params.client.sendOpenClawMessageUpdate({
|
|
15003
15009
|
type: "openclaw_message_update",
|
|
15004
15010
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15011
|
+
streamId: params.streamState.streamId,
|
|
15005
15012
|
messageId: params.streamState.messageId,
|
|
15006
15013
|
text,
|
|
15007
15014
|
links,
|
|
@@ -15023,23 +15030,14 @@ async function deliverCowtailReply(params) {
|
|
|
15023
15030
|
return;
|
|
15024
15031
|
}
|
|
15025
15032
|
params.streamState.text = text;
|
|
15026
|
-
const
|
|
15027
|
-
type: "openclaw_message",
|
|
15028
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
15029
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
15030
|
-
title: params.thread.title,
|
|
15033
|
+
const messageId = await createDurableCowtailReply(params, {
|
|
15031
15034
|
text,
|
|
15032
|
-
authorLabel: "OpenClaw",
|
|
15033
15035
|
links,
|
|
15034
|
-
toolCalls: params.streamState.toolCalls,
|
|
15035
|
-
actions: [],
|
|
15036
15036
|
deliveryState: "sent"
|
|
15037
15037
|
});
|
|
15038
|
-
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
15039
15038
|
if (!messageId) {
|
|
15040
15039
|
return;
|
|
15041
15040
|
}
|
|
15042
|
-
params.streamState.messageId = messageId;
|
|
15043
15041
|
emitCowtailStreamSnapshot({
|
|
15044
15042
|
client: params.client,
|
|
15045
15043
|
logger: params.logger,
|
|
@@ -15052,6 +15050,33 @@ async function deliverCowtailReply(params) {
|
|
|
15052
15050
|
});
|
|
15053
15051
|
params.streamState.completed = true;
|
|
15054
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
|
+
}
|
|
15055
15080
|
async function finalizeCowtailStreamedReply(params) {
|
|
15056
15081
|
if (params.streamState.failed || params.streamState.completed || !params.streamState.messageId || !params.streamState.text.trim() && params.streamState.toolCalls.length === 0) {
|
|
15057
15082
|
return;
|
|
@@ -15059,6 +15084,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
15059
15084
|
await params.client.sendOpenClawMessageUpdate({
|
|
15060
15085
|
type: "openclaw_message_update",
|
|
15061
15086
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15087
|
+
streamId: params.streamState.streamId,
|
|
15062
15088
|
messageId: params.streamState.messageId,
|
|
15063
15089
|
text: params.streamState.text,
|
|
15064
15090
|
links: params.streamState.links,
|
|
@@ -15140,12 +15166,13 @@ function deliverCowtailToolProgress(params) {
|
|
|
15140
15166
|
});
|
|
15141
15167
|
}
|
|
15142
15168
|
function emitCowtailStreamSnapshot(params) {
|
|
15143
|
-
if (params.streamState.failed || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15169
|
+
if (params.streamState.failed && params.allowFailed !== true || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15144
15170
|
return;
|
|
15145
15171
|
}
|
|
15146
15172
|
params.streamState.liveText = params.text;
|
|
15147
15173
|
params.streamState.lastSnapshotText = params.text;
|
|
15148
15174
|
params.streamState.lastSnapshotSentAt = params.updatedAt;
|
|
15175
|
+
params.streamState.snapshotSequence += 1;
|
|
15149
15176
|
params.client.sendOpenClawStreamSnapshot({
|
|
15150
15177
|
type: "openclaw_message_stream_snapshot",
|
|
15151
15178
|
streamId: params.streamState.streamId,
|
|
@@ -15155,11 +15182,30 @@ function emitCowtailStreamSnapshot(params) {
|
|
|
15155
15182
|
links: params.streamState.links.map((link) => ({ ...link })),
|
|
15156
15183
|
toolCalls: structuredClone(params.streamState.toolCalls),
|
|
15157
15184
|
isFinal: params.isFinal,
|
|
15185
|
+
snapshotSequence: params.streamState.snapshotSequence,
|
|
15158
15186
|
updatedAt: params.updatedAt
|
|
15159
15187
|
}).catch((error48) => {
|
|
15160
15188
|
params.logger?.warn?.(`Cowtail stream snapshot send failed: ${errorMessage(error48)}`);
|
|
15161
15189
|
});
|
|
15162
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
|
+
}
|
|
15163
15209
|
function currentLiveCowtailStreamText(streamState) {
|
|
15164
15210
|
return streamState.liveText ?? streamState.text;
|
|
15165
15211
|
}
|
|
@@ -15436,23 +15482,29 @@ function resolveCowtailTarget(to) {
|
|
|
15436
15482
|
if (!normalizedTarget) {
|
|
15437
15483
|
throw new Error("Cowtail target must not be blank");
|
|
15438
15484
|
}
|
|
15439
|
-
return
|
|
15485
|
+
return normalizedTarget;
|
|
15440
15486
|
}
|
|
15441
15487
|
async function sendCowtailText(params) {
|
|
15442
15488
|
const { client, to } = params;
|
|
15443
15489
|
const text = ensureNonBlankText(params.text);
|
|
15444
15490
|
const target = resolveCowtailTarget(to);
|
|
15491
|
+
const sessionKey = buildCowtailTarget(target);
|
|
15445
15492
|
const result = await client.sendOpenClawMessage({
|
|
15446
15493
|
type: "openclaw_message",
|
|
15447
|
-
sessionKey
|
|
15494
|
+
sessionKey,
|
|
15495
|
+
threadHint: target,
|
|
15448
15496
|
text,
|
|
15449
15497
|
links: [],
|
|
15450
15498
|
actions: []
|
|
15451
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
|
+
}
|
|
15452
15504
|
return {
|
|
15453
15505
|
channel: "cowtail",
|
|
15454
|
-
messageId
|
|
15455
|
-
to: target
|
|
15506
|
+
messageId,
|
|
15507
|
+
to: buildCowtailTarget(target)
|
|
15456
15508
|
};
|
|
15457
15509
|
}
|
|
15458
15510
|
|
package/dist/setup-entry.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,7 +13876,8 @@ 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
|
}));
|
|
13877
13882
|
var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
13878
13883
|
type: exports_external.literal("openclaw_message_stream_snapshot"),
|
|
@@ -13884,6 +13889,7 @@ var openclawMessageStreamSnapshotCommandBaseSchema = exports_external.object({
|
|
|
13884
13889
|
links: exports_external.array(openclawLinkSchema).default([]),
|
|
13885
13890
|
toolCalls: exports_external.array(openclawToolCallRecordSchema).default([]),
|
|
13886
13891
|
isFinal: exports_external.boolean(),
|
|
13892
|
+
snapshotSequence: exports_external.number().int().nonnegative(),
|
|
13887
13893
|
updatedAt: timestampSchema
|
|
13888
13894
|
});
|
|
13889
13895
|
var openclawMessageStreamSnapshotCommandSchema = requireOpenClawRenderableContent(openclawMessageStreamSnapshotCommandBaseSchema);
|
|
@@ -13956,11 +13962,18 @@ var openclawRealtimeClientMessageSchema = exports_external.union([
|
|
|
13956
13962
|
openclawSessionBoundCommandSchema,
|
|
13957
13963
|
openclawActionResultCommandSchema
|
|
13958
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
|
+
});
|
|
13959
13972
|
var openclawRealtimeAckSchema = exports_external.object({
|
|
13960
13973
|
type: exports_external.literal("ack"),
|
|
13961
13974
|
requestId: openclawRequestIdSchema,
|
|
13962
13975
|
sequence: openclawSequenceSchema.optional(),
|
|
13963
|
-
payload:
|
|
13976
|
+
payload: openclawRealtimeAckPayloadSchema.optional()
|
|
13964
13977
|
});
|
|
13965
13978
|
var openclawRealtimeErrorSchema = exports_external.object({
|
|
13966
13979
|
type: exports_external.literal("realtime_error"),
|
|
@@ -14009,6 +14022,13 @@ var openclawEventReplayResponseSchema = exports_external.object({
|
|
|
14009
14022
|
ok: exports_external.literal(true),
|
|
14010
14023
|
events: exports_external.array(openclawEventEnvelopeSchema)
|
|
14011
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
|
+
});
|
|
14012
14032
|
// ../protocol/src/fixes.ts
|
|
14013
14033
|
var fixScopeSchema = exports_external.enum(fixScopes);
|
|
14014
14034
|
var fixCreateRequestSchema = exports_external.object({
|
|
@@ -14064,11 +14084,12 @@ var healthResponseSchema = exports_external.object({
|
|
|
14064
14084
|
storageUnit: nonEmptyStringSchema
|
|
14065
14085
|
});
|
|
14066
14086
|
// ../protocol/src/push.ts
|
|
14087
|
+
var pushEnvironmentSchema = exports_external.enum(["development", "production"]);
|
|
14067
14088
|
var pushRegisterRequestSchema = exports_external.object({
|
|
14068
14089
|
identityToken: nonEmptyStringSchema,
|
|
14069
14090
|
deviceToken: nonEmptyStringSchema,
|
|
14070
14091
|
platform: nonEmptyStringSchema.optional(),
|
|
14071
|
-
environment:
|
|
14092
|
+
environment: pushEnvironmentSchema.optional(),
|
|
14072
14093
|
deviceName: nonEmptyStringSchema.optional()
|
|
14073
14094
|
});
|
|
14074
14095
|
var pushRegisterResponseSchema = exports_external.object({
|
|
@@ -14077,6 +14098,7 @@ var pushRegisterResponseSchema = exports_external.object({
|
|
|
14077
14098
|
id: nonEmptyStringSchema
|
|
14078
14099
|
});
|
|
14079
14100
|
var pushUnregisterRequestSchema = exports_external.object({
|
|
14101
|
+
identityToken: nonEmptyStringSchema,
|
|
14080
14102
|
deviceToken: nonEmptyStringSchema
|
|
14081
14103
|
});
|
|
14082
14104
|
var pushUnregisterResponseSchema = exports_external.object({
|
|
@@ -14100,6 +14122,7 @@ var pushResultSchema = exports_external.object({
|
|
|
14100
14122
|
userId: nonEmptyStringSchema,
|
|
14101
14123
|
sent: exports_external.number().int().nonnegative(),
|
|
14102
14124
|
failed: exports_external.number().int().nonnegative(),
|
|
14125
|
+
skipped: exports_external.number().int().nonnegative().default(0),
|
|
14103
14126
|
results: exports_external.array(jsonObjectSchema)
|
|
14104
14127
|
});
|
|
14105
14128
|
// ../protocol/src/responses.ts
|
|
@@ -14120,7 +14143,8 @@ var usersListEntrySchema = exports_external.object({
|
|
|
14120
14143
|
enabledDeviceCount: exports_external.number().int().nonnegative()
|
|
14121
14144
|
});
|
|
14122
14145
|
var userDeviceSchema = exports_external.object({
|
|
14123
|
-
|
|
14146
|
+
id: nonEmptyStringSchema,
|
|
14147
|
+
deviceTokenPreview: nonEmptyStringSchema,
|
|
14124
14148
|
platform: nonEmptyStringSchema,
|
|
14125
14149
|
environment: nonEmptyStringSchema,
|
|
14126
14150
|
enabled: exports_external.boolean(),
|
|
@@ -14192,10 +14216,12 @@ class CowtailRealtimeClient {
|
|
|
14192
14216
|
}
|
|
14193
14217
|
sendOpenClawMessage(command) {
|
|
14194
14218
|
const requestId = this.#requestIdFactory();
|
|
14219
|
+
const idempotencyKey = command.idempotencyKey ?? `cowtail:request:${requestId}`;
|
|
14195
14220
|
return this.#sendCommand({
|
|
14196
14221
|
...command,
|
|
14197
14222
|
requestId,
|
|
14198
|
-
idempotencyKey
|
|
14223
|
+
idempotencyKey,
|
|
14224
|
+
streamId: command.streamId ?? idempotencyKey,
|
|
14199
14225
|
links: command.links ?? [],
|
|
14200
14226
|
toolCalls: command.toolCalls ?? [],
|
|
14201
14227
|
actions: command.actions ?? []
|
|
@@ -14668,6 +14694,7 @@ async function dispatchCowtailTextTurn(params) {
|
|
|
14668
14694
|
idempotencyKey: `cowtail:reply:${message.id}`,
|
|
14669
14695
|
streamId: `cowtail:stream:${message.id}`,
|
|
14670
14696
|
updateIndex: 0,
|
|
14697
|
+
snapshotSequence: 0,
|
|
14671
14698
|
toolFallbackIndex: 0,
|
|
14672
14699
|
toolFallbackIds: {},
|
|
14673
14700
|
text: "",
|
|
@@ -14741,6 +14768,7 @@ async function dispatchCowtailActionTurn(params) {
|
|
|
14741
14768
|
idempotencyKey: `cowtail:action:${action.id}`,
|
|
14742
14769
|
streamId: `cowtail:action-stream:${action.id}`,
|
|
14743
14770
|
updateIndex: 0,
|
|
14771
|
+
snapshotSequence: 0,
|
|
14744
14772
|
toolFallbackIndex: 0,
|
|
14745
14773
|
toolFallbackIds: {},
|
|
14746
14774
|
text: "",
|
|
@@ -14921,28 +14949,17 @@ async function deliverCowtailReply(params) {
|
|
|
14921
14949
|
updatedAt: Date.now()
|
|
14922
14950
|
});
|
|
14923
14951
|
if (!params.streamState.messageId) {
|
|
14924
|
-
|
|
14925
|
-
type: "openclaw_message",
|
|
14926
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14927
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14928
|
-
title: params.thread.title,
|
|
14952
|
+
await createDurableCowtailReply(params, {
|
|
14929
14953
|
text: messageText,
|
|
14930
|
-
authorLabel: "OpenClaw",
|
|
14931
14954
|
links,
|
|
14932
|
-
toolCalls: params.streamState.toolCalls,
|
|
14933
|
-
actions: [],
|
|
14934
14955
|
deliveryState: "pending"
|
|
14935
14956
|
});
|
|
14936
|
-
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14937
|
-
if (!messageId2) {
|
|
14938
|
-
return;
|
|
14939
|
-
}
|
|
14940
|
-
params.streamState.messageId = messageId2;
|
|
14941
14957
|
return;
|
|
14942
14958
|
}
|
|
14943
14959
|
await params.client.sendOpenClawMessageUpdate({
|
|
14944
14960
|
type: "openclaw_message_update",
|
|
14945
14961
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14962
|
+
streamId: params.streamState.streamId,
|
|
14946
14963
|
messageId: params.streamState.messageId,
|
|
14947
14964
|
text: messageText,
|
|
14948
14965
|
links,
|
|
@@ -14967,28 +14984,17 @@ async function deliverCowtailReply(params) {
|
|
|
14967
14984
|
updatedAt: Date.now()
|
|
14968
14985
|
});
|
|
14969
14986
|
if (!params.streamState.messageId) {
|
|
14970
|
-
|
|
14971
|
-
type: "openclaw_message",
|
|
14972
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
14973
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
14974
|
-
title: params.thread.title,
|
|
14987
|
+
await createDurableCowtailReply(params, {
|
|
14975
14988
|
text: params.streamState.text,
|
|
14976
|
-
authorLabel: "OpenClaw",
|
|
14977
14989
|
links,
|
|
14978
|
-
toolCalls: params.streamState.toolCalls,
|
|
14979
|
-
actions: [],
|
|
14980
14990
|
deliveryState: "pending"
|
|
14981
14991
|
});
|
|
14982
|
-
const messageId2 = recordCreatedOpenClawMessageId(params.streamState, result2);
|
|
14983
|
-
if (!messageId2) {
|
|
14984
|
-
return;
|
|
14985
|
-
}
|
|
14986
|
-
params.streamState.messageId = messageId2;
|
|
14987
14992
|
return;
|
|
14988
14993
|
}
|
|
14989
14994
|
await params.client.sendOpenClawMessageUpdate({
|
|
14990
14995
|
type: "openclaw_message_update",
|
|
14991
14996
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
14997
|
+
streamId: params.streamState.streamId,
|
|
14992
14998
|
messageId: params.streamState.messageId,
|
|
14993
14999
|
text: params.streamState.text,
|
|
14994
15000
|
links,
|
|
@@ -15002,6 +15008,7 @@ async function deliverCowtailReply(params) {
|
|
|
15002
15008
|
await params.client.sendOpenClawMessageUpdate({
|
|
15003
15009
|
type: "openclaw_message_update",
|
|
15004
15010
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15011
|
+
streamId: params.streamState.streamId,
|
|
15005
15012
|
messageId: params.streamState.messageId,
|
|
15006
15013
|
text,
|
|
15007
15014
|
links,
|
|
@@ -15023,23 +15030,14 @@ async function deliverCowtailReply(params) {
|
|
|
15023
15030
|
return;
|
|
15024
15031
|
}
|
|
15025
15032
|
params.streamState.text = text;
|
|
15026
|
-
const
|
|
15027
|
-
type: "openclaw_message",
|
|
15028
|
-
idempotencyKey: params.streamState.idempotencyKey,
|
|
15029
|
-
sessionKey: params.thread.sessionKey ?? params.route.sessionKey,
|
|
15030
|
-
title: params.thread.title,
|
|
15033
|
+
const messageId = await createDurableCowtailReply(params, {
|
|
15031
15034
|
text,
|
|
15032
|
-
authorLabel: "OpenClaw",
|
|
15033
15035
|
links,
|
|
15034
|
-
toolCalls: params.streamState.toolCalls,
|
|
15035
|
-
actions: [],
|
|
15036
15036
|
deliveryState: "sent"
|
|
15037
15037
|
});
|
|
15038
|
-
const messageId = recordCreatedOpenClawMessageId(params.streamState, result);
|
|
15039
15038
|
if (!messageId) {
|
|
15040
15039
|
return;
|
|
15041
15040
|
}
|
|
15042
|
-
params.streamState.messageId = messageId;
|
|
15043
15041
|
emitCowtailStreamSnapshot({
|
|
15044
15042
|
client: params.client,
|
|
15045
15043
|
logger: params.logger,
|
|
@@ -15052,6 +15050,33 @@ async function deliverCowtailReply(params) {
|
|
|
15052
15050
|
});
|
|
15053
15051
|
params.streamState.completed = true;
|
|
15054
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
|
+
}
|
|
15055
15080
|
async function finalizeCowtailStreamedReply(params) {
|
|
15056
15081
|
if (params.streamState.failed || params.streamState.completed || !params.streamState.messageId || !params.streamState.text.trim() && params.streamState.toolCalls.length === 0) {
|
|
15057
15082
|
return;
|
|
@@ -15059,6 +15084,7 @@ async function finalizeCowtailStreamedReply(params) {
|
|
|
15059
15084
|
await params.client.sendOpenClawMessageUpdate({
|
|
15060
15085
|
type: "openclaw_message_update",
|
|
15061
15086
|
idempotencyKey: nextStreamUpdateIdempotencyKey(params.streamState),
|
|
15087
|
+
streamId: params.streamState.streamId,
|
|
15062
15088
|
messageId: params.streamState.messageId,
|
|
15063
15089
|
text: params.streamState.text,
|
|
15064
15090
|
links: params.streamState.links,
|
|
@@ -15140,12 +15166,13 @@ function deliverCowtailToolProgress(params) {
|
|
|
15140
15166
|
});
|
|
15141
15167
|
}
|
|
15142
15168
|
function emitCowtailStreamSnapshot(params) {
|
|
15143
|
-
if (params.streamState.failed || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15169
|
+
if (params.streamState.failed && params.allowFailed !== true || !params.text.trim() && params.streamState.links.length === 0 && params.streamState.toolCalls.length === 0) {
|
|
15144
15170
|
return;
|
|
15145
15171
|
}
|
|
15146
15172
|
params.streamState.liveText = params.text;
|
|
15147
15173
|
params.streamState.lastSnapshotText = params.text;
|
|
15148
15174
|
params.streamState.lastSnapshotSentAt = params.updatedAt;
|
|
15175
|
+
params.streamState.snapshotSequence += 1;
|
|
15149
15176
|
params.client.sendOpenClawStreamSnapshot({
|
|
15150
15177
|
type: "openclaw_message_stream_snapshot",
|
|
15151
15178
|
streamId: params.streamState.streamId,
|
|
@@ -15155,11 +15182,30 @@ function emitCowtailStreamSnapshot(params) {
|
|
|
15155
15182
|
links: params.streamState.links.map((link) => ({ ...link })),
|
|
15156
15183
|
toolCalls: structuredClone(params.streamState.toolCalls),
|
|
15157
15184
|
isFinal: params.isFinal,
|
|
15185
|
+
snapshotSequence: params.streamState.snapshotSequence,
|
|
15158
15186
|
updatedAt: params.updatedAt
|
|
15159
15187
|
}).catch((error48) => {
|
|
15160
15188
|
params.logger?.warn?.(`Cowtail stream snapshot send failed: ${errorMessage(error48)}`);
|
|
15161
15189
|
});
|
|
15162
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
|
+
}
|
|
15163
15209
|
function currentLiveCowtailStreamText(streamState) {
|
|
15164
15210
|
return streamState.liveText ?? streamState.text;
|
|
15165
15211
|
}
|
|
@@ -15436,23 +15482,29 @@ function resolveCowtailTarget(to) {
|
|
|
15436
15482
|
if (!normalizedTarget) {
|
|
15437
15483
|
throw new Error("Cowtail target must not be blank");
|
|
15438
15484
|
}
|
|
15439
|
-
return
|
|
15485
|
+
return normalizedTarget;
|
|
15440
15486
|
}
|
|
15441
15487
|
async function sendCowtailText(params) {
|
|
15442
15488
|
const { client, to } = params;
|
|
15443
15489
|
const text = ensureNonBlankText(params.text);
|
|
15444
15490
|
const target = resolveCowtailTarget(to);
|
|
15491
|
+
const sessionKey = buildCowtailTarget(target);
|
|
15445
15492
|
const result = await client.sendOpenClawMessage({
|
|
15446
15493
|
type: "openclaw_message",
|
|
15447
|
-
sessionKey
|
|
15494
|
+
sessionKey,
|
|
15495
|
+
threadHint: target,
|
|
15448
15496
|
text,
|
|
15449
15497
|
links: [],
|
|
15450
15498
|
actions: []
|
|
15451
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
|
+
}
|
|
15452
15504
|
return {
|
|
15453
15505
|
channel: "cowtail",
|
|
15454
|
-
messageId
|
|
15455
|
-
to: target
|
|
15506
|
+
messageId,
|
|
15507
|
+
to: buildCowtailTarget(target)
|
|
15456
15508
|
};
|
|
15457
15509
|
}
|
|
15458
15510
|
|