@botiverse/raft-sdk 0.3.2 → 0.4.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 +69 -24
- package/dist/cjs/index.cjs +292 -323
- package/dist/esm/index.js +292 -324
- package/dist/index.d.ts +99 -438
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -4478,12 +4478,6 @@ const destructive = {
|
|
|
4478
4478
|
destructive: true,
|
|
4479
4479
|
audience: "both"
|
|
4480
4480
|
};
|
|
4481
|
-
const managedNaturalWrite = {
|
|
4482
|
-
sideEffect: "write",
|
|
4483
|
-
idempotency: "natural",
|
|
4484
|
-
destructive: false,
|
|
4485
|
-
audience: "managed"
|
|
4486
|
-
};
|
|
4487
4481
|
const managedWrite = {
|
|
4488
4482
|
sideEffect: "write",
|
|
4489
4483
|
idempotency: "none",
|
|
@@ -4544,15 +4538,6 @@ const AGENT_API_ROUTE_META = {
|
|
|
4544
4538
|
taskConvert: write,
|
|
4545
4539
|
taskAmend: destructive,
|
|
4546
4540
|
taskHistory: read,
|
|
4547
|
-
migrationBegin: {
|
|
4548
|
-
sideEffect: "write",
|
|
4549
|
-
idempotency: "none",
|
|
4550
|
-
destructive: true,
|
|
4551
|
-
audience: "managed"
|
|
4552
|
-
},
|
|
4553
|
-
migrationStatus: read,
|
|
4554
|
-
migrationReady: managedNaturalWrite,
|
|
4555
|
-
migrationArrived: managedNaturalWrite,
|
|
4556
4541
|
reminderList: read,
|
|
4557
4542
|
reminderCreate: managedWrite,
|
|
4558
4543
|
reminderCancel: naturalDestructive,
|
|
@@ -5006,7 +4991,14 @@ const agentApiHistoryQuerySchema = passthroughObject({
|
|
|
5006
4991
|
before: optionalStringSchema,
|
|
5007
4992
|
after: optionalStringSchema,
|
|
5008
4993
|
around: optionalStringSchema,
|
|
5009
|
-
limit: optionalStringSchema
|
|
4994
|
+
limit: optionalStringSchema,
|
|
4995
|
+
/**
|
|
4996
|
+
* `"false"` reads without consuming: the Server returns the page but does
|
|
4997
|
+
* not advance the agent's read cursor, and reports no
|
|
4998
|
+
* `model_seen_up_to_seq`. For reads whose output may never reach the model
|
|
4999
|
+
* (code a hosted agent wrote). Absent or `"true"` keeps the default.
|
|
5000
|
+
*/
|
|
5001
|
+
consume: _enum(["true", "false"]).optional()
|
|
5010
5002
|
});
|
|
5011
5003
|
const agentApiKnowledgeGetQuerySchema = passthroughObject({
|
|
5012
5004
|
topic: string().trim().min(1),
|
|
@@ -6132,61 +6124,6 @@ const agentApiAppConfigResponseSchema = passthroughObject({
|
|
|
6132
6124
|
overrides: record(string(), agentApiAppConfigValueSchema),
|
|
6133
6125
|
effective: record(string(), agentApiAppConfigValueSchema)
|
|
6134
6126
|
});
|
|
6135
|
-
const agentApiMigrationStateSchema = _enum([
|
|
6136
|
-
"provisioning",
|
|
6137
|
-
"prep",
|
|
6138
|
-
"ready",
|
|
6139
|
-
"in_transit",
|
|
6140
|
-
"arriving",
|
|
6141
|
-
"starting",
|
|
6142
|
-
"cancel_requested_pre_flip",
|
|
6143
|
-
"cancel_requested_post_flip",
|
|
6144
|
-
"canceled_pre_flip",
|
|
6145
|
-
"canceled_post_flip",
|
|
6146
|
-
"completed",
|
|
6147
|
-
"aborted",
|
|
6148
|
-
"failed"
|
|
6149
|
-
]);
|
|
6150
|
-
const agentApiMigrationSummarySchema = passthroughObject({
|
|
6151
|
-
id: string(),
|
|
6152
|
-
agentId: string(),
|
|
6153
|
-
sourceMachineId: string(),
|
|
6154
|
-
targetMachineId: string(),
|
|
6155
|
-
state: agentApiMigrationStateSchema,
|
|
6156
|
-
manifestPath: nullableStringSchema,
|
|
6157
|
-
manifestSha256: nullableStringSchema,
|
|
6158
|
-
arrivalReportPath: nullableStringSchema,
|
|
6159
|
-
arrivalReportSha256: nullableStringSchema,
|
|
6160
|
-
abortReason: nullableStringSchema,
|
|
6161
|
-
failureReason: nullableStringSchema,
|
|
6162
|
-
prepDeadlineAt: string().datetime(),
|
|
6163
|
-
transferDeadlineAt: string().datetime(),
|
|
6164
|
-
arrivalDeadlineAt: string().datetime(),
|
|
6165
|
-
readyAt: nullableStringSchema,
|
|
6166
|
-
flippedAt: nullableStringSchema,
|
|
6167
|
-
arrivedAt: nullableStringSchema,
|
|
6168
|
-
completedAt: nullableStringSchema,
|
|
6169
|
-
abortedAt: nullableStringSchema,
|
|
6170
|
-
revision: number$1().int().positive(),
|
|
6171
|
-
createdAt: string().datetime(),
|
|
6172
|
-
updatedAt: string().datetime()
|
|
6173
|
-
});
|
|
6174
|
-
const agentApiMigrationBeginBodySchema = passthroughObject({
|
|
6175
|
-
targetMachineId: string().trim().min(1),
|
|
6176
|
-
prepDeadlineMs: number$1().int().positive().optional(),
|
|
6177
|
-
transferDeadlineMs: number$1().int().positive().optional(),
|
|
6178
|
-
arrivalDeadlineMs: number$1().int().positive().optional()
|
|
6179
|
-
});
|
|
6180
|
-
const agentApiMigrationReadyBodySchema = passthroughObject({
|
|
6181
|
-
manifestPath: string().trim().min(1),
|
|
6182
|
-
manifestSha256: optionalStringSchema
|
|
6183
|
-
});
|
|
6184
|
-
const agentApiMigrationArrivedBodySchema = passthroughObject({
|
|
6185
|
-
reportPath: optionalStringSchema,
|
|
6186
|
-
reportSha256: optionalStringSchema
|
|
6187
|
-
});
|
|
6188
|
-
const agentApiMigrationResponseSchema = passthroughObject({ migration: agentApiMigrationSummarySchema });
|
|
6189
|
-
const agentApiMigrationStatusResponseSchema = passthroughObject({ migration: agentApiMigrationSummarySchema.nullable() });
|
|
6190
6127
|
const agentApiPushWebhookRegisterBodySchema = object({
|
|
6191
6128
|
/** Public HTTPS endpoint that receives `raft-agent-inbox-notice.v1` POSTs. */
|
|
6192
6129
|
url: string().trim().min(1),
|
|
@@ -6788,58 +6725,6 @@ const agentApiContract = {
|
|
|
6788
6725
|
request: { query: agentApiTaskHistoryQuerySchema },
|
|
6789
6726
|
response: { body: agentApiTaskHistoryResponseSchema }
|
|
6790
6727
|
}),
|
|
6791
|
-
migrationBegin: route({
|
|
6792
|
-
key: "migrationBegin",
|
|
6793
|
-
method: "POST",
|
|
6794
|
-
path: "/migrations",
|
|
6795
|
-
client: {
|
|
6796
|
-
resource: "migrations",
|
|
6797
|
-
method: "begin"
|
|
6798
|
-
},
|
|
6799
|
-
capability: "server",
|
|
6800
|
-
description: "Begin a migration for the bound agent credential.",
|
|
6801
|
-
request: { body: agentApiMigrationBeginBodySchema },
|
|
6802
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6803
|
-
}),
|
|
6804
|
-
migrationStatus: route({
|
|
6805
|
-
key: "migrationStatus",
|
|
6806
|
-
method: "GET",
|
|
6807
|
-
path: "/migrations/current",
|
|
6808
|
-
client: {
|
|
6809
|
-
resource: "migrations",
|
|
6810
|
-
method: "status"
|
|
6811
|
-
},
|
|
6812
|
-
capability: "read",
|
|
6813
|
-
description: "Read the active migration for the bound agent credential, if any.",
|
|
6814
|
-
request: {},
|
|
6815
|
-
response: { body: agentApiMigrationStatusResponseSchema }
|
|
6816
|
-
}),
|
|
6817
|
-
migrationReady: route({
|
|
6818
|
-
key: "migrationReady",
|
|
6819
|
-
method: "POST",
|
|
6820
|
-
path: "/migrations/ready",
|
|
6821
|
-
client: {
|
|
6822
|
-
resource: "migrations",
|
|
6823
|
-
method: "ready"
|
|
6824
|
-
},
|
|
6825
|
-
capability: "read",
|
|
6826
|
-
description: "Mark the bound agent's active migration prep phase ready.",
|
|
6827
|
-
request: { body: agentApiMigrationReadyBodySchema },
|
|
6828
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6829
|
-
}),
|
|
6830
|
-
migrationArrived: route({
|
|
6831
|
-
key: "migrationArrived",
|
|
6832
|
-
method: "POST",
|
|
6833
|
-
path: "/migrations/arrived",
|
|
6834
|
-
client: {
|
|
6835
|
-
resource: "migrations",
|
|
6836
|
-
method: "arrived"
|
|
6837
|
-
},
|
|
6838
|
-
capability: "read",
|
|
6839
|
-
description: "Mark the bound agent's active migration arrival phase complete.",
|
|
6840
|
-
request: { body: agentApiMigrationArrivedBodySchema },
|
|
6841
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6842
|
-
}),
|
|
6843
6728
|
reminderList: route({
|
|
6844
6729
|
key: "reminderList",
|
|
6845
6730
|
method: "GET",
|
|
@@ -8872,106 +8757,6 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
8872
8757
|
"body": true
|
|
8873
8758
|
}
|
|
8874
8759
|
},
|
|
8875
|
-
{
|
|
8876
|
-
"key": "migrationBegin",
|
|
8877
|
-
"method": "POST",
|
|
8878
|
-
"path": "/migrations",
|
|
8879
|
-
"fullPath": "/internal/agent-api/migrations",
|
|
8880
|
-
"client": {
|
|
8881
|
-
"resource": "migrations",
|
|
8882
|
-
"method": "begin"
|
|
8883
|
-
},
|
|
8884
|
-
"capability": "server",
|
|
8885
|
-
"description": "Begin a migration for the bound agent credential.",
|
|
8886
|
-
"sideEffect": "write",
|
|
8887
|
-
"idempotency": "none",
|
|
8888
|
-
"destructive": true,
|
|
8889
|
-
"audience": "managed",
|
|
8890
|
-
"request": {
|
|
8891
|
-
"params": false,
|
|
8892
|
-
"query": false,
|
|
8893
|
-
"body": true
|
|
8894
|
-
},
|
|
8895
|
-
"response": {
|
|
8896
|
-
"kind": "json",
|
|
8897
|
-
"body": true
|
|
8898
|
-
}
|
|
8899
|
-
},
|
|
8900
|
-
{
|
|
8901
|
-
"key": "migrationStatus",
|
|
8902
|
-
"method": "GET",
|
|
8903
|
-
"path": "/migrations/current",
|
|
8904
|
-
"fullPath": "/internal/agent-api/migrations/current",
|
|
8905
|
-
"client": {
|
|
8906
|
-
"resource": "migrations",
|
|
8907
|
-
"method": "status"
|
|
8908
|
-
},
|
|
8909
|
-
"capability": "read",
|
|
8910
|
-
"description": "Read the active migration for the bound agent credential, if any.",
|
|
8911
|
-
"sideEffect": "read",
|
|
8912
|
-
"idempotency": "natural",
|
|
8913
|
-
"destructive": false,
|
|
8914
|
-
"audience": "both",
|
|
8915
|
-
"request": {
|
|
8916
|
-
"params": false,
|
|
8917
|
-
"query": false,
|
|
8918
|
-
"body": false
|
|
8919
|
-
},
|
|
8920
|
-
"response": {
|
|
8921
|
-
"kind": "json",
|
|
8922
|
-
"body": true
|
|
8923
|
-
}
|
|
8924
|
-
},
|
|
8925
|
-
{
|
|
8926
|
-
"key": "migrationReady",
|
|
8927
|
-
"method": "POST",
|
|
8928
|
-
"path": "/migrations/ready",
|
|
8929
|
-
"fullPath": "/internal/agent-api/migrations/ready",
|
|
8930
|
-
"client": {
|
|
8931
|
-
"resource": "migrations",
|
|
8932
|
-
"method": "ready"
|
|
8933
|
-
},
|
|
8934
|
-
"capability": "read",
|
|
8935
|
-
"description": "Mark the bound agent's active migration prep phase ready.",
|
|
8936
|
-
"sideEffect": "write",
|
|
8937
|
-
"idempotency": "natural",
|
|
8938
|
-
"destructive": false,
|
|
8939
|
-
"audience": "managed",
|
|
8940
|
-
"request": {
|
|
8941
|
-
"params": false,
|
|
8942
|
-
"query": false,
|
|
8943
|
-
"body": true
|
|
8944
|
-
},
|
|
8945
|
-
"response": {
|
|
8946
|
-
"kind": "json",
|
|
8947
|
-
"body": true
|
|
8948
|
-
}
|
|
8949
|
-
},
|
|
8950
|
-
{
|
|
8951
|
-
"key": "migrationArrived",
|
|
8952
|
-
"method": "POST",
|
|
8953
|
-
"path": "/migrations/arrived",
|
|
8954
|
-
"fullPath": "/internal/agent-api/migrations/arrived",
|
|
8955
|
-
"client": {
|
|
8956
|
-
"resource": "migrations",
|
|
8957
|
-
"method": "arrived"
|
|
8958
|
-
},
|
|
8959
|
-
"capability": "read",
|
|
8960
|
-
"description": "Mark the bound agent's active migration arrival phase complete.",
|
|
8961
|
-
"sideEffect": "write",
|
|
8962
|
-
"idempotency": "natural",
|
|
8963
|
-
"destructive": false,
|
|
8964
|
-
"audience": "managed",
|
|
8965
|
-
"request": {
|
|
8966
|
-
"params": false,
|
|
8967
|
-
"query": false,
|
|
8968
|
-
"body": true
|
|
8969
|
-
},
|
|
8970
|
-
"response": {
|
|
8971
|
-
"kind": "json",
|
|
8972
|
-
"body": true
|
|
8973
|
-
}
|
|
8974
|
-
},
|
|
8975
8760
|
{
|
|
8976
8761
|
"key": "reminderList",
|
|
8977
8762
|
"method": "GET",
|
|
@@ -9874,7 +9659,7 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
9874
9659
|
}
|
|
9875
9660
|
];
|
|
9876
9661
|
/** Content hash of AGENT_API_ROUTE_MANIFEST; see computeAgentApiManifestVersion. */
|
|
9877
|
-
const AGENT_API_MANIFEST_VERSION = "
|
|
9662
|
+
const AGENT_API_MANIFEST_VERSION = "c7a793816a7a90ed";
|
|
9878
9663
|
//#endregion
|
|
9879
9664
|
//#region src/routes.ts
|
|
9880
9665
|
const ROUTE_INFO = Object.fromEntries(AGENT_API_ROUTE_MANIFEST.map((entry) => {
|
|
@@ -10936,6 +10721,20 @@ function formatUtcTimestamp(value) {
|
|
|
10936
10721
|
//#endregion
|
|
10937
10722
|
//#region ../shared/src/agentMessageText.ts
|
|
10938
10723
|
/**
|
|
10724
|
+
* Prefix every continuation line of a quoted body with ` │ `, so body text
|
|
10725
|
+
* never reaches column 0. Structural lines (`[target=…]` / `[1/5 seq=…]` headers,
|
|
10726
|
+
* read cursors, footers) always start at column 0, so a line-anchored reader
|
|
10727
|
+
* (`grep '^\['`) cannot be handed a forged one by message content. The `│` is
|
|
10728
|
+
* non-whitespace on purpose: a reader that trims each line still sees it. It is
|
|
10729
|
+
* the same quote marker as the freshness-hold digest previews. Remove the first
|
|
10730
|
+
* four characters after each line separator to recover the original body.
|
|
10731
|
+
*/
|
|
10732
|
+
const AGENT_BODY_CONTINUATION_PREFIX = " │ ";
|
|
10733
|
+
const AGENT_BODY_LINE_SEPARATOR_GLOBAL = new RegExp(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/.source, "g");
|
|
10734
|
+
function indentAgentBodyContinuationLines(text) {
|
|
10735
|
+
return text.replace(AGENT_BODY_LINE_SEPARATOR_GLOBAL, (separator) => `${separator}${AGENT_BODY_CONTINUATION_PREFIX}`);
|
|
10736
|
+
}
|
|
10737
|
+
/**
|
|
10939
10738
|
* The target an agent passes back to reply where a message came from:
|
|
10940
10739
|
* `#channel`, `#channel:shortid`, `dm:@peer`, `dm:@peer:shortid`, or
|
|
10941
10740
|
* `agent-event:shortid` for third-party app events.
|
|
@@ -10978,8 +10777,8 @@ function formatAgentTaskCurrentProjection(projection, taskNumber, neutralize) {
|
|
|
10978
10777
|
const actorType = projection.amendedByType ?? projection.amended_by_type ?? null;
|
|
10979
10778
|
const actor = actorName ? neutralizeRefs ? `user:${actorName}` : `@${actorName}` : actorType === "system" ? "system" : "<unresolved>";
|
|
10980
10779
|
const amendedAt = projection.amendedAt ?? projection.amended_at ?? null;
|
|
10981
|
-
const lines = [`[${taskNumber ? `task #${taskNumber} ` : "task "}superseded: current projection rev=${revision} source=${source} actor=${actor} time=${amendedAt ? formatUtcTimestamp(amendedAt) : "-"}]`, `Current title: ${neutralizeRefs ? renderPreviewText(projection.title ?? "") : projection.title ?? ""}`];
|
|
10982
|
-
if (projection.description != null) lines.push(`Current description: ${neutralizeRefs ? renderPreviewText(projection.description) : projection.description}`);
|
|
10780
|
+
const lines = [`[${taskNumber ? `task #${taskNumber} ` : "task "}superseded: current projection rev=${revision} source=${source} actor=${actor} time=${amendedAt ? formatUtcTimestamp(amendedAt) : "-"}]`, `Current title: ${indentAgentBodyContinuationLines(neutralizeRefs ? renderPreviewText(projection.title ?? "") : projection.title ?? "")}`];
|
|
10781
|
+
if (projection.description != null) lines.push(`Current description: ${indentAgentBodyContinuationLines(neutralizeRefs ? renderPreviewText(projection.description) : projection.description)}`);
|
|
10983
10782
|
return `\n${lines.join("\n")}`;
|
|
10984
10783
|
}
|
|
10985
10784
|
/** One received-message line: header bracket + sender + content + suffixes. */
|
|
@@ -10998,7 +10797,7 @@ function formatAgentMessageLine(m) {
|
|
|
10998
10797
|
const msgId = m.message_id ? m.message_id.slice(0, 8) : "-";
|
|
10999
10798
|
const time = m.timestamp ? formatUtcTimestamp(m.timestamp) : "-";
|
|
11000
10799
|
const senderType = ` type=${m.sender_type}`;
|
|
11001
|
-
const content = m.content ?? "";
|
|
10800
|
+
const content = indentAgentBodyContinuationLines(m.content ?? "");
|
|
11002
10801
|
const attachSuffix = formatAgentAttachmentSuffix(m.attachments);
|
|
11003
10802
|
const taskSuffix = m.task_status ? ` [task #${m.task_number} status=${m.task_status}${formatAgentTaskAssigneeSuffix(m.task_assignee_id, m.task_assignee_name)}]` : "";
|
|
11004
10803
|
return `[target=${target} msg=${msgId} time=${time}${senderType}] ${formatAgentSenderHandle(m)}: ${content}${attachSuffix}${taskSuffix}${formatAgentReplyAffordanceSuffix(m)}${formatAgentTaskCurrentProjection(m.task_current_projection)}`;
|
|
@@ -11140,6 +10939,89 @@ function projectRaftMessagesInTarget(envelopes, target) {
|
|
|
11140
10939
|
} : envelope)).filter((m) => m !== null);
|
|
11141
10940
|
}
|
|
11142
10941
|
//#endregion
|
|
10942
|
+
//#region ../shared/src/agentOps/interrupt.ts
|
|
10943
|
+
/** Narrow any outcome (SDK or command registry) to an interrupt, without knowing the command. */
|
|
10944
|
+
function isInterrupted(outcome) {
|
|
10945
|
+
return Boolean(outcome) && typeof outcome === "object" && outcome.state === "interrupted" && typeof outcome.interrupt === "object";
|
|
10946
|
+
}
|
|
10947
|
+
/** Build the `unread_messages` interrupt from a Server freshness hold. */
|
|
10948
|
+
function unreadMessagesInterrupt(input) {
|
|
10949
|
+
const { hold, target } = input;
|
|
10950
|
+
const withheld = input.withheld === true || hold.freshnessContextMode === "withheld";
|
|
10951
|
+
const heldMessages = withheld ? [] : projectRaftMessagesInTarget(hold.heldMessages ?? [], target);
|
|
10952
|
+
const newMessageCount = withheld ? hold.withheldMessageCount ?? hold.newMessageCount ?? 0 : hold.newMessageCount ?? heldMessages.length;
|
|
10953
|
+
const omittedMessageCount = withheld ? 0 : hold.omittedMessageCount ?? 0;
|
|
10954
|
+
return {
|
|
10955
|
+
reason: "unread_messages",
|
|
10956
|
+
context: input.context,
|
|
10957
|
+
resume: input.resume,
|
|
10958
|
+
...input.cancel ? { cancel: input.cancel } : {},
|
|
10959
|
+
target,
|
|
10960
|
+
newMessageCount,
|
|
10961
|
+
heldMessages,
|
|
10962
|
+
omittedMessageCount,
|
|
10963
|
+
formalMentionCount: withheld ? 0 : hold.mentionAnnotation?.formalMentionCount ?? 0,
|
|
10964
|
+
seenUpToSeq: typeof hold.seenUpToSeq === "number" ? hold.seenUpToSeq : null,
|
|
10965
|
+
withheld,
|
|
10966
|
+
contextComplete: !withheld && heldMessages.length + omittedMessageCount >= newMessageCount
|
|
10967
|
+
};
|
|
10968
|
+
}
|
|
10969
|
+
/** `raft message send --send-draft` for the draft a held send saved, under its original key. */
|
|
10970
|
+
function sendDraftResume(target, idempotencyKey, extraArgv = []) {
|
|
10971
|
+
return {
|
|
10972
|
+
argv: [
|
|
10973
|
+
"message",
|
|
10974
|
+
"send",
|
|
10975
|
+
"--send-draft",
|
|
10976
|
+
"--target",
|
|
10977
|
+
target,
|
|
10978
|
+
"--expected-draft-key",
|
|
10979
|
+
idempotencyKey,
|
|
10980
|
+
...extraArgv
|
|
10981
|
+
],
|
|
10982
|
+
idempotencyKey
|
|
10983
|
+
};
|
|
10984
|
+
}
|
|
10985
|
+
/** `raft message send --discard-draft` for the draft a held send saved (compare-and-clear on its key). */
|
|
10986
|
+
function discardDraftCancel(target, idempotencyKey, extraArgv = []) {
|
|
10987
|
+
return { argv: [
|
|
10988
|
+
"message",
|
|
10989
|
+
"send",
|
|
10990
|
+
"--discard-draft",
|
|
10991
|
+
"--target",
|
|
10992
|
+
target,
|
|
10993
|
+
"--expected-draft-key",
|
|
10994
|
+
idempotencyKey,
|
|
10995
|
+
...extraArgv
|
|
10996
|
+
] };
|
|
10997
|
+
}
|
|
10998
|
+
/** `raft task claim` argv for a claim request (resume of a held claim). */
|
|
10999
|
+
function taskClaimArgv(target, taskNumbers, messageIds, extraArgv = []) {
|
|
11000
|
+
return [
|
|
11001
|
+
"task",
|
|
11002
|
+
"claim",
|
|
11003
|
+
"--target",
|
|
11004
|
+
target,
|
|
11005
|
+
...taskNumbers.flatMap((n) => ["--number", String(n)]),
|
|
11006
|
+
...messageIds.flatMap((id) => ["--message-id", id]),
|
|
11007
|
+
...extraArgv
|
|
11008
|
+
];
|
|
11009
|
+
}
|
|
11010
|
+
/** `raft task update` argv (resume of a held status update). */
|
|
11011
|
+
function taskUpdateArgv(target, taskNumber, status, extraArgv = []) {
|
|
11012
|
+
return [
|
|
11013
|
+
"task",
|
|
11014
|
+
"update",
|
|
11015
|
+
"--target",
|
|
11016
|
+
target,
|
|
11017
|
+
"--number",
|
|
11018
|
+
String(taskNumber),
|
|
11019
|
+
"--status",
|
|
11020
|
+
status,
|
|
11021
|
+
...extraArgv
|
|
11022
|
+
];
|
|
11023
|
+
}
|
|
11024
|
+
//#endregion
|
|
11143
11025
|
//#region ../shared/src/agentOps/frontier.ts
|
|
11144
11026
|
const MAX_EXACT_SEQS = 2500;
|
|
11145
11027
|
function positiveInt(value) {
|
|
@@ -11191,11 +11073,12 @@ var SeenFrontier = class SeenFrontier {
|
|
|
11191
11073
|
}
|
|
11192
11074
|
}
|
|
11193
11075
|
/**
|
|
11194
|
-
* Attest that the model saw the context
|
|
11195
|
-
*
|
|
11196
|
-
*
|
|
11197
|
-
*
|
|
11198
|
-
* (`contextComplete: false`),
|
|
11076
|
+
* Attest that the model saw the context of an interrupt (`outcome.interrupt`
|
|
11077
|
+
* of an `interrupted` send, claim or task write). Call it only after
|
|
11078
|
+
* `interrupt.context` actually reached the model (the SDK cannot know that,
|
|
11079
|
+
* so it never records this implicitly). Returns false and records nothing
|
|
11080
|
+
* when the context was withheld, not fully shown (`contextComplete: false`),
|
|
11081
|
+
* or the Server sent no boundary.
|
|
11199
11082
|
*/
|
|
11200
11083
|
recordHeld(held) {
|
|
11201
11084
|
if (held.withheld || held.contextComplete === false || held.seenUpToSeq === null) return false;
|
|
@@ -11564,7 +11447,8 @@ async function readHistory(client, request, frontier) {
|
|
|
11564
11447
|
...request.after === void 0 ? {} : { after: String(request.after) },
|
|
11565
11448
|
...request.before === void 0 ? {} : { before: String(request.before) },
|
|
11566
11449
|
...request.around === void 0 ? {} : { around: String(request.around) },
|
|
11567
|
-
...request.limit === void 0 ? {} : { limit: String(request.limit) }
|
|
11450
|
+
...request.limit === void 0 ? {} : { limit: String(request.limit) },
|
|
11451
|
+
...request.consume === false ? { consume: "false" } : {}
|
|
11568
11452
|
});
|
|
11569
11453
|
if (!result.ok) return failureFromClientResult(result);
|
|
11570
11454
|
const data = result.data;
|
|
@@ -11576,7 +11460,7 @@ async function readHistory(client, request, frontier) {
|
|
|
11576
11460
|
lastReadSeq: typeof data.last_read_seq === "number" ? data.last_read_seq : null,
|
|
11577
11461
|
modelSeenUpToSeq: typeof data.model_seen_up_to_seq === "number" ? data.model_seen_up_to_seq : null
|
|
11578
11462
|
};
|
|
11579
|
-
recordHistorySeen(frontier, request.target, page, request.around !== void 0);
|
|
11463
|
+
if (request.consume !== false) recordHistorySeen(frontier, request.target, page, request.around !== void 0);
|
|
11580
11464
|
return {
|
|
11581
11465
|
ok: true,
|
|
11582
11466
|
state: page.messages.length > 0 ? "page" : "empty",
|
|
@@ -11587,6 +11471,7 @@ async function readHistory(client, request, frontier) {
|
|
|
11587
11471
|
}
|
|
11588
11472
|
/** Attempts for a keyed send whose request never reached the Server (transport failure only). */
|
|
11589
11473
|
const SEND_TRANSPORT_ATTEMPTS = 3;
|
|
11474
|
+
/** Today's held text (unchanged); it is the interrupt's `context` and the outcome's `text`. */
|
|
11590
11475
|
function heldText(held, action) {
|
|
11591
11476
|
const noun = held.newMessageCount === 1 ? "message" : "messages";
|
|
11592
11477
|
const head = `Held — ${held.newMessageCount} unread ${noun} in ${held.target}. ${action}`;
|
|
@@ -11599,38 +11484,29 @@ function heldText(held, action) {
|
|
|
11599
11484
|
lines.push(`Full text: raft message read --target "${held.target}"`);
|
|
11600
11485
|
return lines.join("\n");
|
|
11601
11486
|
}
|
|
11602
|
-
|
|
11487
|
+
/**
|
|
11488
|
+
* A Server freshness hold as the `unread_messages` interrupt: the structured
|
|
11489
|
+
* details, today's held text as `context`, and the given resume / cancel.
|
|
11490
|
+
*/
|
|
11491
|
+
function heldInterrupt(target, data, action, resume, cancel) {
|
|
11492
|
+
const interrupt = unreadMessagesInterrupt({
|
|
11493
|
+
target,
|
|
11494
|
+
hold: data,
|
|
11495
|
+
context: "",
|
|
11496
|
+
resume,
|
|
11497
|
+
...cancel ? { cancel } : {}
|
|
11498
|
+
});
|
|
11603
11499
|
return {
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
args: {
|
|
11607
|
-
target: held.target,
|
|
11608
|
-
...held.continuation
|
|
11609
|
-
},
|
|
11610
|
-
why: held.withheld ? "Newer messages exist in this conversation but were withheld; read them, then send again with the same idempotencyKey." : !held.contextComplete ? "Newer messages arrived in this conversation and not all of them are shown here; read the conversation, then send again with the same idempotencyKey." : "Newer messages arrived in this conversation. Show the held messages to the model, call frontier.recordHeld(held) to attest that, then send again with these args (same idempotencyKey, seen.upToSeq)."
|
|
11500
|
+
...interrupt,
|
|
11501
|
+
context: heldText(interrupt, action)
|
|
11611
11502
|
};
|
|
11612
11503
|
}
|
|
11613
|
-
function
|
|
11614
|
-
const withheld = data.freshnessContextMode === "withheld";
|
|
11615
|
-
const heldMessages = projectRaftMessagesInTarget(data.heldMessages ?? [], target);
|
|
11616
|
-
const seenUpToSeq = typeof data.seenUpToSeq === "number" ? data.seenUpToSeq : null;
|
|
11617
|
-
const newMessageCount = withheld ? data.withheldMessageCount ?? 0 : data.newMessageCount ?? heldMessages.length;
|
|
11618
|
-
const omittedMessageCount = data.omittedMessageCount ?? 0;
|
|
11619
|
-
const contextComplete = !withheld && heldMessages.length + omittedMessageCount >= newMessageCount;
|
|
11504
|
+
function heldSendNext(interrupt) {
|
|
11620
11505
|
return {
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
...contextComplete && seenUpToSeq !== null ? { seen: { upToSeq: seenUpToSeq } } : {}
|
|
11626
|
-
},
|
|
11627
|
-
newMessageCount,
|
|
11628
|
-
heldMessages,
|
|
11629
|
-
omittedMessageCount,
|
|
11630
|
-
formalMentionCount: data.mentionAnnotation?.formalMentionCount ?? 0,
|
|
11631
|
-
seenUpToSeq,
|
|
11632
|
-
withheld,
|
|
11633
|
-
contextComplete
|
|
11506
|
+
kind: "resend",
|
|
11507
|
+
command: `raft message read --target "${interrupt.target}"`,
|
|
11508
|
+
args: { target: interrupt.target },
|
|
11509
|
+
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."
|
|
11634
11510
|
};
|
|
11635
11511
|
}
|
|
11636
11512
|
function isHeldResponse(data) {
|
|
@@ -11657,7 +11533,7 @@ function sentOutcome(target, data) {
|
|
|
11657
11533
|
text: `Message sent to ${target}. Message ID: ${sent.messageId}${warn}`
|
|
11658
11534
|
};
|
|
11659
11535
|
}
|
|
11660
|
-
async function sendMessage(client, request, frontier
|
|
11536
|
+
async function sendMessage(client, request, frontier) {
|
|
11661
11537
|
if (!request.target?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A target is required to send a message." }));
|
|
11662
11538
|
if (typeof request.content !== "string" || !request.content.trim() && !request.attachmentIds?.length) return failureOutcome(opError("INVALID_REQUEST", { message: "Message content (or an attachment) is required." }));
|
|
11663
11539
|
const idempotencyKey = request.idempotencyKey?.trim() || crypto.randomUUID();
|
|
@@ -11672,42 +11548,20 @@ async function sendMessage(client, request, frontier, internal = {}) {
|
|
|
11672
11548
|
idempotencyKey,
|
|
11673
11549
|
...request.mentions?.length ? { mentions: request.mentions } : {},
|
|
11674
11550
|
...attestation.seenUpToSeq === void 0 ? {} : { seenUpToSeq: attestation.seenUpToSeq },
|
|
11675
|
-
...attestation.seenExactSeqs.length > 0 ? { seenExactSeqs: attestation.seenExactSeqs.slice(0, 2500) } : {}
|
|
11676
|
-
...internal.sendDraft ? { sendDraft: true } : {},
|
|
11677
|
-
...internal.continueAnyway ? { continueAnyway: true } : {},
|
|
11678
|
-
...internal.reholdCount ? { draftReholdCount: internal.reholdCount } : {}
|
|
11551
|
+
...attestation.seenExactSeqs.length > 0 ? { seenExactSeqs: attestation.seenExactSeqs.slice(0, 2500) } : {}
|
|
11679
11552
|
};
|
|
11680
11553
|
let result = await client.messages.sendV2(body);
|
|
11681
11554
|
for (let attempt = 1; !result.ok && result.error.kind === "transport" && attempt < SEND_TRANSPORT_ATTEMPTS; attempt += 1) result = await client.messages.sendV2(body);
|
|
11682
11555
|
if (!result.ok) return failureFromClientResult(result);
|
|
11683
11556
|
const data = result.data;
|
|
11684
11557
|
if (isHeldResponse(data)) {
|
|
11685
|
-
const
|
|
11686
|
-
const keyed = {
|
|
11687
|
-
...request,
|
|
11688
|
-
idempotencyKey
|
|
11689
|
-
};
|
|
11690
|
-
const base = projectHeld(request.target, data, idempotencyKey);
|
|
11691
|
-
const held = {
|
|
11692
|
-
...base,
|
|
11693
|
-
resend: (options) => sendMessage(client, options.seen === "held" && base.contextComplete && typeof data.seenUpToSeq === "number" ? {
|
|
11694
|
-
...keyed,
|
|
11695
|
-
seen: {
|
|
11696
|
-
upToSeq: data.seenUpToSeq,
|
|
11697
|
-
exactSeqs: attestation.seenExactSeqs
|
|
11698
|
-
}
|
|
11699
|
-
} : keyed, frontier, {
|
|
11700
|
-
sendDraft: true,
|
|
11701
|
-
reholdCount,
|
|
11702
|
-
...options.seen === "anyway" ? { continueAnyway: true } : {}
|
|
11703
|
-
})
|
|
11704
|
-
};
|
|
11558
|
+
const interrupt = heldInterrupt(request.target, data, "Your message was not sent.", sendDraftResume(request.target, idempotencyKey), discardDraftCancel(request.target, idempotencyKey));
|
|
11705
11559
|
return {
|
|
11706
11560
|
ok: true,
|
|
11707
|
-
state: "
|
|
11708
|
-
|
|
11709
|
-
next:
|
|
11710
|
-
text:
|
|
11561
|
+
state: "interrupted",
|
|
11562
|
+
interrupt,
|
|
11563
|
+
next: heldSendNext(interrupt),
|
|
11564
|
+
text: interrupt.context
|
|
11711
11565
|
};
|
|
11712
11566
|
}
|
|
11713
11567
|
if (data.state === "sent") return sentOutcome(request.target, data);
|
|
@@ -11884,6 +11738,24 @@ function formatAgentTaskHistory(data) {
|
|
|
11884
11738
|
//#endregion
|
|
11885
11739
|
//#region ../shared/src/agentOps/tasks.ts
|
|
11886
11740
|
const TASK_CLAIM_REASON_ALREADY_CLAIMED_BY_YOU = "already claimed by you";
|
|
11741
|
+
/**
|
|
11742
|
+
* A held task call: the interrupt whose resume is the identical command, with
|
|
11743
|
+
* no cancel (a held task call saved nothing). `context` is today's held text.
|
|
11744
|
+
*/
|
|
11745
|
+
function heldTaskInterrupt(target, data, action, after, argv) {
|
|
11746
|
+
const interrupt = unreadMessagesInterrupt({
|
|
11747
|
+
target,
|
|
11748
|
+
hold: data,
|
|
11749
|
+
context: "",
|
|
11750
|
+
resume: { argv }
|
|
11751
|
+
});
|
|
11752
|
+
const noun = interrupt.newMessageCount === 1 ? "message" : "messages";
|
|
11753
|
+
const context = `Held — ${interrupt.newMessageCount} unread ${noun} in ${target}. ${action}\nRead them with: raft message read --target "${target}"\n${after}`;
|
|
11754
|
+
return {
|
|
11755
|
+
...interrupt,
|
|
11756
|
+
context
|
|
11757
|
+
};
|
|
11758
|
+
}
|
|
11887
11759
|
function rowState(result) {
|
|
11888
11760
|
if (result.success) return "claimed";
|
|
11889
11761
|
if (result.reason === TASK_CLAIM_REASON_ALREADY_CLAIMED_BY_YOU) return "already_yours";
|
|
@@ -11924,23 +11796,18 @@ async function claimTasks(client, request) {
|
|
|
11924
11796
|
if (!result.ok) return failureFromClientResult(result);
|
|
11925
11797
|
const data = result.data;
|
|
11926
11798
|
if (isHeldResponse(data)) {
|
|
11927
|
-
const
|
|
11928
|
-
const held = {
|
|
11929
|
-
...heldBase,
|
|
11930
|
-
request,
|
|
11931
|
-
retry: () => claimTasks(client, request)
|
|
11932
|
-
};
|
|
11799
|
+
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));
|
|
11933
11800
|
return {
|
|
11934
11801
|
ok: true,
|
|
11935
|
-
state: "
|
|
11936
|
-
|
|
11802
|
+
state: "interrupted",
|
|
11803
|
+
interrupt,
|
|
11937
11804
|
next: {
|
|
11938
11805
|
kind: "retry_claim",
|
|
11939
11806
|
command: `raft message read --target "${request.target}"`,
|
|
11940
|
-
args: {
|
|
11941
|
-
why: "Unread messages in this channel may change the task; read them (frontier.recordHeld(
|
|
11807
|
+
args: { target: request.target },
|
|
11808
|
+
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."
|
|
11942
11809
|
},
|
|
11943
|
-
text:
|
|
11810
|
+
text: interrupt.context
|
|
11944
11811
|
};
|
|
11945
11812
|
}
|
|
11946
11813
|
const rows = (data.results ?? []).map((row) => {
|
|
@@ -12077,23 +11944,20 @@ async function assignTask(client, request) {
|
|
|
12077
11944
|
text: formatAgentTaskAssigned(request.taskNumber, assignee)
|
|
12078
11945
|
};
|
|
12079
11946
|
}
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
const
|
|
12083
|
-
...base,
|
|
12084
|
-
request
|
|
12085
|
-
};
|
|
11947
|
+
/** A held task write: the interrupt whose resume is the identical command; nothing to cancel. */
|
|
11948
|
+
function heldTaskWrite(target, data, action, kind, argv) {
|
|
11949
|
+
const interrupt = heldTaskInterrupt(target, data, action, "After reviewing, repeat the operation if it is still correct.", argv);
|
|
12086
11950
|
return {
|
|
12087
11951
|
ok: true,
|
|
12088
|
-
state: "
|
|
12089
|
-
|
|
11952
|
+
state: "interrupted",
|
|
11953
|
+
interrupt,
|
|
12090
11954
|
next: {
|
|
12091
11955
|
kind,
|
|
12092
|
-
command: `raft message read --target "${
|
|
12093
|
-
args: {
|
|
12094
|
-
why:
|
|
11956
|
+
command: `raft message read --target "${target}"`,
|
|
11957
|
+
args: { target },
|
|
11958
|
+
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."
|
|
12095
11959
|
},
|
|
12096
|
-
text:
|
|
11960
|
+
text: interrupt.context
|
|
12097
11961
|
};
|
|
12098
11962
|
}
|
|
12099
11963
|
async function updateTaskStatus(client, request) {
|
|
@@ -12105,7 +11969,7 @@ async function updateTaskStatus(client, request) {
|
|
|
12105
11969
|
status: request.status
|
|
12106
11970
|
});
|
|
12107
11971
|
if (!result.ok) return failureFromClientResult(result);
|
|
12108
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request, result.data, "The status change was not applied.", "retry_update_status");
|
|
11972
|
+
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));
|
|
12109
11973
|
return {
|
|
12110
11974
|
ok: true,
|
|
12111
11975
|
state: "updated",
|
|
@@ -12117,6 +11981,18 @@ async function updateTaskStatus(client, request) {
|
|
|
12117
11981
|
text: formatAgentTaskStatusUpdated(request.taskNumber, request.status)
|
|
12118
11982
|
};
|
|
12119
11983
|
}
|
|
11984
|
+
function taskAmendArgv(request) {
|
|
11985
|
+
return [
|
|
11986
|
+
"task",
|
|
11987
|
+
"amend",
|
|
11988
|
+
"--target",
|
|
11989
|
+
request.target,
|
|
11990
|
+
"--number",
|
|
11991
|
+
String(request.taskNumber),
|
|
11992
|
+
...request.title === void 0 ? [] : ["--title", request.title],
|
|
11993
|
+
...request.description === void 0 ? [] : request.description === null ? ["--clear-description"] : ["--description", request.description]
|
|
11994
|
+
];
|
|
11995
|
+
}
|
|
12120
11996
|
async function amendTask(client, request) {
|
|
12121
11997
|
const invalid = requireTaskRef(request);
|
|
12122
11998
|
if (invalid) return invalid;
|
|
@@ -12128,7 +12004,7 @@ async function amendTask(client, request) {
|
|
|
12128
12004
|
...request.description === void 0 ? {} : { description: request.description }
|
|
12129
12005
|
});
|
|
12130
12006
|
if (!result.ok) return failureFromClientResult(result);
|
|
12131
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request, result.data, "The amendment was not applied.", "retry_amend");
|
|
12007
|
+
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The amendment was not applied.", "retry_amend", taskAmendArgv(request));
|
|
12132
12008
|
return {
|
|
12133
12009
|
ok: true,
|
|
12134
12010
|
state: "amended",
|
|
@@ -13285,12 +13161,101 @@ async function attachmentComments(client, request) {
|
|
|
13285
13161
|
};
|
|
13286
13162
|
}
|
|
13287
13163
|
//#endregion
|
|
13164
|
+
//#region ../shared/src/zonedTime.ts
|
|
13165
|
+
const MS_PER_SECOND = 1e3;
|
|
13166
|
+
const MS_PER_MINUTE = 6e4;
|
|
13167
|
+
const MS_PER_DAY = 864e5;
|
|
13168
|
+
const formatters = /* @__PURE__ */ new Map();
|
|
13169
|
+
function formatterFor(timeZone) {
|
|
13170
|
+
let formatter = formatters.get(timeZone);
|
|
13171
|
+
if (!formatter) {
|
|
13172
|
+
formatter = new Intl.DateTimeFormat("en-US", {
|
|
13173
|
+
timeZone,
|
|
13174
|
+
hourCycle: "h23",
|
|
13175
|
+
era: "short",
|
|
13176
|
+
year: "numeric",
|
|
13177
|
+
month: "numeric",
|
|
13178
|
+
day: "numeric",
|
|
13179
|
+
hour: "numeric",
|
|
13180
|
+
minute: "numeric",
|
|
13181
|
+
second: "numeric"
|
|
13182
|
+
});
|
|
13183
|
+
formatters.set(timeZone, formatter);
|
|
13184
|
+
}
|
|
13185
|
+
return formatter;
|
|
13186
|
+
}
|
|
13187
|
+
/** Days from 1970-01-01 to the proleptic Gregorian date (H. Hinnant's days_from_civil). */
|
|
13188
|
+
function daysFromCivil(year, month, day) {
|
|
13189
|
+
const y = month <= 2 ? year - 1 : year;
|
|
13190
|
+
const era = Math.floor(y / 400);
|
|
13191
|
+
const yoe = y - era * 400;
|
|
13192
|
+
const mp = (month + 9) % 12;
|
|
13193
|
+
const doy = Math.floor((153 * mp + 2) / 5) + day - 1;
|
|
13194
|
+
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
13195
|
+
return era * 146097 + doe - 719468;
|
|
13196
|
+
}
|
|
13197
|
+
/** The wall clock as milliseconds on a UTC timeline (no Date, so no 0-99 year quirk or range limit). */
|
|
13198
|
+
function wallClockMs(wall) {
|
|
13199
|
+
return daysFromCivil(wall.year, wall.month, wall.day) * MS_PER_DAY + wall.hour * 36e5 + wall.minute * MS_PER_MINUTE + wall.second * MS_PER_SECOND + wall.millisecond;
|
|
13200
|
+
}
|
|
13201
|
+
function floorMod(value, modulus) {
|
|
13202
|
+
return (value % modulus + modulus) % modulus;
|
|
13203
|
+
}
|
|
13204
|
+
/** Wall clock of `epochMs` in `timeZone` plus the exact offset in ms (seconds precision). */
|
|
13205
|
+
function wallClockAt(epochMs, timeZone) {
|
|
13206
|
+
const parts = {};
|
|
13207
|
+
for (const part of formatterFor(timeZone).formatToParts(epochMs)) parts[part.type] = part.value;
|
|
13208
|
+
const eraYear = Number(parts.year);
|
|
13209
|
+
const wall = {
|
|
13210
|
+
year: /^b/i.test(parts.era ?? "") ? 1 - eraYear : eraYear,
|
|
13211
|
+
month: Number(parts.month),
|
|
13212
|
+
day: Number(parts.day),
|
|
13213
|
+
hour: Number(parts.hour),
|
|
13214
|
+
minute: Number(parts.minute),
|
|
13215
|
+
second: Number(parts.second),
|
|
13216
|
+
millisecond: floorMod(epochMs, MS_PER_SECOND)
|
|
13217
|
+
};
|
|
13218
|
+
return {
|
|
13219
|
+
wall,
|
|
13220
|
+
offsetMs: wallClockMs(wall) - epochMs
|
|
13221
|
+
};
|
|
13222
|
+
}
|
|
13223
|
+
function offsetMinutesOf(offsetMs) {
|
|
13224
|
+
return -Math.trunc(-offsetMs / MS_PER_MINUTE);
|
|
13225
|
+
}
|
|
13226
|
+
/** The wall clock and getTimezoneOffset-style offset of `epochMs` in `timeZone`. */
|
|
13227
|
+
function zonedInstant(epochMs, timeZone) {
|
|
13228
|
+
const { wall, offsetMs } = wallClockAt(epochMs, timeZone);
|
|
13229
|
+
return {
|
|
13230
|
+
...wall,
|
|
13231
|
+
offsetMinutes: offsetMinutesOf(offsetMs)
|
|
13232
|
+
};
|
|
13233
|
+
}
|
|
13234
|
+
function pad2(n) {
|
|
13235
|
+
return String(n).padStart(2, "0");
|
|
13236
|
+
}
|
|
13237
|
+
/** `+08:00` / `-04:00` / `+05:30`, as the CLI has always printed offsets. */
|
|
13238
|
+
function formatUtcOffset(offsetMinutes) {
|
|
13239
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
13240
|
+
const abs = Math.abs(offsetMinutes);
|
|
13241
|
+
return `${sign}${pad2(Math.floor(abs / 60))}:${pad2(abs % 60)}`;
|
|
13242
|
+
}
|
|
13243
|
+
//#endregion
|
|
13288
13244
|
//#region ../shared/src/agentText/search.ts
|
|
13289
|
-
/**
|
|
13290
|
-
|
|
13245
|
+
/**
|
|
13246
|
+
* Wall-clock rendering with offset, as the CLI prints search hit times. With
|
|
13247
|
+
* `timeZone` (an IANA name) the time is rendered in that zone; without it, in
|
|
13248
|
+
* the process's local zone (the SDK's historical behaviour). The two agree
|
|
13249
|
+
* byte for byte when `timeZone` is the process zone.
|
|
13250
|
+
*/
|
|
13251
|
+
function formatLocalTimeWithOffset(iso, timeZone) {
|
|
13291
13252
|
const d = new Date(iso);
|
|
13292
13253
|
if (isNaN(d.getTime())) return iso;
|
|
13293
13254
|
const pad = (n) => String(n).padStart(2, "0");
|
|
13255
|
+
if (timeZone !== void 0) {
|
|
13256
|
+
const z = zonedInstant(d.getTime(), timeZone);
|
|
13257
|
+
return `${z.year}-${pad(z.month)}-${pad(z.day)} ${pad(z.hour)}:${pad(z.minute)}:${pad(z.second)} ${formatUtcOffset(z.offsetMinutes)}`;
|
|
13258
|
+
}
|
|
13294
13259
|
const offsetMinutes = -d.getTimezoneOffset();
|
|
13295
13260
|
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
13296
13261
|
const absOffset = Math.abs(offsetMinutes);
|
|
@@ -13413,8 +13378,11 @@ function renderSearchPreview(content, query) {
|
|
|
13413
13378
|
trailingOmit
|
|
13414
13379
|
].join("");
|
|
13415
13380
|
}
|
|
13416
|
-
/**
|
|
13417
|
-
|
|
13381
|
+
/**
|
|
13382
|
+
* Search results with <match>/<omit /> preview markup. Hit times render in
|
|
13383
|
+
* `timeZone` when given, else in the process's local zone.
|
|
13384
|
+
*/
|
|
13385
|
+
function formatAgentSearchResults(query, data, offset, sort, limit, timeZone) {
|
|
13418
13386
|
const trimmedQuery = query.trim();
|
|
13419
13387
|
const oldestShown = data.results?.length ? data.results[data.results.length - 1]?.createdAt : void 0;
|
|
13420
13388
|
const nextPageHint = sort === "recent" && oldestShown ? `page with --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 --offset ${(offset ?? 0) + (data.results?.length ?? 0)}`;
|
|
@@ -13434,7 +13402,7 @@ function formatAgentSearchResults(query, data, offset, sort, limit) {
|
|
|
13434
13402
|
`<result ref="${ref}">`,
|
|
13435
13403
|
`Source: ${renderSearchSource(result)}`,
|
|
13436
13404
|
`Sender: ${sender}${senderType}`,
|
|
13437
|
-
`Time: ${result.createdAt ? formatLocalTimeWithOffset(result.createdAt) : "-"}`,
|
|
13405
|
+
`Time: ${result.createdAt ? formatLocalTimeWithOffset(result.createdAt, timeZone) : "-"}`,
|
|
13438
13406
|
...taskProjection ? [taskProjection] : [],
|
|
13439
13407
|
"",
|
|
13440
13408
|
"<preview>",
|
|
@@ -14145,9 +14113,9 @@ function createRaft(options) {
|
|
|
14145
14113
|
...request,
|
|
14146
14114
|
idempotencyKey: pending.idempotencyKey
|
|
14147
14115
|
} : request, frontier);
|
|
14148
|
-
if (outcome.ok && outcome.state === "
|
|
14116
|
+
if (outcome.ok && outcome.state === "interrupted" && outcome.interrupt.resume.idempotencyKey) session.rememberContinuation({
|
|
14149
14117
|
target: request.target,
|
|
14150
|
-
idempotencyKey: outcome.
|
|
14118
|
+
idempotencyKey: outcome.interrupt.resume.idempotencyKey,
|
|
14151
14119
|
contentHash,
|
|
14152
14120
|
heldAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14153
14121
|
});
|
|
@@ -14298,6 +14266,7 @@ exports.describeRaftRoute = describeRaftRoute;
|
|
|
14298
14266
|
exports.hasAgentMessageIdentity = hasAgentMessageIdentity;
|
|
14299
14267
|
exports.hashRaftSendContent = hashRaftSendContent;
|
|
14300
14268
|
exports.inferAttachmentMimeType = inferAttachmentMimeType;
|
|
14269
|
+
exports.isInterrupted = isInterrupted;
|
|
14301
14270
|
exports.joinRaftChannelByTarget = joinRaftChannelByTarget;
|
|
14302
14271
|
exports.listRaftRoutes = listRaftRoutes;
|
|
14303
14272
|
exports.parseRaftRegularChannelTarget = parseRaftRegularChannelTarget;
|