codex-relay 1.4.4 → 1.4.6
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/dist/api-schema.js +2 -2
- package/dist/api-schema2.js +66 -1
- package/dist/cli.js +1 -1
- package/dist/paths.js +13 -19
- package/dist/src.js +198 -93
- package/package.json +1 -1
- package/src/api-schema.ts +85 -0
package/dist/api-schema.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
export { AgentSkillSchema, AgentSkillSourceSchema, ApprovalDecisionSchema, ApprovalModeSchema, ArchiveThreadResponseSchema, ChatMessageKindSchema, ChatMessagePromptDetailsSchema, ChatMessageRoleSchema, ChatMessageSchema, ChatMessageStateSchema, CheckoutWorkspaceBranchRequestSchema, CodexModelSchema, CommitPushWorkspaceRequestSchema, ContextWindowUsageSchema, CreateThreadRequestSchema, CreateThreadResponseSchema, EncryptedPayloadSchema, ErrorResponseSchema, ImageAttachmentUploadResponseSchema, InterruptThreadRunResponseSchema, IsoDateTimeSchema, KnownReasoningEffortSchema, ListModelsResponseSchema, ListQueuedThreadInputsResponseSchema, ListSkillsResponseSchema, ListThreadsResponseSchema, ListWorkspaceDirectoriesResponseSchema, ListWorkspaceFilesResponseSchema, PairEncryptedPayloadSchema, PairRequestSchema, PairResponseSchema, PendingInputRequestOptionSchema, PendingInputRequestQuestionSchema, PendingInputRequestSchema, PromptAttachmentSchema, PromptAttachmentSummarySchema, PromptContextInputSchema, PromptContextSchema, PromptSkillSchema, PushNotificationIntentSchema, PushNotificationPreferencesSchema, PushNotificationSettingsResponseSchema, QueuedThreadInputActionResponseSchema, QueuedThreadInputSchema, RateLimitBucketSchema, RateLimitWindowSchema, RateLimitsResponseSchema, ReasoningEffortSchema, RegisterPushNotificationRequestSchema, ResolveApprovalRequestSchema, ResolveApprovalResponseSchema, RunThreadRequestSchema, RunThreadResponseSchema, RuntimeModeSchema, RuntimePreferencesByWorkspacePathSchema, RuntimePreferencesResponseSchema, RuntimePreferencesSchema, SandboxModeSchema, StatusResponseSchema, StreamThreadRunEventSchema, StreamThreadRunRequestSchema, SubmitThreadInputResponseSchema, ThreadCollaborationModeSchema, ThreadContextWindowResponseSchema, ThreadDetailResponseSchema, ThreadGoalResponseSchema, ThreadGoalSchema, ThreadGoalStatusSchema, ThreadMessageDetailFieldSchema, ThreadMessageDetailResponseSchema, ThreadRunOptionsSchema, ThreadStateSchema, ThreadSummarySchema, UpdateRuntimePreferencesRequestSchema, UpdateThreadGoalRequestSchema, UpdateWorkspaceFileContentRequestSchema, VersionResponseSchema, WORKSPACE_PREVIEW_OPEN_PROTOCOL, WORKSPACE_PREVIEW_TAB_VALUES, WebPreviewTargetSchema, WorkspaceChangesResponseSchema, WorkspaceDirectoryEntrySchema, WorkspaceFileContentResponseSchema, WorkspaceFileMentionSchema, WorkspaceGitActionResponseSchema, WorkspaceMarkdownPreviewTargetSchema, WorkspacePreviewNavigationRequestSchema, WorkspacePreviewTabSchema, WorkspaceSelectionRequestSchema, WorkspaceTailscaleServeRequestSchema, WorkspaceTailscaleServeResponseSchema, WorkspaceTerminalInputRequestSchema, WorkspaceTerminalOutputChunkSchema, WorkspaceTerminalOutputResponseSchema, WorkspaceTerminalResizeRequestSchema, WorkspaceTerminalSessionResponseSchema, WorkspaceTerminalStartRequestSchema, apiPaths, chatMessageDetailsFromPromptContext, createOpenApiDocument, isPromptSkillMarkdownMention, normalizePromptContext, promptMarkdownWithSkills, promptSkillDisplayName, promptSkillMentionLabel, promptSkillMentionMarkdown, promptSkillMentionTextCandidates, stripPromptSkillMentions };
|
|
1
|
+
import { $ as ResolveApprovalResponseSchema, $t as promptSkillDisplayName, A as PairRequestSchema, At as WorkspaceChangesResponseSchema, B as PushNotificationIntentSchema, Bt as WorkspaceTailscaleServeResponseSchema, C as ListModelsResponseSchema, Ct as UpdateRuntimePreferencesRequestSchema, D as ListWorkspaceDirectoriesResponseSchema, Dt as WORKSPACE_PREVIEW_OPEN_PROTOCOL, E as ListThreadsResponseSchema, Et as VersionResponseSchema, F as PromptAttachmentSchema, Ft as WorkspaceMarkdownPreviewTargetSchema, G as RateLimitBucketSchema, Gt as WorkspaceTerminalSessionResponseSchema, H as PushNotificationSettingsResponseSchema, Ht as WorkspaceTerminalOutputChunkSchema, I as PromptAttachmentSummarySchema, It as WorkspacePreviewNavigationRequestSchema, J as ReasoningEffortSchema, Jt as chatMessageDetailsFromPromptContext, K as RateLimitWindowSchema, Kt as WorkspaceTerminalStartRequestSchema, L as PromptContextInputSchema, Lt as WorkspacePreviewTabSchema, M as PendingInputRequestOptionSchema, Mt as WorkspaceFileContentResponseSchema, N as PendingInputRequestQuestionSchema, Nt as WorkspaceFileMentionSchema, O as ListWorkspaceFilesResponseSchema, Ot as WORKSPACE_PREVIEW_TAB_VALUES, P as PendingInputRequestSchema, Pt as WorkspaceGitActionResponseSchema, Q as ResolveApprovalRequestSchema, Qt as promptMarkdownWithSkills, R as PromptContextSchema, Rt as WorkspaceSelectionRequestSchema, S as KnownReasoningEffortSchema, St as ThreadSummarySchema, T as ListSkillsResponseSchema, Tt as UpdateWorkspaceFileContentRequestSchema, U as QueuedThreadInputActionResponseSchema, Ut as WorkspaceTerminalOutputResponseSchema, V as PushNotificationPreferencesSchema, Vt as WorkspaceTerminalInputRequestSchema, W as QueuedThreadInputSchema, Wt as WorkspaceTerminalResizeRequestSchema, X as RenameThreadRequestSchema, Xt as isPromptSkillMarkdownMention, Y as RegisterPushNotificationRequestSchema, Yt as createOpenApiDocument, Z as RenameThreadResponseSchema, Zt as normalizePromptContext, _ as EncryptedPayloadSchema, _t as ThreadGoalStatusSchema, a as ArchiveThreadResponseSchema, at as RuntimePreferencesResponseSchema, b as InterruptThreadRunResponseSchema, bt as ThreadRunOptionsSchema, c as ChatMessageRoleSchema, ct as StatusResponseSchema, d as CheckoutWorkspaceBranchRequestSchema, dt as SubmitThreadInputResponseSchema, en as promptSkillMentionLabel, et as RewindThreadRequestSchema, f as CodexModelSchema, ft as ThreadCollaborationModeSchema, g as CreateThreadResponseSchema, gt as ThreadGoalSchema, h as CreateThreadRequestSchema, ht as ThreadGoalResponseSchema, i as ApprovalModeSchema, it as RuntimePreferencesByWorkspacePathSchema, j as PairResponseSchema, jt as WorkspaceDirectoryEntrySchema, k as PairEncryptedPayloadSchema, kt as WebPreviewTargetSchema, l as ChatMessageSchema, lt as StreamThreadRunEventSchema, m as ContextWindowUsageSchema, mt as ThreadDetailResponseSchema, n as AgentSkillSourceSchema, nn as promptSkillMentionTextCandidates, nt as RunThreadResponseSchema, o as ChatMessageKindSchema, ot as RuntimePreferencesSchema, p as CommitPushWorkspaceRequestSchema, pt as ThreadContextWindowResponseSchema, q as RateLimitsResponseSchema, qt as apiPaths, r as ApprovalDecisionSchema, rn as stripPromptSkillMentions, rt as RuntimeModeSchema, s as ChatMessagePromptDetailsSchema, st as SandboxModeSchema, t as AgentSkillSchema, tn as promptSkillMentionMarkdown, tt as RunThreadRequestSchema, u as ChatMessageStateSchema, ut as StreamThreadRunRequestSchema, v as ErrorResponseSchema, vt as ThreadMessageDetailFieldSchema, w as ListQueuedThreadInputsResponseSchema, wt as UpdateThreadGoalRequestSchema, x as IsoDateTimeSchema, xt as ThreadStateSchema, y as ImageAttachmentUploadResponseSchema, yt as ThreadMessageDetailResponseSchema, z as PromptSkillSchema, zt as WorkspaceTailscaleServeRequestSchema } from "./api-schema2.js";
|
|
2
|
+
export { AgentSkillSchema, AgentSkillSourceSchema, ApprovalDecisionSchema, ApprovalModeSchema, ArchiveThreadResponseSchema, ChatMessageKindSchema, ChatMessagePromptDetailsSchema, ChatMessageRoleSchema, ChatMessageSchema, ChatMessageStateSchema, CheckoutWorkspaceBranchRequestSchema, CodexModelSchema, CommitPushWorkspaceRequestSchema, ContextWindowUsageSchema, CreateThreadRequestSchema, CreateThreadResponseSchema, EncryptedPayloadSchema, ErrorResponseSchema, ImageAttachmentUploadResponseSchema, InterruptThreadRunResponseSchema, IsoDateTimeSchema, KnownReasoningEffortSchema, ListModelsResponseSchema, ListQueuedThreadInputsResponseSchema, ListSkillsResponseSchema, ListThreadsResponseSchema, ListWorkspaceDirectoriesResponseSchema, ListWorkspaceFilesResponseSchema, PairEncryptedPayloadSchema, PairRequestSchema, PairResponseSchema, PendingInputRequestOptionSchema, PendingInputRequestQuestionSchema, PendingInputRequestSchema, PromptAttachmentSchema, PromptAttachmentSummarySchema, PromptContextInputSchema, PromptContextSchema, PromptSkillSchema, PushNotificationIntentSchema, PushNotificationPreferencesSchema, PushNotificationSettingsResponseSchema, QueuedThreadInputActionResponseSchema, QueuedThreadInputSchema, RateLimitBucketSchema, RateLimitWindowSchema, RateLimitsResponseSchema, ReasoningEffortSchema, RegisterPushNotificationRequestSchema, RenameThreadRequestSchema, RenameThreadResponseSchema, ResolveApprovalRequestSchema, ResolveApprovalResponseSchema, RewindThreadRequestSchema, RunThreadRequestSchema, RunThreadResponseSchema, RuntimeModeSchema, RuntimePreferencesByWorkspacePathSchema, RuntimePreferencesResponseSchema, RuntimePreferencesSchema, SandboxModeSchema, StatusResponseSchema, StreamThreadRunEventSchema, StreamThreadRunRequestSchema, SubmitThreadInputResponseSchema, ThreadCollaborationModeSchema, ThreadContextWindowResponseSchema, ThreadDetailResponseSchema, ThreadGoalResponseSchema, ThreadGoalSchema, ThreadGoalStatusSchema, ThreadMessageDetailFieldSchema, ThreadMessageDetailResponseSchema, ThreadRunOptionsSchema, ThreadStateSchema, ThreadSummarySchema, UpdateRuntimePreferencesRequestSchema, UpdateThreadGoalRequestSchema, UpdateWorkspaceFileContentRequestSchema, VersionResponseSchema, WORKSPACE_PREVIEW_OPEN_PROTOCOL, WORKSPACE_PREVIEW_TAB_VALUES, WebPreviewTargetSchema, WorkspaceChangesResponseSchema, WorkspaceDirectoryEntrySchema, WorkspaceFileContentResponseSchema, WorkspaceFileMentionSchema, WorkspaceGitActionResponseSchema, WorkspaceMarkdownPreviewTargetSchema, WorkspacePreviewNavigationRequestSchema, WorkspacePreviewTabSchema, WorkspaceSelectionRequestSchema, WorkspaceTailscaleServeRequestSchema, WorkspaceTailscaleServeResponseSchema, WorkspaceTerminalInputRequestSchema, WorkspaceTerminalOutputChunkSchema, WorkspaceTerminalOutputResponseSchema, WorkspaceTerminalResizeRequestSchema, WorkspaceTerminalSessionResponseSchema, WorkspaceTerminalStartRequestSchema, apiPaths, chatMessageDetailsFromPromptContext, createOpenApiDocument, isPromptSkillMarkdownMention, normalizePromptContext, promptMarkdownWithSkills, promptSkillDisplayName, promptSkillMentionLabel, promptSkillMentionMarkdown, promptSkillMentionTextCandidates, stripPromptSkillMentions };
|
package/dist/api-schema2.js
CHANGED
|
@@ -553,6 +553,9 @@ const ArchiveThreadResponseSchema = z.object({
|
|
|
553
553
|
threads: z.array(ThreadSummarySchema),
|
|
554
554
|
source: z.enum(["app-server", "memory"]).default("memory")
|
|
555
555
|
});
|
|
556
|
+
const RenameThreadRequestSchema = z.object({ title: z.string().trim().min(1).max(120) });
|
|
557
|
+
const RenameThreadResponseSchema = z.object({ thread: ThreadSummarySchema });
|
|
558
|
+
const RewindThreadRequestSchema = z.object({ turnId: z.string().trim().min(1) });
|
|
556
559
|
const ListModelsResponseSchema = z.object({ models: z.array(CodexModelSchema) });
|
|
557
560
|
const ListSkillsResponseSchema = z.object({ skills: z.array(AgentSkillSchema) });
|
|
558
561
|
const ThreadDetailResponseSchema = z.object({
|
|
@@ -758,6 +761,8 @@ const apiPaths = {
|
|
|
758
761
|
threads: "/v1/threads",
|
|
759
762
|
thread: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}`,
|
|
760
763
|
threadArchive: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}`,
|
|
764
|
+
threadName: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}/name`,
|
|
765
|
+
threadRollback: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}/rollback`,
|
|
761
766
|
threadContextWindow: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}/context-window`,
|
|
762
767
|
threadGoal: (threadId) => `/v1/threads/${encodeURIComponent(threadId)}/goal`,
|
|
763
768
|
threadMessageDetail: (threadId, messageId, field) => `/v1/threads/${encodeURIComponent(threadId)}/messages/${encodeURIComponent(messageId)}/details/${encodeURIComponent(field)}`,
|
|
@@ -840,6 +845,10 @@ function createOpenApiDocument() {
|
|
|
840
845
|
in: "path",
|
|
841
846
|
required: true,
|
|
842
847
|
schema: { type: "string" }
|
|
848
|
+
}, {
|
|
849
|
+
name: "refresh",
|
|
850
|
+
in: "query",
|
|
851
|
+
schema: { type: "boolean" }
|
|
843
852
|
}],
|
|
844
853
|
responses: {
|
|
845
854
|
"200": jsonResponse("ThreadDetailResponse"),
|
|
@@ -861,6 +870,40 @@ function createOpenApiDocument() {
|
|
|
861
870
|
}
|
|
862
871
|
}
|
|
863
872
|
},
|
|
873
|
+
"/v1/threads/{threadId}/name": { post: {
|
|
874
|
+
summary: "Rename a Codex app-server thread",
|
|
875
|
+
parameters: [{
|
|
876
|
+
name: "threadId",
|
|
877
|
+
in: "path",
|
|
878
|
+
required: true,
|
|
879
|
+
schema: { type: "string" }
|
|
880
|
+
}],
|
|
881
|
+
requestBody: jsonRequest("RenameThreadRequest"),
|
|
882
|
+
responses: {
|
|
883
|
+
"200": jsonResponse("RenameThreadResponse"),
|
|
884
|
+
"400": jsonResponse("ErrorResponse"),
|
|
885
|
+
"404": jsonResponse("ErrorResponse"),
|
|
886
|
+
"409": jsonResponse("ErrorResponse"),
|
|
887
|
+
"502": jsonResponse("ErrorResponse")
|
|
888
|
+
}
|
|
889
|
+
} },
|
|
890
|
+
"/v1/threads/{threadId}/rollback": { post: {
|
|
891
|
+
summary: "Rewind a Codex app-server thread to before a selected turn",
|
|
892
|
+
parameters: [{
|
|
893
|
+
name: "threadId",
|
|
894
|
+
in: "path",
|
|
895
|
+
required: true,
|
|
896
|
+
schema: { type: "string" }
|
|
897
|
+
}],
|
|
898
|
+
requestBody: jsonRequest("RewindThreadRequest"),
|
|
899
|
+
responses: {
|
|
900
|
+
"200": jsonResponse("ThreadDetailResponse"),
|
|
901
|
+
"400": jsonResponse("ErrorResponse"),
|
|
902
|
+
"404": jsonResponse("ErrorResponse"),
|
|
903
|
+
"409": jsonResponse("ErrorResponse"),
|
|
904
|
+
"502": jsonResponse("ErrorResponse")
|
|
905
|
+
}
|
|
906
|
+
} },
|
|
864
907
|
"/v1/workspace-directories": { get: {
|
|
865
908
|
summary: "List directories under the configured workspace",
|
|
866
909
|
responses: {
|
|
@@ -1160,6 +1203,28 @@ function createOpenApiDocument() {
|
|
|
1160
1203
|
}, { type: "null" }] }
|
|
1161
1204
|
}
|
|
1162
1205
|
},
|
|
1206
|
+
RenameThreadRequest: {
|
|
1207
|
+
type: "object",
|
|
1208
|
+
required: ["title"],
|
|
1209
|
+
properties: { title: {
|
|
1210
|
+
type: "string",
|
|
1211
|
+
minLength: 1,
|
|
1212
|
+
maxLength: 120
|
|
1213
|
+
} }
|
|
1214
|
+
},
|
|
1215
|
+
RenameThreadResponse: {
|
|
1216
|
+
type: "object",
|
|
1217
|
+
required: ["thread"],
|
|
1218
|
+
properties: { thread: { $ref: "#/components/schemas/ThreadSummary" } }
|
|
1219
|
+
},
|
|
1220
|
+
RewindThreadRequest: {
|
|
1221
|
+
type: "object",
|
|
1222
|
+
required: ["turnId"],
|
|
1223
|
+
properties: { turnId: {
|
|
1224
|
+
type: "string",
|
|
1225
|
+
minLength: 1
|
|
1226
|
+
} }
|
|
1227
|
+
},
|
|
1163
1228
|
ThreadGoalResponse: {
|
|
1164
1229
|
type: "object",
|
|
1165
1230
|
required: ["goal", "thread"],
|
|
@@ -1801,4 +1866,4 @@ function jsonResponse(schemaName) {
|
|
|
1801
1866
|
};
|
|
1802
1867
|
}
|
|
1803
1868
|
//#endregion
|
|
1804
|
-
export {
|
|
1869
|
+
export { ResolveApprovalResponseSchema as $, promptSkillDisplayName as $t, PairRequestSchema as A, WorkspaceChangesResponseSchema as At, PushNotificationIntentSchema as B, WorkspaceTailscaleServeResponseSchema as Bt, ListModelsResponseSchema as C, UpdateRuntimePreferencesRequestSchema as Ct, ListWorkspaceDirectoriesResponseSchema as D, WORKSPACE_PREVIEW_OPEN_PROTOCOL as Dt, ListThreadsResponseSchema as E, VersionResponseSchema as Et, PromptAttachmentSchema as F, WorkspaceMarkdownPreviewTargetSchema as Ft, RateLimitBucketSchema as G, WorkspaceTerminalSessionResponseSchema as Gt, PushNotificationSettingsResponseSchema as H, WorkspaceTerminalOutputChunkSchema as Ht, PromptAttachmentSummarySchema as I, WorkspacePreviewNavigationRequestSchema as It, ReasoningEffortSchema as J, chatMessageDetailsFromPromptContext as Jt, RateLimitWindowSchema as K, WorkspaceTerminalStartRequestSchema as Kt, PromptContextInputSchema as L, WorkspacePreviewTabSchema as Lt, PendingInputRequestOptionSchema as M, WorkspaceFileContentResponseSchema as Mt, PendingInputRequestQuestionSchema as N, WorkspaceFileMentionSchema as Nt, ListWorkspaceFilesResponseSchema as O, WORKSPACE_PREVIEW_TAB_VALUES as Ot, PendingInputRequestSchema as P, WorkspaceGitActionResponseSchema as Pt, ResolveApprovalRequestSchema as Q, promptMarkdownWithSkills as Qt, PromptContextSchema as R, WorkspaceSelectionRequestSchema as Rt, KnownReasoningEffortSchema as S, ThreadSummarySchema as St, ListSkillsResponseSchema as T, UpdateWorkspaceFileContentRequestSchema as Tt, QueuedThreadInputActionResponseSchema as U, WorkspaceTerminalOutputResponseSchema as Ut, PushNotificationPreferencesSchema as V, WorkspaceTerminalInputRequestSchema as Vt, QueuedThreadInputSchema as W, WorkspaceTerminalResizeRequestSchema as Wt, RenameThreadRequestSchema as X, isPromptSkillMarkdownMention as Xt, RegisterPushNotificationRequestSchema as Y, createOpenApiDocument as Yt, RenameThreadResponseSchema as Z, normalizePromptContext as Zt, EncryptedPayloadSchema as _, ThreadGoalStatusSchema as _t, ArchiveThreadResponseSchema as a, RuntimePreferencesResponseSchema as at, InterruptThreadRunResponseSchema as b, ThreadRunOptionsSchema as bt, ChatMessageRoleSchema as c, StatusResponseSchema as ct, CheckoutWorkspaceBranchRequestSchema as d, SubmitThreadInputResponseSchema as dt, promptSkillMentionLabel as en, RewindThreadRequestSchema as et, CodexModelSchema as f, ThreadCollaborationModeSchema as ft, CreateThreadResponseSchema as g, ThreadGoalSchema as gt, CreateThreadRequestSchema as h, ThreadGoalResponseSchema as ht, ApprovalModeSchema as i, RuntimePreferencesByWorkspacePathSchema as it, PairResponseSchema as j, WorkspaceDirectoryEntrySchema as jt, PairEncryptedPayloadSchema as k, WebPreviewTargetSchema as kt, ChatMessageSchema as l, StreamThreadRunEventSchema as lt, ContextWindowUsageSchema as m, ThreadDetailResponseSchema as mt, AgentSkillSourceSchema as n, promptSkillMentionTextCandidates as nn, RunThreadResponseSchema as nt, ChatMessageKindSchema as o, RuntimePreferencesSchema as ot, CommitPushWorkspaceRequestSchema as p, ThreadContextWindowResponseSchema as pt, RateLimitsResponseSchema as q, apiPaths as qt, ApprovalDecisionSchema as r, stripPromptSkillMentions as rn, RuntimeModeSchema as rt, ChatMessagePromptDetailsSchema as s, SandboxModeSchema as st, AgentSkillSchema as t, promptSkillMentionMarkdown as tn, RunThreadRequestSchema as tt, ChatMessageStateSchema as u, StreamThreadRunRequestSchema as ut, ErrorResponseSchema as v, ThreadMessageDetailFieldSchema as vt, ListQueuedThreadInputsResponseSchema as w, UpdateThreadGoalRequestSchema as wt, IsoDateTimeSchema as x, ThreadStateSchema as xt, ImageAttachmentUploadResponseSchema as y, ThreadMessageDetailResponseSchema as yt, PromptSkillSchema as z, WorkspaceTailscaleServeRequestSchema as zt };
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { qt as apiPaths } from "./api-schema2.js";
|
|
3
3
|
import { n as codexRelayHome, o as getConnectUrlGuidance, r as legacyCodexRelayDataPath, s as createTursoPairingSessionStore, t as codexRelayDataPath } from "./paths.js";
|
|
4
4
|
import { Command } from "@commander-js/extra-typings";
|
|
5
5
|
import qrcode from "qrcode-terminal";
|
package/dist/paths.js
CHANGED
|
@@ -92,6 +92,7 @@ function createQueryableDatabase(executor) {
|
|
|
92
92
|
}
|
|
93
93
|
//#endregion
|
|
94
94
|
//#region src/pairing-store.ts
|
|
95
|
+
const permanentClientSessionExpiresAt = Date.parse("9999-12-31T23:59:59.999Z");
|
|
95
96
|
async function createTursoPairingSessionStore(path) {
|
|
96
97
|
if (path !== ":memory:") await mkdir(dirname(path), { recursive: true });
|
|
97
98
|
const db = await connect(path);
|
|
@@ -134,8 +135,8 @@ async function createTursoPairingSessionStore(path) {
|
|
|
134
135
|
);
|
|
135
136
|
`);
|
|
136
137
|
await ensurePairingSessionColumns();
|
|
137
|
-
async function countActive(
|
|
138
|
-
const row = await db.prepare("SELECT COUNT(DISTINCT COALESCE(client_session_id, token_hash)) AS count FROM pairing_sessions
|
|
138
|
+
async function countActive() {
|
|
139
|
+
const row = await db.prepare("SELECT COUNT(DISTINCT COALESCE(client_session_id, token_hash)) AS count FROM pairing_sessions").get();
|
|
139
140
|
return Number(row?.count ?? 0);
|
|
140
141
|
}
|
|
141
142
|
async function deleteSession(tokenHash) {
|
|
@@ -238,8 +239,8 @@ async function createTursoPairingSessionStore(path) {
|
|
|
238
239
|
created_at,
|
|
239
240
|
updated_at
|
|
240
241
|
)
|
|
241
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(tokenHash, session.clientSessionId ?? null, session.clientName ?? null, session.expiresAt, secure?.keyEpoch ?? null, secure?.mobileToServerKey ?? null, secure?.serverToMobileKey ?? null, secure?.lastMobileCounter ?? null, secure?.nextServerCounter ?? null, now, now);
|
|
242
|
-
return countActive(
|
|
242
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(tokenHash, session.clientSessionId ?? null, session.clientName ?? null, session.expiresAt ?? permanentClientSessionExpiresAt, secure?.keyEpoch ?? null, secure?.mobileToServerKey ?? null, secure?.serverToMobileKey ?? null, secure?.lastMobileCounter ?? null, secure?.nextServerCounter ?? null, now, now);
|
|
243
|
+
return countActive();
|
|
243
244
|
},
|
|
244
245
|
deleteSession,
|
|
245
246
|
deletePendingPairing,
|
|
@@ -254,7 +255,7 @@ async function createTursoPairingSessionStore(path) {
|
|
|
254
255
|
WHERE client_session_id = ?`).get(clientSessionId);
|
|
255
256
|
return row ? pushNotificationSubscriptionFromRow(row) : void 0;
|
|
256
257
|
},
|
|
257
|
-
async getValidSession(tokenHash
|
|
258
|
+
async getValidSession(tokenHash) {
|
|
258
259
|
const row = await db.prepare(`SELECT client_name AS clientName,
|
|
259
260
|
client_session_id AS clientSessionId,
|
|
260
261
|
expires_at AS expiresAt,
|
|
@@ -266,19 +267,14 @@ async function createTursoPairingSessionStore(path) {
|
|
|
266
267
|
FROM pairing_sessions
|
|
267
268
|
WHERE token_hash = ?`).get(tokenHash);
|
|
268
269
|
if (!row) return;
|
|
269
|
-
const expiresAt = Number(row.expiresAt);
|
|
270
|
-
if (now > expiresAt) {
|
|
271
|
-
await deleteSession(tokenHash);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
270
|
return {
|
|
275
271
|
clientSessionId: typeof row.clientSessionId === "string" ? row.clientSessionId : void 0,
|
|
276
272
|
clientName: typeof row.clientName === "string" ? row.clientName : void 0,
|
|
277
|
-
expiresAt,
|
|
273
|
+
expiresAt: Number(row.expiresAt),
|
|
278
274
|
secureSession: decodeSecureSession(row)
|
|
279
275
|
};
|
|
280
276
|
},
|
|
281
|
-
async listActivePushNotificationSubscriptions(
|
|
277
|
+
async listActivePushNotificationSubscriptions() {
|
|
282
278
|
return resultRows(await db.prepare(`SELECT subscriptions.client_session_id AS clientSessionId,
|
|
283
279
|
subscriptions.expo_push_token AS expoPushToken,
|
|
284
280
|
subscriptions.platform,
|
|
@@ -287,14 +283,12 @@ async function createTursoPairingSessionStore(path) {
|
|
|
287
283
|
FROM push_notification_subscriptions AS subscriptions
|
|
288
284
|
INNER JOIN pairing_sessions AS sessions
|
|
289
285
|
ON sessions.client_session_id = subscriptions.client_session_id
|
|
290
|
-
|
|
291
|
-
GROUP BY subscriptions.client_session_id`).all(now)).flatMap((row) => {
|
|
286
|
+
GROUP BY subscriptions.client_session_id`).all()).flatMap((row) => {
|
|
292
287
|
const subscription = pushNotificationSubscriptionFromRow(row);
|
|
293
288
|
return subscription ? [subscription] : [];
|
|
294
289
|
});
|
|
295
290
|
},
|
|
296
|
-
async
|
|
297
|
-
await db.prepare("DELETE FROM pairing_sessions WHERE expires_at <= ?").run(now);
|
|
291
|
+
async pruneExpiredPendingPairings(now) {
|
|
298
292
|
await db.prepare("DELETE FROM pending_pairings WHERE expires_at <= ?").run(now);
|
|
299
293
|
await db.prepare(`DELETE FROM push_notification_subscriptions
|
|
300
294
|
WHERE NOT EXISTS (
|
|
@@ -325,9 +319,9 @@ async function createTursoPairingSessionStore(path) {
|
|
|
325
319
|
created_at,
|
|
326
320
|
updated_at
|
|
327
321
|
)
|
|
328
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(newTokenHash, session.clientSessionId ?? null, session.clientName ?? null, session.expiresAt, secure?.keyEpoch ?? null, secure?.mobileToServerKey ?? null, secure?.serverToMobileKey ?? null, secure?.lastMobileCounter ?? null, secure?.nextServerCounter ?? null, now, now);
|
|
322
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(newTokenHash, session.clientSessionId ?? null, session.clientName ?? null, session.expiresAt ?? permanentClientSessionExpiresAt, secure?.keyEpoch ?? null, secure?.mobileToServerKey ?? null, secure?.serverToMobileKey ?? null, secure?.lastMobileCounter ?? null, secure?.nextServerCounter ?? null, now, now);
|
|
329
323
|
})();
|
|
330
|
-
return countActive(
|
|
324
|
+
return countActive();
|
|
331
325
|
},
|
|
332
326
|
async updateSecureSession(tokenHash, secureSession) {
|
|
333
327
|
const secure = encodeSecureSession(secureSession);
|
|
@@ -601,4 +595,4 @@ function defaultCodexRelayHome() {
|
|
|
601
595
|
}
|
|
602
596
|
}
|
|
603
597
|
//#endregion
|
|
604
|
-
export { getConnectUrlCandidates as a, createPairingQrPayload as i, codexRelayHome as n, getConnectUrlGuidance as o, legacyCodexRelayDataPath as r, createTursoPairingSessionStore as s, codexRelayDataPath as t };
|
|
598
|
+
export { getConnectUrlCandidates as a, permanentClientSessionExpiresAt as c, createPairingQrPayload as i, codexRelayHome as n, getConnectUrlGuidance as o, legacyCodexRelayDataPath as r, createTursoPairingSessionStore as s, codexRelayDataPath as t };
|
package/dist/src.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as PairRequestSchema, Bt as
|
|
2
|
-
import { a as getConnectUrlCandidates, i as createPairingQrPayload, o as getConnectUrlGuidance, r as legacyCodexRelayDataPath, s as createTursoPairingSessionStore, t as codexRelayDataPath } from "./paths.js";
|
|
1
|
+
import { $ as ResolveApprovalResponseSchema, A as PairRequestSchema, At as WorkspaceChangesResponseSchema, Bt as WorkspaceTailscaleServeResponseSchema, C as ListModelsResponseSchema, Ct as UpdateRuntimePreferencesRequestSchema, D as ListWorkspaceDirectoriesResponseSchema, E as ListThreadsResponseSchema, Et as VersionResponseSchema, Gt as WorkspaceTerminalSessionResponseSchema, H as PushNotificationSettingsResponseSchema, J as ReasoningEffortSchema, Jt as chatMessageDetailsFromPromptContext, Kt as WorkspaceTerminalStartRequestSchema, Mt as WorkspaceFileContentResponseSchema, O as ListWorkspaceFilesResponseSchema, Pt as WorkspaceGitActionResponseSchema, Q as ResolveApprovalRequestSchema, Qt as promptMarkdownWithSkills, S as KnownReasoningEffortSchema, St as ThreadSummarySchema, T as ListSkillsResponseSchema, Tt as UpdateWorkspaceFileContentRequestSchema, U as QueuedThreadInputActionResponseSchema, Ut as WorkspaceTerminalOutputResponseSchema, Vt as WorkspaceTerminalInputRequestSchema, Wt as WorkspaceTerminalResizeRequestSchema, X as RenameThreadRequestSchema, Y as RegisterPushNotificationRequestSchema, Yt as createOpenApiDocument, Z as RenameThreadResponseSchema, Zt as normalizePromptContext, _ as EncryptedPayloadSchema, _t as ThreadGoalStatusSchema, a as ArchiveThreadResponseSchema, at as RuntimePreferencesResponseSchema, b as InterruptThreadRunResponseSchema, ct as StatusResponseSchema, d as CheckoutWorkspaceBranchRequestSchema, dt as SubmitThreadInputResponseSchema, et as RewindThreadRequestSchema, gt as ThreadGoalSchema, h as CreateThreadRequestSchema, ht as ThreadGoalResponseSchema, j as PairResponseSchema, l as ChatMessageSchema, lt as StreamThreadRunEventSchema, m as ContextWindowUsageSchema, mt as ThreadDetailResponseSchema, ot as RuntimePreferencesSchema, p as CommitPushWorkspaceRequestSchema, pt as ThreadContextWindowResponseSchema, q as RateLimitsResponseSchema, qt as apiPaths, rn as stripPromptSkillMentions, tt as RunThreadRequestSchema, ut as StreamThreadRunRequestSchema, vt as ThreadMessageDetailFieldSchema, w as ListQueuedThreadInputsResponseSchema, wt as UpdateThreadGoalRequestSchema, y as ImageAttachmentUploadResponseSchema, yt as ThreadMessageDetailResponseSchema, zt as WorkspaceTailscaleServeRequestSchema } from "./api-schema2.js";
|
|
2
|
+
import { a as getConnectUrlCandidates, c as permanentClientSessionExpiresAt, i as createPairingQrPayload, o as getConnectUrlGuidance, r as legacyCodexRelayDataPath, s as createTursoPairingSessionStore, t as codexRelayDataPath } from "./paths.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import qrcode from "qrcode-terminal";
|
|
5
5
|
import { execFile, spawn } from "node:child_process";
|
|
@@ -209,6 +209,12 @@ var CodexAppServerClient = class {
|
|
|
209
209
|
async archiveThread(params) {
|
|
210
210
|
await this.request("thread/archive", params);
|
|
211
211
|
}
|
|
212
|
+
async setThreadName(params) {
|
|
213
|
+
await this.request("thread/name/set", params);
|
|
214
|
+
}
|
|
215
|
+
async rollbackThread(params) {
|
|
216
|
+
return (await this.request("thread/rollback", params)).thread;
|
|
217
|
+
}
|
|
212
218
|
async getThreadGoal(params) {
|
|
213
219
|
return (await this.request("thread/goal/get", params)).goal;
|
|
214
220
|
}
|
|
@@ -866,7 +872,7 @@ function createExpoPushNotificationSender(fetchImpl = fetch) {
|
|
|
866
872
|
}
|
|
867
873
|
function createPushNotificationDispatcher(input) {
|
|
868
874
|
return { async dispatch(event) {
|
|
869
|
-
const subscriptions = await input.sessions.listActivePushNotificationSubscriptions(
|
|
875
|
+
const subscriptions = await input.sessions.listActivePushNotificationSubscriptions();
|
|
870
876
|
const selectedTokens = new Set(subscriptions.filter((subscription) => notificationEnabled(subscription, event.intent)).map((subscription) => subscription.expoPushToken));
|
|
871
877
|
if (selectedTokens.size === 0) return;
|
|
872
878
|
const delivery = await input.sender.send([...selectedTokens].map((expoPushToken) => notificationForEvent(expoPushToken, event)));
|
|
@@ -1463,6 +1469,7 @@ function createApp(options = {}) {
|
|
|
1463
1469
|
const resolvedApprovals = /* @__PURE__ */ new Map();
|
|
1464
1470
|
const queuedInputsByThreadId = /* @__PURE__ */ new Map();
|
|
1465
1471
|
const threadOperationTails = /* @__PURE__ */ new Map();
|
|
1472
|
+
const appServerMutationTails = /* @__PURE__ */ new Map();
|
|
1466
1473
|
const workspaceTerminalSessions = /* @__PURE__ */ new Map();
|
|
1467
1474
|
const activeAppServerTurnIdsByThreadId = /* @__PURE__ */ new Map();
|
|
1468
1475
|
const appServerHistoryLoadsByThreadId = /* @__PURE__ */ new Map();
|
|
@@ -1479,6 +1486,15 @@ function createApp(options = {}) {
|
|
|
1479
1486
|
});
|
|
1480
1487
|
return result;
|
|
1481
1488
|
}
|
|
1489
|
+
function runAppServerMutation(threadId, operation) {
|
|
1490
|
+
const result = (appServerMutationTails.get(threadId) ?? Promise.resolve()).then(operation, operation);
|
|
1491
|
+
const tail = result.then(() => void 0, () => void 0);
|
|
1492
|
+
appServerMutationTails.set(threadId, tail);
|
|
1493
|
+
tail.finally(() => {
|
|
1494
|
+
if (appServerMutationTails.get(threadId) === tail) appServerMutationTails.delete(threadId);
|
|
1495
|
+
});
|
|
1496
|
+
return result;
|
|
1497
|
+
}
|
|
1482
1498
|
const pushNotificationDispatcher = options.pairing ? createPushNotificationDispatcher({
|
|
1483
1499
|
sender: options.pushNotificationSender ?? createExpoPushNotificationSender(),
|
|
1484
1500
|
sessions: options.pairing.sessions
|
|
@@ -1492,7 +1508,7 @@ function createApp(options = {}) {
|
|
|
1492
1508
|
threadId
|
|
1493
1509
|
});
|
|
1494
1510
|
const load = appServer.readThread(threadId, { includeTurns: true }).then((threadWithTurns) => {
|
|
1495
|
-
const mappedThread = rememberAppServerThread(threads, threadWithTurns);
|
|
1511
|
+
const mappedThread = rememberAppServerThread(threads, threadWithTurns, { authoritativeMessageCount: true });
|
|
1496
1512
|
const messages = mergeAppServerMessagesWithLocalStatus(mapAppServerMessages(threadWithTurns), messagesByThreadId.get(threadId) ?? cachedMessages);
|
|
1497
1513
|
messagesByThreadId.set(threadId, messages);
|
|
1498
1514
|
relayDebugLog("thread.detail.history.background_completed", {
|
|
@@ -1520,7 +1536,7 @@ function createApp(options = {}) {
|
|
|
1520
1536
|
}
|
|
1521
1537
|
const token = parseBearerToken(c.req.header("authorization"));
|
|
1522
1538
|
const tokenHash = token ? options.pairing.hashClientToken(token) : void 0;
|
|
1523
|
-
const validSession = tokenHash ? await options.pairing.sessions.getValidSession(tokenHash
|
|
1539
|
+
const validSession = tokenHash ? await options.pairing.sessions.getValidSession(tokenHash) : void 0;
|
|
1524
1540
|
if (!tokenHash || !validSession) return c.json(apiError("unauthorized", "Pair this device with the Codex Relay server."), 401);
|
|
1525
1541
|
if (options.pairing.serverIdentity && !secureSessionsByTokenHash.has(tokenHash)) if (validSession.secureSession) secureSessionsByTokenHash.set(tokenHash, validSession.secureSession);
|
|
1526
1542
|
else return c.json(apiError("secure_session_required", "Secure session expired. Pair this device again."), 401);
|
|
@@ -1541,7 +1557,7 @@ function createApp(options = {}) {
|
|
|
1541
1557
|
const parsed = await parsePlainJson(c.req.raw, PairRequestSchema);
|
|
1542
1558
|
if (!parsed.success) return c.json(validationError(parsed.error), 400);
|
|
1543
1559
|
if (!parsed.data.secure || !options.pairing.serverIdentity) return c.json(apiError("secure_pairing_required", "Pairing requires the secure QR approval flow."), 400);
|
|
1544
|
-
await options.pairing.sessions.
|
|
1560
|
+
await options.pairing.sessions.pruneExpiredPendingPairings(Date.now());
|
|
1545
1561
|
const approvalCode = await createApprovalCode(options.pairing.sessions);
|
|
1546
1562
|
const expiresAt = Date.now() + (options.pairing.approvalTtlMs ?? 300 * 1e3);
|
|
1547
1563
|
const requestOrigin = externalRequestOrigin(c.req.url, (name) => c.req.header(name));
|
|
@@ -1579,11 +1595,10 @@ function createApp(options = {}) {
|
|
|
1579
1595
|
approvalCode,
|
|
1580
1596
|
approvalExpiresAt: new Date(pending.expiresAt).toISOString()
|
|
1581
1597
|
}), 202);
|
|
1582
|
-
await options.pairing.sessions.
|
|
1598
|
+
await options.pairing.sessions.pruneExpiredPendingPairings(Date.now());
|
|
1583
1599
|
const clientToken = options.pairing.createClientToken();
|
|
1584
|
-
const expiresAt = Date.now() + options.pairing.tokenTtlMs;
|
|
1585
1600
|
const tokenHash = options.pairing.hashClientToken(clientToken);
|
|
1586
|
-
const clientTokenExpiresAt = new Date(
|
|
1601
|
+
const clientTokenExpiresAt = new Date(permanentClientSessionExpiresAt).toISOString();
|
|
1587
1602
|
const pairing = createSecurePairing({
|
|
1588
1603
|
approvalCode,
|
|
1589
1604
|
clientEphemeralPublicKey: pending.clientEphemeralPublicKey,
|
|
@@ -1597,7 +1612,6 @@ function createApp(options = {}) {
|
|
|
1597
1612
|
const tokenCount = await options.pairing.sessions.createSession(tokenHash, {
|
|
1598
1613
|
clientSessionId: pending.clientSessionId,
|
|
1599
1614
|
clientName: pending.clientName,
|
|
1600
|
-
expiresAt,
|
|
1601
1615
|
secureSession: pairing.session
|
|
1602
1616
|
});
|
|
1603
1617
|
await options.pairing.sessions.deletePendingPairing(approvalCode);
|
|
@@ -1640,14 +1654,12 @@ function createApp(options = {}) {
|
|
|
1640
1654
|
const oldSession = oldToken ? await getValidClientSession(options.pairing, oldToken) : void 0;
|
|
1641
1655
|
if (!oldToken || !oldSession) return c.json(apiError("unauthorized", "Pair this device with the Codex Relay server."), 401);
|
|
1642
1656
|
const clientToken = options.pairing.createClientToken();
|
|
1643
|
-
const expiresAt = Date.now() + options.pairing.tokenTtlMs;
|
|
1644
1657
|
const oldTokenHash = options.pairing.hashClientToken(oldToken);
|
|
1645
1658
|
const newTokenHash = options.pairing.hashClientToken(clientToken);
|
|
1646
1659
|
const clientSessionId = normalizeClientSessionId(c.req.header("x-codex-relay-client-session-id")) ?? oldSession.clientSessionId;
|
|
1647
1660
|
const tokenCount = await options.pairing.sessions.rotateSession(oldTokenHash, newTokenHash, {
|
|
1648
1661
|
clientSessionId,
|
|
1649
1662
|
clientName: oldSession.clientName,
|
|
1650
|
-
expiresAt,
|
|
1651
1663
|
secureSession: secureSessionsByTokenHash.get(oldTokenHash) ?? oldSession.secureSession
|
|
1652
1664
|
});
|
|
1653
1665
|
const secureSession = secureSessionsByTokenHash.get(oldTokenHash) ?? oldSession.secureSession;
|
|
@@ -1658,7 +1670,7 @@ function createApp(options = {}) {
|
|
|
1658
1670
|
});
|
|
1659
1671
|
const response = PairResponseSchema.parse({
|
|
1660
1672
|
clientToken,
|
|
1661
|
-
clientTokenExpiresAt: new Date(
|
|
1673
|
+
clientTokenExpiresAt: new Date(permanentClientSessionExpiresAt).toISOString()
|
|
1662
1674
|
});
|
|
1663
1675
|
const jsonResponse = await secureJson(c, options.pairing, secureSessionsByTokenHash, response, 201);
|
|
1664
1676
|
if (secureSession) {
|
|
@@ -2151,8 +2163,73 @@ function createApp(options = {}) {
|
|
|
2151
2163
|
});
|
|
2152
2164
|
return secureJson(c, options.pairing, secureSessionsByTokenHash, response);
|
|
2153
2165
|
});
|
|
2166
|
+
app.post("/v1/threads/:threadId/name", async (c) => {
|
|
2167
|
+
const threadId = c.req.param("threadId");
|
|
2168
|
+
if (!appServer) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("unsupported", "Renaming threads requires the Codex app-server."), 409);
|
|
2169
|
+
if (!await ensureKnownThread({
|
|
2170
|
+
appServer,
|
|
2171
|
+
threadId,
|
|
2172
|
+
messagesByThreadId,
|
|
2173
|
+
threads
|
|
2174
|
+
})) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", `Thread ${threadId} is not known to this server.`), 404);
|
|
2175
|
+
const parsed = await parseRequestJson(c, options.pairing, secureSessionsByTokenHash, RenameThreadRequestSchema);
|
|
2176
|
+
if (!parsed.success) return secureJson(c, options.pairing, secureSessionsByTokenHash, validationError(parsed.error), 400);
|
|
2177
|
+
try {
|
|
2178
|
+
const body = parsed.data;
|
|
2179
|
+
const thread = await runAppServerMutation(threadId, async () => {
|
|
2180
|
+
await appServer.setThreadName({
|
|
2181
|
+
name: body.title,
|
|
2182
|
+
threadId
|
|
2183
|
+
});
|
|
2184
|
+
return rememberAppServerThread(threads, await appServer.readThread(threadId, { includeTurns: false }));
|
|
2185
|
+
});
|
|
2186
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, RenameThreadResponseSchema.parse({ thread }));
|
|
2187
|
+
} catch (error) {
|
|
2188
|
+
const message = errorMessage(error);
|
|
2189
|
+
const status = /not found|no rollout found/i.test(message) ? 404 : 502;
|
|
2190
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError(status === 404 ? "not_found" : "rename_unavailable", message), status);
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
app.post("/v1/threads/:threadId/rollback", async (c) => {
|
|
2194
|
+
const threadId = c.req.param("threadId");
|
|
2195
|
+
if (!appServer) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("unsupported", "Rewinding threads requires the Codex app-server."), 409);
|
|
2196
|
+
const parsed = await parseRequestJson(c, options.pairing, secureSessionsByTokenHash, RewindThreadRequestSchema);
|
|
2197
|
+
if (!parsed.success) return secureJson(c, options.pairing, secureSessionsByTokenHash, validationError(parsed.error), 400);
|
|
2198
|
+
return runThreadOperation(threadId, () => runAppServerMutation(threadId, async () => {
|
|
2199
|
+
try {
|
|
2200
|
+
const threadBeforeRewind = await appServer.readThread(threadId, { includeTurns: true });
|
|
2201
|
+
if (isSubagentThread(threadBeforeRewind)) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", `Thread ${threadId} is not known to this server.`), 404);
|
|
2202
|
+
if (mapAppServerThreadState(threadBeforeRewind.status, threadBeforeRewind.turns) === "running" || activeAppServerTurnIdsByThreadId.has(threadId)) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("thread_running", "Stop the current turn before rewinding this chat."), 409);
|
|
2203
|
+
const turns = threadBeforeRewind.turns ?? [];
|
|
2204
|
+
const turnIndex = turns.findIndex((turn) => turn.id === parsed.data.turnId);
|
|
2205
|
+
if (turnIndex < 0) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", "The selected message is no longer available to rewind."), 404);
|
|
2206
|
+
const rolledBackThread = await appServer.rollbackThread({
|
|
2207
|
+
threadId,
|
|
2208
|
+
numTurns: turns.length - turnIndex
|
|
2209
|
+
});
|
|
2210
|
+
const threadWithTurns = rolledBackThread.turns === void 0 ? await appServer.readThread(threadId, { includeTurns: true }) : rolledBackThread;
|
|
2211
|
+
const thread = rememberAppServerThread(threads, threadWithTurns, { authoritativeMessageCount: true });
|
|
2212
|
+
const messages = mapAppServerMessages(threadWithTurns);
|
|
2213
|
+
messagesByThreadId.set(threadId, messages);
|
|
2214
|
+
liveThreads.delete(threadId);
|
|
2215
|
+
activeAppServerTurnIdsByThreadId.delete(threadId);
|
|
2216
|
+
queuedInputsByThreadId.delete(threadId);
|
|
2217
|
+
steeringThreads.delete(threadId);
|
|
2218
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, threadDetailResponse({
|
|
2219
|
+
thread,
|
|
2220
|
+
messages,
|
|
2221
|
+
pendingInputRequests: []
|
|
2222
|
+
}));
|
|
2223
|
+
} catch (error) {
|
|
2224
|
+
const message = errorMessage(error);
|
|
2225
|
+
const status = /not found|no rollout found/i.test(message) ? 404 : 502;
|
|
2226
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError(status === 404 ? "not_found" : "rewind_unavailable", message), status);
|
|
2227
|
+
}
|
|
2228
|
+
}));
|
|
2229
|
+
});
|
|
2154
2230
|
app.get("/v1/threads/:threadId", async (c) => {
|
|
2155
2231
|
const threadId = c.req.param("threadId");
|
|
2232
|
+
const forceRefresh = c.req.query("refresh") === "true";
|
|
2156
2233
|
const detailStartedAt = Date.now();
|
|
2157
2234
|
relayDebugLog("thread.detail.requested", { threadId });
|
|
2158
2235
|
const knownThread = threads.get(threadId);
|
|
@@ -2166,21 +2243,29 @@ function createApp(options = {}) {
|
|
|
2166
2243
|
let loadedMessages = false;
|
|
2167
2244
|
let messages = cachedMessages;
|
|
2168
2245
|
let responseThread = preserveKnownRunningThreadState(mappedThread, wasKnownRunning);
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
responseThread = preserveKnownRunningThreadState(responseThread, wasKnownRunning);
|
|
2246
|
+
if (forceRefresh && responseThread.state !== "running") {
|
|
2247
|
+
const threadWithTurns = await appServer.readThread(threadId, { includeTurns: true });
|
|
2248
|
+
responseThread = rememberAppServerThread(threads, threadWithTurns, { authoritativeMessageCount: true });
|
|
2249
|
+
messages = mapAppServerMessages(threadWithTurns);
|
|
2174
2250
|
messagesByThreadId.set(threadId, messages);
|
|
2175
2251
|
loadedMessages = true;
|
|
2176
|
-
} else
|
|
2177
|
-
|
|
2178
|
-
if (messages.length
|
|
2179
|
-
|
|
2252
|
+
} else {
|
|
2253
|
+
const rolloutHistory = readRolloutThreadMessages(threadId, workspacePath);
|
|
2254
|
+
if (rolloutHistory.messages.length > 0) {
|
|
2255
|
+
messages = mergeThreadMessagePages(rolloutHistory.messages, cachedMessages);
|
|
2256
|
+
responseThread = rememberRolloutThreadMessages(threads, responseThread, messages, rolloutHistory.messageCountLowerBound);
|
|
2257
|
+
responseThread = preserveKnownRunningThreadState(responseThread, wasKnownRunning);
|
|
2258
|
+
messagesByThreadId.set(threadId, messages);
|
|
2259
|
+
loadedMessages = true;
|
|
2260
|
+
} else if (cachedMessages.length > 0) {
|
|
2261
|
+
messages = dedupeThreadMessages(cachedMessages);
|
|
2262
|
+
if (messages.length !== cachedMessages.length) messagesByThreadId.set(threadId, messages);
|
|
2263
|
+
loadedMessages = true;
|
|
2264
|
+
}
|
|
2180
2265
|
}
|
|
2181
2266
|
if (!loadedMessages && responseThread.state !== "running") {
|
|
2182
2267
|
const threadWithTurns = await appServer.readThread(threadId, { includeTurns: true });
|
|
2183
|
-
responseThread = rememberAppServerThread(threads, threadWithTurns);
|
|
2268
|
+
responseThread = rememberAppServerThread(threads, threadWithTurns, { authoritativeMessageCount: true });
|
|
2184
2269
|
messages = mergeAppServerMessagesWithLocalStatus(mapAppServerMessages(threadWithTurns), cachedMessages);
|
|
2185
2270
|
messagesByThreadId.set(threadId, messages);
|
|
2186
2271
|
loadedMessages = true;
|
|
@@ -2507,30 +2592,32 @@ function createApp(options = {}) {
|
|
|
2507
2592
|
app.post("/v1/threads/:threadId/input/:inputId/steer", async (c) => {
|
|
2508
2593
|
const threadId = c.req.param("threadId");
|
|
2509
2594
|
const inputId = c.req.param("inputId");
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2595
|
+
return runThreadOperation(threadId, async () => {
|
|
2596
|
+
const knownThread = await ensureKnownThread({
|
|
2597
|
+
appServer,
|
|
2598
|
+
threadId,
|
|
2599
|
+
messagesByThreadId,
|
|
2600
|
+
threads
|
|
2601
|
+
});
|
|
2602
|
+
if (!knownThread) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", `Thread ${threadId} is not known to this server.`), 404);
|
|
2603
|
+
if (!appServer) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("unsupported", "Running-thread input requires the Codex app-server."), 409);
|
|
2604
|
+
if (knownThread.state !== "running") return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("thread_not_running", `Thread ${threadId} is not currently running.`), 409);
|
|
2605
|
+
const queuedInput = removeQueuedInput(queuedInputsByThreadId, threadId, inputId);
|
|
2606
|
+
if (!queuedInput) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", `Queued input ${inputId} is not known to this thread.`), 404);
|
|
2607
|
+
steeringThreads.add(threadId);
|
|
2608
|
+
await runAppServerMutation(threadId, () => startAppServerTurn(appServer, threadId, queuedInput));
|
|
2609
|
+
const thread = updateThread(threads, messagesByThreadId, threadId, {
|
|
2610
|
+
state: "running",
|
|
2611
|
+
lastPrompt: promptWithAttachmentReferences(queuedInput.prompt, queuedInput.attachments),
|
|
2612
|
+
lastError: void 0
|
|
2613
|
+
});
|
|
2614
|
+
const response = QueuedThreadInputActionResponseSchema.parse({
|
|
2615
|
+
input: queuedThreadInputSummary(queuedInput),
|
|
2616
|
+
queueLength: queuedInputsByThreadId.get(threadId)?.length ?? 0,
|
|
2617
|
+
thread
|
|
2618
|
+
});
|
|
2619
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, response, 202);
|
|
2532
2620
|
});
|
|
2533
|
-
return secureJson(c, options.pairing, secureSessionsByTokenHash, response, 202);
|
|
2534
2621
|
});
|
|
2535
2622
|
app.post("/v1/threads/:threadId/runs/interrupt", async (c) => {
|
|
2536
2623
|
const threadId = c.req.param("threadId");
|
|
@@ -2717,6 +2804,7 @@ function createApp(options = {}) {
|
|
|
2717
2804
|
messagesByThreadId,
|
|
2718
2805
|
pendingApprovals,
|
|
2719
2806
|
queuedInputsByThreadId,
|
|
2807
|
+
runAppServerMutation,
|
|
2720
2808
|
runThreadOperation,
|
|
2721
2809
|
prompt: rawPrompt,
|
|
2722
2810
|
attachments: runOptions.attachments ?? [],
|
|
@@ -2763,7 +2851,7 @@ async function pairedClientSessionIdForAuthorization(authorization, pairing) {
|
|
|
2763
2851
|
if (!pairing) return;
|
|
2764
2852
|
const token = parseBearerToken(authorization);
|
|
2765
2853
|
if (!token) return;
|
|
2766
|
-
return (await pairing.sessions.getValidSession(pairing.hashClientToken(token)
|
|
2854
|
+
return (await pairing.sessions.getValidSession(pairing.hashClientToken(token)))?.clientSessionId;
|
|
2767
2855
|
}
|
|
2768
2856
|
function defaultPushNotificationPreferences() {
|
|
2769
2857
|
return {
|
|
@@ -2805,7 +2893,7 @@ async function createApprovalCode(sessions) {
|
|
|
2805
2893
|
throw new Error("Unable to allocate a pairing approval code.");
|
|
2806
2894
|
}
|
|
2807
2895
|
async function getValidClientSession(pairing, token) {
|
|
2808
|
-
return pairing.sessions.getValidSession(pairing.hashClientToken(token)
|
|
2896
|
+
return pairing.sessions.getValidSession(pairing.hashClientToken(token));
|
|
2809
2897
|
}
|
|
2810
2898
|
function externalRequestOrigin(requestUrl, header) {
|
|
2811
2899
|
const request = new URL(requestUrl);
|
|
@@ -2929,6 +3017,7 @@ async function runPromptStreamed(input) {
|
|
|
2929
3017
|
messagesByThreadId: input.messagesByThreadId,
|
|
2930
3018
|
pendingApprovals: input.pendingApprovals,
|
|
2931
3019
|
queuedInputsByThreadId: input.queuedInputsByThreadId,
|
|
3020
|
+
runAppServerMutation: input.runAppServerMutation,
|
|
2932
3021
|
runThreadOperation: input.runThreadOperation,
|
|
2933
3022
|
prompt: input.prompt,
|
|
2934
3023
|
runOptions: input.runOptions,
|
|
@@ -3549,7 +3638,7 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3549
3638
|
observedInputRequest = false;
|
|
3550
3639
|
producedTurnOutput = false;
|
|
3551
3640
|
}
|
|
3552
|
-
function finishTerminalTurn(options) {
|
|
3641
|
+
async function finishTerminalTurn(options) {
|
|
3553
3642
|
const terminalTurnId = options.turnId ?? activeTurnId;
|
|
3554
3643
|
if (terminalTurnId && finalizedTurnIds.has(terminalTurnId)) return;
|
|
3555
3644
|
if (terminalTurnId) {
|
|
@@ -3627,25 +3716,36 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3627
3716
|
handedOffToQueuedTurn = true;
|
|
3628
3717
|
resetTurnTracking();
|
|
3629
3718
|
input.steeringThreads.add(activeThreadId);
|
|
3630
|
-
startAppServerTurn(input.appServer, activeThreadId, nextQueuedInput)
|
|
3631
|
-
cleanupNotificationHandler();
|
|
3632
|
-
rejectCompleted(error);
|
|
3633
|
-
});
|
|
3719
|
+
await processReturnedTurn(await startAppServerTurn(input.appServer, activeThreadId, nextQueuedInput));
|
|
3634
3720
|
return;
|
|
3635
3721
|
}
|
|
3636
3722
|
input.steeringThreads.delete(activeThreadId);
|
|
3637
3723
|
cleanupNotificationHandler();
|
|
3638
3724
|
resolveCompleted();
|
|
3639
3725
|
}
|
|
3640
|
-
function processReturnedTurn(turn) {
|
|
3726
|
+
async function processReturnedTurn(turn) {
|
|
3641
3727
|
if (finalizedTurnIds.has(turn.id)) return;
|
|
3642
3728
|
activeTurnId = turn.id;
|
|
3643
3729
|
input.activeAppServerTurnIdsByThreadId.set(activeThreadId, turn.id);
|
|
3644
3730
|
const turnIsRunning = isAppServerTurnRunning(turn);
|
|
3645
3731
|
for (const item of turn.items) {
|
|
3732
|
+
const previousUserMessage = userMessage;
|
|
3646
3733
|
const canonicalUserMessage = replaceDuplicateInitialUserMessage(input.messagesByThreadId, activeThreadId, turn.id, item, userMessage.id, displayPrompt);
|
|
3647
3734
|
if (canonicalUserMessage) {
|
|
3648
3735
|
userMessage = canonicalUserMessage;
|
|
3736
|
+
if (canonicalUserMessage.id !== previousUserMessage.id || canonicalUserMessage.turnId !== previousUserMessage.turnId) {
|
|
3737
|
+
relayDebugLog("app_server.user_message.canonicalized", {
|
|
3738
|
+
messageId: canonicalUserMessage.id,
|
|
3739
|
+
previousMessageId: previousUserMessage.id,
|
|
3740
|
+
threadId: activeThreadId,
|
|
3741
|
+
turnId: canonicalUserMessage.turnId
|
|
3742
|
+
});
|
|
3743
|
+
sendSse(input.controller, input.encoder, input.secureSession, {
|
|
3744
|
+
type: "thread.message.created",
|
|
3745
|
+
thread: threadSummary,
|
|
3746
|
+
message: canonicalUserMessage
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3649
3749
|
continue;
|
|
3650
3750
|
}
|
|
3651
3751
|
const message = upsertAppServerItemMessage(input.messagesByThreadId, activeThreadId, turn.id, item);
|
|
@@ -3665,13 +3765,20 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3665
3765
|
if (turnIsRunning) return;
|
|
3666
3766
|
const params = { turn };
|
|
3667
3767
|
const state = terminalTurnState("turn/completed", params);
|
|
3668
|
-
finishTerminalTurn({
|
|
3768
|
+
await finishTerminalTurn({
|
|
3669
3769
|
lastError: state === "failed" ? turnErrorMessage(params) : void 0,
|
|
3670
3770
|
method: "turn/returned",
|
|
3671
3771
|
state,
|
|
3672
3772
|
turnId: turn.id
|
|
3673
3773
|
});
|
|
3674
3774
|
}
|
|
3775
|
+
function startAndProcessAppServerTurn(threadId, queuedInput) {
|
|
3776
|
+
return input.runAppServerMutation(threadId, async () => {
|
|
3777
|
+
const turn = await startAppServerTurn(input.appServer, threadId, queuedInput);
|
|
3778
|
+
await processReturnedTurn(turn);
|
|
3779
|
+
return turn;
|
|
3780
|
+
});
|
|
3781
|
+
}
|
|
3675
3782
|
const completed = new Promise((resolve, reject) => {
|
|
3676
3783
|
resolveCompleted = resolve;
|
|
3677
3784
|
rejectCompleted = reject;
|
|
@@ -3711,9 +3818,23 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3711
3818
|
case "item/completed": {
|
|
3712
3819
|
const item = params?.item;
|
|
3713
3820
|
if (!item || typeof item !== "object") return;
|
|
3821
|
+
const previousUserMessage = userMessage;
|
|
3714
3822
|
const canonicalUserMessage = replaceDuplicateInitialUserMessage(input.messagesByThreadId, activeThreadId, firstString(params, ["turnId"]) ?? activeTurnId, item, userMessage.id, displayPrompt);
|
|
3715
3823
|
if (canonicalUserMessage) {
|
|
3716
3824
|
userMessage = canonicalUserMessage;
|
|
3825
|
+
if (canonicalUserMessage.id !== previousUserMessage.id || canonicalUserMessage.turnId !== previousUserMessage.turnId) {
|
|
3826
|
+
relayDebugLog("app_server.user_message.canonicalized", {
|
|
3827
|
+
messageId: canonicalUserMessage.id,
|
|
3828
|
+
previousMessageId: previousUserMessage.id,
|
|
3829
|
+
threadId: activeThreadId,
|
|
3830
|
+
turnId: canonicalUserMessage.turnId
|
|
3831
|
+
});
|
|
3832
|
+
sendSse(input.controller, input.encoder, input.secureSession, {
|
|
3833
|
+
type: "thread.message.created",
|
|
3834
|
+
thread: threadSummary,
|
|
3835
|
+
message: canonicalUserMessage
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3717
3838
|
return;
|
|
3718
3839
|
}
|
|
3719
3840
|
const turnId = firstString(params, ["turnId"]) ?? activeTurnId;
|
|
@@ -3784,12 +3905,12 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3784
3905
|
const state = terminalTurnState(notification.method, params);
|
|
3785
3906
|
const terminalTurnId = firstString(params, ["turnId"]) ?? turnIdFromParams(params) ?? activeTurnId;
|
|
3786
3907
|
input.runThreadOperation(activeThreadId, async () => {
|
|
3787
|
-
finishTerminalTurn({
|
|
3908
|
+
await input.runAppServerMutation(activeThreadId, () => finishTerminalTurn({
|
|
3788
3909
|
lastError: state === "failed" ? turnErrorMessage(params) : void 0,
|
|
3789
3910
|
method: notification.method,
|
|
3790
3911
|
state,
|
|
3791
3912
|
turnId: terminalTurnId
|
|
3792
|
-
});
|
|
3913
|
+
}));
|
|
3793
3914
|
}).catch((error) => {
|
|
3794
3915
|
cleanupNotificationHandler();
|
|
3795
3916
|
rejectCompleted(error);
|
|
@@ -3850,7 +3971,7 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3850
3971
|
debugStream("start turn begin", activeThreadId);
|
|
3851
3972
|
let turn;
|
|
3852
3973
|
try {
|
|
3853
|
-
turn = await
|
|
3974
|
+
turn = await startAndProcessAppServerTurn(activeThreadId, {
|
|
3854
3975
|
attachments: input.attachments,
|
|
3855
3976
|
id: randomUUID(),
|
|
3856
3977
|
prompt,
|
|
@@ -3884,7 +4005,7 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3884
4005
|
thread: threadSummary,
|
|
3885
4006
|
message: userMessage
|
|
3886
4007
|
});
|
|
3887
|
-
turn = await
|
|
4008
|
+
turn = await startAndProcessAppServerTurn(activeThreadId, {
|
|
3888
4009
|
attachments: input.attachments,
|
|
3889
4010
|
id: randomUUID(),
|
|
3890
4011
|
prompt,
|
|
@@ -3894,7 +4015,6 @@ async function runAppServerPromptStreamed(input) {
|
|
|
3894
4015
|
});
|
|
3895
4016
|
}
|
|
3896
4017
|
debugStream("start turn complete", activeThreadId, turn.id);
|
|
3897
|
-
processReturnedTurn(turn);
|
|
3898
4018
|
await completed;
|
|
3899
4019
|
} catch (error) {
|
|
3900
4020
|
debugStream(`failed ${errorMessage(error)}`, activeThreadId, activeTurnId);
|
|
@@ -4862,9 +4982,9 @@ function mapAppServerThread(thread, fallbackMessageCount) {
|
|
|
4862
4982
|
lastActivityAt: updatedAt
|
|
4863
4983
|
});
|
|
4864
4984
|
}
|
|
4865
|
-
function rememberAppServerThread(threads, thread) {
|
|
4985
|
+
function rememberAppServerThread(threads, thread, options = {}) {
|
|
4866
4986
|
const existingThread = threads.get(thread.id);
|
|
4867
|
-
const mappedThread = mapAppServerThread(thread, existingThread?.messageCount);
|
|
4987
|
+
const mappedThread = mapAppServerThread(thread, options.authoritativeMessageCount ? void 0 : existingThread?.messageCount);
|
|
4868
4988
|
const threadWithLocalRuntime = ThreadSummarySchema.parse({
|
|
4869
4989
|
...mappedThread,
|
|
4870
4990
|
goal: existingThread?.goal ?? mappedThread.goal,
|
|
@@ -5053,6 +5173,7 @@ function readRolloutThreadMessages(threadId, workspacePath = defaultWorkspacePat
|
|
|
5053
5173
|
const applyPatchInputs = /* @__PURE__ */ new Map();
|
|
5054
5174
|
const handledApplyPatchCallIds = /* @__PURE__ */ new Set();
|
|
5055
5175
|
const pendingApplyPatchChanges = [];
|
|
5176
|
+
let activeTurnId;
|
|
5056
5177
|
const lines = readFileSync(rolloutPath, "utf8").split("\n");
|
|
5057
5178
|
for (let index = 0; index < lines.length; index += 1) {
|
|
5058
5179
|
const line = lines[index];
|
|
@@ -5061,14 +5182,17 @@ function readRolloutThreadMessages(threadId, workspacePath = defaultWorkspacePat
|
|
|
5061
5182
|
if (!isRolloutMessageLine(line)) continue;
|
|
5062
5183
|
try {
|
|
5063
5184
|
const record = JSON.parse(line);
|
|
5185
|
+
activeTurnId = firstString(record.payload, ["turn_id", "turnId"]) ?? activeTurnId;
|
|
5064
5186
|
rememberRolloutApplyPatchInput(record, applyPatchInputs);
|
|
5065
5187
|
collectRolloutApplyPatchOutput(record, workspacePath, applyPatchInputs, handledApplyPatchCallIds, pendingApplyPatchChanges);
|
|
5066
5188
|
if (isRolloutTaskComplete(record) && pendingApplyPatchChanges.length > 0) {
|
|
5067
5189
|
collected.push(rolloutApplyPatchSummaryMessage(threadId, record, `rollout:${lineNumber}:apply_patch`, pendingApplyPatchChanges));
|
|
5068
5190
|
pendingApplyPatchChanges.length = 0;
|
|
5191
|
+
activeTurnId = void 0;
|
|
5069
5192
|
continue;
|
|
5070
5193
|
}
|
|
5071
|
-
const message = rolloutRecordMessage(threadId, record, `rollout:${lineNumber}`, workspacePath);
|
|
5194
|
+
const message = rolloutRecordMessage(threadId, record, `rollout:${lineNumber}`, workspacePath, activeTurnId);
|
|
5195
|
+
if (isRolloutTaskComplete(record)) activeTurnId = void 0;
|
|
5072
5196
|
if (!message) continue;
|
|
5073
5197
|
collected.push(message);
|
|
5074
5198
|
const patchApplyEndCallId = rolloutPatchApplyEndCallId(record);
|
|
@@ -5103,7 +5227,7 @@ function findRolloutFileForThread(threadId) {
|
|
|
5103
5227
|
function isRolloutTaskComplete(record) {
|
|
5104
5228
|
return record.type === "event_msg" && record.payload?.type === "task_complete";
|
|
5105
5229
|
}
|
|
5106
|
-
function rolloutRecordMessage(threadId, record, messageKey, workspacePath = defaultWorkspacePath) {
|
|
5230
|
+
function rolloutRecordMessage(threadId, record, messageKey, workspacePath = defaultWorkspacePath, turnId) {
|
|
5107
5231
|
const timestamp = typeof record.timestamp === "string" ? record.timestamp : (/* @__PURE__ */ new Date()).toISOString();
|
|
5108
5232
|
const payload = record.payload;
|
|
5109
5233
|
if (!payload) return;
|
|
@@ -5117,7 +5241,8 @@ function rolloutRecordMessage(threadId, record, messageKey, workspacePath = defa
|
|
|
5117
5241
|
content,
|
|
5118
5242
|
details: rolloutUserMessageDetails(payload),
|
|
5119
5243
|
createdAt: timestamp,
|
|
5120
|
-
state: "completed"
|
|
5244
|
+
state: "completed",
|
|
5245
|
+
turnId
|
|
5121
5246
|
});
|
|
5122
5247
|
}
|
|
5123
5248
|
if (record.type === "event_msg" && payload.type === "agent_message") {
|
|
@@ -5131,7 +5256,8 @@ function rolloutRecordMessage(threadId, record, messageKey, workspacePath = defa
|
|
|
5131
5256
|
content: messageParts.content,
|
|
5132
5257
|
details: messageParts.details,
|
|
5133
5258
|
createdAt: timestamp,
|
|
5134
|
-
state: "completed"
|
|
5259
|
+
state: "completed",
|
|
5260
|
+
turnId
|
|
5135
5261
|
});
|
|
5136
5262
|
}
|
|
5137
5263
|
if (record.type === "event_msg" && payload.type === "patch_apply_end") {
|
|
@@ -5339,7 +5465,7 @@ function fileUrlPath(value) {
|
|
|
5339
5465
|
}
|
|
5340
5466
|
}
|
|
5341
5467
|
function isRolloutMessageLine(line) {
|
|
5342
|
-
return line.includes("\"type\":\"event_msg\"") && (line.includes("\"type\":\"user_message\"") || line.includes("\"type\":\"agent_message\"") || line.includes("\"type\":\"patch_apply_end\"") || line.includes("\"type\":\"task_complete\"") || line.includes("\"type\":\"exec_command_end\"") || line.includes("\"type\":\"mcp_tool_call_end\"")) || line.includes("\"type\":\"response_item\"") && (line.includes("\"type\":\"custom_tool_call\"") || line.includes("\"type\":\"custom_tool_call_output\""));
|
|
5468
|
+
return line.includes("\"type\":\"event_msg\"") && (line.includes("\"type\":\"user_message\"") || line.includes("\"type\":\"agent_message\"") || line.includes("\"type\":\"patch_apply_end\"") || line.includes("\"type\":\"task_started\"") || line.includes("\"type\":\"task_complete\"") || line.includes("\"type\":\"exec_command_end\"") || line.includes("\"type\":\"mcp_tool_call_end\"")) || line.includes("\"type\":\"response_item\"") && (line.includes("\"type\":\"custom_tool_call\"") || line.includes("\"type\":\"custom_tool_call_output\""));
|
|
5343
5469
|
}
|
|
5344
5470
|
function threadDetailResponse(input) {
|
|
5345
5471
|
return ThreadDetailResponseSchema.parse({
|
|
@@ -5836,7 +5962,6 @@ function isApprovalServerRequest(method) {
|
|
|
5836
5962
|
}
|
|
5837
5963
|
function observeAppServerPushNotifications(appServer, dispatcher) {
|
|
5838
5964
|
const dispatchedEventIds = /* @__PURE__ */ new Set();
|
|
5839
|
-
const subagentThreadIds = /* @__PURE__ */ new Set();
|
|
5840
5965
|
const rememberEventId = (eventId) => {
|
|
5841
5966
|
if (dispatchedEventIds.size >= 1e3) dispatchedEventIds.clear();
|
|
5842
5967
|
dispatchedEventIds.add(eventId);
|
|
@@ -5844,7 +5969,9 @@ function observeAppServerPushNotifications(appServer, dispatcher) {
|
|
|
5844
5969
|
const dispatch = (event, eventId) => {
|
|
5845
5970
|
if (dispatchedEventIds.has(eventId)) return;
|
|
5846
5971
|
rememberEventId(eventId);
|
|
5847
|
-
|
|
5972
|
+
appServer.readThread(event.threadId, { includeTurns: false }).then((thread) => {
|
|
5973
|
+
if (!isSubagentThread(thread)) return dispatcher.dispatch(event);
|
|
5974
|
+
}).catch((error) => {
|
|
5848
5975
|
relayDebugLog("push_notification.dispatch_failed", {
|
|
5849
5976
|
error: errorMessage(error),
|
|
5850
5977
|
intent: event.intent,
|
|
@@ -5854,36 +5981,16 @@ function observeAppServerPushNotifications(appServer, dispatcher) {
|
|
|
5854
5981
|
});
|
|
5855
5982
|
};
|
|
5856
5983
|
appServer.onNotification((notification) => {
|
|
5857
|
-
rememberSubagentThreadIds(notification, subagentThreadIds);
|
|
5858
5984
|
const event = pushNotificationEventFromTerminalNotification(notification);
|
|
5859
5985
|
if (!event) return;
|
|
5860
|
-
|
|
5861
|
-
if (subagentThreadIds.delete(event.threadId)) {
|
|
5862
|
-
rememberEventId(eventId);
|
|
5863
|
-
return;
|
|
5864
|
-
}
|
|
5865
|
-
dispatch(event, eventId);
|
|
5986
|
+
dispatch(event, `${event.intent}:${event.threadId}:${event.turnId ?? ""}`);
|
|
5866
5987
|
});
|
|
5867
5988
|
appServer.onRequest((request) => {
|
|
5868
5989
|
const event = pushNotificationEventFromApprovalRequest(request);
|
|
5869
5990
|
if (!event) return;
|
|
5870
|
-
|
|
5871
|
-
if (subagentThreadIds.has(event.threadId)) {
|
|
5872
|
-
rememberEventId(eventId);
|
|
5873
|
-
return;
|
|
5874
|
-
}
|
|
5875
|
-
dispatch(event, eventId);
|
|
5991
|
+
dispatch(event, `${event.intent}:${event.threadId}:${event.turnId ?? ""}:${request.id}`);
|
|
5876
5992
|
});
|
|
5877
5993
|
}
|
|
5878
|
-
function rememberSubagentThreadIds(notification, subagentThreadIds) {
|
|
5879
|
-
const item = objectRecord(recordParams(notification)?.item);
|
|
5880
|
-
if (item?.type !== "collabAgentToolCall" || ![
|
|
5881
|
-
"spawnAgent",
|
|
5882
|
-
"sendInput",
|
|
5883
|
-
"resumeAgent"
|
|
5884
|
-
].includes(String(item.tool))) return;
|
|
5885
|
-
for (const threadId of stringArray(item.receiverThreadIds)) subagentThreadIds.add(threadId);
|
|
5886
|
-
}
|
|
5887
5994
|
function pushNotificationEventFromTerminalNotification(notification) {
|
|
5888
5995
|
if (notification.method !== "turn/completed" && notification.method !== "turn/failed") return;
|
|
5889
5996
|
const params = recordParams(notification);
|
|
@@ -6859,7 +6966,6 @@ function errorMessage(error) {
|
|
|
6859
6966
|
//#region src/index.ts
|
|
6860
6967
|
const port = Number(process.env.PORT ?? 8787);
|
|
6861
6968
|
const hostname$1 = process.env.HOST ?? "0.0.0.0";
|
|
6862
|
-
const clientTokenTtlMs = 10080 * 60 * 1e3;
|
|
6863
6969
|
const dangerouslyAutoApprove = process.env.CODEX_RELAY_DANGEROUSLY_AUTO_APPROVE === "1";
|
|
6864
6970
|
const serverIdentity = await getServerIdentity();
|
|
6865
6971
|
const approvalSecret = await getApprovalSecret();
|
|
@@ -6907,7 +7013,6 @@ serve({
|
|
|
6907
7013
|
createClientToken: () => randomBytes(32).toString("base64url"),
|
|
6908
7014
|
hashClientToken,
|
|
6909
7015
|
sessions: sessionStore,
|
|
6910
|
-
tokenTtlMs: clientTokenTtlMs,
|
|
6911
7016
|
onPaired: ({ clientName, tokenCount }) => {
|
|
6912
7017
|
logRuntimeEvent("Paired", `Mobile client connected${clientName ? ` from ${clientName}` : ""}; ${formatClientCount(tokenCount)} active.`);
|
|
6913
7018
|
},
|
package/package.json
CHANGED
package/src/api-schema.ts
CHANGED
|
@@ -681,6 +681,18 @@ export const ArchiveThreadResponseSchema = z.object({
|
|
|
681
681
|
source: z.enum(["app-server", "memory"]).default("memory"),
|
|
682
682
|
});
|
|
683
683
|
|
|
684
|
+
export const RenameThreadRequestSchema = z.object({
|
|
685
|
+
title: z.string().trim().min(1).max(120),
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
export const RenameThreadResponseSchema = z.object({
|
|
689
|
+
thread: ThreadSummarySchema,
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
export const RewindThreadRequestSchema = z.object({
|
|
693
|
+
turnId: z.string().trim().min(1),
|
|
694
|
+
});
|
|
695
|
+
|
|
684
696
|
export const ListModelsResponseSchema = z.object({
|
|
685
697
|
models: z.array(CodexModelSchema),
|
|
686
698
|
});
|
|
@@ -844,6 +856,9 @@ export type UpdateRuntimePreferencesRequest = z.infer<typeof UpdateRuntimePrefer
|
|
|
844
856
|
export type VersionResponse = z.infer<typeof VersionResponseSchema>;
|
|
845
857
|
export type ListThreadsResponse = z.infer<typeof ListThreadsResponseSchema>;
|
|
846
858
|
export type ArchiveThreadResponse = z.infer<typeof ArchiveThreadResponseSchema>;
|
|
859
|
+
export type RenameThreadRequest = z.infer<typeof RenameThreadRequestSchema>;
|
|
860
|
+
export type RenameThreadResponse = z.infer<typeof RenameThreadResponseSchema>;
|
|
861
|
+
export type RewindThreadRequest = z.infer<typeof RewindThreadRequestSchema>;
|
|
847
862
|
export type ListModelsResponse = z.infer<typeof ListModelsResponseSchema>;
|
|
848
863
|
export type ListSkillsResponse = z.infer<typeof ListSkillsResponseSchema>;
|
|
849
864
|
export type ListWorkspaceFilesResponse = z.infer<typeof ListWorkspaceFilesResponseSchema>;
|
|
@@ -1089,6 +1104,8 @@ export const apiPaths = {
|
|
|
1089
1104
|
threads: "/v1/threads",
|
|
1090
1105
|
thread: (threadId: string) => `/v1/threads/${encodeURIComponent(threadId)}`,
|
|
1091
1106
|
threadArchive: (threadId: string) => `/v1/threads/${encodeURIComponent(threadId)}`,
|
|
1107
|
+
threadName: (threadId: string) => `/v1/threads/${encodeURIComponent(threadId)}/name`,
|
|
1108
|
+
threadRollback: (threadId: string) => `/v1/threads/${encodeURIComponent(threadId)}/rollback`,
|
|
1092
1109
|
threadContextWindow: (threadId: string) =>
|
|
1093
1110
|
`/v1/threads/${encodeURIComponent(threadId)}/context-window`,
|
|
1094
1111
|
threadGoal: (threadId: string) => `/v1/threads/${encodeURIComponent(threadId)}/goal`,
|
|
@@ -1191,6 +1208,11 @@ export function createOpenApiDocument() {
|
|
|
1191
1208
|
required: true,
|
|
1192
1209
|
schema: { type: "string" },
|
|
1193
1210
|
},
|
|
1211
|
+
{
|
|
1212
|
+
name: "refresh",
|
|
1213
|
+
in: "query",
|
|
1214
|
+
schema: { type: "boolean" },
|
|
1215
|
+
},
|
|
1194
1216
|
],
|
|
1195
1217
|
responses: {
|
|
1196
1218
|
"200": jsonResponse("ThreadDetailResponse"),
|
|
@@ -1214,6 +1236,48 @@ export function createOpenApiDocument() {
|
|
|
1214
1236
|
},
|
|
1215
1237
|
},
|
|
1216
1238
|
},
|
|
1239
|
+
"/v1/threads/{threadId}/name": {
|
|
1240
|
+
post: {
|
|
1241
|
+
summary: "Rename a Codex app-server thread",
|
|
1242
|
+
parameters: [
|
|
1243
|
+
{
|
|
1244
|
+
name: "threadId",
|
|
1245
|
+
in: "path",
|
|
1246
|
+
required: true,
|
|
1247
|
+
schema: { type: "string" },
|
|
1248
|
+
},
|
|
1249
|
+
],
|
|
1250
|
+
requestBody: jsonRequest("RenameThreadRequest"),
|
|
1251
|
+
responses: {
|
|
1252
|
+
"200": jsonResponse("RenameThreadResponse"),
|
|
1253
|
+
"400": jsonResponse("ErrorResponse"),
|
|
1254
|
+
"404": jsonResponse("ErrorResponse"),
|
|
1255
|
+
"409": jsonResponse("ErrorResponse"),
|
|
1256
|
+
"502": jsonResponse("ErrorResponse"),
|
|
1257
|
+
},
|
|
1258
|
+
},
|
|
1259
|
+
},
|
|
1260
|
+
"/v1/threads/{threadId}/rollback": {
|
|
1261
|
+
post: {
|
|
1262
|
+
summary: "Rewind a Codex app-server thread to before a selected turn",
|
|
1263
|
+
parameters: [
|
|
1264
|
+
{
|
|
1265
|
+
name: "threadId",
|
|
1266
|
+
in: "path",
|
|
1267
|
+
required: true,
|
|
1268
|
+
schema: { type: "string" },
|
|
1269
|
+
},
|
|
1270
|
+
],
|
|
1271
|
+
requestBody: jsonRequest("RewindThreadRequest"),
|
|
1272
|
+
responses: {
|
|
1273
|
+
"200": jsonResponse("ThreadDetailResponse"),
|
|
1274
|
+
"400": jsonResponse("ErrorResponse"),
|
|
1275
|
+
"404": jsonResponse("ErrorResponse"),
|
|
1276
|
+
"409": jsonResponse("ErrorResponse"),
|
|
1277
|
+
"502": jsonResponse("ErrorResponse"),
|
|
1278
|
+
},
|
|
1279
|
+
},
|
|
1280
|
+
},
|
|
1217
1281
|
"/v1/workspace-directories": {
|
|
1218
1282
|
get: {
|
|
1219
1283
|
summary: "List directories under the configured workspace",
|
|
@@ -1452,6 +1516,27 @@ export function createOpenApiDocument() {
|
|
|
1452
1516
|
tokenBudget: { anyOf: [{ type: "integer", minimum: 1 }, { type: "null" }] },
|
|
1453
1517
|
},
|
|
1454
1518
|
},
|
|
1519
|
+
RenameThreadRequest: {
|
|
1520
|
+
type: "object",
|
|
1521
|
+
required: ["title"],
|
|
1522
|
+
properties: {
|
|
1523
|
+
title: { type: "string", minLength: 1, maxLength: 120 },
|
|
1524
|
+
},
|
|
1525
|
+
},
|
|
1526
|
+
RenameThreadResponse: {
|
|
1527
|
+
type: "object",
|
|
1528
|
+
required: ["thread"],
|
|
1529
|
+
properties: {
|
|
1530
|
+
thread: { $ref: "#/components/schemas/ThreadSummary" },
|
|
1531
|
+
},
|
|
1532
|
+
},
|
|
1533
|
+
RewindThreadRequest: {
|
|
1534
|
+
type: "object",
|
|
1535
|
+
required: ["turnId"],
|
|
1536
|
+
properties: {
|
|
1537
|
+
turnId: { type: "string", minLength: 1 },
|
|
1538
|
+
},
|
|
1539
|
+
},
|
|
1455
1540
|
ThreadGoalResponse: {
|
|
1456
1541
|
type: "object",
|
|
1457
1542
|
required: ["goal", "thread"],
|