@botiverse/raft-sdk 0.3.1 → 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 +331 -318
- package/dist/esm/index.js +331 -319
- package/dist/index.d.ts +100 -430
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -4477,12 +4477,6 @@ const destructive = {
|
|
|
4477
4477
|
destructive: true,
|
|
4478
4478
|
audience: "both"
|
|
4479
4479
|
};
|
|
4480
|
-
const managedNaturalWrite = {
|
|
4481
|
-
sideEffect: "write",
|
|
4482
|
-
idempotency: "natural",
|
|
4483
|
-
destructive: false,
|
|
4484
|
-
audience: "managed"
|
|
4485
|
-
};
|
|
4486
4480
|
const managedWrite = {
|
|
4487
4481
|
sideEffect: "write",
|
|
4488
4482
|
idempotency: "none",
|
|
@@ -4543,15 +4537,6 @@ const AGENT_API_ROUTE_META = {
|
|
|
4543
4537
|
taskConvert: write,
|
|
4544
4538
|
taskAmend: destructive,
|
|
4545
4539
|
taskHistory: read,
|
|
4546
|
-
migrationBegin: {
|
|
4547
|
-
sideEffect: "write",
|
|
4548
|
-
idempotency: "none",
|
|
4549
|
-
destructive: true,
|
|
4550
|
-
audience: "managed"
|
|
4551
|
-
},
|
|
4552
|
-
migrationStatus: read,
|
|
4553
|
-
migrationReady: managedNaturalWrite,
|
|
4554
|
-
migrationArrived: managedNaturalWrite,
|
|
4555
4540
|
reminderList: read,
|
|
4556
4541
|
reminderCreate: managedWrite,
|
|
4557
4542
|
reminderCancel: naturalDestructive,
|
|
@@ -5005,7 +4990,14 @@ const agentApiHistoryQuerySchema = passthroughObject({
|
|
|
5005
4990
|
before: optionalStringSchema,
|
|
5006
4991
|
after: optionalStringSchema,
|
|
5007
4992
|
around: optionalStringSchema,
|
|
5008
|
-
limit: optionalStringSchema
|
|
4993
|
+
limit: optionalStringSchema,
|
|
4994
|
+
/**
|
|
4995
|
+
* `"false"` reads without consuming: the Server returns the page but does
|
|
4996
|
+
* not advance the agent's read cursor, and reports no
|
|
4997
|
+
* `model_seen_up_to_seq`. For reads whose output may never reach the model
|
|
4998
|
+
* (code a hosted agent wrote). Absent or `"true"` keeps the default.
|
|
4999
|
+
*/
|
|
5000
|
+
consume: _enum(["true", "false"]).optional()
|
|
5009
5001
|
});
|
|
5010
5002
|
const agentApiKnowledgeGetQuerySchema = passthroughObject({
|
|
5011
5003
|
topic: string().trim().min(1),
|
|
@@ -6131,61 +6123,6 @@ const agentApiAppConfigResponseSchema = passthroughObject({
|
|
|
6131
6123
|
overrides: record(string(), agentApiAppConfigValueSchema),
|
|
6132
6124
|
effective: record(string(), agentApiAppConfigValueSchema)
|
|
6133
6125
|
});
|
|
6134
|
-
const agentApiMigrationStateSchema = _enum([
|
|
6135
|
-
"provisioning",
|
|
6136
|
-
"prep",
|
|
6137
|
-
"ready",
|
|
6138
|
-
"in_transit",
|
|
6139
|
-
"arriving",
|
|
6140
|
-
"starting",
|
|
6141
|
-
"cancel_requested_pre_flip",
|
|
6142
|
-
"cancel_requested_post_flip",
|
|
6143
|
-
"canceled_pre_flip",
|
|
6144
|
-
"canceled_post_flip",
|
|
6145
|
-
"completed",
|
|
6146
|
-
"aborted",
|
|
6147
|
-
"failed"
|
|
6148
|
-
]);
|
|
6149
|
-
const agentApiMigrationSummarySchema = passthroughObject({
|
|
6150
|
-
id: string(),
|
|
6151
|
-
agentId: string(),
|
|
6152
|
-
sourceMachineId: string(),
|
|
6153
|
-
targetMachineId: string(),
|
|
6154
|
-
state: agentApiMigrationStateSchema,
|
|
6155
|
-
manifestPath: nullableStringSchema,
|
|
6156
|
-
manifestSha256: nullableStringSchema,
|
|
6157
|
-
arrivalReportPath: nullableStringSchema,
|
|
6158
|
-
arrivalReportSha256: nullableStringSchema,
|
|
6159
|
-
abortReason: nullableStringSchema,
|
|
6160
|
-
failureReason: nullableStringSchema,
|
|
6161
|
-
prepDeadlineAt: string().datetime(),
|
|
6162
|
-
transferDeadlineAt: string().datetime(),
|
|
6163
|
-
arrivalDeadlineAt: string().datetime(),
|
|
6164
|
-
readyAt: nullableStringSchema,
|
|
6165
|
-
flippedAt: nullableStringSchema,
|
|
6166
|
-
arrivedAt: nullableStringSchema,
|
|
6167
|
-
completedAt: nullableStringSchema,
|
|
6168
|
-
abortedAt: nullableStringSchema,
|
|
6169
|
-
revision: number$1().int().positive(),
|
|
6170
|
-
createdAt: string().datetime(),
|
|
6171
|
-
updatedAt: string().datetime()
|
|
6172
|
-
});
|
|
6173
|
-
const agentApiMigrationBeginBodySchema = passthroughObject({
|
|
6174
|
-
targetMachineId: string().trim().min(1),
|
|
6175
|
-
prepDeadlineMs: number$1().int().positive().optional(),
|
|
6176
|
-
transferDeadlineMs: number$1().int().positive().optional(),
|
|
6177
|
-
arrivalDeadlineMs: number$1().int().positive().optional()
|
|
6178
|
-
});
|
|
6179
|
-
const agentApiMigrationReadyBodySchema = passthroughObject({
|
|
6180
|
-
manifestPath: string().trim().min(1),
|
|
6181
|
-
manifestSha256: optionalStringSchema
|
|
6182
|
-
});
|
|
6183
|
-
const agentApiMigrationArrivedBodySchema = passthroughObject({
|
|
6184
|
-
reportPath: optionalStringSchema,
|
|
6185
|
-
reportSha256: optionalStringSchema
|
|
6186
|
-
});
|
|
6187
|
-
const agentApiMigrationResponseSchema = passthroughObject({ migration: agentApiMigrationSummarySchema });
|
|
6188
|
-
const agentApiMigrationStatusResponseSchema = passthroughObject({ migration: agentApiMigrationSummarySchema.nullable() });
|
|
6189
6126
|
const agentApiPushWebhookRegisterBodySchema = object({
|
|
6190
6127
|
/** Public HTTPS endpoint that receives `raft-agent-inbox-notice.v1` POSTs. */
|
|
6191
6128
|
url: string().trim().min(1),
|
|
@@ -6787,58 +6724,6 @@ const agentApiContract = {
|
|
|
6787
6724
|
request: { query: agentApiTaskHistoryQuerySchema },
|
|
6788
6725
|
response: { body: agentApiTaskHistoryResponseSchema }
|
|
6789
6726
|
}),
|
|
6790
|
-
migrationBegin: route({
|
|
6791
|
-
key: "migrationBegin",
|
|
6792
|
-
method: "POST",
|
|
6793
|
-
path: "/migrations",
|
|
6794
|
-
client: {
|
|
6795
|
-
resource: "migrations",
|
|
6796
|
-
method: "begin"
|
|
6797
|
-
},
|
|
6798
|
-
capability: "server",
|
|
6799
|
-
description: "Begin a migration for the bound agent credential.",
|
|
6800
|
-
request: { body: agentApiMigrationBeginBodySchema },
|
|
6801
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6802
|
-
}),
|
|
6803
|
-
migrationStatus: route({
|
|
6804
|
-
key: "migrationStatus",
|
|
6805
|
-
method: "GET",
|
|
6806
|
-
path: "/migrations/current",
|
|
6807
|
-
client: {
|
|
6808
|
-
resource: "migrations",
|
|
6809
|
-
method: "status"
|
|
6810
|
-
},
|
|
6811
|
-
capability: "read",
|
|
6812
|
-
description: "Read the active migration for the bound agent credential, if any.",
|
|
6813
|
-
request: {},
|
|
6814
|
-
response: { body: agentApiMigrationStatusResponseSchema }
|
|
6815
|
-
}),
|
|
6816
|
-
migrationReady: route({
|
|
6817
|
-
key: "migrationReady",
|
|
6818
|
-
method: "POST",
|
|
6819
|
-
path: "/migrations/ready",
|
|
6820
|
-
client: {
|
|
6821
|
-
resource: "migrations",
|
|
6822
|
-
method: "ready"
|
|
6823
|
-
},
|
|
6824
|
-
capability: "read",
|
|
6825
|
-
description: "Mark the bound agent's active migration prep phase ready.",
|
|
6826
|
-
request: { body: agentApiMigrationReadyBodySchema },
|
|
6827
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6828
|
-
}),
|
|
6829
|
-
migrationArrived: route({
|
|
6830
|
-
key: "migrationArrived",
|
|
6831
|
-
method: "POST",
|
|
6832
|
-
path: "/migrations/arrived",
|
|
6833
|
-
client: {
|
|
6834
|
-
resource: "migrations",
|
|
6835
|
-
method: "arrived"
|
|
6836
|
-
},
|
|
6837
|
-
capability: "read",
|
|
6838
|
-
description: "Mark the bound agent's active migration arrival phase complete.",
|
|
6839
|
-
request: { body: agentApiMigrationArrivedBodySchema },
|
|
6840
|
-
response: { body: agentApiMigrationResponseSchema }
|
|
6841
|
-
}),
|
|
6842
6727
|
reminderList: route({
|
|
6843
6728
|
key: "reminderList",
|
|
6844
6729
|
method: "GET",
|
|
@@ -8871,106 +8756,6 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
8871
8756
|
"body": true
|
|
8872
8757
|
}
|
|
8873
8758
|
},
|
|
8874
|
-
{
|
|
8875
|
-
"key": "migrationBegin",
|
|
8876
|
-
"method": "POST",
|
|
8877
|
-
"path": "/migrations",
|
|
8878
|
-
"fullPath": "/internal/agent-api/migrations",
|
|
8879
|
-
"client": {
|
|
8880
|
-
"resource": "migrations",
|
|
8881
|
-
"method": "begin"
|
|
8882
|
-
},
|
|
8883
|
-
"capability": "server",
|
|
8884
|
-
"description": "Begin a migration for the bound agent credential.",
|
|
8885
|
-
"sideEffect": "write",
|
|
8886
|
-
"idempotency": "none",
|
|
8887
|
-
"destructive": true,
|
|
8888
|
-
"audience": "managed",
|
|
8889
|
-
"request": {
|
|
8890
|
-
"params": false,
|
|
8891
|
-
"query": false,
|
|
8892
|
-
"body": true
|
|
8893
|
-
},
|
|
8894
|
-
"response": {
|
|
8895
|
-
"kind": "json",
|
|
8896
|
-
"body": true
|
|
8897
|
-
}
|
|
8898
|
-
},
|
|
8899
|
-
{
|
|
8900
|
-
"key": "migrationStatus",
|
|
8901
|
-
"method": "GET",
|
|
8902
|
-
"path": "/migrations/current",
|
|
8903
|
-
"fullPath": "/internal/agent-api/migrations/current",
|
|
8904
|
-
"client": {
|
|
8905
|
-
"resource": "migrations",
|
|
8906
|
-
"method": "status"
|
|
8907
|
-
},
|
|
8908
|
-
"capability": "read",
|
|
8909
|
-
"description": "Read the active migration for the bound agent credential, if any.",
|
|
8910
|
-
"sideEffect": "read",
|
|
8911
|
-
"idempotency": "natural",
|
|
8912
|
-
"destructive": false,
|
|
8913
|
-
"audience": "both",
|
|
8914
|
-
"request": {
|
|
8915
|
-
"params": false,
|
|
8916
|
-
"query": false,
|
|
8917
|
-
"body": false
|
|
8918
|
-
},
|
|
8919
|
-
"response": {
|
|
8920
|
-
"kind": "json",
|
|
8921
|
-
"body": true
|
|
8922
|
-
}
|
|
8923
|
-
},
|
|
8924
|
-
{
|
|
8925
|
-
"key": "migrationReady",
|
|
8926
|
-
"method": "POST",
|
|
8927
|
-
"path": "/migrations/ready",
|
|
8928
|
-
"fullPath": "/internal/agent-api/migrations/ready",
|
|
8929
|
-
"client": {
|
|
8930
|
-
"resource": "migrations",
|
|
8931
|
-
"method": "ready"
|
|
8932
|
-
},
|
|
8933
|
-
"capability": "read",
|
|
8934
|
-
"description": "Mark the bound agent's active migration prep phase ready.",
|
|
8935
|
-
"sideEffect": "write",
|
|
8936
|
-
"idempotency": "natural",
|
|
8937
|
-
"destructive": false,
|
|
8938
|
-
"audience": "managed",
|
|
8939
|
-
"request": {
|
|
8940
|
-
"params": false,
|
|
8941
|
-
"query": false,
|
|
8942
|
-
"body": true
|
|
8943
|
-
},
|
|
8944
|
-
"response": {
|
|
8945
|
-
"kind": "json",
|
|
8946
|
-
"body": true
|
|
8947
|
-
}
|
|
8948
|
-
},
|
|
8949
|
-
{
|
|
8950
|
-
"key": "migrationArrived",
|
|
8951
|
-
"method": "POST",
|
|
8952
|
-
"path": "/migrations/arrived",
|
|
8953
|
-
"fullPath": "/internal/agent-api/migrations/arrived",
|
|
8954
|
-
"client": {
|
|
8955
|
-
"resource": "migrations",
|
|
8956
|
-
"method": "arrived"
|
|
8957
|
-
},
|
|
8958
|
-
"capability": "read",
|
|
8959
|
-
"description": "Mark the bound agent's active migration arrival phase complete.",
|
|
8960
|
-
"sideEffect": "write",
|
|
8961
|
-
"idempotency": "natural",
|
|
8962
|
-
"destructive": false,
|
|
8963
|
-
"audience": "managed",
|
|
8964
|
-
"request": {
|
|
8965
|
-
"params": false,
|
|
8966
|
-
"query": false,
|
|
8967
|
-
"body": true
|
|
8968
|
-
},
|
|
8969
|
-
"response": {
|
|
8970
|
-
"kind": "json",
|
|
8971
|
-
"body": true
|
|
8972
|
-
}
|
|
8973
|
-
},
|
|
8974
8759
|
{
|
|
8975
8760
|
"key": "reminderList",
|
|
8976
8761
|
"method": "GET",
|
|
@@ -9873,7 +9658,7 @@ const AGENT_API_ROUTE_MANIFEST = [
|
|
|
9873
9658
|
}
|
|
9874
9659
|
];
|
|
9875
9660
|
/** Content hash of AGENT_API_ROUTE_MANIFEST; see computeAgentApiManifestVersion. */
|
|
9876
|
-
const AGENT_API_MANIFEST_VERSION = "
|
|
9661
|
+
const AGENT_API_MANIFEST_VERSION = "c7a793816a7a90ed";
|
|
9877
9662
|
//#endregion
|
|
9878
9663
|
//#region src/routes.ts
|
|
9879
9664
|
const ROUTE_INFO = Object.fromEntries(AGENT_API_ROUTE_MANIFEST.map((entry) => {
|
|
@@ -10935,6 +10720,20 @@ function formatUtcTimestamp(value) {
|
|
|
10935
10720
|
//#endregion
|
|
10936
10721
|
//#region ../shared/src/agentMessageText.ts
|
|
10937
10722
|
/**
|
|
10723
|
+
* Prefix every continuation line of a quoted body with ` │ `, so body text
|
|
10724
|
+
* never reaches column 0. Structural lines (`[target=…]` / `[1/5 seq=…]` headers,
|
|
10725
|
+
* read cursors, footers) always start at column 0, so a line-anchored reader
|
|
10726
|
+
* (`grep '^\['`) cannot be handed a forged one by message content. The `│` is
|
|
10727
|
+
* non-whitespace on purpose: a reader that trims each line still sees it. It is
|
|
10728
|
+
* the same quote marker as the freshness-hold digest previews. Remove the first
|
|
10729
|
+
* four characters after each line separator to recover the original body.
|
|
10730
|
+
*/
|
|
10731
|
+
const AGENT_BODY_CONTINUATION_PREFIX = " │ ";
|
|
10732
|
+
const AGENT_BODY_LINE_SEPARATOR_GLOBAL = new RegExp(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/.source, "g");
|
|
10733
|
+
function indentAgentBodyContinuationLines(text) {
|
|
10734
|
+
return text.replace(AGENT_BODY_LINE_SEPARATOR_GLOBAL, (separator) => `${separator}${AGENT_BODY_CONTINUATION_PREFIX}`);
|
|
10735
|
+
}
|
|
10736
|
+
/**
|
|
10938
10737
|
* The target an agent passes back to reply where a message came from:
|
|
10939
10738
|
* `#channel`, `#channel:shortid`, `dm:@peer`, `dm:@peer:shortid`, or
|
|
10940
10739
|
* `agent-event:shortid` for third-party app events.
|
|
@@ -10977,8 +10776,8 @@ function formatAgentTaskCurrentProjection(projection, taskNumber, neutralize) {
|
|
|
10977
10776
|
const actorType = projection.amendedByType ?? projection.amended_by_type ?? null;
|
|
10978
10777
|
const actor = actorName ? neutralizeRefs ? `user:${actorName}` : `@${actorName}` : actorType === "system" ? "system" : "<unresolved>";
|
|
10979
10778
|
const amendedAt = projection.amendedAt ?? projection.amended_at ?? null;
|
|
10980
|
-
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 ?? ""}`];
|
|
10981
|
-
if (projection.description != null) lines.push(`Current description: ${neutralizeRefs ? renderPreviewText(projection.description) : projection.description}`);
|
|
10779
|
+
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 ?? "")}`];
|
|
10780
|
+
if (projection.description != null) lines.push(`Current description: ${indentAgentBodyContinuationLines(neutralizeRefs ? renderPreviewText(projection.description) : projection.description)}`);
|
|
10982
10781
|
return `\n${lines.join("\n")}`;
|
|
10983
10782
|
}
|
|
10984
10783
|
/** One received-message line: header bracket + sender + content + suffixes. */
|
|
@@ -10997,7 +10796,7 @@ function formatAgentMessageLine(m) {
|
|
|
10997
10796
|
const msgId = m.message_id ? m.message_id.slice(0, 8) : "-";
|
|
10998
10797
|
const time = m.timestamp ? formatUtcTimestamp(m.timestamp) : "-";
|
|
10999
10798
|
const senderType = ` type=${m.sender_type}`;
|
|
11000
|
-
const content = m.content ?? "";
|
|
10799
|
+
const content = indentAgentBodyContinuationLines(m.content ?? "");
|
|
11001
10800
|
const attachSuffix = formatAgentAttachmentSuffix(m.attachments);
|
|
11002
10801
|
const taskSuffix = m.task_status ? ` [task #${m.task_number} status=${m.task_status}${formatAgentTaskAssigneeSuffix(m.task_assignee_id, m.task_assignee_name)}]` : "";
|
|
11003
10802
|
return `[target=${target} msg=${msgId} time=${time}${senderType}] ${formatAgentSenderHandle(m)}: ${content}${attachSuffix}${taskSuffix}${formatAgentReplyAffordanceSuffix(m)}${formatAgentTaskCurrentProjection(m.task_current_projection)}`;
|
|
@@ -11101,6 +10900,126 @@ function sortBySeq(messages) {
|
|
|
11101
10900
|
function projectRaftMessages(envelopes) {
|
|
11102
10901
|
return envelopes.map(projectRaftMessage).filter((m) => m !== null);
|
|
11103
10902
|
}
|
|
10903
|
+
/** The conversation fields a target string names; `null` for a shape this cannot read. */
|
|
10904
|
+
function identityFromTarget(target) {
|
|
10905
|
+
const dm = /^dm:@([^:\s]+)(?::([^:\s]+))?$/.exec(target);
|
|
10906
|
+
if (dm) return dm[2] ? {
|
|
10907
|
+
channel_type: "thread",
|
|
10908
|
+
channel_name: dm[2],
|
|
10909
|
+
parent_channel_name: dm[1],
|
|
10910
|
+
parent_channel_type: "dm"
|
|
10911
|
+
} : {
|
|
10912
|
+
channel_type: "dm",
|
|
10913
|
+
channel_name: dm[1]
|
|
10914
|
+
};
|
|
10915
|
+
const channel = /^#([^:\s]+)(?::([^:\s]+))?$/.exec(target);
|
|
10916
|
+
if (channel) return channel[2] ? {
|
|
10917
|
+
channel_type: "thread",
|
|
10918
|
+
channel_name: channel[2],
|
|
10919
|
+
parent_channel_name: channel[1],
|
|
10920
|
+
parent_channel_type: "channel"
|
|
10921
|
+
} : {
|
|
10922
|
+
channel_type: "channel",
|
|
10923
|
+
channel_name: channel[1]
|
|
10924
|
+
};
|
|
10925
|
+
return null;
|
|
10926
|
+
}
|
|
10927
|
+
/**
|
|
10928
|
+
* Project envelopes that all belong to one known conversation. Some Server
|
|
10929
|
+
* responses (held previews) send envelopes without conversation fields
|
|
10930
|
+
* because the request already named the target; fill them from `target`
|
|
10931
|
+
* instead of dropping the message.
|
|
10932
|
+
*/
|
|
10933
|
+
function projectRaftMessagesInTarget(envelopes, target) {
|
|
10934
|
+
const identity = identityFromTarget(target);
|
|
10935
|
+
return envelopes.map((envelope) => projectRaftMessage(identity && !hasAgentMessageIdentity(envelope) ? {
|
|
10936
|
+
...envelope,
|
|
10937
|
+
...identity
|
|
10938
|
+
} : envelope)).filter((m) => m !== null);
|
|
10939
|
+
}
|
|
10940
|
+
//#endregion
|
|
10941
|
+
//#region ../shared/src/agentOps/interrupt.ts
|
|
10942
|
+
/** Narrow any outcome (SDK or command registry) to an interrupt, without knowing the command. */
|
|
10943
|
+
function isInterrupted(outcome) {
|
|
10944
|
+
return Boolean(outcome) && typeof outcome === "object" && outcome.state === "interrupted" && typeof outcome.interrupt === "object";
|
|
10945
|
+
}
|
|
10946
|
+
/** Build the `unread_messages` interrupt from a Server freshness hold. */
|
|
10947
|
+
function unreadMessagesInterrupt(input) {
|
|
10948
|
+
const { hold, target } = input;
|
|
10949
|
+
const withheld = input.withheld === true || hold.freshnessContextMode === "withheld";
|
|
10950
|
+
const heldMessages = withheld ? [] : projectRaftMessagesInTarget(hold.heldMessages ?? [], target);
|
|
10951
|
+
const newMessageCount = withheld ? hold.withheldMessageCount ?? hold.newMessageCount ?? 0 : hold.newMessageCount ?? heldMessages.length;
|
|
10952
|
+
const omittedMessageCount = withheld ? 0 : hold.omittedMessageCount ?? 0;
|
|
10953
|
+
return {
|
|
10954
|
+
reason: "unread_messages",
|
|
10955
|
+
context: input.context,
|
|
10956
|
+
resume: input.resume,
|
|
10957
|
+
...input.cancel ? { cancel: input.cancel } : {},
|
|
10958
|
+
target,
|
|
10959
|
+
newMessageCount,
|
|
10960
|
+
heldMessages,
|
|
10961
|
+
omittedMessageCount,
|
|
10962
|
+
formalMentionCount: withheld ? 0 : hold.mentionAnnotation?.formalMentionCount ?? 0,
|
|
10963
|
+
seenUpToSeq: typeof hold.seenUpToSeq === "number" ? hold.seenUpToSeq : null,
|
|
10964
|
+
withheld,
|
|
10965
|
+
contextComplete: !withheld && heldMessages.length + omittedMessageCount >= newMessageCount
|
|
10966
|
+
};
|
|
10967
|
+
}
|
|
10968
|
+
/** `raft message send --send-draft` for the draft a held send saved, under its original key. */
|
|
10969
|
+
function sendDraftResume(target, idempotencyKey, extraArgv = []) {
|
|
10970
|
+
return {
|
|
10971
|
+
argv: [
|
|
10972
|
+
"message",
|
|
10973
|
+
"send",
|
|
10974
|
+
"--send-draft",
|
|
10975
|
+
"--target",
|
|
10976
|
+
target,
|
|
10977
|
+
"--expected-draft-key",
|
|
10978
|
+
idempotencyKey,
|
|
10979
|
+
...extraArgv
|
|
10980
|
+
],
|
|
10981
|
+
idempotencyKey
|
|
10982
|
+
};
|
|
10983
|
+
}
|
|
10984
|
+
/** `raft message send --discard-draft` for the draft a held send saved (compare-and-clear on its key). */
|
|
10985
|
+
function discardDraftCancel(target, idempotencyKey, extraArgv = []) {
|
|
10986
|
+
return { argv: [
|
|
10987
|
+
"message",
|
|
10988
|
+
"send",
|
|
10989
|
+
"--discard-draft",
|
|
10990
|
+
"--target",
|
|
10991
|
+
target,
|
|
10992
|
+
"--expected-draft-key",
|
|
10993
|
+
idempotencyKey,
|
|
10994
|
+
...extraArgv
|
|
10995
|
+
] };
|
|
10996
|
+
}
|
|
10997
|
+
/** `raft task claim` argv for a claim request (resume of a held claim). */
|
|
10998
|
+
function taskClaimArgv(target, taskNumbers, messageIds, extraArgv = []) {
|
|
10999
|
+
return [
|
|
11000
|
+
"task",
|
|
11001
|
+
"claim",
|
|
11002
|
+
"--target",
|
|
11003
|
+
target,
|
|
11004
|
+
...taskNumbers.flatMap((n) => ["--number", String(n)]),
|
|
11005
|
+
...messageIds.flatMap((id) => ["--message-id", id]),
|
|
11006
|
+
...extraArgv
|
|
11007
|
+
];
|
|
11008
|
+
}
|
|
11009
|
+
/** `raft task update` argv (resume of a held status update). */
|
|
11010
|
+
function taskUpdateArgv(target, taskNumber, status, extraArgv = []) {
|
|
11011
|
+
return [
|
|
11012
|
+
"task",
|
|
11013
|
+
"update",
|
|
11014
|
+
"--target",
|
|
11015
|
+
target,
|
|
11016
|
+
"--number",
|
|
11017
|
+
String(taskNumber),
|
|
11018
|
+
"--status",
|
|
11019
|
+
status,
|
|
11020
|
+
...extraArgv
|
|
11021
|
+
];
|
|
11022
|
+
}
|
|
11104
11023
|
//#endregion
|
|
11105
11024
|
//#region ../shared/src/agentOps/frontier.ts
|
|
11106
11025
|
const MAX_EXACT_SEQS = 2500;
|
|
@@ -11153,13 +11072,15 @@ var SeenFrontier = class SeenFrontier {
|
|
|
11153
11072
|
}
|
|
11154
11073
|
}
|
|
11155
11074
|
/**
|
|
11156
|
-
* Attest that the model saw the context
|
|
11157
|
-
*
|
|
11158
|
-
*
|
|
11159
|
-
*
|
|
11075
|
+
* Attest that the model saw the context of an interrupt (`outcome.interrupt`
|
|
11076
|
+
* of an `interrupted` send, claim or task write). Call it only after
|
|
11077
|
+
* `interrupt.context` actually reached the model (the SDK cannot know that,
|
|
11078
|
+
* so it never records this implicitly). Returns false and records nothing
|
|
11079
|
+
* when the context was withheld, not fully shown (`contextComplete: false`),
|
|
11080
|
+
* or the Server sent no boundary.
|
|
11160
11081
|
*/
|
|
11161
11082
|
recordHeld(held) {
|
|
11162
|
-
if (held.withheld || held.seenUpToSeq === null) return false;
|
|
11083
|
+
if (held.withheld || held.contextComplete === false || held.seenUpToSeq === null) return false;
|
|
11163
11084
|
this.recordUpTo(held.target, held.seenUpToSeq);
|
|
11164
11085
|
return true;
|
|
11165
11086
|
}
|
|
@@ -11525,7 +11446,8 @@ async function readHistory(client, request, frontier) {
|
|
|
11525
11446
|
...request.after === void 0 ? {} : { after: String(request.after) },
|
|
11526
11447
|
...request.before === void 0 ? {} : { before: String(request.before) },
|
|
11527
11448
|
...request.around === void 0 ? {} : { around: String(request.around) },
|
|
11528
|
-
...request.limit === void 0 ? {} : { limit: String(request.limit) }
|
|
11449
|
+
...request.limit === void 0 ? {} : { limit: String(request.limit) },
|
|
11450
|
+
...request.consume === false ? { consume: "false" } : {}
|
|
11529
11451
|
});
|
|
11530
11452
|
if (!result.ok) return failureFromClientResult(result);
|
|
11531
11453
|
const data = result.data;
|
|
@@ -11537,7 +11459,7 @@ async function readHistory(client, request, frontier) {
|
|
|
11537
11459
|
lastReadSeq: typeof data.last_read_seq === "number" ? data.last_read_seq : null,
|
|
11538
11460
|
modelSeenUpToSeq: typeof data.model_seen_up_to_seq === "number" ? data.model_seen_up_to_seq : null
|
|
11539
11461
|
};
|
|
11540
|
-
recordHistorySeen(frontier, request.target, page, request.around !== void 0);
|
|
11462
|
+
if (request.consume !== false) recordHistorySeen(frontier, request.target, page, request.around !== void 0);
|
|
11541
11463
|
return {
|
|
11542
11464
|
ok: true,
|
|
11543
11465
|
state: page.messages.length > 0 ? "page" : "empty",
|
|
@@ -11548,6 +11470,7 @@ async function readHistory(client, request, frontier) {
|
|
|
11548
11470
|
}
|
|
11549
11471
|
/** Attempts for a keyed send whose request never reached the Server (transport failure only). */
|
|
11550
11472
|
const SEND_TRANSPORT_ATTEMPTS = 3;
|
|
11473
|
+
/** Today's held text (unchanged); it is the interrupt's `context` and the outcome's `text`. */
|
|
11551
11474
|
function heldText(held, action) {
|
|
11552
11475
|
const noun = held.newMessageCount === 1 ? "message" : "messages";
|
|
11553
11476
|
const head = `Held — ${held.newMessageCount} unread ${noun} in ${held.target}. ${action}`;
|
|
@@ -11556,37 +11479,33 @@ function heldText(held, action) {
|
|
|
11556
11479
|
if (held.formalMentionCount > 0) lines.push(`Note: ${held.formalMentionCount} of these messages formally @mention you.`);
|
|
11557
11480
|
if (held.omittedMessageCount > 0) lines.push(`${held.omittedMessageCount} earlier ${held.omittedMessageCount === 1 ? "message" : "messages"} not shown.`);
|
|
11558
11481
|
if (held.heldMessages.length > 0) lines.push(formatAgentMessages(held.heldMessages.map((m) => toAgentMessageLike(m.raw))));
|
|
11482
|
+
if (!held.contextComplete) lines.push("Not all of them are shown here; read the conversation before sending again.");
|
|
11559
11483
|
lines.push(`Full text: raft message read --target "${held.target}"`);
|
|
11560
11484
|
return lines.join("\n");
|
|
11561
11485
|
}
|
|
11562
|
-
|
|
11486
|
+
/**
|
|
11487
|
+
* A Server freshness hold as the `unread_messages` interrupt: the structured
|
|
11488
|
+
* details, today's held text as `context`, and the given resume / cancel.
|
|
11489
|
+
*/
|
|
11490
|
+
function heldInterrupt(target, data, action, resume, cancel) {
|
|
11491
|
+
const interrupt = unreadMessagesInterrupt({
|
|
11492
|
+
target,
|
|
11493
|
+
hold: data,
|
|
11494
|
+
context: "",
|
|
11495
|
+
resume,
|
|
11496
|
+
...cancel ? { cancel } : {}
|
|
11497
|
+
});
|
|
11563
11498
|
return {
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
args: {
|
|
11567
|
-
target: held.target,
|
|
11568
|
-
...held.continuation
|
|
11569
|
-
},
|
|
11570
|
-
why: held.withheld ? "Newer messages exist in this conversation but were withheld; read them, 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)."
|
|
11499
|
+
...interrupt,
|
|
11500
|
+
context: heldText(interrupt, action)
|
|
11571
11501
|
};
|
|
11572
11502
|
}
|
|
11573
|
-
function
|
|
11574
|
-
const withheld = data.freshnessContextMode === "withheld";
|
|
11575
|
-
const heldMessages = projectRaftMessages(data.heldMessages ?? []);
|
|
11576
|
-
const seenUpToSeq = typeof data.seenUpToSeq === "number" ? data.seenUpToSeq : null;
|
|
11503
|
+
function heldSendNext(interrupt) {
|
|
11577
11504
|
return {
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
...!withheld && seenUpToSeq !== null ? { seen: { upToSeq: seenUpToSeq } } : {}
|
|
11583
|
-
},
|
|
11584
|
-
newMessageCount: withheld ? data.withheldMessageCount ?? 0 : data.newMessageCount ?? heldMessages.length,
|
|
11585
|
-
heldMessages,
|
|
11586
|
-
omittedMessageCount: data.omittedMessageCount ?? 0,
|
|
11587
|
-
formalMentionCount: data.mentionAnnotation?.formalMentionCount ?? 0,
|
|
11588
|
-
seenUpToSeq,
|
|
11589
|
-
withheld
|
|
11505
|
+
kind: "resend",
|
|
11506
|
+
command: `raft message read --target "${interrupt.target}"`,
|
|
11507
|
+
args: { target: interrupt.target },
|
|
11508
|
+
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."
|
|
11590
11509
|
};
|
|
11591
11510
|
}
|
|
11592
11511
|
function isHeldResponse(data) {
|
|
@@ -11613,7 +11532,7 @@ function sentOutcome(target, data) {
|
|
|
11613
11532
|
text: `Message sent to ${target}. Message ID: ${sent.messageId}${warn}`
|
|
11614
11533
|
};
|
|
11615
11534
|
}
|
|
11616
|
-
async function sendMessage(client, request, frontier
|
|
11535
|
+
async function sendMessage(client, request, frontier) {
|
|
11617
11536
|
if (!request.target?.trim()) return failureOutcome(opError("INVALID_REQUEST", { message: "A target is required to send a message." }));
|
|
11618
11537
|
if (typeof request.content !== "string" || !request.content.trim() && !request.attachmentIds?.length) return failureOutcome(opError("INVALID_REQUEST", { message: "Message content (or an attachment) is required." }));
|
|
11619
11538
|
const idempotencyKey = request.idempotencyKey?.trim() || crypto.randomUUID();
|
|
@@ -11628,41 +11547,20 @@ async function sendMessage(client, request, frontier, internal = {}) {
|
|
|
11628
11547
|
idempotencyKey,
|
|
11629
11548
|
...request.mentions?.length ? { mentions: request.mentions } : {},
|
|
11630
11549
|
...attestation.seenUpToSeq === void 0 ? {} : { seenUpToSeq: attestation.seenUpToSeq },
|
|
11631
|
-
...attestation.seenExactSeqs.length > 0 ? { seenExactSeqs: attestation.seenExactSeqs.slice(0, 2500) } : {}
|
|
11632
|
-
...internal.sendDraft ? { sendDraft: true } : {},
|
|
11633
|
-
...internal.continueAnyway ? { continueAnyway: true } : {},
|
|
11634
|
-
...internal.reholdCount ? { draftReholdCount: internal.reholdCount } : {}
|
|
11550
|
+
...attestation.seenExactSeqs.length > 0 ? { seenExactSeqs: attestation.seenExactSeqs.slice(0, 2500) } : {}
|
|
11635
11551
|
};
|
|
11636
11552
|
let result = await client.messages.sendV2(body);
|
|
11637
11553
|
for (let attempt = 1; !result.ok && result.error.kind === "transport" && attempt < SEND_TRANSPORT_ATTEMPTS; attempt += 1) result = await client.messages.sendV2(body);
|
|
11638
11554
|
if (!result.ok) return failureFromClientResult(result);
|
|
11639
11555
|
const data = result.data;
|
|
11640
11556
|
if (isHeldResponse(data)) {
|
|
11641
|
-
const
|
|
11642
|
-
const keyed = {
|
|
11643
|
-
...request,
|
|
11644
|
-
idempotencyKey
|
|
11645
|
-
};
|
|
11646
|
-
const held = {
|
|
11647
|
-
...projectHeld(request.target, data, idempotencyKey),
|
|
11648
|
-
resend: (options) => sendMessage(client, options.seen === "held" && typeof data.seenUpToSeq === "number" ? {
|
|
11649
|
-
...keyed,
|
|
11650
|
-
seen: {
|
|
11651
|
-
upToSeq: data.seenUpToSeq,
|
|
11652
|
-
exactSeqs: attestation.seenExactSeqs
|
|
11653
|
-
}
|
|
11654
|
-
} : keyed, frontier, {
|
|
11655
|
-
sendDraft: true,
|
|
11656
|
-
reholdCount,
|
|
11657
|
-
...options.seen === "anyway" ? { continueAnyway: true } : {}
|
|
11658
|
-
})
|
|
11659
|
-
};
|
|
11557
|
+
const interrupt = heldInterrupt(request.target, data, "Your message was not sent.", sendDraftResume(request.target, idempotencyKey), discardDraftCancel(request.target, idempotencyKey));
|
|
11660
11558
|
return {
|
|
11661
11559
|
ok: true,
|
|
11662
|
-
state: "
|
|
11663
|
-
|
|
11664
|
-
next:
|
|
11665
|
-
text:
|
|
11560
|
+
state: "interrupted",
|
|
11561
|
+
interrupt,
|
|
11562
|
+
next: heldSendNext(interrupt),
|
|
11563
|
+
text: interrupt.context
|
|
11666
11564
|
};
|
|
11667
11565
|
}
|
|
11668
11566
|
if (data.state === "sent") return sentOutcome(request.target, data);
|
|
@@ -11839,6 +11737,24 @@ function formatAgentTaskHistory(data) {
|
|
|
11839
11737
|
//#endregion
|
|
11840
11738
|
//#region ../shared/src/agentOps/tasks.ts
|
|
11841
11739
|
const TASK_CLAIM_REASON_ALREADY_CLAIMED_BY_YOU = "already claimed by you";
|
|
11740
|
+
/**
|
|
11741
|
+
* A held task call: the interrupt whose resume is the identical command, with
|
|
11742
|
+
* no cancel (a held task call saved nothing). `context` is today's held text.
|
|
11743
|
+
*/
|
|
11744
|
+
function heldTaskInterrupt(target, data, action, after, argv) {
|
|
11745
|
+
const interrupt = unreadMessagesInterrupt({
|
|
11746
|
+
target,
|
|
11747
|
+
hold: data,
|
|
11748
|
+
context: "",
|
|
11749
|
+
resume: { argv }
|
|
11750
|
+
});
|
|
11751
|
+
const noun = interrupt.newMessageCount === 1 ? "message" : "messages";
|
|
11752
|
+
const context = `Held — ${interrupt.newMessageCount} unread ${noun} in ${target}. ${action}\nRead them with: raft message read --target "${target}"\n${after}`;
|
|
11753
|
+
return {
|
|
11754
|
+
...interrupt,
|
|
11755
|
+
context
|
|
11756
|
+
};
|
|
11757
|
+
}
|
|
11842
11758
|
function rowState(result) {
|
|
11843
11759
|
if (result.success) return "claimed";
|
|
11844
11760
|
if (result.reason === TASK_CLAIM_REASON_ALREADY_CLAIMED_BY_YOU) return "already_yours";
|
|
@@ -11879,23 +11795,18 @@ async function claimTasks(client, request) {
|
|
|
11879
11795
|
if (!result.ok) return failureFromClientResult(result);
|
|
11880
11796
|
const data = result.data;
|
|
11881
11797
|
if (isHeldResponse(data)) {
|
|
11882
|
-
const
|
|
11883
|
-
const held = {
|
|
11884
|
-
...heldBase,
|
|
11885
|
-
request,
|
|
11886
|
-
retry: () => claimTasks(client, request)
|
|
11887
|
-
};
|
|
11798
|
+
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));
|
|
11888
11799
|
return {
|
|
11889
11800
|
ok: true,
|
|
11890
|
-
state: "
|
|
11891
|
-
|
|
11801
|
+
state: "interrupted",
|
|
11802
|
+
interrupt,
|
|
11892
11803
|
next: {
|
|
11893
11804
|
kind: "retry_claim",
|
|
11894
11805
|
command: `raft message read --target "${request.target}"`,
|
|
11895
|
-
args: {
|
|
11896
|
-
why: "Unread messages in this channel may change the task; read them (frontier.recordHeld(
|
|
11806
|
+
args: { target: request.target },
|
|
11807
|
+
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."
|
|
11897
11808
|
},
|
|
11898
|
-
text:
|
|
11809
|
+
text: interrupt.context
|
|
11899
11810
|
};
|
|
11900
11811
|
}
|
|
11901
11812
|
const rows = (data.results ?? []).map((row) => {
|
|
@@ -12032,23 +11943,20 @@ async function assignTask(client, request) {
|
|
|
12032
11943
|
text: formatAgentTaskAssigned(request.taskNumber, assignee)
|
|
12033
11944
|
};
|
|
12034
11945
|
}
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
const
|
|
12038
|
-
...base,
|
|
12039
|
-
request
|
|
12040
|
-
};
|
|
11946
|
+
/** A held task write: the interrupt whose resume is the identical command; nothing to cancel. */
|
|
11947
|
+
function heldTaskWrite(target, data, action, kind, argv) {
|
|
11948
|
+
const interrupt = heldTaskInterrupt(target, data, action, "After reviewing, repeat the operation if it is still correct.", argv);
|
|
12041
11949
|
return {
|
|
12042
11950
|
ok: true,
|
|
12043
|
-
state: "
|
|
12044
|
-
|
|
11951
|
+
state: "interrupted",
|
|
11952
|
+
interrupt,
|
|
12045
11953
|
next: {
|
|
12046
11954
|
kind,
|
|
12047
|
-
command: `raft message read --target "${
|
|
12048
|
-
args: {
|
|
12049
|
-
why:
|
|
11955
|
+
command: `raft message read --target "${target}"`,
|
|
11956
|
+
args: { target },
|
|
11957
|
+
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."
|
|
12050
11958
|
},
|
|
12051
|
-
text:
|
|
11959
|
+
text: interrupt.context
|
|
12052
11960
|
};
|
|
12053
11961
|
}
|
|
12054
11962
|
async function updateTaskStatus(client, request) {
|
|
@@ -12060,7 +11968,7 @@ async function updateTaskStatus(client, request) {
|
|
|
12060
11968
|
status: request.status
|
|
12061
11969
|
});
|
|
12062
11970
|
if (!result.ok) return failureFromClientResult(result);
|
|
12063
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request, result.data, "The status change was not applied.", "retry_update_status");
|
|
11971
|
+
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));
|
|
12064
11972
|
return {
|
|
12065
11973
|
ok: true,
|
|
12066
11974
|
state: "updated",
|
|
@@ -12072,6 +11980,18 @@ async function updateTaskStatus(client, request) {
|
|
|
12072
11980
|
text: formatAgentTaskStatusUpdated(request.taskNumber, request.status)
|
|
12073
11981
|
};
|
|
12074
11982
|
}
|
|
11983
|
+
function taskAmendArgv(request) {
|
|
11984
|
+
return [
|
|
11985
|
+
"task",
|
|
11986
|
+
"amend",
|
|
11987
|
+
"--target",
|
|
11988
|
+
request.target,
|
|
11989
|
+
"--number",
|
|
11990
|
+
String(request.taskNumber),
|
|
11991
|
+
...request.title === void 0 ? [] : ["--title", request.title],
|
|
11992
|
+
...request.description === void 0 ? [] : request.description === null ? ["--clear-description"] : ["--description", request.description]
|
|
11993
|
+
];
|
|
11994
|
+
}
|
|
12075
11995
|
async function amendTask(client, request) {
|
|
12076
11996
|
const invalid = requireTaskRef(request);
|
|
12077
11997
|
if (invalid) return invalid;
|
|
@@ -12083,7 +12003,7 @@ async function amendTask(client, request) {
|
|
|
12083
12003
|
...request.description === void 0 ? {} : { description: request.description }
|
|
12084
12004
|
});
|
|
12085
12005
|
if (!result.ok) return failureFromClientResult(result);
|
|
12086
|
-
if (isHeldResponse(result.data)) return heldTaskWrite(request, result.data, "The amendment was not applied.", "retry_amend");
|
|
12006
|
+
if (isHeldResponse(result.data)) return heldTaskWrite(request.target, result.data, "The amendment was not applied.", "retry_amend", taskAmendArgv(request));
|
|
12087
12007
|
return {
|
|
12088
12008
|
ok: true,
|
|
12089
12009
|
state: "amended",
|
|
@@ -13240,12 +13160,101 @@ async function attachmentComments(client, request) {
|
|
|
13240
13160
|
};
|
|
13241
13161
|
}
|
|
13242
13162
|
//#endregion
|
|
13163
|
+
//#region ../shared/src/zonedTime.ts
|
|
13164
|
+
const MS_PER_SECOND = 1e3;
|
|
13165
|
+
const MS_PER_MINUTE = 6e4;
|
|
13166
|
+
const MS_PER_DAY = 864e5;
|
|
13167
|
+
const formatters = /* @__PURE__ */ new Map();
|
|
13168
|
+
function formatterFor(timeZone) {
|
|
13169
|
+
let formatter = formatters.get(timeZone);
|
|
13170
|
+
if (!formatter) {
|
|
13171
|
+
formatter = new Intl.DateTimeFormat("en-US", {
|
|
13172
|
+
timeZone,
|
|
13173
|
+
hourCycle: "h23",
|
|
13174
|
+
era: "short",
|
|
13175
|
+
year: "numeric",
|
|
13176
|
+
month: "numeric",
|
|
13177
|
+
day: "numeric",
|
|
13178
|
+
hour: "numeric",
|
|
13179
|
+
minute: "numeric",
|
|
13180
|
+
second: "numeric"
|
|
13181
|
+
});
|
|
13182
|
+
formatters.set(timeZone, formatter);
|
|
13183
|
+
}
|
|
13184
|
+
return formatter;
|
|
13185
|
+
}
|
|
13186
|
+
/** Days from 1970-01-01 to the proleptic Gregorian date (H. Hinnant's days_from_civil). */
|
|
13187
|
+
function daysFromCivil(year, month, day) {
|
|
13188
|
+
const y = month <= 2 ? year - 1 : year;
|
|
13189
|
+
const era = Math.floor(y / 400);
|
|
13190
|
+
const yoe = y - era * 400;
|
|
13191
|
+
const mp = (month + 9) % 12;
|
|
13192
|
+
const doy = Math.floor((153 * mp + 2) / 5) + day - 1;
|
|
13193
|
+
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
13194
|
+
return era * 146097 + doe - 719468;
|
|
13195
|
+
}
|
|
13196
|
+
/** The wall clock as milliseconds on a UTC timeline (no Date, so no 0-99 year quirk or range limit). */
|
|
13197
|
+
function wallClockMs(wall) {
|
|
13198
|
+
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;
|
|
13199
|
+
}
|
|
13200
|
+
function floorMod(value, modulus) {
|
|
13201
|
+
return (value % modulus + modulus) % modulus;
|
|
13202
|
+
}
|
|
13203
|
+
/** Wall clock of `epochMs` in `timeZone` plus the exact offset in ms (seconds precision). */
|
|
13204
|
+
function wallClockAt(epochMs, timeZone) {
|
|
13205
|
+
const parts = {};
|
|
13206
|
+
for (const part of formatterFor(timeZone).formatToParts(epochMs)) parts[part.type] = part.value;
|
|
13207
|
+
const eraYear = Number(parts.year);
|
|
13208
|
+
const wall = {
|
|
13209
|
+
year: /^b/i.test(parts.era ?? "") ? 1 - eraYear : eraYear,
|
|
13210
|
+
month: Number(parts.month),
|
|
13211
|
+
day: Number(parts.day),
|
|
13212
|
+
hour: Number(parts.hour),
|
|
13213
|
+
minute: Number(parts.minute),
|
|
13214
|
+
second: Number(parts.second),
|
|
13215
|
+
millisecond: floorMod(epochMs, MS_PER_SECOND)
|
|
13216
|
+
};
|
|
13217
|
+
return {
|
|
13218
|
+
wall,
|
|
13219
|
+
offsetMs: wallClockMs(wall) - epochMs
|
|
13220
|
+
};
|
|
13221
|
+
}
|
|
13222
|
+
function offsetMinutesOf(offsetMs) {
|
|
13223
|
+
return -Math.trunc(-offsetMs / MS_PER_MINUTE);
|
|
13224
|
+
}
|
|
13225
|
+
/** The wall clock and getTimezoneOffset-style offset of `epochMs` in `timeZone`. */
|
|
13226
|
+
function zonedInstant(epochMs, timeZone) {
|
|
13227
|
+
const { wall, offsetMs } = wallClockAt(epochMs, timeZone);
|
|
13228
|
+
return {
|
|
13229
|
+
...wall,
|
|
13230
|
+
offsetMinutes: offsetMinutesOf(offsetMs)
|
|
13231
|
+
};
|
|
13232
|
+
}
|
|
13233
|
+
function pad2(n) {
|
|
13234
|
+
return String(n).padStart(2, "0");
|
|
13235
|
+
}
|
|
13236
|
+
/** `+08:00` / `-04:00` / `+05:30`, as the CLI has always printed offsets. */
|
|
13237
|
+
function formatUtcOffset(offsetMinutes) {
|
|
13238
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
13239
|
+
const abs = Math.abs(offsetMinutes);
|
|
13240
|
+
return `${sign}${pad2(Math.floor(abs / 60))}:${pad2(abs % 60)}`;
|
|
13241
|
+
}
|
|
13242
|
+
//#endregion
|
|
13243
13243
|
//#region ../shared/src/agentText/search.ts
|
|
13244
|
-
/**
|
|
13245
|
-
|
|
13244
|
+
/**
|
|
13245
|
+
* Wall-clock rendering with offset, as the CLI prints search hit times. With
|
|
13246
|
+
* `timeZone` (an IANA name) the time is rendered in that zone; without it, in
|
|
13247
|
+
* the process's local zone (the SDK's historical behaviour). The two agree
|
|
13248
|
+
* byte for byte when `timeZone` is the process zone.
|
|
13249
|
+
*/
|
|
13250
|
+
function formatLocalTimeWithOffset(iso, timeZone) {
|
|
13246
13251
|
const d = new Date(iso);
|
|
13247
13252
|
if (isNaN(d.getTime())) return iso;
|
|
13248
13253
|
const pad = (n) => String(n).padStart(2, "0");
|
|
13254
|
+
if (timeZone !== void 0) {
|
|
13255
|
+
const z = zonedInstant(d.getTime(), timeZone);
|
|
13256
|
+
return `${z.year}-${pad(z.month)}-${pad(z.day)} ${pad(z.hour)}:${pad(z.minute)}:${pad(z.second)} ${formatUtcOffset(z.offsetMinutes)}`;
|
|
13257
|
+
}
|
|
13249
13258
|
const offsetMinutes = -d.getTimezoneOffset();
|
|
13250
13259
|
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
13251
13260
|
const absOffset = Math.abs(offsetMinutes);
|
|
@@ -13368,8 +13377,11 @@ function renderSearchPreview(content, query) {
|
|
|
13368
13377
|
trailingOmit
|
|
13369
13378
|
].join("");
|
|
13370
13379
|
}
|
|
13371
|
-
/**
|
|
13372
|
-
|
|
13380
|
+
/**
|
|
13381
|
+
* Search results with <match>/<omit /> preview markup. Hit times render in
|
|
13382
|
+
* `timeZone` when given, else in the process's local zone.
|
|
13383
|
+
*/
|
|
13384
|
+
function formatAgentSearchResults(query, data, offset, sort, limit, timeZone) {
|
|
13373
13385
|
const trimmedQuery = query.trim();
|
|
13374
13386
|
const oldestShown = data.results?.length ? data.results[data.results.length - 1]?.createdAt : void 0;
|
|
13375
13387
|
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)}`;
|
|
@@ -13389,7 +13401,7 @@ function formatAgentSearchResults(query, data, offset, sort, limit) {
|
|
|
13389
13401
|
`<result ref="${ref}">`,
|
|
13390
13402
|
`Source: ${renderSearchSource(result)}`,
|
|
13391
13403
|
`Sender: ${sender}${senderType}`,
|
|
13392
|
-
`Time: ${result.createdAt ? formatLocalTimeWithOffset(result.createdAt) : "-"}`,
|
|
13404
|
+
`Time: ${result.createdAt ? formatLocalTimeWithOffset(result.createdAt, timeZone) : "-"}`,
|
|
13393
13405
|
...taskProjection ? [taskProjection] : [],
|
|
13394
13406
|
"",
|
|
13395
13407
|
"<preview>",
|
|
@@ -14100,9 +14112,9 @@ function createRaft(options) {
|
|
|
14100
14112
|
...request,
|
|
14101
14113
|
idempotencyKey: pending.idempotencyKey
|
|
14102
14114
|
} : request, frontier);
|
|
14103
|
-
if (outcome.ok && outcome.state === "
|
|
14115
|
+
if (outcome.ok && outcome.state === "interrupted" && outcome.interrupt.resume.idempotencyKey) session.rememberContinuation({
|
|
14104
14116
|
target: request.target,
|
|
14105
|
-
idempotencyKey: outcome.
|
|
14117
|
+
idempotencyKey: outcome.interrupt.resume.idempotencyKey,
|
|
14106
14118
|
contentHash,
|
|
14107
14119
|
heldAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14108
14120
|
});
|
|
@@ -14234,4 +14246,4 @@ function createRaft(options) {
|
|
|
14234
14246
|
};
|
|
14235
14247
|
}
|
|
14236
14248
|
//#endregion
|
|
14237
|
-
export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, bootstrapRaftCredential, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, describeRaftRoute, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, joinRaftChannelByTarget, listRaftRoutes, parseRaftRegularChannelTarget, parseRaftState, projectRaftMessage, projectRaftMessages, readLatestReadThread, verifyInboxNotice };
|
|
14249
|
+
export { RAFT_INBOX_NOTICE_SCHEMA, RAFT_NOTICE_DELIVERY_ID_HEADER, RAFT_NOTICE_SIGNATURE_HEADER, RAFT_STATE_CONTINUATIONS_PER_TARGET, RAFT_STATE_CONTINUATIONS_TOTAL, RAFT_STATE_SCHEMA, RaftCredentialError, RaftSdkConfigurationError, SeenFrontier, bootstrapRaftCredential, createFileCredentialStore, createRaft, createRaftClient, createRaftClientFromStore, createRaftRoutes, describeRaftRoute, hasAgentMessageIdentity, hashRaftSendContent, inferAttachmentMimeType, isInterrupted, joinRaftChannelByTarget, listRaftRoutes, parseRaftRegularChannelTarget, parseRaftState, projectRaftMessage, projectRaftMessages, readLatestReadThread, verifyInboxNotice };
|