@botiverse/raft-sdk 0.9.0 → 0.11.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 +41 -5
- package/dist/cjs/index.cjs +860 -427
- package/dist/esm/index.js +859 -428
- package/dist/index.d.ts +185 -15
- package/operations.json +153 -5
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -4752,6 +4752,7 @@ const AGENT_API_ROUTE_META = {
|
|
|
4752
4752
|
attachmentUploadSessionCancel: naturalDestructive,
|
|
4753
4753
|
attachmentUploadSessionStatus: read,
|
|
4754
4754
|
attachmentDownload: read,
|
|
4755
|
+
attachmentDownloadUrl: read,
|
|
4755
4756
|
attachmentCommentsList: read,
|
|
4756
4757
|
pushWebhookStatus: {
|
|
4757
4758
|
sideEffect: "read",
|
|
@@ -5280,6 +5281,18 @@ const agentApiMessageReactionBodySchema = passthroughObject({ emoji: string().tr
|
|
|
5280
5281
|
const agentApiChannelMembershipParamsSchema = passthroughObject({ channelId: string().trim().min(1).transform(asChannelId) });
|
|
5281
5282
|
const agentApiChannelLifecycleBodySchema = passthroughObject({ target: string().trim().min(1) });
|
|
5282
5283
|
const agentApiAttachmentDownloadParamsSchema = passthroughObject({ attachmentId: string().trim().min(1) });
|
|
5284
|
+
/**
|
|
5285
|
+
* Short-lived download URL for an attachment visible to the bound agent
|
|
5286
|
+
* credential (`GET /attachments/:attachmentId/url`). For runtimes that cannot
|
|
5287
|
+
* take binary tool results: the agent fetches the bytes itself from `url`
|
|
5288
|
+
* before `expiresAt`. The URL is a bearer capability; never log it.
|
|
5289
|
+
*/
|
|
5290
|
+
const agentApiAttachmentDownloadUrlResponseSchema = passthroughObject({
|
|
5291
|
+
url: string().min(1),
|
|
5292
|
+
expiresAt: string().datetime(),
|
|
5293
|
+
filename: string(),
|
|
5294
|
+
mimeType: string()
|
|
5295
|
+
});
|
|
5283
5296
|
const agentApiAttachmentCommentsParamsSchema = passthroughObject({ attachmentId: string().trim().min(1) });
|
|
5284
5297
|
const agentApiAttachmentCommentsQuerySchema = passthroughObject({ limit: optionalStringSchema });
|
|
5285
5298
|
const agentApiAttachmentCommentAnchorSchema = passthroughObject({
|
|
@@ -7336,6 +7349,19 @@ const agentApiContract = {
|
|
|
7336
7349
|
request: { params: agentApiAttachmentDownloadParamsSchema },
|
|
7337
7350
|
response: { kind: "binary" }
|
|
7338
7351
|
}),
|
|
7352
|
+
attachmentDownloadUrl: route({
|
|
7353
|
+
key: "attachmentDownloadUrl",
|
|
7354
|
+
method: "GET",
|
|
7355
|
+
path: "/attachments/:attachmentId/url",
|
|
7356
|
+
client: {
|
|
7357
|
+
resource: "attachments",
|
|
7358
|
+
method: "downloadUrl"
|
|
7359
|
+
},
|
|
7360
|
+
capability: "read",
|
|
7361
|
+
description: "Mint a short-lived (5 minute) download URL for an attachment visible to the bound agent credential, with its filename and MIME type. 409 download_url_unavailable when this Server's storage cannot presign; use the binary download instead.",
|
|
7362
|
+
request: { params: agentApiAttachmentDownloadParamsSchema },
|
|
7363
|
+
response: { body: agentApiAttachmentDownloadUrlResponseSchema }
|
|
7364
|
+
}),
|
|
7339
7365
|
attachmentCommentsList: route({
|
|
7340
7366
|
key: "attachmentCommentsList",
|
|
7341
7367
|
method: "GET",
|
|
@@ -9731,6 +9757,31 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
9731
9757
|
"body": false
|
|
9732
9758
|
}
|
|
9733
9759
|
},
|
|
9760
|
+
{
|
|
9761
|
+
"key": "attachmentDownloadUrl",
|
|
9762
|
+
"method": "GET",
|
|
9763
|
+
"path": "/attachments/:attachmentId/url",
|
|
9764
|
+
"fullPath": "/internal/agent-api/attachments/:attachmentId/url",
|
|
9765
|
+
"client": {
|
|
9766
|
+
"resource": "attachments",
|
|
9767
|
+
"method": "downloadUrl"
|
|
9768
|
+
},
|
|
9769
|
+
"capability": "read",
|
|
9770
|
+
"description": "Mint a short-lived (5 minute) download URL for an attachment visible to the bound agent credential, with its filename and MIME type. 409 download_url_unavailable when this Server's storage cannot presign; use the binary download instead.",
|
|
9771
|
+
"sideEffect": "read",
|
|
9772
|
+
"idempotency": "natural",
|
|
9773
|
+
"destructive": false,
|
|
9774
|
+
"audience": "both",
|
|
9775
|
+
"request": {
|
|
9776
|
+
"params": true,
|
|
9777
|
+
"query": false,
|
|
9778
|
+
"body": false
|
|
9779
|
+
},
|
|
9780
|
+
"response": {
|
|
9781
|
+
"kind": "json",
|
|
9782
|
+
"body": true
|
|
9783
|
+
}
|
|
9784
|
+
},
|
|
9734
9785
|
{
|
|
9735
9786
|
"key": "attachmentCommentsList",
|
|
9736
9787
|
"method": "GET",
|
|
@@ -9858,7 +9909,7 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
9858
9909
|
}
|
|
9859
9910
|
];
|
|
9860
9911
|
/** Content hash of AGENT_API_ROUTE_MANIFEST; see computeAgentApiManifestVersion. */
|
|
9861
|
-
const AGENT_API_MANIFEST_VERSION = "
|
|
9912
|
+
const AGENT_API_MANIFEST_VERSION = "c762a744e3542f89";
|
|
9862
9913
|
//#endregion
|
|
9863
9914
|
//#region src/routes.ts
|
|
9864
9915
|
const ROUTE_INFO = Object.fromEntries(AGENT_API_ROUTE_MANIFEST.map((entry) => {
|
|
@@ -10453,6 +10504,277 @@ function fileReadError() {
|
|
|
10453
10504
|
return new RaftCredentialError("CREDENTIAL_STORE_READ_FAILED", "The Raft credential file is invalid or unreadable");
|
|
10454
10505
|
}
|
|
10455
10506
|
//#endregion
|
|
10507
|
+
//#region ../shared/src/agentOps/hint.ts
|
|
10508
|
+
/** `tasks.updateStatus` → `tasks_update_status`: the manifest's tool name for an operation name. */
|
|
10509
|
+
function raftToolNameFor(name) {
|
|
10510
|
+
return name.replace(/\./g, "_").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
10511
|
+
}
|
|
10512
|
+
/** Tool-form wording for a CLI command that has no operation (channel / server admin writes). */
|
|
10513
|
+
const RAFT_NO_TOOL_WORDING = "ask a human via an action card (`actions_prepare`)";
|
|
10514
|
+
const ELLIPSIS = "…";
|
|
10515
|
+
function q(value) {
|
|
10516
|
+
return `"${value}"`;
|
|
10517
|
+
}
|
|
10518
|
+
function hint(cli, op, fill) {
|
|
10519
|
+
if (!op) return { cli };
|
|
10520
|
+
const args = Object.fromEntries(Object.entries(op.args).filter(([, value]) => value !== void 0));
|
|
10521
|
+
return fill && fill.length > 0 ? {
|
|
10522
|
+
cli,
|
|
10523
|
+
op: {
|
|
10524
|
+
name: op.name,
|
|
10525
|
+
args,
|
|
10526
|
+
partial: true
|
|
10527
|
+
},
|
|
10528
|
+
fill
|
|
10529
|
+
} : {
|
|
10530
|
+
cli,
|
|
10531
|
+
op: {
|
|
10532
|
+
name: op.name,
|
|
10533
|
+
args
|
|
10534
|
+
}
|
|
10535
|
+
};
|
|
10536
|
+
}
|
|
10537
|
+
function toolArgs(hint) {
|
|
10538
|
+
const parts = Object.entries(hint.op?.args ?? {}).map(([key, value]) => `${key}: ${JSON.stringify(value)}`);
|
|
10539
|
+
for (const key of hint.fill ?? []) parts.push(`${key}: ${ELLIPSIS}`);
|
|
10540
|
+
return parts.length > 0 ? `{ ${parts.join(", ")} }` : "{}";
|
|
10541
|
+
}
|
|
10542
|
+
/** Render a hint: `raft message read --target "#ops"` (cli) or `messages_read({ target: "#ops" })` (tool). */
|
|
10543
|
+
function formatHint(hint, style = "cli") {
|
|
10544
|
+
if (style === "cli") return ["raft", ...hint.cli].join(" ");
|
|
10545
|
+
if (!hint.op) return RAFT_NO_TOOL_WORDING;
|
|
10546
|
+
if (hint.codeOnly) return `raft.${hint.op.name}(${toolArgs(hint)})`;
|
|
10547
|
+
return `${raftToolNameFor(hint.op.name)}(${toolArgs(hint)})`;
|
|
10548
|
+
}
|
|
10549
|
+
/** Just the command's name, for prose that lists commands: `raft channel join` (cli) or `channels_join` (tool). */
|
|
10550
|
+
function formatHintName(hint, style = "cli") {
|
|
10551
|
+
if (style === "cli") return ["raft", ...hint.cli].join(" ");
|
|
10552
|
+
if (!hint.op) return RAFT_NO_TOOL_WORDING;
|
|
10553
|
+
return hint.codeOnly ? `raft.${hint.op.name}` : raftToolNameFor(hint.op.name);
|
|
10554
|
+
}
|
|
10555
|
+
/** A flag named in prose: `--limit` (cli) or `limit` (tool, the argument name). */
|
|
10556
|
+
function formatHintFlag(flag, arg, style = "cli") {
|
|
10557
|
+
return style === "cli" ? `--${flag}` : arg;
|
|
10558
|
+
}
|
|
10559
|
+
/**
|
|
10560
|
+
* The hint as a next step: `command` is the rendered hint, `operation` the
|
|
10561
|
+
* structured call (when there is one). `args` keeps the step's own arguments.
|
|
10562
|
+
*/
|
|
10563
|
+
function hintStep(kind, hint, why, style = "cli", args) {
|
|
10564
|
+
return {
|
|
10565
|
+
kind,
|
|
10566
|
+
command: formatHint(hint, style),
|
|
10567
|
+
...args ? { args } : {},
|
|
10568
|
+
...hint.op ? { operation: hint.op } : {},
|
|
10569
|
+
why
|
|
10570
|
+
};
|
|
10571
|
+
}
|
|
10572
|
+
/**
|
|
10573
|
+
* Every hint the shared formatters and operations produce. Placeholder
|
|
10574
|
+
* arguments (`<name>`, `"…"`) are `fill` keys: the CLI form prints the
|
|
10575
|
+
* placeholder, the tool form `name: …`.
|
|
10576
|
+
*/
|
|
10577
|
+
const RAFT_HINTS = {
|
|
10578
|
+
messageRead: ({ target, after, before, around }) => hint([
|
|
10579
|
+
"message",
|
|
10580
|
+
"read",
|
|
10581
|
+
"--target",
|
|
10582
|
+
q(target),
|
|
10583
|
+
...after === void 0 ? [] : ["--after", String(after)],
|
|
10584
|
+
...before === void 0 ? [] : ["--before", String(before)],
|
|
10585
|
+
...around === void 0 ? [] : ["--around", around.shown]
|
|
10586
|
+
], {
|
|
10587
|
+
name: "messages.read",
|
|
10588
|
+
args: {
|
|
10589
|
+
target,
|
|
10590
|
+
after,
|
|
10591
|
+
before,
|
|
10592
|
+
around: around?.id
|
|
10593
|
+
}
|
|
10594
|
+
}),
|
|
10595
|
+
/** Send into a conversation; `content` is always the caller's. Without a target the target is left too. */
|
|
10596
|
+
messageSend: ({ target, attachmentId }) => hint([
|
|
10597
|
+
"message",
|
|
10598
|
+
"send",
|
|
10599
|
+
...target === void 0 ? [] : ["--target", q(target)],
|
|
10600
|
+
...attachmentId === void 0 ? [] : ["--attachment-id", attachmentId]
|
|
10601
|
+
], {
|
|
10602
|
+
name: "messages.send",
|
|
10603
|
+
args: {
|
|
10604
|
+
target,
|
|
10605
|
+
attachmentIds: attachmentId === void 0 ? void 0 : [attachmentId]
|
|
10606
|
+
}
|
|
10607
|
+
}, target === void 0 ? ["target", "content"] : ["content"]),
|
|
10608
|
+
/** The send command's name alone (prose, never a call). */
|
|
10609
|
+
messageSendName: () => hint(["message", "send"], {
|
|
10610
|
+
name: "messages.send",
|
|
10611
|
+
args: {}
|
|
10612
|
+
}, ["target", "content"]),
|
|
10613
|
+
messageCheck: () => hint(["message", "check"], {
|
|
10614
|
+
name: "inbox.check",
|
|
10615
|
+
args: {}
|
|
10616
|
+
}),
|
|
10617
|
+
inboxList: ({ view, before } = {}) => hint([
|
|
10618
|
+
"inbox",
|
|
10619
|
+
"check",
|
|
10620
|
+
...view === void 0 ? [] : ["--view", view],
|
|
10621
|
+
...before === void 0 ? [] : ["--before", String(before)]
|
|
10622
|
+
], {
|
|
10623
|
+
name: "inbox.list",
|
|
10624
|
+
args: {
|
|
10625
|
+
view,
|
|
10626
|
+
before
|
|
10627
|
+
}
|
|
10628
|
+
}),
|
|
10629
|
+
/** `query: true` is the `<name>` placeholder. */
|
|
10630
|
+
serverInfo: ({ view, offset, limit, query, joined } = {}) => hint([
|
|
10631
|
+
"server",
|
|
10632
|
+
"info",
|
|
10633
|
+
...view === void 0 ? [] : [`--${view}`],
|
|
10634
|
+
...offset === void 0 ? [] : ["--offset", String(offset)],
|
|
10635
|
+
...limit === void 0 ? [] : ["--limit", String(limit)],
|
|
10636
|
+
...query === void 0 ? [] : ["--query", query === true ? "<name>" : JSON.stringify(query)],
|
|
10637
|
+
...joined ? ["--joined"] : []
|
|
10638
|
+
], {
|
|
10639
|
+
name: "server.info",
|
|
10640
|
+
args: {
|
|
10641
|
+
view,
|
|
10642
|
+
offset,
|
|
10643
|
+
limit,
|
|
10644
|
+
query: typeof query === "string" ? query : void 0,
|
|
10645
|
+
joined: joined ? true : void 0
|
|
10646
|
+
}
|
|
10647
|
+
}, query === true ? ["query"] : void 0),
|
|
10648
|
+
/** `name` undefined is the `<name>` placeholder. */
|
|
10649
|
+
userInfo: ({ name, offset, limit } = {}) => hint([
|
|
10650
|
+
"user",
|
|
10651
|
+
"info",
|
|
10652
|
+
name === void 0 ? "<name>" : `@${name}`,
|
|
10653
|
+
...offset === void 0 ? [] : ["--offset", String(offset)],
|
|
10654
|
+
...limit === void 0 ? [] : ["--limit", String(limit)]
|
|
10655
|
+
], {
|
|
10656
|
+
name: "users.info",
|
|
10657
|
+
args: {
|
|
10658
|
+
name: name === void 0 ? void 0 : `@${name}`,
|
|
10659
|
+
offset,
|
|
10660
|
+
limit
|
|
10661
|
+
}
|
|
10662
|
+
}, name === void 0 ? ["name"] : void 0),
|
|
10663
|
+
/** The `<name>` placeholder form. */
|
|
10664
|
+
channelInfo: () => hint([
|
|
10665
|
+
"channel",
|
|
10666
|
+
"info",
|
|
10667
|
+
"<name>"
|
|
10668
|
+
], {
|
|
10669
|
+
name: "channels.info",
|
|
10670
|
+
args: {}
|
|
10671
|
+
}, ["target"]),
|
|
10672
|
+
channelMembers: (target) => hint([
|
|
10673
|
+
"channel",
|
|
10674
|
+
"members",
|
|
10675
|
+
q(target)
|
|
10676
|
+
], {
|
|
10677
|
+
name: "channels.members",
|
|
10678
|
+
args: { target }
|
|
10679
|
+
}),
|
|
10680
|
+
/** Channel attention commands by name (prose). */
|
|
10681
|
+
channelJoinName: () => hint(["channel", "join"], {
|
|
10682
|
+
name: "channels.join",
|
|
10683
|
+
args: {}
|
|
10684
|
+
}, ["target"]),
|
|
10685
|
+
channelLeaveName: () => hint(["channel", "leave"], {
|
|
10686
|
+
name: "channels.leave",
|
|
10687
|
+
args: {}
|
|
10688
|
+
}, ["target"]),
|
|
10689
|
+
channelMuteName: () => hint(["channel", "mute"], {
|
|
10690
|
+
name: "channels.mute",
|
|
10691
|
+
args: {}
|
|
10692
|
+
}, ["target"]),
|
|
10693
|
+
channelUnmuteName: () => hint(["channel", "unmute"], {
|
|
10694
|
+
name: "channels.unmute",
|
|
10695
|
+
args: {}
|
|
10696
|
+
}, ["target"]),
|
|
10697
|
+
threadUnfollowName: () => hint(["thread", "unfollow"], {
|
|
10698
|
+
name: "threads.unfollow",
|
|
10699
|
+
args: {}
|
|
10700
|
+
}, ["target"]),
|
|
10701
|
+
/** Channel / server admin writes: no operation by policy (a human acts through an action card). */
|
|
10702
|
+
channelCreateName: () => hint(["channel", "create"]),
|
|
10703
|
+
serverUpdateName: () => hint(["server", "update"]),
|
|
10704
|
+
taskClaim: ({ target, taskNumber }) => hint([
|
|
10705
|
+
"task",
|
|
10706
|
+
"claim",
|
|
10707
|
+
"--target",
|
|
10708
|
+
q(target),
|
|
10709
|
+
"--number",
|
|
10710
|
+
String(taskNumber)
|
|
10711
|
+
], {
|
|
10712
|
+
name: "tasks.claim",
|
|
10713
|
+
args: {
|
|
10714
|
+
target,
|
|
10715
|
+
taskNumbers: [taskNumber]
|
|
10716
|
+
}
|
|
10717
|
+
}),
|
|
10718
|
+
taskListAll: (target) => hint([
|
|
10719
|
+
"task",
|
|
10720
|
+
"list",
|
|
10721
|
+
"--target",
|
|
10722
|
+
q(target),
|
|
10723
|
+
"--status",
|
|
10724
|
+
"all"
|
|
10725
|
+
], {
|
|
10726
|
+
name: "tasks.list",
|
|
10727
|
+
args: {
|
|
10728
|
+
target,
|
|
10729
|
+
status: "all"
|
|
10730
|
+
}
|
|
10731
|
+
}),
|
|
10732
|
+
mentionAction: (action, resolutionId) => hint([
|
|
10733
|
+
"mention",
|
|
10734
|
+
action,
|
|
10735
|
+
resolutionId
|
|
10736
|
+
], {
|
|
10737
|
+
name: action === "notify" ? "mentions.notify" : "mentions.add",
|
|
10738
|
+
args: { resolutionIds: [resolutionId] }
|
|
10739
|
+
}),
|
|
10740
|
+
mentionPending: () => hint(["mention", "pending"], {
|
|
10741
|
+
name: "mentions.pending",
|
|
10742
|
+
args: {}
|
|
10743
|
+
}),
|
|
10744
|
+
/** `intent` and `reason` are always the caller's. */
|
|
10745
|
+
manualGet: (topic) => hint([
|
|
10746
|
+
"manual",
|
|
10747
|
+
"get",
|
|
10748
|
+
topic,
|
|
10749
|
+
"--intent",
|
|
10750
|
+
q(ELLIPSIS),
|
|
10751
|
+
"--reason",
|
|
10752
|
+
q(ELLIPSIS)
|
|
10753
|
+
], {
|
|
10754
|
+
name: "manual.get",
|
|
10755
|
+
args: { topic }
|
|
10756
|
+
}, ["intent", "reason"]),
|
|
10757
|
+
/** The download pointer on message lines; the tool form mints a URL (one attachment: its id; several: left to fill). */
|
|
10758
|
+
attachmentView: (attachmentId) => hint(["attachment", "view"], {
|
|
10759
|
+
name: "attachments.downloadUrl",
|
|
10760
|
+
args: { attachmentId }
|
|
10761
|
+
}, attachmentId === void 0 ? ["attachmentId"] : void 0),
|
|
10762
|
+
/** The binary download (typed method only): where an attachment whose URL cannot be minted is fetched. */
|
|
10763
|
+
attachmentDownload: (attachmentId) => ({
|
|
10764
|
+
...hint([
|
|
10765
|
+
"attachment",
|
|
10766
|
+
"view",
|
|
10767
|
+
attachmentId,
|
|
10768
|
+
"--output",
|
|
10769
|
+
"<path>"
|
|
10770
|
+
], {
|
|
10771
|
+
name: "attachments.download",
|
|
10772
|
+
args: { attachmentId }
|
|
10773
|
+
}),
|
|
10774
|
+
codeOnly: true
|
|
10775
|
+
})
|
|
10776
|
+
};
|
|
10777
|
+
//#endregion
|
|
10456
10778
|
//#region ../shared/src/agentOps/outcome.ts
|
|
10457
10779
|
const SERVER_ERROR_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
10458
10780
|
const DEFAULT_MESSAGES = {
|
|
@@ -10469,6 +10791,9 @@ const DEFAULT_MESSAGES = {
|
|
|
10469
10791
|
UNAVAILABLE: "The Raft Server could not serve this operation right now.",
|
|
10470
10792
|
MODEL_ONLY: "This operation only counts when the model sees its result, so it cannot be run from code; nothing was sent."
|
|
10471
10793
|
};
|
|
10794
|
+
function notFoundNextAction(style) {
|
|
10795
|
+
return `Check the target spelling with \`${formatHint(RAFT_HINTS.serverInfo({ view: "channels" }), style)}\` or resolve the message id first.`;
|
|
10796
|
+
}
|
|
10472
10797
|
const DEFAULT_NEXT_ACTION = {
|
|
10473
10798
|
INVALID_REQUEST: "Fix the request arguments; nothing was sent.",
|
|
10474
10799
|
TRANSPORT_ERROR: "Check connectivity to the Raft Server and retry if the operation is safe to repeat.",
|
|
@@ -10476,7 +10801,7 @@ const DEFAULT_NEXT_ACTION = {
|
|
|
10476
10801
|
INVALID_RESPONSE: "Upgrade the SDK or report the Server version; the response shape is not the one this SDK knows.",
|
|
10477
10802
|
CAPABILITY_NOT_AUTHORIZED: "Ask a human who can mint credentials to include the missing capability.",
|
|
10478
10803
|
SCOPE_DENIED: "Ask a human with editAgents authority to extend this agent's scopes.",
|
|
10479
|
-
NOT_FOUND: "
|
|
10804
|
+
NOT_FOUND: notFoundNextAction("cli"),
|
|
10480
10805
|
CONFLICT: "Read the current state before repeating this operation.",
|
|
10481
10806
|
IDEMPOTENCY_KEY_REUSED: "Use a new idempotency key for a different request, or resend the identical request to reconcile.",
|
|
10482
10807
|
UNSUPPORTED_FOR_EXTERNAL_AGENTS: "Use your own runtime for this; the Server does not provide it to External Agents.",
|
|
@@ -10568,6 +10893,31 @@ function failureOutcome(error) {
|
|
|
10568
10893
|
};
|
|
10569
10894
|
}
|
|
10570
10895
|
/**
|
|
10896
|
+
* Render the SDK's own default next action in a hint style. Only NOT_FOUND's
|
|
10897
|
+
* default names a command; it is set deep in the shared client-error mapping,
|
|
10898
|
+
* so `createRaft({ hints: "tool" })` re-renders it here instead of threading
|
|
10899
|
+
* the style through every failure. A Server-sent next action is left as is.
|
|
10900
|
+
*/
|
|
10901
|
+
function restyleDefaultNextAction(outcome, style) {
|
|
10902
|
+
if (style === "cli" || !outcome || typeof outcome !== "object") return outcome;
|
|
10903
|
+
const failure = outcome;
|
|
10904
|
+
if (failure.ok !== false || !failure.error || failure.error.nextAction !== DEFAULT_NEXT_ACTION.NOT_FOUND) return outcome;
|
|
10905
|
+
const error = {
|
|
10906
|
+
...failure.error,
|
|
10907
|
+
nextAction: notFoundNextAction(style)
|
|
10908
|
+
};
|
|
10909
|
+
const next = failure.next && failure.next.why === DEFAULT_NEXT_ACTION.NOT_FOUND ? {
|
|
10910
|
+
...failure.next,
|
|
10911
|
+
why: error.nextAction
|
|
10912
|
+
} : failure.next ?? null;
|
|
10913
|
+
return {
|
|
10914
|
+
...failure,
|
|
10915
|
+
error,
|
|
10916
|
+
next,
|
|
10917
|
+
text: formatOpErrorText(error)
|
|
10918
|
+
};
|
|
10919
|
+
}
|
|
10920
|
+
/**
|
|
10571
10921
|
* A failure of a keyed write (`idempotencyKey`). A retryable failure (the
|
|
10572
10922
|
* request may not have reached the Server, or the Server was unavailable)
|
|
10573
10923
|
* says to repeat the SAME request with the SAME key, and carries the key in
|
|
@@ -10990,9 +11340,10 @@ function formatAgentSenderHandle(m) {
|
|
|
10990
11340
|
const desc = m.sender_description ?? null;
|
|
10991
11341
|
return desc ? `@${name} — ${desc}` : `@${name}`;
|
|
10992
11342
|
}
|
|
10993
|
-
function formatAgentAttachmentSuffix(attachments) {
|
|
11343
|
+
function formatAgentAttachmentSuffix(attachments, style = "cli") {
|
|
10994
11344
|
if (!attachments?.length) return "";
|
|
10995
|
-
|
|
11345
|
+
const download = formatHint(RAFT_HINTS.attachmentView(style === "tool" && attachments.length === 1 ? attachments[0].id : void 0), style);
|
|
11346
|
+
return ` [${attachments.length} attachment${attachments.length > 1 ? "s" : ""}: ${attachments.map((a) => `${a.filename} (id:${a.id})`).join(", ")} — use ${download} to download]`;
|
|
10996
11347
|
}
|
|
10997
11348
|
function formatAgentTaskAssigneeSuffix(assigneeId, assigneeName) {
|
|
10998
11349
|
if (!assigneeId) return "";
|
|
@@ -11018,7 +11369,7 @@ function formatAgentTaskCurrentProjection(projection, taskNumber, neutralize) {
|
|
|
11018
11369
|
return `\n${lines.join("\n")}`;
|
|
11019
11370
|
}
|
|
11020
11371
|
/** One received-message line: header bracket + sender + content + suffixes. */
|
|
11021
|
-
function formatAgentMessageLine(m) {
|
|
11372
|
+
function formatAgentMessageLine(m, style = "cli") {
|
|
11022
11373
|
if (m.third_party_event) {
|
|
11023
11374
|
const msgId = m.message_id ? m.message_id.slice(0, 8) : m.third_party_event.id.slice(0, 8);
|
|
11024
11375
|
const time = m.timestamp ? formatUtcTimestamp(m.timestamp) : "-";
|
|
@@ -11034,22 +11385,22 @@ function formatAgentMessageLine(m) {
|
|
|
11034
11385
|
const time = m.timestamp ? formatUtcTimestamp(m.timestamp) : "-";
|
|
11035
11386
|
const senderType = ` type=${m.sender_type}`;
|
|
11036
11387
|
const content = indentAgentBodyContinuationLines(m.content ?? "");
|
|
11037
|
-
const attachSuffix = formatAgentAttachmentSuffix(m.attachments);
|
|
11388
|
+
const attachSuffix = formatAgentAttachmentSuffix(m.attachments, style);
|
|
11038
11389
|
const taskSuffix = m.task_status ? ` [task #${m.task_number} status=${m.task_status}${formatAgentTaskAssigneeSuffix(m.task_assignee_id, m.task_assignee_name)}]` : "";
|
|
11039
11390
|
return `[target=${target} msg=${msgId} time=${time}${senderType}] ${formatAgentSenderHandle(m)}: ${content}${attachSuffix}${taskSuffix}${formatAgentReplyAffordanceSuffix(m)}${formatAgentTaskCurrentProjection(m.task_current_projection)}`;
|
|
11040
11391
|
}
|
|
11041
11392
|
/** Batch of received-message lines (`raft message check` output). */
|
|
11042
|
-
function formatAgentMessages(messages) {
|
|
11393
|
+
function formatAgentMessages(messages, style = "cli") {
|
|
11043
11394
|
if (messages.length === 0) return "No new inbox messages.";
|
|
11044
|
-
return messages.map(formatAgentMessageLine).join("\n");
|
|
11395
|
+
return messages.map((m) => formatAgentMessageLine(m, style)).join("\n");
|
|
11045
11396
|
}
|
|
11046
11397
|
/**
|
|
11047
11398
|
* `message check` hands over a bounded batch, oldest first per conversation;
|
|
11048
11399
|
* the server reports how many conversations still have unread after it.
|
|
11049
11400
|
*/
|
|
11050
|
-
function formatAgentInboxHint(hint) {
|
|
11401
|
+
function formatAgentInboxHint(hint, style = "cli") {
|
|
11051
11402
|
const n = hint.unread_conversations;
|
|
11052
|
-
return `Still unread: ${n} ${n === 1 ? "conversation" : "conversations"}. Run
|
|
11403
|
+
return `Still unread: ${n} ${n === 1 ? "conversation" : "conversations"}. Run \`${formatHint(RAFT_HINTS.inboxList(), style)}\` to list them.`;
|
|
11053
11404
|
}
|
|
11054
11405
|
//#endregion
|
|
11055
11406
|
//#region ../shared/src/agentOps/message.ts
|
|
@@ -11093,7 +11444,7 @@ function hasAgentMessageIdentity(envelope) {
|
|
|
11093
11444
|
return true;
|
|
11094
11445
|
}
|
|
11095
11446
|
/** Project one envelope; `null` when it has no conversation identity (skip it rather than render `#undefined`). */
|
|
11096
|
-
function projectRaftMessage(envelope) {
|
|
11447
|
+
function projectRaftMessage(envelope, style = "cli") {
|
|
11097
11448
|
if (!hasAgentMessageIdentity(envelope)) return null;
|
|
11098
11449
|
const like = toAgentMessageLike(envelope);
|
|
11099
11450
|
const id = nullableString(like.message_id);
|
|
@@ -11126,7 +11477,7 @@ function projectRaftMessage(envelope) {
|
|
|
11126
11477
|
id: nullableString(envelope.threadId),
|
|
11127
11478
|
replyCount: nullableNumber(envelope.replyCount)
|
|
11128
11479
|
},
|
|
11129
|
-
text: formatAgentMessageLine(like),
|
|
11480
|
+
text: formatAgentMessageLine(like, style),
|
|
11130
11481
|
raw: envelope
|
|
11131
11482
|
};
|
|
11132
11483
|
}
|
|
@@ -11134,8 +11485,8 @@ function sortBySeq(messages) {
|
|
|
11134
11485
|
return [...messages].sort((a, b) => (a.seq ?? Number.MAX_SAFE_INTEGER) - (b.seq ?? Number.MAX_SAFE_INTEGER));
|
|
11135
11486
|
}
|
|
11136
11487
|
/** Project a list, skipping envelopes without a conversation identity. */
|
|
11137
|
-
function projectRaftMessages(envelopes) {
|
|
11138
|
-
return envelopes.map(projectRaftMessage).filter((m) => m !== null);
|
|
11488
|
+
function projectRaftMessages(envelopes, style = "cli") {
|
|
11489
|
+
return envelopes.map((envelope) => projectRaftMessage(envelope, style)).filter((m) => m !== null);
|
|
11139
11490
|
}
|
|
11140
11491
|
/** The conversation fields a target string names; `null` for a shape this cannot read. */
|
|
11141
11492
|
function identityFromTarget(target) {
|
|
@@ -11167,12 +11518,12 @@ function identityFromTarget(target) {
|
|
|
11167
11518
|
* because the request already named the target; fill them from `target`
|
|
11168
11519
|
* instead of dropping the message.
|
|
11169
11520
|
*/
|
|
11170
|
-
function projectRaftMessagesInTarget(envelopes, target) {
|
|
11521
|
+
function projectRaftMessagesInTarget(envelopes, target, style = "cli") {
|
|
11171
11522
|
const identity = identityFromTarget(target);
|
|
11172
11523
|
return envelopes.map((envelope) => projectRaftMessage(identity && !hasAgentMessageIdentity(envelope) ? {
|
|
11173
11524
|
...envelope,
|
|
11174
11525
|
...identity
|
|
11175
|
-
} : envelope)).filter((m) => m !== null);
|
|
11526
|
+
} : envelope, style)).filter((m) => m !== null);
|
|
11176
11527
|
}
|
|
11177
11528
|
//#endregion
|
|
11178
11529
|
//#region ../shared/src/agentOps/interrupt.ts
|
|
@@ -11184,7 +11535,7 @@ function isInterrupted(outcome) {
|
|
|
11184
11535
|
function unreadMessagesInterrupt(input) {
|
|
11185
11536
|
const { hold, target } = input;
|
|
11186
11537
|
const withheld = input.withheld === true || hold.freshnessContextMode === "withheld";
|
|
11187
|
-
const heldMessages = withheld ? [] : projectRaftMessagesInTarget(hold.heldMessages ?? [], target);
|
|
11538
|
+
const heldMessages = withheld ? [] : projectRaftMessagesInTarget(hold.heldMessages ?? [], target, input.hints);
|
|
11188
11539
|
const newMessageCount = withheld ? hold.withheldMessageCount ?? hold.newMessageCount ?? 0 : hold.newMessageCount ?? heldMessages.length;
|
|
11189
11540
|
const omittedMessageCount = withheld ? 0 : hold.omittedMessageCount ?? 0;
|
|
11190
11541
|
return {
|
|
@@ -11475,18 +11826,9 @@ const inboxPullFields = {
|
|
|
11475
11826
|
};
|
|
11476
11827
|
const checkInboxRequestSchema = requestSchema()(object(inboxPullFields));
|
|
11477
11828
|
const MAX_DRAIN_ROUNDS = 50;
|
|
11478
|
-
function batchNext(batch) {
|
|
11479
|
-
if (batch.hasMore) return {
|
|
11480
|
-
|
|
11481
|
-
command: "raft message check",
|
|
11482
|
-
...batch.cursor === null ? {} : { args: { since: batch.cursor } },
|
|
11483
|
-
why: "The Server trimmed this batch; more messages are pending."
|
|
11484
|
-
};
|
|
11485
|
-
if ((batch.stillUnreadConversations ?? 0) > 0) return {
|
|
11486
|
-
kind: "list_inbox",
|
|
11487
|
-
command: "raft inbox check",
|
|
11488
|
-
why: "Conversations remain unread beyond this batch."
|
|
11489
|
-
};
|
|
11829
|
+
function batchNext(batch, style) {
|
|
11830
|
+
if (batch.hasMore) return hintStep("check_inbox_again", RAFT_HINTS.messageCheck(), "The Server trimmed this batch; more messages are pending.", style, batch.cursor === null ? void 0 : { since: batch.cursor });
|
|
11831
|
+
if ((batch.stillUnreadConversations ?? 0) > 0) return hintStep("list_inbox", RAFT_HINTS.inboxList(), "Conversations remain unread beyond this batch.", style);
|
|
11490
11832
|
if (batch.messages.length > 0) return {
|
|
11491
11833
|
kind: "reply_or_act",
|
|
11492
11834
|
args: { target: batch.messages[0].target },
|
|
@@ -11494,11 +11836,11 @@ function batchNext(batch) {
|
|
|
11494
11836
|
};
|
|
11495
11837
|
return null;
|
|
11496
11838
|
}
|
|
11497
|
-
function batchText(batch) {
|
|
11498
|
-
const lines = [formatAgentMessages(batch.messages.map((m) => toAgentMessageLike(m.raw)))];
|
|
11499
|
-
if (batch.hasMore) lines.push(
|
|
11839
|
+
function batchText(batch, style) {
|
|
11840
|
+
const lines = [formatAgentMessages(batch.messages.map((m) => toAgentMessageLike(m.raw)), style)];
|
|
11841
|
+
if (batch.hasMore) lines.push(`More messages are pending. Run \`${formatHint(RAFT_HINTS.messageCheck(), style)}\` again.`);
|
|
11500
11842
|
else if (batch.messages.length > 0) lines.push("No more new inbox messages.");
|
|
11501
|
-
if ((batch.stillUnreadConversations ?? 0) > 0) lines.push(formatAgentInboxHint({ unread_conversations: batch.stillUnreadConversations }));
|
|
11843
|
+
if ((batch.stillUnreadConversations ?? 0) > 0) lines.push(formatAgentInboxHint({ unread_conversations: batch.stillUnreadConversations }, style));
|
|
11502
11844
|
return lines.join("\n");
|
|
11503
11845
|
}
|
|
11504
11846
|
function recordExactSeen(frontier, messages) {
|
|
@@ -11511,7 +11853,8 @@ function recordExactSeen(frontier, messages) {
|
|
|
11511
11853
|
for (const [target, seqs] of byTarget) frontier.recordExact(target, seqs);
|
|
11512
11854
|
}
|
|
11513
11855
|
/** One bounded pull. Records exact seen seqs on `frontier` (sparse drains never advance the high-water mark). */
|
|
11514
|
-
async function checkInbox(client, request = {}, frontier) {
|
|
11856
|
+
async function checkInbox(client, request = {}, frontier, options = {}) {
|
|
11857
|
+
const style = options.hints ?? "cli";
|
|
11515
11858
|
const invalid = validateOpRequest(checkInboxRequestSchema, request);
|
|
11516
11859
|
if (invalid) return invalid;
|
|
11517
11860
|
const ack = request.ack ?? "cursor";
|
|
@@ -11522,7 +11865,7 @@ async function checkInbox(client, request = {}, frontier) {
|
|
|
11522
11865
|
});
|
|
11523
11866
|
if (!result.ok) return failureFromClientResult(result);
|
|
11524
11867
|
const data = result.data;
|
|
11525
|
-
const messages = sortBySeq(projectRaftMessages(data.events));
|
|
11868
|
+
const messages = sortBySeq(projectRaftMessages(data.events, style));
|
|
11526
11869
|
recordExactSeen(frontier, messages);
|
|
11527
11870
|
const batch = {
|
|
11528
11871
|
messages,
|
|
@@ -11536,8 +11879,8 @@ async function checkInbox(client, request = {}, frontier) {
|
|
|
11536
11879
|
ok: true,
|
|
11537
11880
|
state: messages.length > 0 ? "batch" : "empty",
|
|
11538
11881
|
data: batch,
|
|
11539
|
-
next: batchNext(batch),
|
|
11540
|
-
text: batchText(batch)
|
|
11882
|
+
next: batchNext(batch, style),
|
|
11883
|
+
text: batchText(batch, style)
|
|
11541
11884
|
};
|
|
11542
11885
|
}
|
|
11543
11886
|
const drainInboxRequestSchema = requestSchema()(object(inboxPullFields));
|
|
@@ -11551,7 +11894,7 @@ const drainInboxRequestSchema = requestSchema()(object(inboxPullFields));
|
|
|
11551
11894
|
* return value summarises the drain; the batch that ends the iteration is
|
|
11552
11895
|
* acknowledged only by the caller's next pull (`summary.cursor`).
|
|
11553
11896
|
*/
|
|
11554
|
-
async function* drainInbox(client, request = {}, frontier, onPull) {
|
|
11897
|
+
async function* drainInbox(client, request = {}, frontier, onPull, options = {}) {
|
|
11555
11898
|
const ack = request.ack ?? "cursor";
|
|
11556
11899
|
const invalid = validateOpRequest(drainInboxRequestSchema, request);
|
|
11557
11900
|
if (invalid) return {
|
|
@@ -11573,7 +11916,7 @@ async function* drainInbox(client, request = {}, frontier, onPull) {
|
|
|
11573
11916
|
...sent === null ? {} : { since: sent },
|
|
11574
11917
|
limit: request.limit,
|
|
11575
11918
|
ack
|
|
11576
|
-
}, frontier);
|
|
11919
|
+
}, frontier, options);
|
|
11577
11920
|
if (!round.ok) return {
|
|
11578
11921
|
cursor,
|
|
11579
11922
|
ackMode,
|
|
@@ -11623,25 +11966,18 @@ async function* drainInbox(client, request = {}, frontier, onPull) {
|
|
|
11623
11966
|
};
|
|
11624
11967
|
}
|
|
11625
11968
|
/** Fold a finished drain into one outcome; a drain that failed before its first batch is that failure. */
|
|
11626
|
-
function drainedInboxOutcome(batches, summary) {
|
|
11969
|
+
function drainedInboxOutcome(batches, summary, options = {}) {
|
|
11627
11970
|
if (summary.error && batches.length === 0) return summary.error;
|
|
11971
|
+
const style = options.hints ?? "cli";
|
|
11628
11972
|
const messages = batches.flatMap((batch) => batch.messages);
|
|
11629
|
-
const lines = [formatAgentMessages(messages.map((m) => toAgentMessageLike(m.raw)))];
|
|
11973
|
+
const lines = [formatAgentMessages(messages.map((m) => toAgentMessageLike(m.raw)), style)];
|
|
11630
11974
|
if (summary.error) lines.push("The drain stopped early on an error; more messages may be pending. Check the inbox again.");
|
|
11631
11975
|
else if (summary.hasMore) lines.push("More messages are pending. Check the inbox again.");
|
|
11632
11976
|
else if (messages.length > 0) lines.push("No more new inbox messages.");
|
|
11633
11977
|
const stillUnread = summary.stillUnreadConversations ?? 0;
|
|
11634
|
-
if (stillUnread > 0) lines.push(formatAgentInboxHint({ unread_conversations: stillUnread }));
|
|
11978
|
+
if (stillUnread > 0) lines.push(formatAgentInboxHint({ unread_conversations: stillUnread }, style));
|
|
11635
11979
|
const first = messages[0];
|
|
11636
|
-
const next = summary.hasMore ? {
|
|
11637
|
-
kind: "check_inbox_again",
|
|
11638
|
-
command: "raft message check",
|
|
11639
|
-
why: "More messages are pending."
|
|
11640
|
-
} : stillUnread > 0 ? {
|
|
11641
|
-
kind: "list_inbox",
|
|
11642
|
-
command: "raft inbox check",
|
|
11643
|
-
why: "Conversations remain unread beyond this drain."
|
|
11644
|
-
} : first ? {
|
|
11980
|
+
const next = summary.hasMore ? hintStep("check_inbox_again", RAFT_HINTS.messageCheck(), "More messages are pending.", style) : stillUnread > 0 ? hintStep("list_inbox", RAFT_HINTS.inboxList(), "Conversations remain unread beyond this drain.", style) : first ? {
|
|
11645
11981
|
kind: "reply_or_act",
|
|
11646
11982
|
args: { target: first.target },
|
|
11647
11983
|
why: "Handle the messages above; reply where each one came from."
|
|
@@ -11663,23 +11999,21 @@ const listInboxRequestSchema = requestSchema()(object({
|
|
|
11663
11999
|
before: number$1().int().nonnegative().optional().describe("Next page: the nextBeforeSeq of the previous page."),
|
|
11664
12000
|
limit: number$1().int().positive().optional().describe("Conversations per page, 1..50 (Server default 20).")
|
|
11665
12001
|
}));
|
|
11666
|
-
function
|
|
11667
|
-
return
|
|
12002
|
+
function openHint(item) {
|
|
12003
|
+
return RAFT_HINTS.messageRead({
|
|
12004
|
+
target: item.target,
|
|
12005
|
+
after: item.lastReadSeq
|
|
12006
|
+
});
|
|
11668
12007
|
}
|
|
11669
|
-
function listingNext(listing) {
|
|
12008
|
+
function listingNext(listing, style) {
|
|
11670
12009
|
const first = listing.conversations[0];
|
|
11671
|
-
if (first) return {
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
target: first.target,
|
|
11676
|
-
after: first.lastReadSeq
|
|
11677
|
-
},
|
|
11678
|
-
why: "Open the newest unread conversation from your read position."
|
|
11679
|
-
};
|
|
12010
|
+
if (first) return hintStep("read_target", openHint(first), "Open the newest unread conversation from your read position.", style, {
|
|
12011
|
+
target: first.target,
|
|
12012
|
+
after: first.lastReadSeq
|
|
12013
|
+
});
|
|
11680
12014
|
return null;
|
|
11681
12015
|
}
|
|
11682
|
-
function listingText(listing) {
|
|
12016
|
+
function listingText(listing, style) {
|
|
11683
12017
|
const t = listing.totals;
|
|
11684
12018
|
const head = t.conversations === 0 ? "Inbox: nothing unread." : `Inbox: ${t.conversations} unread ${t.conversations === 1 ? "conversation" : "conversations"} (${t.dms} DMs, ${t.mentions} with mentions).${listing.conversations.length > 0 ? " Newest activity first." : ""}`;
|
|
11685
12019
|
const rows = listing.conversations.map((c) => {
|
|
@@ -11687,8 +12021,14 @@ function listingText(listing) {
|
|
|
11687
12021
|
return `${c.target} · ${c.unread} unread${flags ? ` · ${flags}` : ""}${c.latestSenderName ? ` · latest @${c.latestSenderName}` : ""}\n open: ${c.openCommand}`;
|
|
11688
12022
|
});
|
|
11689
12023
|
const trailer = [];
|
|
11690
|
-
if (listing.hasMore && listing.nextBeforeSeq !== null)
|
|
11691
|
-
|
|
12024
|
+
if (listing.hasMore && listing.nextBeforeSeq !== null) {
|
|
12025
|
+
const more = RAFT_HINTS.inboxList({
|
|
12026
|
+
...listing.view === "mentions" ? { view: "mentions" } : {},
|
|
12027
|
+
before: listing.nextBeforeSeq
|
|
12028
|
+
});
|
|
12029
|
+
trailer.push(`More: ${formatHint(more, style)}`);
|
|
12030
|
+
}
|
|
12031
|
+
const next = listingNext(listing, style);
|
|
11692
12032
|
trailer.push(next?.command ? `Next: open the first conversation above: ${next.command}` : "Next: nothing to do.");
|
|
11693
12033
|
return [
|
|
11694
12034
|
head,
|
|
@@ -11697,7 +12037,8 @@ function listingText(listing) {
|
|
|
11697
12037
|
].join("\n");
|
|
11698
12038
|
}
|
|
11699
12039
|
/** The agent's Activity panel. Lists only; nothing is consumed. */
|
|
11700
|
-
async function listInbox(client, request = {}) {
|
|
12040
|
+
async function listInbox(client, request = {}, options = {}) {
|
|
12041
|
+
const style = options.hints ?? "cli";
|
|
11701
12042
|
const invalid = validateOpRequest(listInboxRequestSchema, request);
|
|
11702
12043
|
if (invalid) return invalid;
|
|
11703
12044
|
const result = await client.inbox.list({
|
|
@@ -11718,7 +12059,7 @@ async function listInbox(client, request = {}) {
|
|
|
11718
12059
|
activitySeq: item.activitySeq,
|
|
11719
12060
|
latestSenderName: item.latestSenderName,
|
|
11720
12061
|
latestAt: item.latestAt,
|
|
11721
|
-
openCommand:
|
|
12062
|
+
openCommand: formatHint(openHint(item), style)
|
|
11722
12063
|
})),
|
|
11723
12064
|
totals: data.totals,
|
|
11724
12065
|
hasMore: data.hasMore,
|
|
@@ -11728,8 +12069,8 @@ async function listInbox(client, request = {}) {
|
|
|
11728
12069
|
ok: true,
|
|
11729
12070
|
state: listing.conversations.length > 0 ? "listed" : "empty",
|
|
11730
12071
|
data: listing,
|
|
11731
|
-
next: listingNext(listing),
|
|
11732
|
-
text: listingText(listing)
|
|
12072
|
+
next: listingNext(listing, style),
|
|
12073
|
+
text: listingText(listing, style)
|
|
11733
12074
|
};
|
|
11734
12075
|
}
|
|
11735
12076
|
//#endregion
|
|
@@ -11744,38 +12085,34 @@ const readHistoryRequestSchema = requestSchema()(object({
|
|
|
11744
12085
|
limit: number$1().int().positive().optional().describe("Maximum messages in the window."),
|
|
11745
12086
|
consume: boolean().optional().describe("false reads without consuming: the conversation is not marked read and nothing counts as seen.")
|
|
11746
12087
|
}));
|
|
11747
|
-
function historyNext(page) {
|
|
12088
|
+
function historyNext(page, style) {
|
|
11748
12089
|
const seqs = page.messages.map((m) => m.seq).filter((s) => s !== null);
|
|
11749
12090
|
if (page.hasNewer && seqs.length > 0) {
|
|
11750
12091
|
const max = Math.max(...seqs);
|
|
11751
|
-
return {
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
why: "Newer messages exist beyond this window."
|
|
11759
|
-
};
|
|
12092
|
+
return hintStep("read_newer", RAFT_HINTS.messageRead({
|
|
12093
|
+
target: page.target,
|
|
12094
|
+
after: max
|
|
12095
|
+
}), "Newer messages exist beyond this window.", style, {
|
|
12096
|
+
target: page.target,
|
|
12097
|
+
after: max
|
|
12098
|
+
});
|
|
11760
12099
|
}
|
|
11761
12100
|
if (page.hasOlder && seqs.length > 0) {
|
|
11762
12101
|
const min = Math.min(...seqs);
|
|
11763
|
-
return {
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
why: "Older messages exist before this window; read them only if the task needs them."
|
|
11771
|
-
};
|
|
12102
|
+
return hintStep("read_older", RAFT_HINTS.messageRead({
|
|
12103
|
+
target: page.target,
|
|
12104
|
+
before: min
|
|
12105
|
+
}), "Older messages exist before this window; read them only if the task needs them.", style, {
|
|
12106
|
+
target: page.target,
|
|
12107
|
+
before: min
|
|
12108
|
+
});
|
|
11772
12109
|
}
|
|
11773
12110
|
return null;
|
|
11774
12111
|
}
|
|
11775
|
-
function historyText(page) {
|
|
12112
|
+
function historyText(page, style) {
|
|
11776
12113
|
if (page.messages.length === 0) return `No messages in ${page.target}.`;
|
|
11777
|
-
const lines = [formatAgentMessages(page.messages.map((m) => toAgentMessageLike(m.raw)))];
|
|
11778
|
-
const next = historyNext(page);
|
|
12114
|
+
const lines = [formatAgentMessages(page.messages.map((m) => toAgentMessageLike(m.raw)), style)];
|
|
12115
|
+
const next = historyNext(page, style);
|
|
11779
12116
|
if (next?.command) lines.push(`${next.kind === "read_newer" ? "Newer" : "Older"} exist: ${next.command}`);
|
|
11780
12117
|
return lines.join("\n");
|
|
11781
12118
|
}
|
|
@@ -11795,7 +12132,8 @@ function recordHistorySeen(frontier, requested, page, around) {
|
|
|
11795
12132
|
}
|
|
11796
12133
|
frontier.recordExact(page.target, seqs);
|
|
11797
12134
|
}
|
|
11798
|
-
async function readHistory(client, request, frontier) {
|
|
12135
|
+
async function readHistory(client, request, frontier, options = {}) {
|
|
12136
|
+
const style = options.hints ?? "cli";
|
|
11799
12137
|
const invalid = validateOpRequest(readHistoryRequestSchema, request);
|
|
11800
12138
|
if (invalid) return invalid;
|
|
11801
12139
|
if (!request.target?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A target is required to read history." }));
|
|
@@ -11811,7 +12149,7 @@ async function readHistory(client, request, frontier) {
|
|
|
11811
12149
|
const data = result.data;
|
|
11812
12150
|
const page = {
|
|
11813
12151
|
target: typeof data.target === "string" && data.target ? data.target : request.target,
|
|
11814
|
-
messages: sortBySeq(projectRaftMessages(data.messages)),
|
|
12152
|
+
messages: sortBySeq(projectRaftMessages(data.messages, style)),
|
|
11815
12153
|
hasOlder: data.has_older === true,
|
|
11816
12154
|
hasNewer: data.has_newer === true,
|
|
11817
12155
|
lastReadSeq: typeof data.last_read_seq === "number" ? data.last_read_seq : null,
|
|
@@ -11822,8 +12160,8 @@ async function readHistory(client, request, frontier) {
|
|
|
11822
12160
|
ok: true,
|
|
11823
12161
|
state: page.messages.length > 0 ? "page" : "empty",
|
|
11824
12162
|
data: page,
|
|
11825
|
-
next: historyNext(page),
|
|
11826
|
-
text: historyText(page)
|
|
12163
|
+
next: historyNext(page, style),
|
|
12164
|
+
text: historyText(page, style)
|
|
11827
12165
|
};
|
|
11828
12166
|
}
|
|
11829
12167
|
/** Attempts for a keyed send whose request never reached the Server (transport failure only). */
|
|
@@ -11847,68 +12185,60 @@ const replyToRequestSchema = requestSchema()(object({
|
|
|
11847
12185
|
...sendMessageFields
|
|
11848
12186
|
}));
|
|
11849
12187
|
/** Today's held text (unchanged); it is the interrupt's `context` and the outcome's `text`. */
|
|
11850
|
-
function heldText(held, action) {
|
|
12188
|
+
function heldText(held, action, style) {
|
|
11851
12189
|
const noun = held.newMessageCount === 1 ? "message" : "messages";
|
|
11852
12190
|
const head = `Held — ${held.newMessageCount} unread ${noun} in ${held.target}. ${action}`;
|
|
11853
12191
|
if (held.withheld) return `${head}\nContext withheld (reviewer isolation).`;
|
|
11854
12192
|
const lines = [head];
|
|
11855
12193
|
if (held.formalMentionCount > 0) lines.push(`Note: ${held.formalMentionCount} of these messages formally @mention you.`);
|
|
11856
12194
|
if (held.omittedMessageCount > 0) lines.push(`${held.omittedMessageCount} earlier ${held.omittedMessageCount === 1 ? "message" : "messages"} not shown.`);
|
|
11857
|
-
if (held.heldMessages.length > 0) lines.push(formatAgentMessages(held.heldMessages.map((m) => toAgentMessageLike(m.raw))));
|
|
12195
|
+
if (held.heldMessages.length > 0) lines.push(formatAgentMessages(held.heldMessages.map((m) => toAgentMessageLike(m.raw)), style));
|
|
11858
12196
|
if (!held.contextComplete) lines.push("Not all of them are shown here; read the conversation before sending again.");
|
|
11859
|
-
lines.push(`Full text:
|
|
12197
|
+
lines.push(`Full text: ${formatHint(RAFT_HINTS.messageRead({ target: held.target }), style)}`);
|
|
11860
12198
|
return lines.join("\n");
|
|
11861
12199
|
}
|
|
11862
12200
|
/**
|
|
11863
12201
|
* A Server freshness hold as the `unread_messages` interrupt: the structured
|
|
11864
12202
|
* details, today's held text as `context`, and the given resume / cancel.
|
|
11865
12203
|
*/
|
|
11866
|
-
function heldInterrupt(target, data, action, resume, cancel) {
|
|
12204
|
+
function heldInterrupt(target, data, action, resume, cancel, style = "cli") {
|
|
11867
12205
|
const interrupt = unreadMessagesInterrupt({
|
|
11868
12206
|
target,
|
|
11869
12207
|
hold: data,
|
|
11870
12208
|
context: "",
|
|
11871
12209
|
resume,
|
|
11872
|
-
...cancel ? { cancel } : {}
|
|
12210
|
+
...cancel ? { cancel } : {},
|
|
12211
|
+
hints: style
|
|
11873
12212
|
});
|
|
11874
12213
|
return {
|
|
11875
12214
|
...interrupt,
|
|
11876
|
-
context: heldText(interrupt, action)
|
|
12215
|
+
context: heldText(interrupt, action, style)
|
|
11877
12216
|
};
|
|
11878
12217
|
}
|
|
11879
|
-
function heldSendNext(interrupt) {
|
|
11880
|
-
return {
|
|
11881
|
-
kind: "resend",
|
|
11882
|
-
command: `raft message read --target "${interrupt.target}"`,
|
|
11883
|
-
args: { target: interrupt.target },
|
|
11884
|
-
why: interrupt.withheld ? "Newer messages exist in this conversation but were withheld; read them, then resume the send (interrupt.resume, same idempotencyKey) or cancel it." : !interrupt.contextComplete ? "Newer messages arrived in this conversation and not all of them are shown here; read the conversation, then resume the send (interrupt.resume, same idempotencyKey) or cancel it." : "Newer messages arrived in this conversation. Show interrupt.context to the model, call frontier.recordHeld(interrupt) to attest that, then resume the send (interrupt.resume, same idempotencyKey) or cancel it."
|
|
11885
|
-
};
|
|
12218
|
+
function heldSendNext(interrupt, style) {
|
|
12219
|
+
return hintStep("resend", RAFT_HINTS.messageRead({ target: interrupt.target }), interrupt.withheld ? "Newer messages exist in this conversation but were withheld; read them, then resume the send (interrupt.resume, same idempotencyKey) or cancel it." : !interrupt.contextComplete ? "Newer messages arrived in this conversation and not all of them are shown here; read the conversation, then resume the send (interrupt.resume, same idempotencyKey) or cancel it." : "Newer messages arrived in this conversation. Show interrupt.context to the model, call frontier.recordHeld(interrupt) to attest that, then resume the send (interrupt.resume, same idempotencyKey) or cancel it.", style, { target: interrupt.target });
|
|
11886
12220
|
}
|
|
11887
12221
|
function isHeldResponse(data) {
|
|
11888
12222
|
return Boolean(data) && typeof data === "object" && data.state === "held";
|
|
11889
12223
|
}
|
|
11890
|
-
function sentOutcome(target, data) {
|
|
12224
|
+
function sentOutcome(target, data, style) {
|
|
11891
12225
|
const sent = {
|
|
11892
12226
|
messageId: data.messageId,
|
|
11893
12227
|
messageSeq: typeof data.messageSeq === "number" ? data.messageSeq : null,
|
|
11894
12228
|
unresolvedMentionHandles: data.unresolvedMentionHandles ?? [],
|
|
11895
|
-
recentUnread: projectRaftMessages(data.recentUnread ?? [])
|
|
12229
|
+
recentUnread: projectRaftMessages(data.recentUnread ?? [], style)
|
|
11896
12230
|
};
|
|
11897
12231
|
const warn = sent.unresolvedMentionHandles.length > 0 ? ` Unresolved @handles: ${sent.unresolvedMentionHandles.map((h) => `@${h}`).join(", ")}.` : "";
|
|
11898
12232
|
return {
|
|
11899
12233
|
ok: true,
|
|
11900
12234
|
state: "sent",
|
|
11901
12235
|
data: sent,
|
|
11902
|
-
next: sent.recentUnread.length > 0 ? {
|
|
11903
|
-
kind: "read_target",
|
|
11904
|
-
command: `raft message read --target "${target}"`,
|
|
11905
|
-
args: { target },
|
|
11906
|
-
why: "Newer messages arrived while you were sending."
|
|
11907
|
-
} : null,
|
|
12236
|
+
next: sent.recentUnread.length > 0 ? hintStep("read_target", RAFT_HINTS.messageRead({ target }), "Newer messages arrived while you were sending.", style, { target }) : null,
|
|
11908
12237
|
text: `Message sent to ${target}. Message ID: ${sent.messageId}${warn}`
|
|
11909
12238
|
};
|
|
11910
12239
|
}
|
|
11911
|
-
async function sendMessage(client, request, frontier) {
|
|
12240
|
+
async function sendMessage(client, request, frontier, options = {}) {
|
|
12241
|
+
const style = options.hints ?? "cli";
|
|
11912
12242
|
const invalid = validateOpRequest(sendMessageRequestSchema, request);
|
|
11913
12243
|
if (invalid) return invalid;
|
|
11914
12244
|
if (!request.target?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A target is required to send a message." }));
|
|
@@ -11932,16 +12262,16 @@ async function sendMessage(client, request, frontier) {
|
|
|
11932
12262
|
if (!result.ok) return failureFromClientResult(result);
|
|
11933
12263
|
const data = result.data;
|
|
11934
12264
|
if (isHeldResponse(data)) {
|
|
11935
|
-
const interrupt = heldInterrupt(request.target, data, "Your message was not sent.", inProcessSendResume(idempotencyKey));
|
|
12265
|
+
const interrupt = heldInterrupt(request.target, data, "Your message was not sent.", inProcessSendResume(idempotencyKey), void 0, style);
|
|
11936
12266
|
return {
|
|
11937
12267
|
ok: true,
|
|
11938
12268
|
state: "interrupted",
|
|
11939
12269
|
interrupt,
|
|
11940
|
-
next: heldSendNext(interrupt),
|
|
12270
|
+
next: heldSendNext(interrupt, style),
|
|
11941
12271
|
text: interrupt.context
|
|
11942
12272
|
};
|
|
11943
12273
|
}
|
|
11944
|
-
if (data.state === "sent") return sentOutcome(request.target, data);
|
|
12274
|
+
if (data.state === "sent") return sentOutcome(request.target, data, style);
|
|
11945
12275
|
return failureOutcome(opError("INVALID_RESPONSE", { message: `Unexpected send state "${data.state}".` }));
|
|
11946
12276
|
}
|
|
11947
12277
|
function taskTimestamps(t) {
|
|
@@ -12023,13 +12353,13 @@ function formatAgentMyTaskList(data, statusFilter) {
|
|
|
12023
12353
|
].join("\n");
|
|
12024
12354
|
}
|
|
12025
12355
|
/** Receipt for task create. */
|
|
12026
|
-
function formatAgentTasksCreated(channel, data) {
|
|
12356
|
+
function formatAgentTasksCreated(channel, data, style = "cli") {
|
|
12027
12357
|
const created = data.tasks.map((t) => {
|
|
12028
12358
|
const assignee = t.claimedById ? t.claimedByName ? `@${t.claimedByName}` : "<unresolved>" : "unassigned";
|
|
12029
12359
|
const resourceReceipt = t.requiresResourceReceipt ? " resource-receipt=pending" : "";
|
|
12030
12360
|
return `#${t.taskNumber} [${t.status}] assignee=${assignee} claimedAt=${t.claimedAt ?? "null"} msg=${t.messageId.slice(0, 8)}${resourceReceipt} "${t.title}"`;
|
|
12031
12361
|
}).join("\n");
|
|
12032
|
-
const threadHints = data.tasks.map((t) => `#${t.taskNumber} →
|
|
12362
|
+
const threadHints = data.tasks.map((t) => `#${t.taskNumber} → ${formatHint(RAFT_HINTS.messageSend({ target: `${channel}:${t.messageId.slice(0, 8)}` }), style)}`).join("\n");
|
|
12033
12363
|
const receipt = data.assignmentReceipt ? `\n\nAssignment receipt (msg=${data.assignmentReceipt.messageId.slice(0, 8)}):\n${data.assignmentReceipt.content}` : "";
|
|
12034
12364
|
return `Created ${data.tasks.length} task(s) in ${channel}:\n${created}${receipt}\n\nTo follow up in each task's thread:\n${threadHints}`;
|
|
12035
12365
|
}
|
|
@@ -12052,7 +12382,7 @@ function agentTaskThreadTarget(target, messageId) {
|
|
|
12052
12382
|
return `${canonicalAgentTaskTarget(target)}:${messageId.slice(0, 8)}`;
|
|
12053
12383
|
}
|
|
12054
12384
|
/** Claim results incl. concurrency-lock guidance on failed claims. */
|
|
12055
|
-
function formatAgentClaimResults(channel, data) {
|
|
12385
|
+
function formatAgentClaimResults(channel, data, style = "cli") {
|
|
12056
12386
|
const lines = data.results.map((r) => {
|
|
12057
12387
|
const label = r.taskNumber ? `#${r.taskNumber}` : `msg:${r.messageId}`;
|
|
12058
12388
|
if (r.success) return `${label} (msg:${r.messageId ? r.messageId.slice(0, 8) : ""}): claimed`;
|
|
@@ -12064,7 +12394,7 @@ function formatAgentClaimResults(channel, data) {
|
|
|
12064
12394
|
const failed = data.results.length - succeeded;
|
|
12065
12395
|
let summary = `${succeeded} claimed`;
|
|
12066
12396
|
if (failed > 0) summary += `, ${failed} failed`;
|
|
12067
|
-
const claimedMsgs = data.results.filter((r) => r.success && r.messageId).map((r) => `#${r.taskNumber} →
|
|
12397
|
+
const claimedMsgs = data.results.filter((r) => r.success && r.messageId).map((r) => `#${r.taskNumber} → ${formatHint(RAFT_HINTS.messageSend({ target: agentTaskThreadTarget(channel, r.messageId) }), style)}`).join("\n");
|
|
12068
12398
|
const threadHint = claimedMsgs ? `\n\nFollow up in each task's thread:\n${claimedMsgs}` : "";
|
|
12069
12399
|
return `Claim results (${summary}):\n${lines.join("\n")}${threadHint}`;
|
|
12070
12400
|
}
|
|
@@ -12081,13 +12411,13 @@ function formatAgentTaskDeleted(taskNumber) {
|
|
|
12081
12411
|
return `#${taskNumber} deleted.`;
|
|
12082
12412
|
}
|
|
12083
12413
|
/** Message→task conversion receipt. */
|
|
12084
|
-
function formatAgentTaskConverted(channel, task) {
|
|
12414
|
+
function formatAgentTaskConverted(channel, task, style = "cli") {
|
|
12085
12415
|
const target = `${canonicalAgentTaskTarget(channel)}:${task.messageId.slice(0, 8)}`;
|
|
12086
12416
|
return [
|
|
12087
12417
|
`Converted msg=${task.messageId.slice(0, 8)} to task #${task.taskNumber} [${task.status}] assignee=unassigned "${task.title}"`,
|
|
12088
12418
|
"",
|
|
12089
12419
|
`To follow up in the task's thread:`,
|
|
12090
|
-
|
|
12420
|
+
formatHint(RAFT_HINTS.messageSend({ target }), style)
|
|
12091
12421
|
].join("\n");
|
|
12092
12422
|
}
|
|
12093
12423
|
function formatAgentTaskAmended(data) {
|
|
@@ -12149,15 +12479,16 @@ const claimTasksRequestSchema = requestSchema()(object({
|
|
|
12149
12479
|
* A held task call: the interrupt whose resume is the identical command, with
|
|
12150
12480
|
* no cancel (a held task call saved nothing). `context` is today's held text.
|
|
12151
12481
|
*/
|
|
12152
|
-
function heldTaskInterrupt(target, data, action, after, argv) {
|
|
12482
|
+
function heldTaskInterrupt(target, data, action, after, argv, style) {
|
|
12153
12483
|
const interrupt = unreadMessagesInterrupt({
|
|
12154
12484
|
target,
|
|
12155
12485
|
hold: data,
|
|
12156
12486
|
context: "",
|
|
12157
|
-
resume: { argv }
|
|
12487
|
+
resume: { argv },
|
|
12488
|
+
hints: style
|
|
12158
12489
|
});
|
|
12159
12490
|
const noun = interrupt.newMessageCount === 1 ? "message" : "messages";
|
|
12160
|
-
const context = `Held — ${interrupt.newMessageCount} unread ${noun} in ${target}. ${action}\nRead them with:
|
|
12491
|
+
const context = `Held — ${interrupt.newMessageCount} unread ${noun} in ${target}. ${action}\nRead them with: ${formatHint(RAFT_HINTS.messageRead({ target }), style)}\n${after}`;
|
|
12161
12492
|
return {
|
|
12162
12493
|
...interrupt,
|
|
12163
12494
|
context
|
|
@@ -12169,17 +12500,14 @@ function rowState(result) {
|
|
|
12169
12500
|
if (result.conflict?.kind === "claim_conflict") return "conflict";
|
|
12170
12501
|
return "refused";
|
|
12171
12502
|
}
|
|
12172
|
-
function claimNext(claim) {
|
|
12503
|
+
function claimNext(claim, style) {
|
|
12173
12504
|
const first = claim.rows.find((row) => row.mayWork);
|
|
12174
12505
|
if (first) {
|
|
12175
12506
|
const thread = first.messageId ? agentTaskThreadTarget(claim.target, first.messageId) : null;
|
|
12176
|
-
|
|
12507
|
+
const why = "The claim is yours; post progress in the task's thread.";
|
|
12508
|
+
return thread ? hintStep("start_work", RAFT_HINTS.messageSend({ target: thread }), why, style, { target: thread }) : {
|
|
12177
12509
|
kind: "start_work",
|
|
12178
|
-
|
|
12179
|
-
command: `raft message send --target "${thread}"`,
|
|
12180
|
-
args: { thread }
|
|
12181
|
-
} : {},
|
|
12182
|
-
why: "The claim is yours; post progress in the task's thread."
|
|
12510
|
+
why
|
|
12183
12511
|
};
|
|
12184
12512
|
}
|
|
12185
12513
|
return {
|
|
@@ -12187,10 +12515,11 @@ function claimNext(claim) {
|
|
|
12187
12515
|
why: "No claim authorised work. Do not retry the identical claim and do not start conflicting execution; if you own this lane, correct the routing in the original thread."
|
|
12188
12516
|
};
|
|
12189
12517
|
}
|
|
12190
|
-
function claimText(claim) {
|
|
12191
|
-
return formatAgentClaimResults(claim.target, { results: claim.rows.map((row) => row.raw) });
|
|
12518
|
+
function claimText(claim, style) {
|
|
12519
|
+
return formatAgentClaimResults(claim.target, { results: claim.rows.map((row) => row.raw) }, style);
|
|
12192
12520
|
}
|
|
12193
|
-
async function claimTasks(client, request) {
|
|
12521
|
+
async function claimTasks(client, request, options = {}) {
|
|
12522
|
+
const style = options.hints ?? "cli";
|
|
12194
12523
|
const numbers = (request.taskNumbers ?? []).filter((n) => Number.isInteger(n) && n > 0);
|
|
12195
12524
|
const ids = (request.messageIds ?? []).map((id) => id.trim()).filter(Boolean);
|
|
12196
12525
|
const invalid = validateOpRequest(claimTasksRequestSchema, request);
|
|
@@ -12205,17 +12534,12 @@ async function claimTasks(client, request) {
|
|
|
12205
12534
|
if (!result.ok) return failureFromClientResult(result);
|
|
12206
12535
|
const data = result.data;
|
|
12207
12536
|
if (isHeldResponse(data)) {
|
|
12208
|
-
const interrupt = heldTaskInterrupt(request.target, data, "Your task claim was not applied.", "After reviewing, rerun the claim if it is still correct.", taskClaimArgv(request.target, numbers, ids));
|
|
12537
|
+
const interrupt = heldTaskInterrupt(request.target, data, "Your task claim was not applied.", "After reviewing, rerun the claim if it is still correct.", taskClaimArgv(request.target, numbers, ids), style);
|
|
12209
12538
|
return {
|
|
12210
12539
|
ok: true,
|
|
12211
12540
|
state: "interrupted",
|
|
12212
12541
|
interrupt,
|
|
12213
|
-
next: {
|
|
12214
|
-
kind: "retry_claim",
|
|
12215
|
-
command: `raft message read --target "${request.target}"`,
|
|
12216
|
-
args: { target: request.target },
|
|
12217
|
-
why: "Unread messages in this channel may change the task; read them (frontier.recordHeld(interrupt) once the model saw them), then resume the claim (interrupt.resume) if it is still right."
|
|
12218
|
-
},
|
|
12542
|
+
next: hintStep("retry_claim", RAFT_HINTS.messageRead({ target: request.target }), "Unread messages in this channel may change the task; read them (frontier.recordHeld(interrupt) once the model saw them), then resume the claim (interrupt.resume) if it is still right.", style, { target: request.target }),
|
|
12219
12543
|
text: interrupt.context
|
|
12220
12544
|
};
|
|
12221
12545
|
}
|
|
@@ -12242,8 +12566,8 @@ async function claimTasks(client, request) {
|
|
|
12242
12566
|
ok: true,
|
|
12243
12567
|
state: !claim.anyAuthorised ? "refused" : rows.every((row) => row.mayWork) ? "claimed" : "partial",
|
|
12244
12568
|
data: claim,
|
|
12245
|
-
next: claimNext(claim),
|
|
12246
|
-
text: claimText(claim)
|
|
12569
|
+
next: claimNext(claim, style),
|
|
12570
|
+
text: claimText(claim, style)
|
|
12247
12571
|
};
|
|
12248
12572
|
}
|
|
12249
12573
|
const listTasksRequestSchema = requestSchema()(object({
|
|
@@ -12258,7 +12582,7 @@ const listTasksRequestSchema = requestSchema()(object({
|
|
|
12258
12582
|
"all"
|
|
12259
12583
|
]).optional().describe("Filter by status; all includes done and closed.")
|
|
12260
12584
|
}));
|
|
12261
|
-
async function listTasks(client, request) {
|
|
12585
|
+
async function listTasks(client, request, options = {}) {
|
|
12262
12586
|
const invalid = validateOpRequest(listTasksRequestSchema, request);
|
|
12263
12587
|
if (invalid) return invalid;
|
|
12264
12588
|
const mine = request.mine === true;
|
|
@@ -12277,15 +12601,13 @@ async function listTasks(client, request) {
|
|
|
12277
12601
|
};
|
|
12278
12602
|
const text = mine ? formatAgentMyTaskList(data, request.status) : formatAgentTaskList(request.target, data, request.status);
|
|
12279
12603
|
const open = board.tasks.find((t) => t.status === "todo" && !t.claimedByName);
|
|
12280
|
-
const next = open?.taskNumber && board.target ? {
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
why: "An unassigned todo task is open; claim it before working on it."
|
|
12288
|
-
} : null;
|
|
12604
|
+
const next = open?.taskNumber && board.target ? hintStep("claim_task", RAFT_HINTS.taskClaim({
|
|
12605
|
+
target: board.target,
|
|
12606
|
+
taskNumber: open.taskNumber
|
|
12607
|
+
}), "An unassigned todo task is open; claim it before working on it.", options.hints, {
|
|
12608
|
+
target: board.target,
|
|
12609
|
+
taskNumbers: [open.taskNumber]
|
|
12610
|
+
}) : null;
|
|
12289
12611
|
return {
|
|
12290
12612
|
ok: true,
|
|
12291
12613
|
state: board.tasks.length > 0 ? "board" : "empty",
|
|
@@ -12303,7 +12625,7 @@ const createTasksRequestSchema = requestSchema()(object({
|
|
|
12303
12625
|
assignee: string().optional().describe("`@handle`: yourself to start in_progress, or (owner/admin) someone else to reserve a todo."),
|
|
12304
12626
|
idempotencyKey: string().optional().describe("One key per logical create; generated when omitted and returned. Repeat the same request with the same key within 24 hours to retry without creating the tasks twice.")
|
|
12305
12627
|
}));
|
|
12306
|
-
async function createTasks(client, request) {
|
|
12628
|
+
async function createTasks(client, request, options = {}) {
|
|
12307
12629
|
const invalid = validateOpRequest(createTasksRequestSchema, request);
|
|
12308
12630
|
if (invalid) return invalid;
|
|
12309
12631
|
if (!request.target?.trim() || !request.tasks?.length) return failureOutcome(opError("INVALID_REQUEST", { message: "A channel target and at least one task title are required." }));
|
|
@@ -12328,15 +12650,15 @@ async function createTasks(client, request) {
|
|
|
12328
12650
|
target: request.target,
|
|
12329
12651
|
idempotencyKey
|
|
12330
12652
|
},
|
|
12331
|
-
next: first ?
|
|
12332
|
-
|
|
12333
|
-
command: `raft message send --target "${agentTaskThreadTarget(request.target, first.messageId)}"`,
|
|
12334
|
-
args: { thread: agentTaskThreadTarget(request.target, first.messageId) },
|
|
12335
|
-
why: "Follow up in each task's thread."
|
|
12336
|
-
} : null,
|
|
12337
|
-
text: formatAgentTasksCreated(request.target, data)
|
|
12653
|
+
next: first ? taskThreadStep(request.target, first.messageId, "Follow up in each task's thread.", options.hints) : null,
|
|
12654
|
+
text: formatAgentTasksCreated(request.target, data, options.hints)
|
|
12338
12655
|
};
|
|
12339
12656
|
}
|
|
12657
|
+
/** Post in a task's thread (a send: `content` is the caller's). */
|
|
12658
|
+
function taskThreadStep(target, messageId, why, style = "cli") {
|
|
12659
|
+
const thread = agentTaskThreadTarget(target, messageId);
|
|
12660
|
+
return hintStep("post_in_task_thread", RAFT_HINTS.messageSend({ target: thread }), why, style, { target: thread });
|
|
12661
|
+
}
|
|
12340
12662
|
const taskRefFields = {
|
|
12341
12663
|
target: taskChannelSchema,
|
|
12342
12664
|
taskNumber: taskNumberSchema
|
|
@@ -12426,22 +12748,17 @@ const updateTaskStatusRequestSchema = requestSchema()(object({
|
|
|
12426
12748
|
status: raftTaskStatusSchema.describe("todo → in_progress → in_review → done; closed from anywhere.")
|
|
12427
12749
|
}));
|
|
12428
12750
|
/** A held task write: the interrupt whose resume is the identical command; nothing to cancel. */
|
|
12429
|
-
function heldTaskWrite(target, data, action, kind, argv) {
|
|
12430
|
-
const interrupt = heldTaskInterrupt(target, data, action, "After reviewing, repeat the operation if it is still correct.", argv);
|
|
12751
|
+
function heldTaskWrite(target, data, action, kind, argv, style) {
|
|
12752
|
+
const interrupt = heldTaskInterrupt(target, data, action, "After reviewing, repeat the operation if it is still correct.", argv, style);
|
|
12431
12753
|
return {
|
|
12432
12754
|
ok: true,
|
|
12433
12755
|
state: "interrupted",
|
|
12434
12756
|
interrupt,
|
|
12435
|
-
next: {
|
|
12436
|
-
kind,
|
|
12437
|
-
command: `raft message read --target "${target}"`,
|
|
12438
|
-
args: { target },
|
|
12439
|
-
why: "Unread messages in this channel may change the task; read them (frontier.recordHeld(interrupt) once the model saw them), then resume (interrupt.resume) if it is still right."
|
|
12440
|
-
},
|
|
12757
|
+
next: hintStep(kind, RAFT_HINTS.messageRead({ target }), "Unread messages in this channel may change the task; read them (frontier.recordHeld(interrupt) once the model saw them), then resume (interrupt.resume) if it is still right.", style, { target }),
|
|
12441
12758
|
text: interrupt.context
|
|
12442
12759
|
};
|
|
12443
12760
|
}
|
|
12444
|
-
async function updateTaskStatus(client, request) {
|
|
12761
|
+
async function updateTaskStatus(client, request, options = {}) {
|
|
12445
12762
|
const invalid = requireTaskRef(request, updateTaskStatusRequestSchema);
|
|
12446
12763
|
if (invalid) return invalid;
|
|
12447
12764
|
const result = await client.tasks.updateStatus({
|
|
@@ -12450,7 +12767,7 @@ async function updateTaskStatus(client, request) {
|
|
|
12450
12767
|
status: request.status
|
|
12451
12768
|
});
|
|
12452
12769
|
if (!result.ok) return failureFromClientResult(result);
|
|
12453
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The status change was not applied.", "retry_update_status", taskUpdateArgv(request.target, request.taskNumber, request.status));
|
|
12770
|
+
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The status change was not applied.", "retry_update_status", taskUpdateArgv(request.target, request.taskNumber, request.status), options.hints ?? "cli");
|
|
12454
12771
|
return {
|
|
12455
12772
|
ok: true,
|
|
12456
12773
|
state: "updated",
|
|
@@ -12479,7 +12796,7 @@ function taskAmendArgv(request) {
|
|
|
12479
12796
|
...request.description === void 0 ? [] : request.description === null ? ["--clear-description"] : ["--description", request.description]
|
|
12480
12797
|
];
|
|
12481
12798
|
}
|
|
12482
|
-
async function amendTask(client, request) {
|
|
12799
|
+
async function amendTask(client, request, options = {}) {
|
|
12483
12800
|
const invalid = requireTaskRef(request, amendTaskRequestSchema);
|
|
12484
12801
|
if (invalid) return invalid;
|
|
12485
12802
|
if (request.title === void 0 && request.description === void 0) return failureOutcome(opError("INVALID_REQUEST", { message: "Pass a new title, a new description, or description: null to clear it." }));
|
|
@@ -12490,7 +12807,7 @@ async function amendTask(client, request) {
|
|
|
12490
12807
|
...request.description === void 0 ? {} : { description: request.description }
|
|
12491
12808
|
});
|
|
12492
12809
|
if (!result.ok) return failureFromClientResult(result);
|
|
12493
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The amendment was not applied.", "retry_amend", taskAmendArgv(request));
|
|
12810
|
+
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The amendment was not applied.", "retry_amend", taskAmendArgv(request), options.hints ?? "cli");
|
|
12494
12811
|
return {
|
|
12495
12812
|
ok: true,
|
|
12496
12813
|
state: "amended",
|
|
@@ -12527,7 +12844,7 @@ async function taskHistory(client, request) {
|
|
|
12527
12844
|
* and picks the task; a miss says whether the Server asserted the list is
|
|
12528
12845
|
* complete, exactly as the CLI does.
|
|
12529
12846
|
*/
|
|
12530
|
-
async function showTask(client, request) {
|
|
12847
|
+
async function showTask(client, request, options = {}) {
|
|
12531
12848
|
const invalid = requireTaskRef(request);
|
|
12532
12849
|
if (invalid) return invalid;
|
|
12533
12850
|
const { target, taskNumber } = request;
|
|
@@ -12540,7 +12857,7 @@ async function showTask(client, request) {
|
|
|
12540
12857
|
const task = tasks.find((candidate) => candidate.taskNumber === taskNumber);
|
|
12541
12858
|
if (!task) return failureOutcome(opError("NOT_FOUND", {
|
|
12542
12859
|
message: result.data.pagination?.mode === "complete" && result.data.pagination.truncated === false ? `task #${taskNumber} not found in ${target} (searched ${tasks.length} task(s), status=all; server asserts this list is complete)` : tasks.length === 0 ? `task #${taskNumber} not found in ${target}: the server returned 0 tasks and did not assert the list is complete. That can mean the channel has no tasks, or that the server failed to read them (it currently reports some read errors as an empty list), and this command cannot tell which — so this is not evidence that task #${taskNumber} does not exist` : `task #${taskNumber} not found in ${target} (searched ${tasks.length} task(s), status=all; this surface does NOT assert completeness — so this is "absent from what was returned", not "does not exist")`,
|
|
12543
|
-
nextAction: `Check the number with
|
|
12860
|
+
nextAction: `Check the number with \`${formatHint(RAFT_HINTS.taskListAll(target), options.hints)}\`.`
|
|
12544
12861
|
}));
|
|
12545
12862
|
return {
|
|
12546
12863
|
ok: true,
|
|
@@ -12557,7 +12874,7 @@ const convertMessageToTaskRequestSchema = requestSchema()(object({
|
|
|
12557
12874
|
target: taskChannelSchema,
|
|
12558
12875
|
messageId: string().describe("Full or short id of a top-level message in that channel.")
|
|
12559
12876
|
}));
|
|
12560
|
-
async function convertMessageToTask(client, request) {
|
|
12877
|
+
async function convertMessageToTask(client, request, options = {}) {
|
|
12561
12878
|
const invalid = validateOpRequest(convertMessageToTaskRequestSchema, request);
|
|
12562
12879
|
if (invalid) return invalid;
|
|
12563
12880
|
if (!request.target?.trim() || !request.messageId?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A channel target and a message id are required." }));
|
|
@@ -12574,13 +12891,8 @@ async function convertMessageToTask(client, request) {
|
|
|
12574
12891
|
target: request.target,
|
|
12575
12892
|
task
|
|
12576
12893
|
},
|
|
12577
|
-
next:
|
|
12578
|
-
|
|
12579
|
-
command: `raft message send --target "${agentTaskThreadTarget(request.target, task.messageId)}"`,
|
|
12580
|
-
args: { thread: agentTaskThreadTarget(request.target, task.messageId) },
|
|
12581
|
-
why: "Follow up in the task's thread; it is unassigned until someone claims it."
|
|
12582
|
-
},
|
|
12583
|
-
text: formatAgentTaskConverted(request.target, task)
|
|
12894
|
+
next: taskThreadStep(request.target, task.messageId, "Follow up in the task's thread; it is unassigned until someone claims it.", options.hints),
|
|
12895
|
+
text: formatAgentTaskConverted(request.target, task, options.hints)
|
|
12584
12896
|
};
|
|
12585
12897
|
}
|
|
12586
12898
|
async function deleteTask(client, request) {
|
|
@@ -12810,7 +13122,7 @@ function formatCurrentAgent(data) {
|
|
|
12810
13122
|
return `${lines.join("\n")}\n\n`;
|
|
12811
13123
|
}
|
|
12812
13124
|
/** Server overview: runtime context, channels, agents, humans. */
|
|
12813
|
-
function formatAgentServerInfo(data) {
|
|
13125
|
+
function formatAgentServerInfo(data, style = "cli") {
|
|
12814
13126
|
let text = "## Server\n\n";
|
|
12815
13127
|
const channels = data.channels ?? [];
|
|
12816
13128
|
const agents = data.agents ?? [];
|
|
@@ -12818,8 +13130,14 @@ function formatAgentServerInfo(data) {
|
|
|
12818
13130
|
text += formatRuntimeContext(data.runtimeContext);
|
|
12819
13131
|
text += formatCurrentAgent(data);
|
|
12820
13132
|
text += "### Channels\n";
|
|
12821
|
-
text += "Visible public channels may appear even when `joined=false`. Private channels are shown only when you are a member; do not disclose private-channel names, membership, or content outside that channel.
|
|
12822
|
-
text += "
|
|
13133
|
+
text += "Visible public channels may appear even when `joined=false`. Private channels are shown only when you are a member; do not disclose private-channel names, membership, or content outside that channel. ";
|
|
13134
|
+
text += style === "cli" ? `Use channel attention commands (\`${formatHintName(RAFT_HINTS.channelJoinName())}\`, \`leave\`, \`mute\`, \`unmute\`; \`${formatHintName(RAFT_HINTS.threadUnfollowName())}\`) for your own delivery state. Existing channel management commands (\`${formatHintName(RAFT_HINTS.channelCreateName())}\`, \`update\`, \`archive\`, \`unarchive\`, \`add-member\`, \`remove-member\`) are authorized per channel; a channel-admin role never grants delete, visibility, federation, or server-profile actions. There is no Agent command for changing channel roles. Run any subcommand with \`--help\` for syntax.\n` : `Use the channel attention tools (${[
|
|
13135
|
+
RAFT_HINTS.channelJoinName(),
|
|
13136
|
+
RAFT_HINTS.channelLeaveName(),
|
|
13137
|
+
RAFT_HINTS.channelMuteName(),
|
|
13138
|
+
RAFT_HINTS.channelUnmuteName()
|
|
13139
|
+
].map((hint) => `\`${formatHintName(hint, style)}\``).join(", ")}; \`${formatHintName(RAFT_HINTS.threadUnfollowName(), style)}\`) for your own delivery state. Channel management (create, update, archive, unarchive, add-member, remove-member) has no tool: ${RAFT_NO_TOOL_WORDING}; a channel-admin role never grants delete, visibility, federation, or server-profile actions. There is no tool for changing channel roles.\n`;
|
|
13140
|
+
text += style === "cli" ? `Server-profile changes still use ${formatHintName(RAFT_HINTS.serverUpdateName())} and remain server-role gated.\n` : `Server-profile changes have no tool and remain server-role gated: ${RAFT_NO_TOOL_WORDING}.\n`;
|
|
12823
13141
|
text += "Mute state is shown when the server provides it; otherwise it is omitted.\n";
|
|
12824
13142
|
if (channels.length > 0) for (const t of channels) {
|
|
12825
13143
|
const statusParts = [channelVisibility(t), t.joined ? "joined" : "not joined"];
|
|
@@ -12842,7 +13160,8 @@ function formatAgentServerInfo(data) {
|
|
|
12842
13160
|
}
|
|
12843
13161
|
else text += " (none)\n";
|
|
12844
13162
|
text += "\n### Humans\n";
|
|
12845
|
-
|
|
13163
|
+
const newDm = formatHint(RAFT_HINTS.messageSend({ target: "dm:@name" }), style);
|
|
13164
|
+
text += style === "cli" ? `To start a new DM: ${newDm} <<'RAFTMSG' followed by the message body and RAFTMSG. To reply in an existing DM: reuse the target from received messages.\n` : `To start a new DM: ${newDm}. To reply in an existing DM: reuse the target from received messages.\n`;
|
|
12846
13165
|
text += "Role labels show server-level owner/admin authority; no role label means ordinary member.\n";
|
|
12847
13166
|
if (humans.length > 0) for (const u of humans) {
|
|
12848
13167
|
const role = roleLabel(u.role);
|
|
@@ -12882,7 +13201,7 @@ function formatPageFooter(page) {
|
|
|
12882
13201
|
return `${lines.join("\n")}\n`;
|
|
12883
13202
|
}
|
|
12884
13203
|
/** Single channel detail block. */
|
|
12885
|
-
function formatAgentChannelInfo(channel, memberCounts) {
|
|
13204
|
+
function formatAgentChannelInfo(channel, memberCounts, style = "cli") {
|
|
12886
13205
|
const lines = ["## Channel", ""];
|
|
12887
13206
|
lines.push(`Channel: ${agentChannelRef(channel.name, channel.type)}`);
|
|
12888
13207
|
if (channel.id) lines.push(`ID: ${channel.id}`);
|
|
@@ -12902,11 +13221,11 @@ function formatAgentChannelInfo(channel, memberCounts) {
|
|
|
12902
13221
|
lines.push(`Members: ${agents + humans} (${agents} agents, ${humans} humans)`);
|
|
12903
13222
|
}
|
|
12904
13223
|
lines.push("");
|
|
12905
|
-
lines.push(`More:
|
|
13224
|
+
lines.push(`More: ${formatHint(RAFT_HINTS.channelMembers(agentChannelRef(channel.name, channel.type)), style)}`);
|
|
12906
13225
|
return `${lines.join("\n")}\n`;
|
|
12907
13226
|
}
|
|
12908
13227
|
/** Compact server summary. */
|
|
12909
|
-
function formatAgentServerSummary(data) {
|
|
13228
|
+
function formatAgentServerSummary(data, style = "cli") {
|
|
12910
13229
|
const channels = data.channels ?? [];
|
|
12911
13230
|
const agents = data.agents ?? [];
|
|
12912
13231
|
const humans = data.humans ?? [];
|
|
@@ -12919,13 +13238,15 @@ function formatAgentServerSummary(data) {
|
|
|
12919
13238
|
`Humans: ${humans.length}`,
|
|
12920
13239
|
"",
|
|
12921
13240
|
"Narrow queries:",
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
13241
|
+
...[
|
|
13242
|
+
RAFT_HINTS.serverInfo({ view: "channels" }),
|
|
13243
|
+
RAFT_HINTS.serverInfo({ view: "agents" }),
|
|
13244
|
+
RAFT_HINTS.serverInfo({ view: "humans" }),
|
|
13245
|
+
RAFT_HINTS.channelInfo(),
|
|
13246
|
+
RAFT_HINTS.userInfo()
|
|
13247
|
+
].map((hint) => `- ${formatHint(hint, style)}`),
|
|
12927
13248
|
"",
|
|
12928
|
-
|
|
13249
|
+
`Full dump: ${formatHint(RAFT_HINTS.serverInfo({ view: "full" }), style)}`
|
|
12929
13250
|
].join("\n")}\n`;
|
|
12930
13251
|
}
|
|
12931
13252
|
/** Channel listing page. */
|
|
@@ -13206,7 +13527,7 @@ const unfollowThreadRequestSchema = requestSchema()(object({
|
|
|
13206
13527
|
reason: string().optional().describe("Short reason, kept with the unfollow.")
|
|
13207
13528
|
}));
|
|
13208
13529
|
const INVALID_CHANNEL_TARGET = "Target must be a regular channel in the form '#channel-name'. DMs and thread targets are not supported.";
|
|
13209
|
-
async function resolveRegularChannel(client, target) {
|
|
13530
|
+
async function resolveRegularChannel(client, target, options) {
|
|
13210
13531
|
const name = parseRaftRegularChannelTarget$1(target ?? "");
|
|
13211
13532
|
if (!name) return failureOutcome(opError("INVALID_REQUEST", { message: INVALID_CHANNEL_TARGET }));
|
|
13212
13533
|
const info = await client.server.info();
|
|
@@ -13214,7 +13535,7 @@ async function resolveRegularChannel(client, target) {
|
|
|
13214
13535
|
const channel = info.data.channels.find((candidate) => candidate.name === name);
|
|
13215
13536
|
if (!channel) return failureOutcome(opError("NOT_FOUND", {
|
|
13216
13537
|
message: `Channel not found: ${target}`,
|
|
13217
|
-
nextAction:
|
|
13538
|
+
nextAction: `List visible channels with \`${formatHint(RAFT_HINTS.serverInfo({ view: "channels" }), options.hints)}\`; private channels need a human to add you.`
|
|
13218
13539
|
}));
|
|
13219
13540
|
return {
|
|
13220
13541
|
id: channel.id,
|
|
@@ -13222,7 +13543,7 @@ async function resolveRegularChannel(client, target) {
|
|
|
13222
13543
|
joined: channel.joined
|
|
13223
13544
|
};
|
|
13224
13545
|
}
|
|
13225
|
-
async function joinChannel(client, request) {
|
|
13546
|
+
async function joinChannel(client, request, options = {}) {
|
|
13226
13547
|
const invalid = validateOpRequest(channelTargetRequestSchema, request);
|
|
13227
13548
|
if (invalid) return invalid;
|
|
13228
13549
|
const result = await joinRaftChannelByTarget$1(client, { target: request.target });
|
|
@@ -13248,19 +13569,14 @@ async function joinChannel(client, request) {
|
|
|
13248
13569
|
target: result.data.target,
|
|
13249
13570
|
channelId: result.data.channelId
|
|
13250
13571
|
},
|
|
13251
|
-
next: {
|
|
13252
|
-
kind: "read_target",
|
|
13253
|
-
command: `raft message read --target "${result.data.target}"`,
|
|
13254
|
-
args: { target: result.data.target },
|
|
13255
|
-
why: "Read the channel before posting."
|
|
13256
|
-
},
|
|
13572
|
+
next: hintStep("read_target", RAFT_HINTS.messageRead({ target: result.data.target }), "Read the channel before posting.", options.hints, { target: result.data.target }),
|
|
13257
13573
|
text: state === "joined" ? `Joined ${result.data.target}.` : `Already a member of ${result.data.target}.`
|
|
13258
13574
|
};
|
|
13259
13575
|
}
|
|
13260
|
-
async function leaveChannel(client, request) {
|
|
13576
|
+
async function leaveChannel(client, request, options = {}) {
|
|
13261
13577
|
const invalid = validateOpRequest(channelTargetRequestSchema, request);
|
|
13262
13578
|
if (invalid) return invalid;
|
|
13263
|
-
const channel = await resolveRegularChannel(client, request.target);
|
|
13579
|
+
const channel = await resolveRegularChannel(client, request.target, options);
|
|
13264
13580
|
if ("ok" in channel) return channel;
|
|
13265
13581
|
if (!channel.joined) return {
|
|
13266
13582
|
ok: true,
|
|
@@ -13291,10 +13607,10 @@ async function leaveChannel(client, request) {
|
|
|
13291
13607
|
function formatSeq(value) {
|
|
13292
13608
|
return value == null ? "none" : String(value);
|
|
13293
13609
|
}
|
|
13294
|
-
async function setChannelMute(client, request, action) {
|
|
13610
|
+
async function setChannelMute(client, request, action, options) {
|
|
13295
13611
|
const invalid = validateOpRequest(channelTargetRequestSchema, request);
|
|
13296
13612
|
if (invalid) return invalid;
|
|
13297
|
-
const channel = await resolveRegularChannel(client, request.target);
|
|
13613
|
+
const channel = await resolveRegularChannel(client, request.target, options);
|
|
13298
13614
|
if ("ok" in channel) return channel;
|
|
13299
13615
|
const result = action === "mute" ? await client.channels.mute({ channelId: channel.id }, {}) : await client.channels.unmute({ channelId: channel.id });
|
|
13300
13616
|
if (!result.ok) return failureFromClientResult(result);
|
|
@@ -13329,11 +13645,11 @@ async function setChannelMute(client, request, action) {
|
|
|
13329
13645
|
text: lines.join("\n")
|
|
13330
13646
|
};
|
|
13331
13647
|
}
|
|
13332
|
-
function muteChannel(client, request) {
|
|
13333
|
-
return setChannelMute(client, request, "mute");
|
|
13648
|
+
function muteChannel(client, request, options = {}) {
|
|
13649
|
+
return setChannelMute(client, request, "mute", options);
|
|
13334
13650
|
}
|
|
13335
|
-
function unmuteChannel(client, request) {
|
|
13336
|
-
return setChannelMute(client, request, "unmute");
|
|
13651
|
+
function unmuteChannel(client, request, options = {}) {
|
|
13652
|
+
return setChannelMute(client, request, "unmute", options);
|
|
13337
13653
|
}
|
|
13338
13654
|
async function channelMembers(client, request) {
|
|
13339
13655
|
const invalid = validateOpRequest(channelMembersRequestSchema, request);
|
|
@@ -13383,7 +13699,7 @@ const channelInfoRequestSchema = requestSchema()(object({ target: string().descr
|
|
|
13383
13699
|
* `raft channel info <target>`: the channel's facts from `server.info`, plus
|
|
13384
13700
|
* member counts from its roster when the Server shows it.
|
|
13385
13701
|
*/
|
|
13386
|
-
async function channelInfo(client, request) {
|
|
13702
|
+
async function channelInfo(client, request, options = {}) {
|
|
13387
13703
|
const invalid = validateOpRequest(channelInfoRequestSchema, request);
|
|
13388
13704
|
if (invalid) return invalid;
|
|
13389
13705
|
const trimmed = request.target.trim();
|
|
@@ -13395,7 +13711,10 @@ async function channelInfo(client, request) {
|
|
|
13395
13711
|
const channel = info.data.channels.find((candidate) => candidate.name === name);
|
|
13396
13712
|
if (!channel) return failureOutcome(opError("NOT_FOUND", {
|
|
13397
13713
|
message: `Channel not found or not visible: ${input}`,
|
|
13398
|
-
nextAction:
|
|
13714
|
+
nextAction: `Run \`${formatHint(RAFT_HINTS.serverInfo({
|
|
13715
|
+
view: "channels",
|
|
13716
|
+
query: true
|
|
13717
|
+
}), options.hints)}\` to inspect visible channels, or ask a channel member to add you if this is private.`
|
|
13399
13718
|
}));
|
|
13400
13719
|
const members = await client.channels.members({ channel: `#${name}` });
|
|
13401
13720
|
const memberCounts = members.ok ? {
|
|
@@ -13410,7 +13729,7 @@ async function channelInfo(client, request) {
|
|
|
13410
13729
|
memberCounts
|
|
13411
13730
|
},
|
|
13412
13731
|
next: null,
|
|
13413
|
-
text: formatAgentChannelInfo(channel, memberCounts)
|
|
13732
|
+
text: formatAgentChannelInfo(channel, memberCounts, options.hints)
|
|
13414
13733
|
};
|
|
13415
13734
|
}
|
|
13416
13735
|
//#endregion
|
|
@@ -13425,45 +13744,54 @@ const serverInfoRequestSchema = requestSchema()(object({
|
|
|
13425
13744
|
]).optional().describe("summary (default): counts; full: the whole overview; channels / agents / humans: one paged section."),
|
|
13426
13745
|
offset: number$1().optional().describe("Section paging: rows to skip."),
|
|
13427
13746
|
limit: number$1().optional().describe("Section paging: rows per page (default 50)."),
|
|
13428
|
-
joined: boolean().optional().describe("channels view only: only channels you have joined.")
|
|
13747
|
+
joined: boolean().optional().describe("channels view only: only channels you have joined."),
|
|
13748
|
+
query: string().optional().describe("channels / agents / humans view only: keep rows whose name, description, or other visible text contains this (case-insensitive).")
|
|
13429
13749
|
}));
|
|
13430
13750
|
const showProfileRequestSchema = requestSchema()(object({ target: string().optional().describe("`@handle` of someone else; omit for your own profile.") }));
|
|
13431
13751
|
/** The Agent API's profile body schema; at least one field is required (checked by the operation). */
|
|
13432
13752
|
const updateProfileRequestSchema = agentApiProfileUpdateBodySchema;
|
|
13433
|
-
|
|
13753
|
+
/** The next page of a section, or null on the last page (`--query` / `--joined` carried, in the CLI's order). */
|
|
13754
|
+
function nextPageArgs(section, request, offset, limit, total) {
|
|
13434
13755
|
const nextOffset = offset + limit;
|
|
13435
|
-
if (nextOffset >= total) return
|
|
13436
|
-
const
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13756
|
+
if (nextOffset >= total) return null;
|
|
13757
|
+
const query = request.query?.trim() || void 0;
|
|
13758
|
+
const joined = section === "channels" && request.joined === true ? true : void 0;
|
|
13759
|
+
return {
|
|
13760
|
+
view: section,
|
|
13761
|
+
offset: nextOffset,
|
|
13762
|
+
limit,
|
|
13763
|
+
...query === void 0 ? {} : { query },
|
|
13764
|
+
...joined ? { joined } : {}
|
|
13765
|
+
};
|
|
13444
13766
|
}
|
|
13445
|
-
|
|
13767
|
+
/** The CLI's `--query` match: any string field contains the needle, case-insensitively. */
|
|
13768
|
+
function includesQuery(row, query) {
|
|
13769
|
+
const needle = query?.trim().toLowerCase();
|
|
13770
|
+
if (!needle) return true;
|
|
13771
|
+
return Object.values(row).some((value) => typeof value === "string" && value.toLowerCase().includes(needle));
|
|
13772
|
+
}
|
|
13773
|
+
async function serverInfo(client, request = {}, options = {}) {
|
|
13446
13774
|
const invalid = validateOpRequest(serverInfoRequestSchema, request);
|
|
13447
13775
|
if (invalid) return invalid;
|
|
13776
|
+
const style = options.hints ?? "cli";
|
|
13448
13777
|
const result = await client.server.info();
|
|
13449
13778
|
if (!result.ok) return failureFromClientResult(result);
|
|
13450
13779
|
const server = result.data;
|
|
13451
13780
|
const view = request.view ?? "summary";
|
|
13452
|
-
if (view === "summary")
|
|
13453
|
-
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
}
|
|
13465
|
-
|
|
13466
|
-
};
|
|
13781
|
+
if (view === "summary") {
|
|
13782
|
+
const next = hintStep("list_channels", RAFT_HINTS.serverInfo({ view: "channels" }), "The summary only counts; list a section to see names.", style);
|
|
13783
|
+
return {
|
|
13784
|
+
ok: true,
|
|
13785
|
+
state: "info",
|
|
13786
|
+
data: {
|
|
13787
|
+
view,
|
|
13788
|
+
server,
|
|
13789
|
+
page: null
|
|
13790
|
+
},
|
|
13791
|
+
next,
|
|
13792
|
+
text: formatAgentServerSummary(server, style)
|
|
13793
|
+
};
|
|
13794
|
+
}
|
|
13467
13795
|
if (view === "full") return {
|
|
13468
13796
|
ok: true,
|
|
13469
13797
|
state: "info",
|
|
@@ -13473,30 +13801,23 @@ async function serverInfo(client, request = {}) {
|
|
|
13473
13801
|
page: null
|
|
13474
13802
|
},
|
|
13475
13803
|
next: null,
|
|
13476
|
-
text: formatAgentServerInfo(server)
|
|
13804
|
+
text: formatAgentServerInfo(server, style)
|
|
13477
13805
|
};
|
|
13478
13806
|
const limit = Math.max(1, Math.trunc(request.limit ?? 50));
|
|
13479
13807
|
const offset = Math.max(0, Math.trunc(request.offset ?? 0));
|
|
13480
|
-
const rows = view === "channels" ? server.channels.filter((c) => !request.joined || c.joined) : view === "agents" ? server.agents : server.humans;
|
|
13808
|
+
const rows = (view === "channels" ? server.channels.filter((c) => !request.joined || c.joined) : view === "agents" ? server.agents : server.humans).filter((row) => includesQuery(row, request.query));
|
|
13481
13809
|
const pageRows = rows.slice(offset, offset + limit);
|
|
13810
|
+
const nextArgs = nextPageArgs(view, request, offset, limit, rows.length);
|
|
13811
|
+
const nextHint = nextArgs ? RAFT_HINTS.serverInfo(nextArgs) : null;
|
|
13482
13812
|
const page = {
|
|
13483
13813
|
section: view,
|
|
13484
13814
|
total: rows.length,
|
|
13485
13815
|
offset,
|
|
13486
13816
|
limit,
|
|
13487
|
-
nextCommand:
|
|
13817
|
+
nextCommand: nextHint ? formatHint(nextHint, style) : void 0
|
|
13488
13818
|
};
|
|
13489
13819
|
const text = view === "channels" ? formatAgentServerChannels(pageRows, page) : view === "agents" ? formatAgentServerAgents(pageRows, page) : formatAgentServerHumans(pageRows, page);
|
|
13490
|
-
const next = page.
|
|
13491
|
-
kind: "next_page",
|
|
13492
|
-
command: page.nextCommand,
|
|
13493
|
-
args: {
|
|
13494
|
-
view,
|
|
13495
|
-
offset: offset + limit,
|
|
13496
|
-
limit
|
|
13497
|
-
},
|
|
13498
|
-
why: "More rows exist; one page is one page."
|
|
13499
|
-
} : null;
|
|
13820
|
+
const next = nextArgs && nextHint ? hintStep("next_page", nextHint, "More rows exist; one page is one page.", style, nextArgs) : null;
|
|
13500
13821
|
return {
|
|
13501
13822
|
ok: true,
|
|
13502
13823
|
state: "info",
|
|
@@ -13546,7 +13867,7 @@ const userInfoRequestSchema = requestSchema()(object({
|
|
|
13546
13867
|
* their memberships among one page of the visible channels, checked one
|
|
13547
13868
|
* channel roster at a time (a rejected roster is skipped and counted).
|
|
13548
13869
|
*/
|
|
13549
|
-
async function userInfo(client, request) {
|
|
13870
|
+
async function userInfo(client, request, options = {}) {
|
|
13550
13871
|
const invalid = validateOpRequest(userInfoRequestSchema, request);
|
|
13551
13872
|
if (invalid) return invalid;
|
|
13552
13873
|
const trimmed = request.name.trim();
|
|
@@ -13567,7 +13888,13 @@ async function userInfo(client, request) {
|
|
|
13567
13888
|
} : null;
|
|
13568
13889
|
if (!user) return failureOutcome(opError("NOT_FOUND", {
|
|
13569
13890
|
message: `User not found or not visible: @${name}`,
|
|
13570
|
-
nextAction:
|
|
13891
|
+
nextAction: `Run \`${formatHint(RAFT_HINTS.serverInfo({
|
|
13892
|
+
view: "agents",
|
|
13893
|
+
query: true
|
|
13894
|
+
}), options.hints)}\` or \`${formatHint(RAFT_HINTS.serverInfo({
|
|
13895
|
+
view: "humans",
|
|
13896
|
+
query: true
|
|
13897
|
+
}), options.hints)}\` to inspect visible users.`
|
|
13571
13898
|
}));
|
|
13572
13899
|
const visibleChannels = info.data.channels;
|
|
13573
13900
|
const memberships = [];
|
|
@@ -13586,22 +13913,22 @@ async function userInfo(client, request) {
|
|
|
13586
13913
|
});
|
|
13587
13914
|
}
|
|
13588
13915
|
const nextOffset = offset + limit;
|
|
13916
|
+
const nextHint = nextOffset < visibleChannels.length ? RAFT_HINTS.userInfo({
|
|
13917
|
+
name,
|
|
13918
|
+
offset: nextOffset,
|
|
13919
|
+
limit
|
|
13920
|
+
}) : null;
|
|
13589
13921
|
const page = {
|
|
13590
13922
|
total: visibleChannels.length,
|
|
13591
13923
|
offset,
|
|
13592
13924
|
limit,
|
|
13593
|
-
nextCommand:
|
|
13925
|
+
nextCommand: nextHint ? formatHint(nextHint, options.hints) : void 0
|
|
13594
13926
|
};
|
|
13595
|
-
const next = page.
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
offset: nextOffset,
|
|
13601
|
-
limit
|
|
13602
|
-
},
|
|
13603
|
-
why: "Only one page of visible channels was inspected for memberships."
|
|
13604
|
-
} : null;
|
|
13927
|
+
const next = nextHint ? hintStep("next_page", nextHint, "Only one page of visible channels was inspected for memberships.", options.hints, {
|
|
13928
|
+
name: `@${name}`,
|
|
13929
|
+
offset: nextOffset,
|
|
13930
|
+
limit
|
|
13931
|
+
}) : null;
|
|
13605
13932
|
return {
|
|
13606
13933
|
ok: true,
|
|
13607
13934
|
state: "info",
|
|
@@ -13618,8 +13945,9 @@ async function userInfo(client, request) {
|
|
|
13618
13945
|
//#endregion
|
|
13619
13946
|
//#region ../shared/src/agentText/attachments.ts
|
|
13620
13947
|
/** Upload receipt with attachment id and send-usage hint. */
|
|
13621
|
-
function formatAgentAttachmentUploaded(attachment) {
|
|
13622
|
-
|
|
13948
|
+
function formatAgentAttachmentUploaded(attachment, style = "cli") {
|
|
13949
|
+
const send = formatHint(RAFT_HINTS.messageSend({ attachmentId: attachment.id }), style);
|
|
13950
|
+
return `File uploaded: ${attachment.filename} (${(attachment.sizeBytes / 1024).toFixed(1)}KB)\nAttachment ID: ${attachment.id}\n\nUse this ID with ${send} to include it in a message.\n`;
|
|
13623
13951
|
}
|
|
13624
13952
|
function anchorSummary(anchor) {
|
|
13625
13953
|
if (anchor.type === "md-section") {
|
|
@@ -13661,6 +13989,7 @@ const attachmentCommentsRequestSchema = requestSchema()(object({
|
|
|
13661
13989
|
attachmentId: string().describe("The attachment id."),
|
|
13662
13990
|
limit: number$1().int().positive().optional().describe("Maximum comments to return.")
|
|
13663
13991
|
}));
|
|
13992
|
+
const downloadAttachmentUrlRequestSchema = requestSchema()(object({ attachmentId: string().describe("The attachment id, as message lines show it (`id:…`).") }));
|
|
13664
13993
|
/** Compatibility fallback for Servers that predate the capability endpoint (the CLI's constant). */
|
|
13665
13994
|
const AGENT_ATTACHMENT_UPLOAD_FALLBACK_MAX_BYTES = 52428800;
|
|
13666
13995
|
const FILENAME_MIME_MAP = {
|
|
@@ -13713,7 +14042,7 @@ function inferAttachmentMimeType(filename, bytes, explicit) {
|
|
|
13713
14042
|
* `POST /upload` below the Server's direct-upload threshold, an upload session
|
|
13714
14043
|
* (create → PUT to a presigned URL → complete) at or above it.
|
|
13715
14044
|
*/
|
|
13716
|
-
async function uploadAttachment(client, transport, request) {
|
|
14045
|
+
async function uploadAttachment(client, transport, request, options = {}) {
|
|
13717
14046
|
if (!request.target?.trim() || !request.filename?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A target and a filename are required to upload." }));
|
|
13718
14047
|
if (!(request.bytes instanceof Uint8Array) || request.bytes.byteLength === 0) return failureOutcome(opError("INVALID_REQUEST", { message: "Refusing to upload a 0-byte attachment." }));
|
|
13719
14048
|
if (request.mimeType !== void 0 && !MIME_TYPE_RE.test(request.mimeType.trim())) return failureOutcome(opError("INVALID_REQUEST", { message: `mimeType must look like type/subtype, got: ${request.mimeType}` }));
|
|
@@ -13725,7 +14054,7 @@ async function uploadAttachment(client, transport, request) {
|
|
|
13725
14054
|
if (!resolved.ok) return failureFromClientResult(resolved);
|
|
13726
14055
|
const channelId = resolved.data.channelId;
|
|
13727
14056
|
const mimeType = inferAttachmentMimeType(request.filename, request.bytes, request.mimeType);
|
|
13728
|
-
if (threshold !== null && request.bytes.byteLength >= threshold) return uploadThroughSession(client, transport, request, channelId, mimeType);
|
|
14057
|
+
if (threshold !== null && request.bytes.byteLength >= threshold) return uploadThroughSession(client, transport, request, channelId, mimeType, options);
|
|
13729
14058
|
const copy = new Uint8Array(request.bytes.byteLength);
|
|
13730
14059
|
copy.set(request.bytes);
|
|
13731
14060
|
const form = new FormData();
|
|
@@ -13765,9 +14094,9 @@ async function uploadAttachment(client, transport, request) {
|
|
|
13765
14094
|
}
|
|
13766
14095
|
const parsed = agentApiContract.attachmentUpload.response.body.safeParse(body);
|
|
13767
14096
|
if (!parsed.success) return failureOutcome(opError("INVALID_RESPONSE"));
|
|
13768
|
-
return uploadedOutcome(request.target, parsed.data, mimeType);
|
|
14097
|
+
return uploadedOutcome(request.target, parsed.data, mimeType, options);
|
|
13769
14098
|
}
|
|
13770
|
-
function uploadedOutcome(target, data, mimeType) {
|
|
14099
|
+
function uploadedOutcome(target, data, mimeType, options) {
|
|
13771
14100
|
return {
|
|
13772
14101
|
ok: true,
|
|
13773
14102
|
state: "uploaded",
|
|
@@ -13776,16 +14105,14 @@ function uploadedOutcome(target, data, mimeType) {
|
|
|
13776
14105
|
target,
|
|
13777
14106
|
mimeType: data.mimeType ?? mimeType
|
|
13778
14107
|
},
|
|
13779
|
-
next: {
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
},
|
|
13788
|
-
text: formatAgentAttachmentUploaded(data)
|
|
14108
|
+
next: hintStep("send_with_attachment", RAFT_HINTS.messageSend({
|
|
14109
|
+
target,
|
|
14110
|
+
attachmentId: data.id
|
|
14111
|
+
}), "The upload alone posts nothing; send a message that links the attachment id.", options.hints, {
|
|
14112
|
+
target,
|
|
14113
|
+
attachmentIds: [data.id]
|
|
14114
|
+
}),
|
|
14115
|
+
text: formatAgentAttachmentUploaded(data, options.hints)
|
|
13789
14116
|
};
|
|
13790
14117
|
}
|
|
13791
14118
|
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -13796,7 +14123,7 @@ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
13796
14123
|
* verifies against the object store. A PUT that definitely failed cancels the
|
|
13797
14124
|
* session; a PUT whose outcome is unknown leaves it for completion to verify.
|
|
13798
14125
|
*/
|
|
13799
|
-
async function uploadThroughSession(client, transport, request, channelId, mimeType) {
|
|
14126
|
+
async function uploadThroughSession(client, transport, request, channelId, mimeType, options) {
|
|
13800
14127
|
const created = await client.attachments.createUploadSession({
|
|
13801
14128
|
channelId,
|
|
13802
14129
|
filename: request.filename,
|
|
@@ -13843,7 +14170,7 @@ async function uploadThroughSession(client, transport, request, channelId, mimeT
|
|
|
13843
14170
|
const completed = await client.attachments.completeUploadSession({ uploadId });
|
|
13844
14171
|
if (completed.ok) {
|
|
13845
14172
|
const attachment = completed.data.attachment;
|
|
13846
|
-
return uploadedOutcome(request.target, attachment, mimeType);
|
|
14173
|
+
return uploadedOutcome(request.target, attachment, mimeType, options);
|
|
13847
14174
|
}
|
|
13848
14175
|
const code = completed.error.kind === "http" ? completed.error.errorCode : null;
|
|
13849
14176
|
if (!(code === "UPLOAD_OBJECT_NOT_FOUND" || code === "UPLOAD_VERIFICATION_IN_PROGRESS") || attempt === 2) return failureFromClientResult(completed);
|
|
@@ -13867,6 +14194,46 @@ async function downloadAttachment(client, request) {
|
|
|
13867
14194
|
text: `Downloaded attachment ${request.attachmentId.slice(0, 8)} (${bytes.byteLength} bytes).`
|
|
13868
14195
|
};
|
|
13869
14196
|
}
|
|
14197
|
+
/**
|
|
14198
|
+
* Mint a short-lived URL for an attachment's bytes, for runtimes whose tools
|
|
14199
|
+
* cannot return binary data: the runtime (not the model) fetches `url` before
|
|
14200
|
+
* `expiresAt`. The URL is a bearer capability; do not log it. A Server whose
|
|
14201
|
+
* storage cannot presign answers 409 `download_url_unavailable`; that failure's
|
|
14202
|
+
* `next` points at the binary download (`attachments.download`).
|
|
14203
|
+
*/
|
|
14204
|
+
async function downloadAttachmentUrl(client, request, options = {}) {
|
|
14205
|
+
const invalid = validateOpRequest(downloadAttachmentUrlRequestSchema, request);
|
|
14206
|
+
if (invalid) return invalid;
|
|
14207
|
+
const attachmentId = request.attachmentId?.trim();
|
|
14208
|
+
if (!attachmentId) return failureOutcome(opError("INVALID_REQUEST", { message: "An attachment id is required." }));
|
|
14209
|
+
const result = await client.attachments.downloadUrl({ attachmentId });
|
|
14210
|
+
if (!result.ok) {
|
|
14211
|
+
const failure = failureFromClientResult(result);
|
|
14212
|
+
if (failure.error.serverCode !== "download_url_unavailable") return failure;
|
|
14213
|
+
const download = RAFT_HINTS.attachmentDownload(attachmentId);
|
|
14214
|
+
const nextAction = `This Server's storage cannot mint download URLs; download the bytes instead: \`${formatHint(download, options.hints)}\`.`;
|
|
14215
|
+
return {
|
|
14216
|
+
...failureOutcome({
|
|
14217
|
+
...failure.error,
|
|
14218
|
+
nextAction
|
|
14219
|
+
}),
|
|
14220
|
+
next: hintStep("download_bytes", download, nextAction, options.hints, { attachmentId })
|
|
14221
|
+
};
|
|
14222
|
+
}
|
|
14223
|
+
const { url, expiresAt, filename, mimeType } = result.data;
|
|
14224
|
+
return {
|
|
14225
|
+
ok: true,
|
|
14226
|
+
state: "url",
|
|
14227
|
+
data: {
|
|
14228
|
+
url,
|
|
14229
|
+
expiresAt,
|
|
14230
|
+
filename,
|
|
14231
|
+
mimeType
|
|
14232
|
+
},
|
|
14233
|
+
next: null,
|
|
14234
|
+
text: `Download URL for ${filename} (${mimeType}), valid until ${expiresAt}:\n${url}`
|
|
14235
|
+
};
|
|
14236
|
+
}
|
|
13870
14237
|
async function attachmentComments(client, request) {
|
|
13871
14238
|
const invalid = validateOpRequest(attachmentCommentsRequestSchema, request);
|
|
13872
14239
|
if (invalid) return invalid;
|
|
@@ -14015,14 +14382,15 @@ function renderSearchPreview(content, query) {
|
|
|
14015
14382
|
].join("");
|
|
14016
14383
|
}
|
|
14017
14384
|
/** Search results with <match>/<omit /> preview markup. */
|
|
14018
|
-
function formatAgentSearchResults(query, data, offset, sort, limit) {
|
|
14385
|
+
function formatAgentSearchResults(query, data, offset, sort, limit, style = "cli") {
|
|
14019
14386
|
const trimmedQuery = query.trim();
|
|
14387
|
+
const flag = (name) => formatHintFlag(name, name, style);
|
|
14020
14388
|
const oldestShown = data.results?.length ? data.results[data.results.length - 1]?.createdAt : void 0;
|
|
14021
|
-
const nextPageHint = sort === "recent" && oldestShown ? `page with
|
|
14389
|
+
const nextPageHint = sort === "recent" && oldestShown ? `page with ${flag("before")} ${oldestShown} (pages OLDER only; NOT a complete traversal: stored times are microsecond but this key is millisecond, so rows inside the boundary millisecond can be skipped, and a full page sharing one timestamp can repeat indefinitely; copy the key verbatim)` : `page with ${flag("offset")} ${(offset ?? 0) + (data.results?.length ?? 0)}`;
|
|
14022
14390
|
const effectiveLimit = Math.min(limit ?? 20, 50);
|
|
14023
14391
|
const countEqualsLimit = (data.results?.length ?? 0) === effectiveLimit;
|
|
14024
|
-
const limitSource = limit === void 0 ? `the server default of ${effectiveLimit}` : limit > 50 ? `the server cap of ${effectiveLimit} (your
|
|
14025
|
-
const atCapRemedy = effectiveLimit < 50 ?
|
|
14392
|
+
const limitSource = limit === void 0 ? `the server default of ${effectiveLimit}` : limit > 50 ? `the server cap of ${effectiveLimit} (your ${flag("limit")} ${limit} was clamped)` : `the ${flag("limit")} ${effectiveLimit} that was requested`;
|
|
14393
|
+
const atCapRemedy = effectiveLimit < 50 ? `re-run with a higher ${flag("limit")} to tell the two apart` : `this is already the server's maximum page, so completeness CANNOT be determined from this result: a higher ${flag("limit")} is clamped back to ${effectiveLimit} and paging will not reveal it; narrow the query (add ${flag("sender")}, ${flag("target")}, ${flag("after")} or ${flag("before")}) until fewer than ${effectiveLimit} results match`;
|
|
14026
14394
|
const truncation = data.hasMore === true ? `truncated=true · more results exist, ${nextPageHint}` : data.hasMore === false ? countEqualsLimit ? `truncated=unknown · server reported hasMore=false, but this page returned exactly ${limitSource}, which is also what a capped page returns; ${atCapRemedy}` : "truncated=false" : "truncated=unknown · server did not report hasMore";
|
|
14027
14395
|
if (!data.results || data.results.length === 0) return `No search results. (${truncation})`;
|
|
14028
14396
|
const formatted = data.results.map((result) => {
|
|
@@ -14071,7 +14439,7 @@ const reactRequestSchema = requestSchema()(object({
|
|
|
14071
14439
|
messageId: string().describe("Full or short message id."),
|
|
14072
14440
|
emoji: string().describe("One reaction emoji.")
|
|
14073
14441
|
}));
|
|
14074
|
-
async function searchMessages(client, request) {
|
|
14442
|
+
async function searchMessages(client, request, options = {}) {
|
|
14075
14443
|
const invalid = validateOpRequest(searchMessagesRequestSchema, request);
|
|
14076
14444
|
if (invalid) return invalid;
|
|
14077
14445
|
if (!request.query?.trim() && !request.target && !request.sender) return failureOutcome(opError("INVALID_REQUEST", { message: "Pass a query, or filter by target or sender." }));
|
|
@@ -14093,11 +14461,16 @@ async function searchMessages(client, request) {
|
|
|
14093
14461
|
results: data.results,
|
|
14094
14462
|
hasMore
|
|
14095
14463
|
};
|
|
14464
|
+
const nextArgs = {
|
|
14465
|
+
...request,
|
|
14466
|
+
offset: (request.offset ?? 0) + data.results.length
|
|
14467
|
+
};
|
|
14096
14468
|
const next = hasMore ? {
|
|
14097
14469
|
kind: "next_search_page",
|
|
14098
|
-
args:
|
|
14099
|
-
|
|
14100
|
-
|
|
14470
|
+
args: nextArgs,
|
|
14471
|
+
operation: {
|
|
14472
|
+
name: "messages.search",
|
|
14473
|
+
args: nextArgs
|
|
14101
14474
|
},
|
|
14102
14475
|
why: "More results exist; page on, or narrow the query."
|
|
14103
14476
|
} : null;
|
|
@@ -14109,31 +14482,32 @@ async function searchMessages(client, request) {
|
|
|
14109
14482
|
text: formatAgentSearchResults(page.query, {
|
|
14110
14483
|
results: data.results,
|
|
14111
14484
|
...hasMore === null ? {} : { hasMore }
|
|
14112
|
-
}, request.offset, request.sort, request.limit)
|
|
14485
|
+
}, request.offset, request.sort, request.limit, options.hints)
|
|
14113
14486
|
};
|
|
14114
14487
|
}
|
|
14115
|
-
async function resolveMessage(client, request) {
|
|
14488
|
+
async function resolveMessage(client, request, options = {}) {
|
|
14116
14489
|
const invalid = validateOpRequest(resolveMessageRequestSchema, request);
|
|
14117
14490
|
if (invalid) return invalid;
|
|
14118
14491
|
if (!request.messageId?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A message id is required." }));
|
|
14119
14492
|
const result = await client.messages.resolve({ msgId: request.messageId });
|
|
14120
14493
|
if (!result.ok) return failureFromClientResult(result);
|
|
14121
|
-
const message = projectRaftMessage(result.data.message);
|
|
14494
|
+
const message = projectRaftMessage(result.data.message, options.hints);
|
|
14122
14495
|
if (!message) return failureOutcome(opError("INVALID_RESPONSE", { message: "The resolved message carries no conversation identity." }));
|
|
14123
14496
|
return {
|
|
14124
14497
|
ok: true,
|
|
14125
14498
|
state: "message",
|
|
14126
14499
|
data: message,
|
|
14127
|
-
next: {
|
|
14128
|
-
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
|
|
14136
|
-
|
|
14500
|
+
next: hintStep("read_target", RAFT_HINTS.messageRead({
|
|
14501
|
+
target: message.target,
|
|
14502
|
+
around: {
|
|
14503
|
+
shown: message.shortId ?? request.messageId,
|
|
14504
|
+
id: message.id ?? request.messageId
|
|
14505
|
+
}
|
|
14506
|
+
}), "Read the surrounding context before acting on one message.", options.hints, {
|
|
14507
|
+
target: message.target,
|
|
14508
|
+
around: message.id ?? request.messageId
|
|
14509
|
+
}),
|
|
14510
|
+
text: formatAgentMessages([toAgentMessageLike(message.raw)], options.hints)
|
|
14137
14511
|
};
|
|
14138
14512
|
}
|
|
14139
14513
|
async function reactToMessage(client, request, action = "add") {
|
|
@@ -14163,17 +14537,20 @@ function normalizeAgentMentionAction(action) {
|
|
|
14163
14537
|
if (action === "add" || action === "invite") return "add";
|
|
14164
14538
|
return null;
|
|
14165
14539
|
}
|
|
14166
|
-
function
|
|
14540
|
+
function actionVerbs(action) {
|
|
14167
14541
|
const verbs = action.availableActions.map(normalizeAgentMentionAction).filter((verb) => verb !== null);
|
|
14168
|
-
return Array.from(new Set(verbs))
|
|
14542
|
+
return Array.from(new Set(verbs));
|
|
14543
|
+
}
|
|
14544
|
+
function formatActionCommands(action, style) {
|
|
14545
|
+
return actionVerbs(action).map((verb) => ` ${verb}: ${formatHint(RAFT_HINTS.mentionAction(verb, action.resolutionId), style)}`);
|
|
14169
14546
|
}
|
|
14170
14547
|
function formatAuthoredMentionToken(targetHandle) {
|
|
14171
14548
|
return targetHandle.startsWith("@") ? targetHandle : `@${targetHandle}`;
|
|
14172
14549
|
}
|
|
14173
14550
|
const PENDING_MENTION_ACTION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
14174
14551
|
/** Per-token mention recovery command line; null when the id is not a UUID (fail closed). */
|
|
14175
|
-
function formatAgentMentionNotifyRecoveryCommand(resolutionId) {
|
|
14176
|
-
return PENDING_MENTION_ACTION_ID_RE.test(resolutionId) ?
|
|
14552
|
+
function formatAgentMentionNotifyRecoveryCommand(resolutionId, style = "cli") {
|
|
14553
|
+
return PENDING_MENTION_ACTION_ID_RE.test(resolutionId) ? formatHint(RAFT_HINTS.mentionAction("notify", resolutionId), style) : null;
|
|
14177
14554
|
}
|
|
14178
14555
|
function toAgentSenderPendingMentionAction(action) {
|
|
14179
14556
|
return {
|
|
@@ -14230,22 +14607,24 @@ function normalizeAgentMentionActionResults(data) {
|
|
|
14230
14607
|
})).filter((item) => item.resolutionId.length > 0);
|
|
14231
14608
|
}
|
|
14232
14609
|
const PENDING_DEFAULT_LIMIT = 50;
|
|
14233
|
-
function pendingPageVerdict(hasMore, limit, shown) {
|
|
14234
|
-
const
|
|
14235
|
-
|
|
14610
|
+
function pendingPageVerdict(hasMore, limit, shown, style) {
|
|
14611
|
+
const limitFlag = formatHintFlag("limit", "limit", style);
|
|
14612
|
+
const asked = limit === void 0 ? "server default 50" : `${limitFlag} ${limit}`;
|
|
14613
|
+
if (hasMore === true) return (limit ?? PENDING_DEFAULT_LIMIT) >= 100 ? `shown ${shown}, ${asked} — truncated=true · more pending actions exist AND this is the server's maximum page (100); this route has no offset or cursor, so the rest cannot be reached from here — resolve what you can and re-run; rows with no available actions are not actionable here and will remain until they expire` : `shown ${shown}, ${asked} — truncated=true · more pending actions exist; raise ${limitFlag} (server caps at 100) or resolve these first and re-run`;
|
|
14236
14614
|
if (hasMore === false) return `shown ${shown}, ${asked} — truncated=false · this is the complete list`;
|
|
14237
14615
|
return `shown ${shown}, ${asked} — truncated=unknown · server did not report has_more, so completeness is NOT asserted`;
|
|
14238
14616
|
}
|
|
14239
14617
|
/** Undelivered-mentions partial result (send) or the pending list. */
|
|
14240
14618
|
function formatAgentPendingMentionActions(actions, opts = {}) {
|
|
14619
|
+
const style = opts.hints ?? "cli";
|
|
14241
14620
|
const unresolvedMentionHandles = opts.source === "send" ? Array.from(new Set(opts.unresolvedMentionHandles ?? [])) : [];
|
|
14242
|
-
const pageNote = opts.source === "pending" ? pendingPageVerdict(opts.hasMore, opts.limit, actions.length) : "";
|
|
14621
|
+
const pageNote = opts.source === "pending" ? pendingPageVerdict(opts.hasMore, opts.limit, actions.length, style) : "";
|
|
14243
14622
|
if (actions.length === 0 && unresolvedMentionHandles.length === 0) return opts.source === "pending" ? `Pending mention actions\n\nNo pending mention actions. (${pageNote})\n` : "";
|
|
14244
14623
|
if (opts.source === "send") {
|
|
14245
14624
|
const lines = [
|
|
14246
14625
|
"Undelivered mentions — partial result",
|
|
14247
14626
|
"Message effect: status=queued. Queue acceptance is the only message proof.",
|
|
14248
|
-
|
|
14627
|
+
`Do not rerun \`${formatHintName(RAFT_HINTS.messageSendName(), style)}\`; the message is already queued and a retry could duplicate it.`,
|
|
14249
14628
|
"Each row below is bound to the literal @token from your message.",
|
|
14250
14629
|
"For a literal name rather than a recipient, wrap the @handle in inline or fenced code.",
|
|
14251
14630
|
""
|
|
@@ -14259,10 +14638,10 @@ function formatAgentPendingMentionActions(actions, opts = {}) {
|
|
|
14259
14638
|
if (action.messageId) lines.push(` message: ${action.messageId}`);
|
|
14260
14639
|
lines.push(` expires: ${action.expiresAt ?? "unknown"}`);
|
|
14261
14640
|
if (action.recoveryCommand) {
|
|
14262
|
-
lines.push(` recovery: ${action.recoveryCommand}`);
|
|
14641
|
+
lines.push(` recovery: ${style === "cli" ? action.recoveryCommand : formatAgentMentionNotifyRecoveryCommand(action.resolutionId, style)}`);
|
|
14263
14642
|
lines.push(" note: the handle resolved, but the target was not in this conversation at send time. This does not prove the person left the server.");
|
|
14264
14643
|
lines.push(" note: notify exits nonzero unless the target queue accepts the delivery.");
|
|
14265
|
-
} else lines.push(
|
|
14644
|
+
} else lines.push(` recovery: unavailable because the pending action id is invalid; inspect \`${formatHint(RAFT_HINTS.mentionPending(), style)}\` without resending the message.`);
|
|
14266
14645
|
}
|
|
14267
14646
|
for (const rawHandle of unresolvedMentionHandles) {
|
|
14268
14647
|
const warning = toAgentSenderUnresolvedMentionWarning(rawHandle);
|
|
@@ -14286,11 +14665,11 @@ function formatAgentPendingMentionActions(actions, opts = {}) {
|
|
|
14286
14665
|
if (action.messageId) lines.push(` message: ${action.messageId}`);
|
|
14287
14666
|
lines.push(` reason: ${formatPendingReason(action.reason)}`);
|
|
14288
14667
|
if (action.expiresAt) lines.push(` expires: ${action.expiresAt}`);
|
|
14289
|
-
const commands = formatActionCommands(action);
|
|
14668
|
+
const commands = formatActionCommands(action, style);
|
|
14290
14669
|
if (commands.length > 0) {
|
|
14291
14670
|
lines.push(" recovery commands:");
|
|
14292
14671
|
lines.push(...commands);
|
|
14293
|
-
if (
|
|
14672
|
+
if (actionVerbs(action).includes("notify")) lines.push(" note: notify exits nonzero unless the target queue accepts the delivery.");
|
|
14294
14673
|
}
|
|
14295
14674
|
}
|
|
14296
14675
|
return `${lines.join("\n")}\n`;
|
|
@@ -14341,12 +14720,14 @@ function formatAgentSenderMentionDeliveries(messageId, deliveries) {
|
|
|
14341
14720
|
//#endregion
|
|
14342
14721
|
//#region ../shared/src/agentOps/mentions.ts
|
|
14343
14722
|
const pendingMentionActionsRequestSchema = requestSchema()(object({ limit: number$1().int().positive().optional().describe("Maximum pending mentions to list.") }));
|
|
14723
|
+
const mentionResolutionIdsRequestSchema = requestSchema()(object({ resolutionIds: array(string()).describe("resolutionId values from mentions.pending.") }));
|
|
14724
|
+
/** @deprecated The request of the deprecated `mentions.execute`; use `mentionResolutionIdsRequestSchema` (`mentions.notify` / `mentions.add`). */
|
|
14344
14725
|
const executeMentionActionRequestSchema = requestSchema()(object({
|
|
14345
14726
|
action: _enum(["notify", "add"]).describe("notify: tell the mentioned target about the message; add: add them to the conversation."),
|
|
14346
14727
|
resolutionIds: array(string()).describe("resolutionId values from mentions.pending.")
|
|
14347
14728
|
}));
|
|
14348
14729
|
const senderMentionDeliveriesRequestSchema = requestSchema()(object({ messageId: string().describe("Id of a message you sent.") }));
|
|
14349
|
-
async function pendingMentionActions(client, request = {}) {
|
|
14730
|
+
async function pendingMentionActions(client, request = {}, options = {}) {
|
|
14350
14731
|
const invalid = validateOpRequest(pendingMentionActionsRequestSchema, request);
|
|
14351
14732
|
if (invalid) return invalid;
|
|
14352
14733
|
const result = await client.mentions.pendingActions(request.limit === void 0 ? {} : { limit: String(request.limit) });
|
|
@@ -14354,15 +14735,10 @@ async function pendingMentionActions(client, request = {}) {
|
|
|
14354
14735
|
const actions = normalizeAgentPendingMentionActions(result.data);
|
|
14355
14736
|
const hasMore = typeof result.data.has_more === "boolean" ? result.data.has_more : null;
|
|
14356
14737
|
const first = actions.find((a) => a.availableActions.length > 0);
|
|
14357
|
-
const next = first ? {
|
|
14358
|
-
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
action: "notify",
|
|
14362
|
-
resolutionIds: [first.resolutionId]
|
|
14363
|
-
},
|
|
14364
|
-
why: "This @mention reached nobody at send time; notify the target (or add them) so the message is seen."
|
|
14365
|
-
} : null;
|
|
14738
|
+
const next = first ? hintStep("resolve_mention", RAFT_HINTS.mentionAction("notify", first.resolutionId), "This @mention reached nobody at send time; notify the target (or add them) so the message is seen.", options.hints, {
|
|
14739
|
+
action: "notify",
|
|
14740
|
+
resolutionIds: [first.resolutionId]
|
|
14741
|
+
}) : null;
|
|
14366
14742
|
return {
|
|
14367
14743
|
ok: true,
|
|
14368
14744
|
state: actions.length > 0 ? "pending" : "empty",
|
|
@@ -14375,17 +14751,36 @@ async function pendingMentionActions(client, request = {}) {
|
|
|
14375
14751
|
text: formatAgentPendingMentionActions(actions, {
|
|
14376
14752
|
source: "pending",
|
|
14377
14753
|
...hasMore === null ? {} : { hasMore },
|
|
14378
|
-
limit: request.limit
|
|
14754
|
+
limit: request.limit,
|
|
14755
|
+
hints: options.hints
|
|
14379
14756
|
})
|
|
14380
14757
|
};
|
|
14381
14758
|
}
|
|
14759
|
+
/** Tell the targets of unreached @mentions about the message (`raft mention notify`). */
|
|
14760
|
+
async function notifyMentions(client, request) {
|
|
14761
|
+
const invalid = validateOpRequest(mentionResolutionIdsRequestSchema, request);
|
|
14762
|
+
if (invalid) return invalid;
|
|
14763
|
+
return runMentionAction(client, "notify", request.resolutionIds);
|
|
14764
|
+
}
|
|
14765
|
+
/** Add the targets of unreached @mentions to the conversation (`raft mention add`). */
|
|
14766
|
+
async function addMentions(client, request) {
|
|
14767
|
+
const invalid = validateOpRequest(mentionResolutionIdsRequestSchema, request);
|
|
14768
|
+
if (invalid) return invalid;
|
|
14769
|
+
return runMentionAction(client, "add", request.resolutionIds);
|
|
14770
|
+
}
|
|
14771
|
+
/** @deprecated Backs the deprecated `mentions.execute`; use `notifyMentions` / `addMentions`. */
|
|
14382
14772
|
async function executeMentionAction(client, request) {
|
|
14383
14773
|
const invalid = validateOpRequest(executeMentionActionRequestSchema, request);
|
|
14384
14774
|
if (invalid) return invalid;
|
|
14385
|
-
const
|
|
14386
|
-
if (
|
|
14775
|
+
const missing = "Pass an action (notify | add) and at least one resolution id.";
|
|
14776
|
+
if (request.action !== "notify" && request.action !== "add") return failureOutcome(opError("INVALID_REQUEST", { message: missing }));
|
|
14777
|
+
return runMentionAction(client, request.action, request.resolutionIds, missing);
|
|
14778
|
+
}
|
|
14779
|
+
async function runMentionAction(client, action, resolutionIds, missingIdsMessage = "Pass at least one resolution id.") {
|
|
14780
|
+
const ids = (resolutionIds ?? []).map((id) => id.trim()).filter(Boolean);
|
|
14781
|
+
if (ids.length === 0) return failureOutcome(opError("INVALID_REQUEST", { message: missingIdsMessage }));
|
|
14387
14782
|
const result = await client.mentions.executeAction({
|
|
14388
|
-
action
|
|
14783
|
+
action,
|
|
14389
14784
|
resolutionIds: ids
|
|
14390
14785
|
});
|
|
14391
14786
|
if (!result.ok) return failureFromClientResult(result);
|
|
@@ -14394,11 +14789,11 @@ async function executeMentionAction(client, request) {
|
|
|
14394
14789
|
ok: true,
|
|
14395
14790
|
state: "executed",
|
|
14396
14791
|
data: {
|
|
14397
|
-
action
|
|
14792
|
+
action,
|
|
14398
14793
|
results
|
|
14399
14794
|
},
|
|
14400
14795
|
next: null,
|
|
14401
|
-
text: formatAgentMentionActionResults(
|
|
14796
|
+
text: formatAgentMentionActionResults(action, results)
|
|
14402
14797
|
};
|
|
14403
14798
|
}
|
|
14404
14799
|
async function senderMentionDeliveries(client, request) {
|
|
@@ -14473,7 +14868,7 @@ async function getManualTopic(client, request) {
|
|
|
14473
14868
|
text: formatAgentKnowledgeStdout(result.data.content)
|
|
14474
14869
|
};
|
|
14475
14870
|
}
|
|
14476
|
-
async function searchManual(client, request) {
|
|
14871
|
+
async function searchManual(client, request, options = {}) {
|
|
14477
14872
|
const malformed = validateOpRequest(searchManualRequestSchema, request);
|
|
14478
14873
|
if (malformed) return malformed;
|
|
14479
14874
|
const invalid = requireContext(request);
|
|
@@ -14489,12 +14884,7 @@ async function searchManual(client, request) {
|
|
|
14489
14884
|
const data = result.data;
|
|
14490
14885
|
const results = data.results;
|
|
14491
14886
|
const first = results[0];
|
|
14492
|
-
const next = first ? {
|
|
14493
|
-
kind: "read_manual_topic",
|
|
14494
|
-
command: `raft manual get ${first.slug} --intent "…" --reason "…"`,
|
|
14495
|
-
args: { topic: first.slug },
|
|
14496
|
-
why: "Open the best-matching topic."
|
|
14497
|
-
} : null;
|
|
14887
|
+
const next = first ? hintStep("read_manual_topic", RAFT_HINTS.manualGet(first.slug), "Open the best-matching topic.", options.hints, { topic: first.slug }) : null;
|
|
14498
14888
|
return {
|
|
14499
14889
|
ok: true,
|
|
14500
14890
|
state: results.length > 0 ? "results" : "empty",
|
|
@@ -14695,29 +15085,26 @@ function formatAgentActionCardPosted(target, messageId) {
|
|
|
14695
15085
|
* the preparer in the card's own thread; a card posted inside a thread has no
|
|
14696
15086
|
* thread of its own, so the reply lands in that same thread.
|
|
14697
15087
|
*/
|
|
14698
|
-
function awaitConfirmationNext(target, messageId) {
|
|
15088
|
+
function awaitConfirmationNext(target, messageId, style) {
|
|
14699
15089
|
const short = messageId.slice(0, 8);
|
|
14700
|
-
if (getParentTargetForThread(target) !== null) return {
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14707
|
-
|
|
14708
|
-
|
|
15090
|
+
if (getParentTargetForThread(target) !== null) return hintStep("await_confirmation", RAFT_HINTS.messageRead({
|
|
15091
|
+
target,
|
|
15092
|
+
around: {
|
|
15093
|
+
shown: short,
|
|
15094
|
+
id: messageId
|
|
15095
|
+
}
|
|
15096
|
+
}), "A human must click the card to commit it. When it is executed (or fails), the outcome arrives as a reply in this thread that @mentions you; you do not need to poll.", style, {
|
|
15097
|
+
target,
|
|
15098
|
+
around: messageId,
|
|
15099
|
+
messageId
|
|
15100
|
+
});
|
|
14709
15101
|
const thread = agentTaskThreadTarget(target, messageId);
|
|
14710
|
-
return {
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
target: thread,
|
|
14715
|
-
messageId
|
|
14716
|
-
},
|
|
14717
|
-
why: "A human must click the card to commit it. When it is executed (or fails), the outcome arrives as a reply in the card's thread that @mentions you; you do not need to poll."
|
|
14718
|
-
};
|
|
15102
|
+
return hintStep("await_confirmation", RAFT_HINTS.messageRead({ target: thread }), "A human must click the card to commit it. When it is executed (or fails), the outcome arrives as a reply in the card's thread that @mentions you; you do not need to poll.", style, {
|
|
15103
|
+
target: thread,
|
|
15104
|
+
messageId
|
|
15105
|
+
});
|
|
14719
15106
|
}
|
|
14720
|
-
async function prepareActionCard(client, request) {
|
|
15107
|
+
async function prepareActionCard(client, request, options = {}) {
|
|
14721
15108
|
if (typeof request?.target !== "string" || !request.target.trim() || !request.action) return failureOutcome(opError("INVALID_REQUEST", { message: "A target and an action are required to prepare a card." }));
|
|
14722
15109
|
const invalid = validateOpRequest(prepareActionCardRequestSchema, request);
|
|
14723
15110
|
if (invalid) return invalid;
|
|
@@ -14736,7 +15123,7 @@ async function prepareActionCard(client, request) {
|
|
|
14736
15123
|
ok: true,
|
|
14737
15124
|
state: "prepared",
|
|
14738
15125
|
data: card,
|
|
14739
|
-
next: awaitConfirmationNext(request.target, card.messageId),
|
|
15126
|
+
next: awaitConfirmationNext(request.target, card.messageId, options.hints ?? "cli"),
|
|
14740
15127
|
text: formatAgentActionCardPosted(request.target, card.messageId)
|
|
14741
15128
|
};
|
|
14742
15129
|
}
|
|
@@ -15147,6 +15534,14 @@ const OPERATION_DEFS = [
|
|
|
15147
15534
|
consumes: nothing,
|
|
15148
15535
|
output: small
|
|
15149
15536
|
},
|
|
15537
|
+
{
|
|
15538
|
+
name: "attachments.downloadUrl",
|
|
15539
|
+
description: "Get a short-lived (5 minute) URL for an attachment's bytes, with its filename and MIME type, for runtimes that fetch files themselves. The URL grants access to the file: do not post it in messages.",
|
|
15540
|
+
schema: downloadAttachmentUrlRequestSchema,
|
|
15541
|
+
routes: ["attachmentDownloadUrl"],
|
|
15542
|
+
consumes: nothing,
|
|
15543
|
+
output: small
|
|
15544
|
+
},
|
|
15150
15545
|
{
|
|
15151
15546
|
name: "attachments.comments",
|
|
15152
15547
|
description: "List the comments on an attachment.",
|
|
@@ -15170,21 +15565,47 @@ const OPERATION_DEFS = [
|
|
|
15170
15565
|
}
|
|
15171
15566
|
},
|
|
15172
15567
|
{
|
|
15173
|
-
name: "mentions.
|
|
15174
|
-
description: "Deliver unreached @mentions
|
|
15175
|
-
schema:
|
|
15568
|
+
name: "mentions.notify",
|
|
15569
|
+
description: "Deliver unreached @mentions by notifying each mentioned target about the message, without adding them to the conversation. Takes resolutionId values from mentions.pending.",
|
|
15570
|
+
schema: mentionResolutionIdsRequestSchema,
|
|
15176
15571
|
routes: ["mentionActionsExecute"],
|
|
15177
15572
|
consumes: nothing,
|
|
15178
15573
|
output: small
|
|
15179
15574
|
},
|
|
15180
15575
|
{
|
|
15181
|
-
name: "mentions.
|
|
15576
|
+
name: "mentions.add",
|
|
15577
|
+
description: "Deliver unreached @mentions by adding each mentioned target to the conversation, so they see the message and what follows. Takes resolutionId values from mentions.pending.",
|
|
15578
|
+
schema: mentionResolutionIdsRequestSchema,
|
|
15579
|
+
routes: ["mentionActionsExecute"],
|
|
15580
|
+
consumes: nothing,
|
|
15581
|
+
output: small
|
|
15582
|
+
},
|
|
15583
|
+
{
|
|
15584
|
+
name: "mentions.delivery",
|
|
15182
15585
|
description: "Whether each @mention in a message you sent reached its target.",
|
|
15183
15586
|
schema: senderMentionDeliveriesRequestSchema,
|
|
15184
15587
|
routes: ["senderMentionDeliveries"],
|
|
15185
15588
|
consumes: nothing,
|
|
15186
15589
|
output: small
|
|
15187
15590
|
},
|
|
15591
|
+
{
|
|
15592
|
+
name: "mentions.execute",
|
|
15593
|
+
description: "Deprecated: use mentions.notify / mentions.add. Removed in the next minor release. Deliver unreached @mentions: notify the mentioned target, or add them to the conversation.",
|
|
15594
|
+
schema: executeMentionActionRequestSchema,
|
|
15595
|
+
routes: ["mentionActionsExecute"],
|
|
15596
|
+
consumes: nothing,
|
|
15597
|
+
output: small,
|
|
15598
|
+
deprecated: true
|
|
15599
|
+
},
|
|
15600
|
+
{
|
|
15601
|
+
name: "mentions.deliveries",
|
|
15602
|
+
description: "Deprecated: use mentions.delivery. Removed in the next minor release. Whether each @mention in a message you sent reached its target.",
|
|
15603
|
+
schema: senderMentionDeliveriesRequestSchema,
|
|
15604
|
+
routes: ["senderMentionDeliveries"],
|
|
15605
|
+
consumes: nothing,
|
|
15606
|
+
output: small,
|
|
15607
|
+
deprecated: true
|
|
15608
|
+
},
|
|
15188
15609
|
{
|
|
15189
15610
|
name: "actions.prepare",
|
|
15190
15611
|
description: "Post an action card (create a channel, add members, create an agent, or an integration step) for a human to confirm; the human who clicks it carries it out as themselves. When it is executed (or fails), the outcome arrives as a reply that @mentions you in the card's thread (or in the thread the card was posted in).",
|
|
@@ -15448,10 +15869,6 @@ const OPERATION_DEFS = [
|
|
|
15448
15869
|
output: small
|
|
15449
15870
|
}
|
|
15450
15871
|
];
|
|
15451
|
-
/** `tasks.updateStatus` → `tasks_update_status`. */
|
|
15452
|
-
function raftToolNameFor(name) {
|
|
15453
|
-
return name.replace(/\./g, "_").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
15454
|
-
}
|
|
15455
15872
|
const IDEMPOTENCY_STRENGTH = {
|
|
15456
15873
|
natural: 0,
|
|
15457
15874
|
key: 1,
|
|
@@ -15523,11 +15940,17 @@ function createRaft(options) {
|
|
|
15523
15940
|
const serverUrl = requireServerUrl(options.serverUrl);
|
|
15524
15941
|
const authorization = `Bearer ${requireAgentCredential(options.credential)}`;
|
|
15525
15942
|
const frontier = SeenFrontier.fromSnapshot(options.frontier);
|
|
15943
|
+
if (options.hints !== void 0 && options.hints !== "cli" && options.hints !== "tool") throw new TypeError("createRaft: hints must be \"cli\" or \"tool\".");
|
|
15944
|
+
const hints = options.hints ?? "cli";
|
|
15945
|
+
/** How every operation renders its hints. */
|
|
15946
|
+
const style = { hints };
|
|
15947
|
+
/** The SDK's default NOT_FOUND next action names a command; render it in the configured style. */
|
|
15948
|
+
const styled = (outcome) => restyleDefaultNextAction(outcome, hints);
|
|
15526
15949
|
const session = new RaftStateSession(options.state, frontier, options.onStateSaveError);
|
|
15527
15950
|
/** Load before, run, then save if the operation succeeded and changed the state. */
|
|
15528
15951
|
const withState = async (run) => {
|
|
15529
15952
|
await session.ensureLoaded();
|
|
15530
|
-
const outcome = await run();
|
|
15953
|
+
const outcome = styled(await run());
|
|
15531
15954
|
if (outcome.ok) await session.save();
|
|
15532
15955
|
return outcome;
|
|
15533
15956
|
};
|
|
@@ -15563,7 +15986,7 @@ function createRaft(options) {
|
|
|
15563
15986
|
const outcome = await sendMessage(api, pending ? {
|
|
15564
15987
|
...request,
|
|
15565
15988
|
idempotencyKey: pending.idempotencyKey
|
|
15566
|
-
} : request, seen);
|
|
15989
|
+
} : request, seen, style);
|
|
15567
15990
|
if (outcome.ok && outcome.state === "interrupted" && outcome.interrupt.resume.idempotencyKey) session.rememberContinuation({
|
|
15568
15991
|
target: request.target,
|
|
15569
15992
|
idempotencyKey: outcome.interrupt.resume.idempotencyKey,
|
|
@@ -15578,7 +16001,7 @@ function createRaft(options) {
|
|
|
15578
16001
|
const outcome = await checkInbox(inboxApi, {
|
|
15579
16002
|
...request,
|
|
15580
16003
|
...since === void 0 ? {} : { since }
|
|
15581
|
-
}, seen);
|
|
16004
|
+
}, seen, style);
|
|
15582
16005
|
if (outcome.ok) {
|
|
15583
16006
|
session.markDirty();
|
|
15584
16007
|
if (since !== void 0 && (request.ack ?? "cursor") === "cursor") session.commit(since);
|
|
@@ -15597,7 +16020,7 @@ function createRaft(options) {
|
|
|
15597
16020
|
if (batch.ackMode === "cursor" && batch.messages.length > 0) session.setPending(batch.cursor);
|
|
15598
16021
|
session.markDirty();
|
|
15599
16022
|
await session.save();
|
|
15600
|
-
});
|
|
16023
|
+
}, style);
|
|
15601
16024
|
})();
|
|
15602
16025
|
const commitInbox = async (target) => {
|
|
15603
16026
|
await session.ensureLoaded();
|
|
@@ -15609,7 +16032,7 @@ function createRaft(options) {
|
|
|
15609
16032
|
};
|
|
15610
16033
|
/** `seen` undefined: read without recording anything (a code read). */
|
|
15611
16034
|
const readWithState = (request, seen) => withState(async () => {
|
|
15612
|
-
const outcome = await readHistory(api, request, seen);
|
|
16035
|
+
const outcome = await readHistory(api, request, seen, style);
|
|
15613
16036
|
if (outcome.ok && seen) session.markDirty();
|
|
15614
16037
|
return outcome;
|
|
15615
16038
|
});
|
|
@@ -15618,16 +16041,16 @@ function createRaft(options) {
|
|
|
15618
16041
|
wake: {
|
|
15619
16042
|
verifyNotice: (input) => verifyInboxNotice(input),
|
|
15620
16043
|
webhook: {
|
|
15621
|
-
status: () => webhookStatus(api),
|
|
15622
|
-
register: (request) => registerWebhook(api, request),
|
|
15623
|
-
unregister: () => unregisterWebhook(api)
|
|
16044
|
+
status: () => webhookStatus(api).then(styled),
|
|
16045
|
+
register: (request) => registerWebhook(api, request).then(styled),
|
|
16046
|
+
unregister: () => unregisterWebhook(api).then(styled)
|
|
15624
16047
|
}
|
|
15625
16048
|
},
|
|
15626
16049
|
inbox: {
|
|
15627
16050
|
check: (request = {}) => checkWithState(request, frontier),
|
|
15628
16051
|
commit: (target) => commitInbox(target),
|
|
15629
16052
|
drain: (request = {}) => drainWithState(request, frontier),
|
|
15630
|
-
list: (request) => listInbox(api, request)
|
|
16053
|
+
list: (request) => listInbox(api, request, style).then(styled)
|
|
15631
16054
|
},
|
|
15632
16055
|
messages: {
|
|
15633
16056
|
read: (request) => readWithState(request, frontier),
|
|
@@ -15636,10 +16059,10 @@ function createRaft(options) {
|
|
|
15636
16059
|
...request,
|
|
15637
16060
|
target: message.target
|
|
15638
16061
|
}, frontier),
|
|
15639
|
-
search: (request) => searchMessages(api, request),
|
|
15640
|
-
resolve: (request) => resolveMessage(api, request),
|
|
15641
|
-
react: (request) => reactToMessage(api, request, "add"),
|
|
15642
|
-
unreact: (request) => reactToMessage(api, request, "remove")
|
|
16062
|
+
search: (request) => searchMessages(api, request, style).then(styled),
|
|
16063
|
+
resolve: (request) => resolveMessage(api, request, style).then(styled),
|
|
16064
|
+
react: (request) => reactToMessage(api, request, "add").then(styled),
|
|
16065
|
+
unreact: (request) => reactToMessage(api, request, "remove").then(styled)
|
|
15643
16066
|
},
|
|
15644
16067
|
attachments: {
|
|
15645
16068
|
upload: (request) => uploadAttachment(api, {
|
|
@@ -15647,51 +16070,55 @@ function createRaft(options) {
|
|
|
15647
16070
|
fetch: options.fetch ?? fetch,
|
|
15648
16071
|
headers: Object.fromEntries(new Headers(options.headers)),
|
|
15649
16072
|
authorization
|
|
15650
|
-
}, request),
|
|
15651
|
-
download: (request) => downloadAttachment(api, request),
|
|
15652
|
-
|
|
16073
|
+
}, request, style).then(styled),
|
|
16074
|
+
download: (request) => downloadAttachment(api, request).then(styled),
|
|
16075
|
+
downloadUrl: (request) => downloadAttachmentUrl(api, request, style).then(styled),
|
|
16076
|
+
comments: (request) => attachmentComments(api, request).then(styled)
|
|
15653
16077
|
},
|
|
15654
16078
|
mentions: {
|
|
15655
|
-
pending: (request) => pendingMentionActions(api, request),
|
|
15656
|
-
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
16079
|
+
pending: (request) => pendingMentionActions(api, request, style).then(styled),
|
|
16080
|
+
notify: (request) => notifyMentions(api, request).then(styled),
|
|
16081
|
+
add: (request) => addMentions(api, request).then(styled),
|
|
16082
|
+
delivery: (request) => senderMentionDeliveries(api, request).then(styled),
|
|
16083
|
+
execute: (request) => executeMentionAction(api, request).then(styled),
|
|
16084
|
+
deliveries: (request) => senderMentionDeliveries(api, request).then(styled)
|
|
16085
|
+
},
|
|
16086
|
+
actions: { prepare: (request) => prepareActionCard(api, request, style).then(styled) },
|
|
15660
16087
|
manual: {
|
|
15661
|
-
get: (request) => getManualTopic(api, request),
|
|
15662
|
-
search: (request) => searchManual(api, request)
|
|
16088
|
+
get: (request) => getManualTopic(api, request).then(styled),
|
|
16089
|
+
search: (request) => searchManual(api, request, style).then(styled)
|
|
15663
16090
|
},
|
|
15664
16091
|
tasks: {
|
|
15665
|
-
claim: (request) => claimTasks(api, request),
|
|
15666
|
-
list: (request) => listTasks(api, request),
|
|
15667
|
-
create: (request) => createTasks(api, request),
|
|
15668
|
-
unclaim: (request) => unclaimTask(api, request),
|
|
15669
|
-
assign: (request) => assignTask(api, request),
|
|
15670
|
-
unassign: (request) => unassignTask(api, request),
|
|
15671
|
-
updateStatus: (request) => updateTaskStatus(api, request),
|
|
15672
|
-
amend: (request) => amendTask(api, request),
|
|
15673
|
-
history: (request) => taskHistory(api, request),
|
|
15674
|
-
show: (request) => showTask(api, request),
|
|
15675
|
-
convert: (request) => convertMessageToTask(api, request),
|
|
15676
|
-
delete: (request) => deleteTask(api, request)
|
|
16092
|
+
claim: (request) => claimTasks(api, request, style).then(styled),
|
|
16093
|
+
list: (request) => listTasks(api, request, style).then(styled),
|
|
16094
|
+
create: (request) => createTasks(api, request, style).then(styled),
|
|
16095
|
+
unclaim: (request) => unclaimTask(api, request).then(styled),
|
|
16096
|
+
assign: (request) => assignTask(api, request).then(styled),
|
|
16097
|
+
unassign: (request) => unassignTask(api, request).then(styled),
|
|
16098
|
+
updateStatus: (request) => updateTaskStatus(api, request, style).then(styled),
|
|
16099
|
+
amend: (request) => amendTask(api, request, style).then(styled),
|
|
16100
|
+
history: (request) => taskHistory(api, request).then(styled),
|
|
16101
|
+
show: (request) => showTask(api, request, style).then(styled),
|
|
16102
|
+
convert: (request) => convertMessageToTask(api, request, style).then(styled),
|
|
16103
|
+
delete: (request) => deleteTask(api, request).then(styled)
|
|
15677
16104
|
},
|
|
15678
16105
|
channels: {
|
|
15679
|
-
join: (request) => joinChannel(api, request),
|
|
15680
|
-
leave: (request) => leaveChannel(api, request),
|
|
15681
|
-
mute: (request) => muteChannel(api, request),
|
|
15682
|
-
unmute: (request) => unmuteChannel(api, request),
|
|
15683
|
-
members: (request) => channelMembers(api, request),
|
|
15684
|
-
info: (request) => channelInfo(api, request)
|
|
16106
|
+
join: (request) => joinChannel(api, request, style).then(styled),
|
|
16107
|
+
leave: (request) => leaveChannel(api, request, style).then(styled),
|
|
16108
|
+
mute: (request) => muteChannel(api, request, style).then(styled),
|
|
16109
|
+
unmute: (request) => unmuteChannel(api, request, style).then(styled),
|
|
16110
|
+
members: (request) => channelMembers(api, request).then(styled),
|
|
16111
|
+
info: (request) => channelInfo(api, request, style).then(styled)
|
|
15685
16112
|
},
|
|
15686
16113
|
threads: {
|
|
15687
|
-
list: () => listThreads(api),
|
|
15688
|
-
unfollow: (request) => unfollowThread(api, request)
|
|
16114
|
+
list: () => listThreads(api).then(styled),
|
|
16115
|
+
unfollow: (request) => unfollowThread(api, request).then(styled)
|
|
15689
16116
|
},
|
|
15690
|
-
server: { info: (request) => serverInfo(api, request) },
|
|
15691
|
-
users: { info: (request) => userInfo(api, request) },
|
|
16117
|
+
server: { info: (request) => serverInfo(api, request, style).then(styled) },
|
|
16118
|
+
users: { info: (request) => userInfo(api, request, style).then(styled) },
|
|
15692
16119
|
profile: {
|
|
15693
|
-
show: (request) => showProfile(api, request),
|
|
15694
|
-
update: (request) => updateProfile(api, request)
|
|
16120
|
+
show: (request) => showProfile(api, request).then(styled),
|
|
16121
|
+
update: (request) => updateProfile(api, request).then(styled)
|
|
15695
16122
|
},
|
|
15696
16123
|
frontier,
|
|
15697
16124
|
state: {
|
|
@@ -15712,7 +16139,7 @@ function createRaft(options) {
|
|
|
15712
16139
|
const drain = drainWithState(args, call.seen);
|
|
15713
16140
|
const batches = [];
|
|
15714
16141
|
for (let step = await drain.next();; step = await drain.next()) {
|
|
15715
|
-
if (step.done) return drainedInboxOutcome(batches, step.value);
|
|
16142
|
+
if (step.done) return styled(drainedInboxOutcome(batches, step.value, style));
|
|
15716
16143
|
batches.push(step.value);
|
|
15717
16144
|
}
|
|
15718
16145
|
},
|
|
@@ -15740,8 +16167,12 @@ function createRaft(options) {
|
|
|
15740
16167
|
"messages.resolve": (args) => raft.messages.resolve(args),
|
|
15741
16168
|
"messages.react": (args) => raft.messages.react(args),
|
|
15742
16169
|
"messages.unreact": (args) => raft.messages.unreact(args),
|
|
16170
|
+
"attachments.downloadUrl": (args) => raft.attachments.downloadUrl(args),
|
|
15743
16171
|
"attachments.comments": (args) => raft.attachments.comments(args),
|
|
15744
16172
|
"mentions.pending": (args) => raft.mentions.pending(args),
|
|
16173
|
+
"mentions.notify": (args) => raft.mentions.notify(args),
|
|
16174
|
+
"mentions.add": (args) => raft.mentions.add(args),
|
|
16175
|
+
"mentions.delivery": (args) => raft.mentions.delivery(args),
|
|
15745
16176
|
"mentions.execute": (args) => raft.mentions.execute(args),
|
|
15746
16177
|
"mentions.deliveries": (args) => raft.mentions.deliveries(args),
|
|
15747
16178
|
"actions.prepare": (args) => raft.actions.prepare(args),
|
|
@@ -15812,4 +16243,4 @@ function whoamiOutcome(result) {
|
|
|
15812
16243
|
};
|
|
15813
16244
|
}
|
|
15814
16245
|
//#endregion
|
|
15815
|
-
export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_JSON_SCHEMA_KEYWORDS, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_OPERATIONS, RAFT_OPERATIONS_SCHEMA, RAFT_OPERATIONS_VERSION, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, amendTaskRequestSchema, assignTaskRequestSchema, attachmentCommentsRequestSchema, bootstrapRaftCredential, channelInfoRequestSchema, channelMembersRequestSchema, channelTargetRequestSchema, checkInboxRequestSchema, claimTasksRequestSchema, commitInboxRequestSchema, convertMessageToTaskRequestSchema, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, createTasksRequestSchema, describeRaftRoute, drainInboxRequestSchema, executeMentionActionRequestSchema, getManualTopicRequestSchema, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, isInterrupted, joinRaftChannelByTarget, listInboxRequestSchema, listRaftRoutes, listTasksRequestSchema, listThreadsRequestSchema, parseRaftRegularChannelTarget, parseRaftState, pendingMentionActionsRequestSchema, prepareActionCardRequestSchema, projectRaftMessage, projectRaftMessages, raftToolNameFor, reactRequestSchema, readHistoryRequestSchema, readLatestReadThread, replyToRequestSchema, resolveMessageRequestSchema, searchManualRequestSchema, searchMessagesRequestSchema, sendMessageRequestSchema, senderMentionDeliveriesRequestSchema, serverInfoRequestSchema, showProfileRequestSchema, taskRefSchema, unfollowThreadRequestSchema, updateProfileRequestSchema, updateTaskStatusRequestSchema, userInfoRequestSchema, verifyInboxNotice, whoamiRequestSchema };
|
|
16246
|
+
export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_JSON_SCHEMA_KEYWORDS, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_OPERATIONS, RAFT_OPERATIONS_SCHEMA, RAFT_OPERATIONS_VERSION, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, amendTaskRequestSchema, assignTaskRequestSchema, attachmentCommentsRequestSchema, bootstrapRaftCredential, channelInfoRequestSchema, channelMembersRequestSchema, channelTargetRequestSchema, checkInboxRequestSchema, claimTasksRequestSchema, commitInboxRequestSchema, convertMessageToTaskRequestSchema, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, createTasksRequestSchema, describeRaftRoute, downloadAttachmentUrlRequestSchema, drainInboxRequestSchema, executeMentionActionRequestSchema, getManualTopicRequestSchema, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, isInterrupted, joinRaftChannelByTarget, listInboxRequestSchema, listRaftRoutes, listTasksRequestSchema, listThreadsRequestSchema, mentionResolutionIdsRequestSchema, parseRaftRegularChannelTarget, parseRaftState, pendingMentionActionsRequestSchema, prepareActionCardRequestSchema, projectRaftMessage, projectRaftMessages, raftToolNameFor, reactRequestSchema, readHistoryRequestSchema, readLatestReadThread, replyToRequestSchema, resolveMessageRequestSchema, searchManualRequestSchema, searchMessagesRequestSchema, sendMessageRequestSchema, senderMentionDeliveriesRequestSchema, serverInfoRequestSchema, showProfileRequestSchema, taskRefSchema, unfollowThreadRequestSchema, updateProfileRequestSchema, updateTaskStatusRequestSchema, userInfoRequestSchema, verifyInboxNotice, whoamiRequestSchema };
|