refactor(schedule): make absolute times explicit

This commit is contained in:
Tianyi Cui
2026-08-09 16:30:11 +08:00
parent 3d6498e91b
commit b7ec8429a9
109 changed files with 1248 additions and 3219 deletions

View File

@@ -36,25 +36,8 @@ export const rpcErrorSchema: z.ZodType<RpcError> = z.discriminatedUnion('code',
z.object({ code: z.literal('cancelled'), message: z.string(), details: z.object({}) }),
z.object({ code: z.literal('session-not-found'), message: z.string(), details: z.object({ sessionId: z.string() }) }),
z.object({ code: z.literal('model-unavailable'), message: z.string(), details: z.object({ provider: z.string(), model: z.string() }) }),
z.object({
code: z.literal('session-conflict'),
message: z.string(),
details: z.object({
sessionId: z.string(),
requestedCwd: z.string(),
existingCwd: z.string().optional(),
requestedTimeZone: z.string(),
existingTimeZone: z.string().optional(),
}),
}),
z.object({
code: z.literal('invalid-time-zone'),
message: z.string(),
details: z.object({
field: z.union([z.literal('timeZone'), z.literal('clientTimeZone')]),
value: z.union([z.string(), z.null()]),
}),
}),
z.object({ code: z.literal('session-conflict'), message: z.string(), details: z.object({ sessionId: z.string(), requestedCwd: z.string(), existingCwd: z.string().optional() }) }),
z.object({ code: z.literal('invalid-time-zone'), message: z.string(), details: z.object({ value: z.string() }) }),
z.object({ code: z.literal('workspace-attach-failed'), message: z.string(), details: z.object({ sessionId: z.string(), workspaceId: z.string() }) }),
z.object({ code: z.literal('workspace-not-found'), message: z.string(), details: z.object({ workspaceId: z.string() }) }),
z.object({ code: z.literal('workspace-invalid-path'), message: z.string(), details: z.object({ path: z.string() }) }),

View File

@@ -34,14 +34,8 @@ export interface RpcErrorDetailsMap {
'cancelled': {}
'session-not-found': { sessionId: SessionId }
'model-unavailable': { provider: string; model: string }
'session-conflict': {
sessionId: SessionId
requestedCwd: string
existingCwd?: string
requestedTimeZone: string
existingTimeZone?: string
}
'invalid-time-zone': { field: 'timeZone' | 'clientTimeZone'; value: string | null }
'session-conflict': { sessionId: SessionId; requestedCwd: string; existingCwd?: string }
'invalid-time-zone': { value: string }
'workspace-attach-failed': { sessionId: SessionId; workspaceId: string }
'workspace-not-found': { workspaceId: string }
'workspace-invalid-path': { path: string }

View File

@@ -95,12 +95,11 @@ export const sessionSearchValueSchema = z.object({
hasMore: z.boolean(),
}) satisfies z.ZodType<Wire<ResponseValue<'session.search'>>>
/** session.create payload; timeZone stays schema-optional so Host omission returns `invalid-time-zone`. */
/** session.create request payload (at most one of workspaceId / cwd). */
export const sessionCreateRequestSchema = z.object({
workspaceId: workspaceIdSchema.optional(),
cwd: z.string().optional(),
sessionId: sessionIdSchema.optional(),
timeZone: z.string().optional(),
}).refine(
payload => payload.workspaceId === undefined || payload.cwd === undefined,
{ message: 'session.create accepts workspaceId or cwd, not both' },
@@ -247,7 +246,7 @@ export const sessionSelectModelValueSchema = z.object({
/** ContentBlock passthrough: core is merge-extensible — the type discriminant envelope is strict, the rest stays wide. */
export const contentBlockSchema = z.looseObject({ type: z.string() })
/** session.prompt payload; clientTimeZone stays schema-optional so Host omission returns `invalid-time-zone`. */
/** session.prompt request payload, including optional browser-local request provenance. */
export const sessionPromptRequestSchema = z.object({
sessionId: sessionIdSchema,
mode: z.union([z.literal('queue'), z.literal('steer')]),

View File

@@ -20,9 +20,10 @@ declare module '@deepseek-ai/dsh-llm' {
* The prompt's rpcId is passed through MessageSource into the `user/message` event
* (the client uses it to reconcile the optimistically
* echoed provisional message with the event stream). kind stays `'user'` — the model face
* carries no transport vocabulary; rpcId is an extra durable-JSON field passed back to the client with the event.
* carries no transport vocabulary; rpcId and the optional Host-validated browser zone are
* durable JSON fields passed back to the client with the event.
*/
'user-rpc': { kind: 'user'; rpcId: RpcId; clientTimeZone: string }
'user-rpc': { kind: 'user'; rpcId: RpcId; clientTimeZone?: string }
}
}
@@ -204,20 +205,12 @@ export interface SessionsApi {
/**
* Creates a real session and its idle agent. At most one of `workspaceId` /
* `cwd` is accepted; an omitted project uses the Host cwd. A caller may
* preallocate `sessionId`: retries with the same id, cwd, and canonical time
* zone return the same session, while a different owned identity fails with
* `session-conflict`. A headerless persisted session remains compatible with
* the same cwd but never absorbs the request zone. Workspace
* preallocate `sessionId`: retries with the same id and cwd return the same
* session, while a different cwd fails with `session-conflict`. Workspace
* creation attaches the session after publication; an attach failure
* returns `workspace-attach-failed` with the published session id.
*/
create(request: RpcRequest<{
workspaceId?: WorkspaceId
cwd?: string
sessionId?: SessionId
/** Required by the Host; optional here so omission returns the stable `invalid-time-zone` RPC error. */
timeZone?: string
}>):
create(request: RpcRequest<{ workspaceId?: WorkspaceId; cwd?: string; sessionId?: SessionId }>):
Promise<RpcResponse<{ sessionId: SessionId }>>
/**
@@ -296,12 +289,16 @@ export interface SessionsApi {
fork(request: RpcRequest<{ sessionId: SessionId; atSeq?: number }>):
Promise<RpcResponse<{ sessionId: SessionId }>>
/** Sends a message to an ordinary session Agent. Session-backed subagents reject with `agent-busy` and use `subagent.prompt`. */
/**
* Sends a message to an ordinary session Agent. Browser callers attach their current IANA zone;
* the Host validates, canonicalizes, and records it on that exact user message. Omission remains
* valid for non-browser callers. Session-backed subagents reject with `agent-busy` and use
* `subagent.prompt`.
*/
prompt(request: RpcRequest<{
sessionId: SessionId
mode: 'queue' | 'steer'
content: ContentBlock[]
/** Required by the Host; optional here so omission returns the stable `invalid-time-zone` RPC error. */
clientTimeZone?: string
}>):
Promise<RpcResponse<{ accepted: true; command?: { kind: 'success'; text?: string } }>>