@young1lin/dsh-gpt-sub 0.1.0 → 0.1.2

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.
@@ -0,0 +1,140 @@
1
+ /** Persisted Codex compaction windows and their Responses input projection. */
2
+ import type { ContentBlock, MessageSource, RequestMessage } from '@deepseek-ai/dsh-llm'
3
+ import type { CompactionCheckpointSource } from '@deepseek-ai/dsh-compaction/checkpoint'
4
+ import { z } from 'zod'
5
+
6
+ /** Lossless JSON validation for provider-native Responses items. */
7
+ export const nativeItemsSchema = z.array(z.record(z.string(), z.json()))
8
+ /** One lossless provider-native Responses input item. */
9
+ export type NativeItem = z.infer<typeof nativeItemsSchema>[number]
10
+ const checkpointSchema = z.object({
11
+ version: z.literal(1),
12
+ provider: z.literal('openai-codex'),
13
+ model: z.string().min(1),
14
+ items: nativeItemsSchema.min(1),
15
+ contextTokens: z.number().int().nonnegative(),
16
+ })
17
+
18
+ /** Native window carried by a persisted replacement message. */
19
+ export type CodexCheckpoint = z.infer<typeof checkpointSchema>
20
+
21
+ /** Backend-independent checkpoint identity with plugin-owned native state. */
22
+ export type CodexCheckpointSource = CompactionCheckpointSource & { readonly nativeCodex: CodexCheckpoint }
23
+
24
+ /** Completed native compaction output and the retained user messages. */
25
+ export interface NativeCompactionResultBlock {
26
+ type: 'codex-compaction-result'
27
+ item: NativeItem
28
+ retained: NativeItem[]
29
+ responseId: string
30
+ summaryTokens: number
31
+ }
32
+
33
+ declare module '@deepseek-ai/dsh-llm' {
34
+ interface ContentBlockMap {
35
+ 'codex-compaction-result': NativeCompactionResultBlock
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Validate plugin state restored with one checkpoint source.
41
+ * @param source - source of the durable message.
42
+ * @returns native state, or undefined for other producers.
43
+ */
44
+ export function readCheckpoint(source: MessageSource): CodexCheckpoint | undefined {
45
+ if (!('nativeCodex' in source)) return undefined
46
+ if (source.kind !== 'compact-checkpoint') throw new Error('Codex native state requires a compaction checkpoint')
47
+ const state = checkpointSchema.parse(source.nativeCodex)
48
+ if (state.items.filter(item => item['type'] === 'compaction').length !== 1) {
49
+ throw new Error('Codex checkpoint must contain exactly one compaction item')
50
+ }
51
+ const item = state.items.find(value => value['type'] === 'compaction')
52
+ if (typeof item?.['encrypted_content'] !== 'string' || item['encrypted_content'].length === 0) {
53
+ throw new Error('Codex checkpoint is missing encrypted_content')
54
+ }
55
+ return state
56
+ }
57
+
58
+ /**
59
+ * Replace logged checkpoint markers with their exact native items.
60
+ * @param input - serialized Responses input.
61
+ * @param messages - durable history that produced the input.
62
+ * @param provider - captured provider route.
63
+ * @param model - captured model id.
64
+ * @returns input with each checkpoint expanded once, preserving order.
65
+ */
66
+ export function expandCheckpoints(
67
+ input: readonly NativeItem[], messages: readonly RequestMessage[], provider: string, model: string,
68
+ ): NativeItem[] {
69
+ const checkpoints = new Map<string, CodexCheckpoint>()
70
+ for (const message of messages) {
71
+ if (!('source' in message)) continue
72
+ const state = readCheckpoint(message.source)
73
+ if (state === undefined) continue
74
+ if (state.provider !== provider || state.model !== model) {
75
+ throw new Error(`Codex checkpoint belongs to ${state.provider}/${state.model}; start a new Session to use ${provider}/${model}`)
76
+ }
77
+ const marker = message.content.filter(block => block.type === 'text').map(block => block.text).join('')
78
+ if (marker.length === 0 || checkpoints.has(marker)) throw new Error('invalid Codex checkpoint marker')
79
+ checkpoints.set(marker, state)
80
+ }
81
+ if (checkpoints.size === 0) return [...input]
82
+ const remaining = new Set(checkpoints.keys())
83
+ const output: NativeItem[] = []
84
+ for (const item of input) {
85
+ const content = item['content']
86
+ const text = item['role'] === 'user' && Array.isArray(content)
87
+ ? content.map(value => typeof value === 'object' && value !== null && !Array.isArray(value)
88
+ && value['type'] === 'input_text' && typeof value['text'] === 'string' ? value['text'] : '').join('')
89
+ : ''
90
+ const checkpoint = checkpoints.get(text)
91
+ if (checkpoint === undefined) output.push(item)
92
+ else {
93
+ if (!remaining.delete(text)) throw new Error('Codex checkpoint marker was serialized more than once')
94
+ output.push(...checkpoint.items)
95
+ }
96
+ }
97
+ if (remaining.size > 0) throw new Error('Codex checkpoint marker was lost during request conversion')
98
+ return output
99
+ }
100
+
101
+ /**
102
+ * Retain recent user items within a structural token budget.
103
+ * @param input - expanded native history sent for compaction.
104
+ * @param budget - maximum estimated tokens retained verbatim.
105
+ * @returns recent user items in conversation order.
106
+ */
107
+ export function retainUserItems(input: readonly NativeItem[], budget: number): NativeItem[] {
108
+ const retained: NativeItem[] = []
109
+ let remaining = budget
110
+ for (const item of [...input].reverse()) {
111
+ if (item['role'] !== 'user' || (item['type'] !== undefined && item['type'] !== 'message')) continue
112
+ const price = nativeItemTokens(item)
113
+ if (price > remaining) break
114
+ retained.push(item)
115
+ remaining -= price
116
+ }
117
+ return retained.reverse()
118
+ }
119
+
120
+ /**
121
+ * Estimate a plaintext native item's serialized token cost.
122
+ * @param item - retained user item, excluding encrypted compaction state.
123
+ * @returns conservative structural token estimate.
124
+ */
125
+ export function nativeItemTokens(item: NativeItem): number {
126
+ return Math.ceil(JSON.stringify(item).length / 4) + 4
127
+ }
128
+
129
+ /**
130
+ * Read the completed compaction block assembled from the auxiliary stream.
131
+ * @param blocks - complete auxiliary output.
132
+ * @returns the unique native compaction result.
133
+ */
134
+ export function nativeResult(blocks: readonly ContentBlock[]): NativeCompactionResultBlock {
135
+ const results = blocks.filter(block => block.type === 'codex-compaction-result')
136
+ if (results.length !== 1) throw new Error('native Codex compaction did not return exactly one result')
137
+ const result = results[0]
138
+ if (result === undefined) throw new Error('native Codex compaction result is missing')
139
+ return result
140
+ }
package/src/types.ts CHANGED
@@ -14,4 +14,10 @@ export interface Config {
14
14
  bootstrapRetries: number
15
15
  /** Where the panel's runtime overrides (proxy, credential file) are persisted. */
16
16
  stateFile: string
17
+ /** Total timeout for a native Codex compaction request. */
18
+ nativeCompactionTimeoutMs: number
19
+ /** Recent user-message budget retained alongside the encrypted summary. */
20
+ nativeRetainTokens: number
21
+ /** Maximum streamed bytes accepted from one native compaction response. */
22
+ nativeResponseMaxBytes: number
17
23
  }