@pure01fx/dsh-openai-codex-auth 0.13.2 → 0.13.3
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/CHANGELOG.md +4 -0
- package/README.md +5 -1
- package/cordis.patch.yml +5 -0
- package/lib/index.js +2 -2
- package/lib/native-adapter.d.ts +17 -1
- package/lib/native-adapter.js +43 -0
- package/lib/replay.d.ts +11 -1
- package/lib/replay.js +23 -0
- package/lib/responses.js +1 -1
- package/lib/token-meter.d.ts +26 -0
- package/lib/token-meter.js +135 -0
- package/package.json +16 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.13.3
|
|
6
|
+
|
|
7
|
+
- Supplies a replacement token-meter service through the package composition patch, so Codex encrypted reasoning participates in retained-history pricing and pressure reductions after compaction without changing Harness source. Reuses ordinary host pricing, preserves fixed heuristic projections, and corrects usage anchors without double-counting reasoning output. Preserves an explicitly reported zero reasoning count so it does not trigger the missing-detail fallback.
|
|
8
|
+
|
|
5
9
|
## 0.13.2
|
|
6
10
|
|
|
7
11
|
- Stops putting `is_error` on a replayed `function_call_output`. The Responses wire has no such field (Codex reports a failed tool through the output text and keeps its own `success` flag internal), one Lite model answers the unknown item field with a 400 `INVALID_REQUEST`, and because the item is replayed from durable history, a single failed tool call then fails every later request in that session.
|
package/README.md
CHANGED
|
@@ -259,7 +259,11 @@ $DSH_HOME/openai-codex-auth.json
|
|
|
259
259
|
|
|
260
260
|
从 0.6 开始,Native Adapter 是插件默认 Provider,并持有生产 route `openai-codex`。旧预览会话确实需要时,可显式设置 `nativeCompatibilityRoute: true`,让同一个 adapter 同时注册 `openai-codex-native` 兼容 route;启用兼容 route 时两者仍原子注册,任一 route 已被占用都会整体失败。默认只暴露生产 route。
|
|
261
261
|
|
|
262
|
-
|
|
262
|
+
本包提供 Codex Provider 和计量服务替代入口,不发布具体 Profile。整合包必须在挂载本插件前释放已有的 `openai-codex` route,例如从自己的 `llm-pi-ai` provider map 中移除该项;本包不会清空未知的 sibling providers。只想复用 OAuth/UI 并继续使用外部 Provider 的组合可以显式设置 `nativeAdapter: false`。从 pi-ai 切到 Native 时,旧 foreign replay 会降级为可见持久历史;反向切回 pi-ai 后,已产生 Native replay 的进行中 session 不保证可续跑,应新建 session。
|
|
263
|
+
|
|
264
|
+
`cordis.patch.yml` 会禁用 base bundle 的 `token-meter` 节点,并挂载本包 `/token-meter` 入口作为唯一的 `ctx.tokenMeter`;无需修改 DSH 源码。自定义组合应禁用自己的默认计量服务,再挂载同一入口,不能同时运行两个计量服务。服务复用宿主的文本、图片、文件和投影实现,只对源 route 与目标 route 属于同一个活跃 Native Codex adapter 的历史补充加密推理价格;`nativeAdapter: false` 和其他模型沿用宿主价格。
|
|
265
|
+
|
|
266
|
+
加密推理计量优先使用原始响应的 `usage.reasoningTokens`,每次响应计一次;缺少推理细分时以 `outputTokens` 作为生成推理的保守上界,连用量也没有时才用解码密文的字节数作体积估算。这些都是重放占用估计,不是精确的服务端输入计费。计量会同时修正节点 `tokens`、`surfaceTokens`、完整锚点与有符号的 `surfaceDeltaTokens`,服务端已计入的推理不会再加一次,压缩移除历史时会扣减隐藏占用;`heuristicTokens`、持久消息和服务端用量保持原语义。宿主 UI 的固定启发式投影仍由原实现提供,不包含本包的隐藏推理估计。
|
|
263
267
|
|
|
264
268
|
上游 Native Codex Responses 请求没有输出 token 上限字段,因此普通会话若显式设置 `maxTokens` 仍会在 Provider I/O 前失败。DSH 的压缩与会话标题辅助调用会固定携带 `maxTokens`,并分别通过 `purpose: compaction` 与 `purpose: session-title` 标识;本适配器允许这两类 hint 通过,但不会把它序列化为 `max_output_tokens`,实际输出长度仍由 Native Codex 决定。
|
|
265
269
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Native Codex is the package default. Integration bundles own any removal or
|
|
2
2
|
# replacement of an existing openai-codex route before mounting this plugin.
|
|
3
|
+
# Replace the service provider without renaming the base token-meter row.
|
|
4
|
+
- id: token-meter
|
|
5
|
+
disabled: true
|
|
3
6
|
- insert:
|
|
4
7
|
- id: openai-codex-auth
|
|
5
8
|
name: '@pure01fx/dsh-openai-codex-auth'
|
|
9
|
+
- id: codex-token-meter
|
|
10
|
+
name: '@pure01fx/dsh-openai-codex-auth/token-meter'
|
package/lib/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { createHash, randomBytes } from 'node:crypto';
|
|
|
9
9
|
import { readFile, stat, unlink } from 'node:fs/promises';
|
|
10
10
|
import { join, resolve } from 'node:path';
|
|
11
11
|
import { INVALID_CREDENTIAL_CODE, LlmError } from '@deepseek-ai/dsh-llm';
|
|
12
|
-
import { CODEX_PROVIDER, NATIVE_CODEX_PROVIDER, NativeCodexAdapter, } from './native-adapter.js';
|
|
12
|
+
import { CODEX_PROVIDER, NATIVE_CODEX_PROVIDER, NativeCodexAdapter, registerNativeCodexAdapter, } from './native-adapter.js';
|
|
13
13
|
export { CODEX_PROVIDER, NATIVE_CODEX_PROVIDER } from './native-adapter.js';
|
|
14
14
|
import { NativeCodexCatalog } from './catalog.js';
|
|
15
15
|
import { NativeCodexHttpTransport } from './native-http.js';
|
|
@@ -795,7 +795,7 @@ export class OpenAICodexAuth extends Service {
|
|
|
795
795
|
ctx.effect(() => () => { transport.dispose(); }, 'openai-codex-auth: dispose native WebSockets');
|
|
796
796
|
}
|
|
797
797
|
ctx.inject(['llm'], (llmCtx) => {
|
|
798
|
-
llmCtx
|
|
798
|
+
registerNativeCodexAdapter(llmCtx, [
|
|
799
799
|
CODEX_PROVIDER,
|
|
800
800
|
...(this.routeConfig.nativeCompatibilityRoute ? [NATIVE_CODEX_PROVIDER] : []),
|
|
801
801
|
], new NativeCodexAdapter(catalog, transport));
|
package/lib/native-adapter.d.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
/** Native Codex adapter with live catalog and HTTP/WebSocket transport delegation. */
|
|
2
|
-
import { LlmAdapter, type GenerateOptions, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { LlmAdapter, type GenerateOptions, type LlmModelInfo, type LlmRuntime, type LlmProviderInfo, type LlmResolvedModelInfo, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import { type Context } from '@deepseek-ai/cordis';
|
|
3
4
|
import type { NativeCodexModel, NativeCodexModelCatalog } from './catalog.js';
|
|
4
5
|
/** Production provider route owned by the package native Codex adapter after M6 cutover. */
|
|
5
6
|
export declare const CODEX_PROVIDER = "openai-codex";
|
|
6
7
|
/** Compatibility route retained for sessions created during the native preview. */
|
|
7
8
|
export declare const NATIVE_CODEX_PROVIDER = "openai-codex-native";
|
|
9
|
+
/**
|
|
10
|
+
* Register native routes and their replay-pricing ownership in the same Cordis scope.
|
|
11
|
+
* @param ctx - scope owning the native adapter registration.
|
|
12
|
+
* @param providers - canonical and optional compatibility routes for this instance.
|
|
13
|
+
* @param adapter - native adapter that will replay its own continuation state.
|
|
14
|
+
*/
|
|
15
|
+
export declare function registerNativeCodexAdapter(ctx: Context, providers: string[], adapter: NativeCodexAdapter): void;
|
|
16
|
+
/**
|
|
17
|
+
* Match the runtime's same-adapter ownership rule for native continuation replay.
|
|
18
|
+
* @param runtime - current global LLM service instance.
|
|
19
|
+
* @param sourceProvider - provider that produced the historical assistant message.
|
|
20
|
+
* @param targetProvider - provider preparing the measured request.
|
|
21
|
+
* @returns whether both routes are currently owned by the same native adapter.
|
|
22
|
+
*/
|
|
23
|
+
export declare function canReplayNativeCodex(runtime: LlmRuntime, sourceProvider: string, targetProvider: string): boolean;
|
|
8
24
|
export declare const CODEX_FAST_ALIAS_SUFFIX = "-fast";
|
|
9
25
|
export declare const CODEX_FAST_SERVICE_TIER = "priority";
|
|
10
26
|
/** Pure network establishment failure; retried without consuming the finite stream budget. */
|
package/lib/native-adapter.js
CHANGED
|
@@ -1,10 +1,53 @@
|
|
|
1
1
|
/** Native Codex adapter with live catalog and HTTP/WebSocket transport delegation. */
|
|
2
2
|
import { LlmAdapter, LlmError, ReasoningEffortId, } from '@deepseek-ai/dsh-llm';
|
|
3
|
+
import { symbols } from '@deepseek-ai/cordis';
|
|
3
4
|
/** Production provider route owned by the package native Codex adapter after M6 cutover. */
|
|
4
5
|
export const CODEX_PROVIDER = 'openai-codex';
|
|
5
6
|
/** Compatibility route retained for sessions created during the native preview. */
|
|
6
7
|
export const NATIVE_CODEX_PROVIDER = 'openai-codex-native';
|
|
7
8
|
const OWNED_CODEX_PROVIDERS = new Set([CODEX_PROVIDER, NATIVE_CODEX_PROVIDER]);
|
|
9
|
+
const replayOwners = new WeakMap();
|
|
10
|
+
// Cordis returns scope-traced views; use the original service for ownership identity.
|
|
11
|
+
function runtimeKey(runtime) {
|
|
12
|
+
return Reflect.get(runtime, symbols.original) ?? runtime;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Register native routes and their replay-pricing ownership in the same Cordis scope.
|
|
16
|
+
* @param ctx - scope owning the native adapter registration.
|
|
17
|
+
* @param providers - canonical and optional compatibility routes for this instance.
|
|
18
|
+
* @param adapter - native adapter that will replay its own continuation state.
|
|
19
|
+
*/
|
|
20
|
+
export function registerNativeCodexAdapter(ctx, providers, adapter) {
|
|
21
|
+
const runtime = ctx.get('llm');
|
|
22
|
+
if (runtime === undefined)
|
|
23
|
+
throw new Error('native Codex registration requires llm');
|
|
24
|
+
ctx.llm.registerAdapter(providers, adapter);
|
|
25
|
+
ctx.effect(() => {
|
|
26
|
+
let owners = replayOwners.get(runtimeKey(runtime));
|
|
27
|
+
if (owners === undefined)
|
|
28
|
+
replayOwners.set(runtimeKey(runtime), owners = new Map());
|
|
29
|
+
for (const provider of providers)
|
|
30
|
+
owners.set(provider, adapter);
|
|
31
|
+
return () => {
|
|
32
|
+
for (const provider of providers) {
|
|
33
|
+
if (owners.get(provider) === adapter)
|
|
34
|
+
owners.delete(provider);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Match the runtime's same-adapter ownership rule for native continuation replay.
|
|
41
|
+
* @param runtime - current global LLM service instance.
|
|
42
|
+
* @param sourceProvider - provider that produced the historical assistant message.
|
|
43
|
+
* @param targetProvider - provider preparing the measured request.
|
|
44
|
+
* @returns whether both routes are currently owned by the same native adapter.
|
|
45
|
+
*/
|
|
46
|
+
export function canReplayNativeCodex(runtime, sourceProvider, targetProvider) {
|
|
47
|
+
const owners = replayOwners.get(runtimeKey(runtime));
|
|
48
|
+
const adapter = owners?.get(targetProvider);
|
|
49
|
+
return adapter !== undefined && owners?.get(sourceProvider) === adapter;
|
|
50
|
+
}
|
|
8
51
|
export const CODEX_FAST_ALIAS_SUFFIX = '-fast';
|
|
9
52
|
export const CODEX_FAST_SERVICE_TIER = 'priority';
|
|
10
53
|
/** Pure network establishment failure; retried without consuming the finite stream budget. */
|
package/lib/replay.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Versioned Codex Responses continuation state. */
|
|
2
|
-
import { type ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
2
|
+
import { type AssistantProviderMetadata, type ContentBlock, type TokenUsage } from '@deepseek-ai/dsh-llm';
|
|
3
3
|
export declare const NATIVE_CODEX_REPLAY_KIND = "openai-codex-native.responses-replay";
|
|
4
4
|
export declare const NATIVE_CODEX_REPLAY_VERSION = 1;
|
|
5
5
|
export type CodexMessagePhase = 'commentary' | 'partial_answer' | 'final_answer';
|
|
@@ -36,6 +36,16 @@ export interface NativeCodexReplaySource {
|
|
|
36
36
|
export declare function replayableItemId(value: string | undefined): string | undefined;
|
|
37
37
|
/** True only for legacy raw state or an rc.2 envelope emitted by this package. */
|
|
38
38
|
export declare function hasNativeCodexReplayKind(value: unknown): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Estimate hidden reasoning only when the native continuation replays encrypted items.
|
|
41
|
+
* A response's reasoning usage is charged once, not once per reasoning item.
|
|
42
|
+
* Without reasoning details, output usage bounds the generated reasoning; without
|
|
43
|
+
* usage, decoded ciphertext bytes are a size heuristic, not exact token billing.
|
|
44
|
+
* @param source - original provider/model and native continuation state.
|
|
45
|
+
* @param usage - original response usage, when available in the durable event.
|
|
46
|
+
* @returns additional hidden replay tokens; zero for non-native or unencrypted state.
|
|
47
|
+
*/
|
|
48
|
+
export declare function estimateNativeCodexReplayTokens(source: AssistantProviderMetadata, usage?: TokenUsage): number;
|
|
39
49
|
/** Attempt-local accumulator for completed replay descriptors. */
|
|
40
50
|
export declare class NativeCodexReplayCapture {
|
|
41
51
|
private readonly provider;
|
package/lib/replay.js
CHANGED
|
@@ -125,6 +125,29 @@ function parseState(value) {
|
|
|
125
125
|
items,
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Estimate hidden reasoning only when the native continuation replays encrypted items.
|
|
130
|
+
* A response's reasoning usage is charged once, not once per reasoning item.
|
|
131
|
+
* Without reasoning details, output usage bounds the generated reasoning; without
|
|
132
|
+
* usage, decoded ciphertext bytes are a size heuristic, not exact token billing.
|
|
133
|
+
* @param source - original provider/model and native continuation state.
|
|
134
|
+
* @param usage - original response usage, when available in the durable event.
|
|
135
|
+
* @returns additional hidden replay tokens; zero for non-native or unencrypted state.
|
|
136
|
+
*/
|
|
137
|
+
export function estimateNativeCodexReplayTokens(source, usage) {
|
|
138
|
+
if (!hasNativeCodexReplayKind(source.replayState))
|
|
139
|
+
return 0;
|
|
140
|
+
const state = parseState(source.replayState);
|
|
141
|
+
if (state.provider !== source.provider || state.model !== source.model) {
|
|
142
|
+
throw failure('native Codex replay identity does not match its assistant message');
|
|
143
|
+
}
|
|
144
|
+
const encrypted = state.items.flatMap(item => item.type === 'reasoning' && item.encryptedContent !== undefined ? [item.encryptedContent] : []);
|
|
145
|
+
if (encrypted.length === 0)
|
|
146
|
+
return 0;
|
|
147
|
+
if (usage !== undefined)
|
|
148
|
+
return usage.reasoningTokens ?? usage.outputTokens;
|
|
149
|
+
return encrypted.reduce((total, content) => total + Buffer.byteLength(content, 'base64'), 0);
|
|
150
|
+
}
|
|
128
151
|
/** Attempt-local accumulator for completed replay descriptors. */
|
|
129
152
|
export class NativeCodexReplayCapture {
|
|
130
153
|
provider;
|
package/lib/responses.js
CHANGED
|
@@ -289,7 +289,7 @@ export function mapResponsesUsage(usage) {
|
|
|
289
289
|
inputTokens: uncached, outputTokens: output,
|
|
290
290
|
...cached === 0 ? {} : { cacheReadTokens: cached },
|
|
291
291
|
...written === 0 ? {} : { cacheWriteTokens: written },
|
|
292
|
-
...
|
|
292
|
+
...usage.output_tokens_details?.reasoning_tokens === undefined ? {} : { reasoningTokens: reasoning },
|
|
293
293
|
};
|
|
294
294
|
}
|
|
295
295
|
function retryDelay(message) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Codex hidden-replay pricing layered over the host's ordinary token meter. */
|
|
2
|
+
import { TokenMeter } from '@deepseek-ai/dsh-token-meter';
|
|
3
|
+
import type { TokenMeasurement } from '@deepseek-ai/dsh-token-meter';
|
|
4
|
+
import type { EpochHeader, Session } from '@deepseek-ai/dsh-session';
|
|
5
|
+
/**
|
|
6
|
+
* Replacement tokenMeter service that charges native Codex encrypted reasoning.
|
|
7
|
+
* Ordinary prices and projections come from the host meter. Hidden prices apply
|
|
8
|
+
* only between routes currently owned by the same native adapter; fixed
|
|
9
|
+
* heuristicTokens stay unchanged. Provider usage is not charged a second time.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CodexTokenMeter extends TokenMeter {
|
|
12
|
+
private readonly hiddenFolds;
|
|
13
|
+
/**
|
|
14
|
+
* Return a detached measurement including opaque native replay in node prices,
|
|
15
|
+
* surface totals, and signed anchor deltas. Recheck usage conservatism against
|
|
16
|
+
* the corrected full anchor before reusing the provider sample.
|
|
17
|
+
* @param session - session to price through its current durable tail.
|
|
18
|
+
* @param requestHeader - optional effective routed request envelope.
|
|
19
|
+
* @returns immutable request pressure and positional message prices.
|
|
20
|
+
*/
|
|
21
|
+
measure(session: Session, requestHeader?: EpochHeader): TokenMeasurement;
|
|
22
|
+
/** Track only replay metadata and surface positions; the host validates each event first. */
|
|
23
|
+
private syncHidden;
|
|
24
|
+
private foldHidden;
|
|
25
|
+
}
|
|
26
|
+
export default CodexTokenMeter;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/** Codex hidden-replay pricing layered over the host's ordinary token meter. */
|
|
2
|
+
import { TokenMeter } from '@deepseek-ai/dsh-token-meter';
|
|
3
|
+
import { estimateToolsTokens } from '@deepseek-ai/dsh-token-meter/estimate';
|
|
4
|
+
import { assembleAssistantStream } from '@deepseek-ai/dsh-llm';
|
|
5
|
+
import { canonicalHeader, deriveEventMessage, headerEquals, isSurfaceEvent, SessionSeq, } from '@deepseek-ai/dsh-session';
|
|
6
|
+
import { canReplayNativeCodex } from './native-adapter.js';
|
|
7
|
+
import { estimateNativeCodexReplayTokens } from './replay.js';
|
|
8
|
+
function replayPrice(message, usage) {
|
|
9
|
+
if (message?.role !== 'assistant' || message.source.kind !== 'model')
|
|
10
|
+
return undefined;
|
|
11
|
+
return { source: message.source, usage };
|
|
12
|
+
}
|
|
13
|
+
function sameHeader(a, b) {
|
|
14
|
+
return a === undefined || b === undefined ? a === b : headerEquals(a, b);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Replacement tokenMeter service that charges native Codex encrypted reasoning.
|
|
18
|
+
* Ordinary prices and projections come from the host meter. Hidden prices apply
|
|
19
|
+
* only between routes currently owned by the same native adapter; fixed
|
|
20
|
+
* heuristicTokens stay unchanged. Provider usage is not charged a second time.
|
|
21
|
+
*/
|
|
22
|
+
export class CodexTokenMeter extends TokenMeter {
|
|
23
|
+
hiddenFolds = new WeakMap();
|
|
24
|
+
/**
|
|
25
|
+
* Return a detached measurement including opaque native replay in node prices,
|
|
26
|
+
* surface totals, and signed anchor deltas. Recheck usage conservatism against
|
|
27
|
+
* the corrected full anchor before reusing the provider sample.
|
|
28
|
+
* @param session - session to price through its current durable tail.
|
|
29
|
+
* @param requestHeader - optional effective routed request envelope.
|
|
30
|
+
* @returns immutable request pressure and positional message prices.
|
|
31
|
+
*/
|
|
32
|
+
measure(session, requestHeader) {
|
|
33
|
+
const base = super.measure(session, requestHeader);
|
|
34
|
+
const state = this.syncHidden(session, base.logRevision);
|
|
35
|
+
const header = requestHeader === undefined ? state.header : canonicalHeader(requestHeader);
|
|
36
|
+
const runtime = this.ctx.get('llm');
|
|
37
|
+
const provider = header?.config?.provider;
|
|
38
|
+
if (runtime === undefined || provider === undefined)
|
|
39
|
+
return base;
|
|
40
|
+
const price = (replay) => {
|
|
41
|
+
if (replay === undefined || !canReplayNativeCodex(runtime, replay.source.provider, provider))
|
|
42
|
+
return 0;
|
|
43
|
+
return replay.tokens ??= estimateNativeCodexReplayTokens(replay.source, replay.usage);
|
|
44
|
+
};
|
|
45
|
+
const current = new Map(state.nodes.map(node => [node.seq, price(node.replay)]));
|
|
46
|
+
const hiddenCurrent = base.nodes.reduce((total, node) => total + (current.get(node.seq) ?? 0), 0);
|
|
47
|
+
const anchor = state.anchor;
|
|
48
|
+
const matched = anchor !== undefined && sameHeader(anchor.header, header);
|
|
49
|
+
const hiddenAnchor = matched
|
|
50
|
+
? anchor.nodes.reduce((total, node) => total + price(node.replay), 0) + price(anchor.assistant)
|
|
51
|
+
: 0;
|
|
52
|
+
if (hiddenCurrent === 0 && hiddenAnchor === 0)
|
|
53
|
+
return base;
|
|
54
|
+
let baseline = base.baseline;
|
|
55
|
+
let surfaceDeltaTokens = base.surfaceDeltaTokens;
|
|
56
|
+
if (matched) {
|
|
57
|
+
surfaceDeltaTokens += hiddenCurrent - hiddenAnchor;
|
|
58
|
+
if (base.baseline.kind === 'usage') {
|
|
59
|
+
const estimatedAnchor = estimateToolsTokens(header)
|
|
60
|
+
+ base.surfaceTokens - base.surfaceDeltaTokens + hiddenAnchor;
|
|
61
|
+
if (base.baseline.tokens < estimatedAnchor) {
|
|
62
|
+
baseline = Object.freeze({ kind: 'estimated', tokens: estimatedAnchor });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (base.baseline.kind === 'estimated') {
|
|
66
|
+
baseline = Object.freeze({ kind: 'estimated', tokens: base.baseline.tokens + hiddenAnchor });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else if (base.baseline.kind === 'estimated') {
|
|
70
|
+
baseline = Object.freeze({ kind: 'estimated', tokens: base.baseline.tokens + hiddenCurrent });
|
|
71
|
+
}
|
|
72
|
+
const nodes = Object.freeze(base.nodes.map(node => Object.freeze({
|
|
73
|
+
...node, tokens: node.tokens + (current.get(node.seq) ?? 0),
|
|
74
|
+
})));
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
...base,
|
|
77
|
+
baseline,
|
|
78
|
+
surfaceDeltaTokens,
|
|
79
|
+
totalTokens: Math.max(0, baseline.tokens + surfaceDeltaTokens),
|
|
80
|
+
surfaceTokens: base.surfaceTokens + hiddenCurrent,
|
|
81
|
+
nodes,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Track only replay metadata and surface positions; the host validates each event first. */
|
|
85
|
+
syncHidden(session, revision) {
|
|
86
|
+
let state = this.hiddenFolds.get(session);
|
|
87
|
+
if (state === undefined) {
|
|
88
|
+
state = { consumed: 0, header: undefined, nodes: [], anchor: undefined };
|
|
89
|
+
this.hiddenFolds.set(session, state);
|
|
90
|
+
}
|
|
91
|
+
while (state.consumed < revision) {
|
|
92
|
+
const event = session.eventAt(SessionSeq(state.consumed));
|
|
93
|
+
if (event === undefined)
|
|
94
|
+
throw new Error('Codex token meter: missing consumed session event');
|
|
95
|
+
this.foldHidden(state, event);
|
|
96
|
+
state.consumed++;
|
|
97
|
+
}
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
foldHidden(state, event) {
|
|
101
|
+
const header = event.type === 'request/header' ? canonicalHeader(event.data.header) : state.header;
|
|
102
|
+
const node = isSurfaceEvent(event) ? {
|
|
103
|
+
seq: event.seq,
|
|
104
|
+
replay: replayPrice(deriveEventMessage(event), event.type === 'assistant/message' ? event.data.usage : undefined),
|
|
105
|
+
} : undefined;
|
|
106
|
+
let anchor = state.anchor;
|
|
107
|
+
if (event.type === 'assistant/message') {
|
|
108
|
+
const route = header?.config;
|
|
109
|
+
const original = event.data.usage !== undefined && route !== undefined
|
|
110
|
+
? { source: {
|
|
111
|
+
provider: route.provider,
|
|
112
|
+
model: route.model,
|
|
113
|
+
replayState: assembleAssistantStream(event.data.stream).replayState,
|
|
114
|
+
}, usage: event.data.usage }
|
|
115
|
+
: node?.replay;
|
|
116
|
+
anchor = { header, nodes: state.nodes.slice(), assistant: original };
|
|
117
|
+
}
|
|
118
|
+
if (node !== undefined && isSurfaceEvent(event)) {
|
|
119
|
+
if (event.surfaceOp === 'append') {
|
|
120
|
+
state.nodes.push(node);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const { startSeq, endSeq } = event.surfaceOp;
|
|
124
|
+
const first = state.nodes.findIndex(item => item.seq === startSeq);
|
|
125
|
+
const last = state.nodes.findIndex(item => item.seq === endSeq);
|
|
126
|
+
if (first < 0 || last < first)
|
|
127
|
+
throw new Error('Codex token meter: invalid surface replacement');
|
|
128
|
+
state.nodes.splice(first, last - first + 1, node);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
state.header = header;
|
|
132
|
+
state.anchor = anchor;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export default CodexTokenMeter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pure01fx/dsh-openai-codex-auth",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "Native ChatGPT Codex provider, device-code-first login, and same-origin Web integration for DeepSeek Harness",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
"types": "./lib/index.d.ts",
|
|
28
28
|
"default": "./lib/index.js"
|
|
29
29
|
},
|
|
30
|
+
"./token-meter": {
|
|
31
|
+
"types": "./lib/token-meter.d.ts",
|
|
32
|
+
"default": "./lib/token-meter.js"
|
|
33
|
+
},
|
|
30
34
|
"./client": "./client.js",
|
|
31
35
|
"./locale/*.json": "./locale/*.json",
|
|
32
36
|
"./package.json": "./package.json"
|
|
@@ -55,6 +59,8 @@
|
|
|
55
59
|
"lib/responses.d.ts",
|
|
56
60
|
"lib/replay.js",
|
|
57
61
|
"lib/replay.d.ts",
|
|
62
|
+
"lib/token-meter.js",
|
|
63
|
+
"lib/token-meter.d.ts",
|
|
58
64
|
"lib/retry-after.js",
|
|
59
65
|
"lib/retry-after.d.ts",
|
|
60
66
|
"lib/rate-limits.js",
|
|
@@ -116,12 +122,14 @@
|
|
|
116
122
|
}
|
|
117
123
|
},
|
|
118
124
|
"peerDependencies": {
|
|
125
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.2",
|
|
119
126
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
120
127
|
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
121
128
|
"@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
|
|
122
129
|
"@deepseek-ai/dsh-fs": "0.2.0-rc.2",
|
|
123
130
|
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
|
|
124
131
|
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
132
|
+
"@deepseek-ai/dsh-token-meter": "0.2.0-rc.2",
|
|
125
133
|
"@deepseek-ai/dsh-sandbox": "0.2.0-rc.2",
|
|
126
134
|
"@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2",
|
|
127
135
|
"@deepseek-ai/dsh-shell": "0.2.0-rc.2",
|
|
@@ -138,7 +146,13 @@
|
|
|
138
146
|
},
|
|
139
147
|
"devDependencies": {
|
|
140
148
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
149
|
+
"@deepseek-ai/cordis-plugin-loader": "1.0.5",
|
|
150
|
+
"@deepseek-ai/cordis-plugin-include": "1.0.9",
|
|
151
|
+
"js-yaml": "^4.1.0",
|
|
152
|
+
"@types/js-yaml": "^4.0.9",
|
|
141
153
|
"@deepseek-ai/dsh-agent": "0.2.0-rc.2",
|
|
154
|
+
"@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2",
|
|
155
|
+
"@deepseek-ai/dsh-session-projection": "0.2.0-rc.2",
|
|
142
156
|
"@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
|
|
143
157
|
"@deepseek-ai/dsh-attachment-local": "0.2.0-rc.2",
|
|
144
158
|
"@deepseek-ai/dsh-client-store": "0.2.0-rc.2",
|
|
@@ -147,6 +161,7 @@
|
|
|
147
161
|
"@deepseek-ai/dsh-fs": "0.2.0-rc.2",
|
|
148
162
|
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
|
|
149
163
|
"@deepseek-ai/dsh-llm": "0.2.0-rc.2",
|
|
164
|
+
"@deepseek-ai/dsh-token-meter": "0.2.0-rc.2",
|
|
150
165
|
"@deepseek-ai/dsh-sandbox": "0.2.0-rc.2",
|
|
151
166
|
"@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2",
|
|
152
167
|
"@deepseek-ai/dsh-scope": "0.2.0-rc.2",
|