Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
96e5ee1
feat(web-ui): session source pill bar redesign
ymkiux May 16, 2026
c3cbe9b
feat(web-ui): session search + cost removal
ymkiux May 16, 2026
b872093
feat(web-ui): refine usage tab UI
ymkiux May 16, 2026
beb3bcd
fix(web-ui): range filter in buildUsageChartGroups
ymkiux May 16, 2026
f8e6f6f
fix(web-ui): invalidate usage cache on range change
ymkiux May 16, 2026
d7f6acd
feat(web-ui): refine trash tab UI
ymkiux May 16, 2026
2c5c9f2
feat(web-ui): refine codex and claude config tab UI
ymkiux May 16, 2026
b3a8abf
fix(web-ui): restore CLAUDE.md editor section
ymkiux May 16, 2026
50b0d17
fix(web-ui): move AGENTS.md above model selector
ymkiux May 16, 2026
318cac4
feat(web-ui): refine docs/install tab UI
ymkiux May 16, 2026
aabaaca
fix(bridge): preserve thinking-mode reasoning_content across turns
ymkiux May 16, 2026
e6d6268
feat(web-ui): paste buttons for config template and agents editors
ymkiux May 16, 2026
bffa3ca
fix(bridge): flatten tool history when upstream rejects thinking-mode…
ymkiux May 17, 2026
95426c8
fix(bridge): port codex-relay strategy for reasoning round-trip and t…
ymkiux May 17, 2026
2f3a486
fix(bridge): keep tools in flattened retry so model still emits struc…
ymkiux May 17, 2026
91154c6
Revert "fix(bridge): keep tools in flattened retry so model still emi…
ymkiux May 17, 2026
067aceb
Revert "fix(bridge): port codex-relay strategy for reasoning round-tr…
ymkiux May 17, 2026
1671abd
Revert "fix(bridge): flatten tool history when upstream rejects think…
ymkiux May 17, 2026
7041c56
Revert "fix(bridge): preserve thinking-mode reasoning_content across …
ymkiux May 17, 2026
c50a644
fix(web-ui): restore Claude model selector and preset providers
ymkiux May 17, 2026
1d11882
fix(web-ui): disable clone button on codex provider cards
ymkiux May 17, 2026
3ae6fba
feat(web-ui): show version number at sidebar bottom
ymkiux May 17, 2026
a47d278
fix(web-ui): remove conflicting display:flex from lang-fab
ymkiux May 17, 2026
c65d360
fix(web-ui): move version inside side-rail-lang for proper stacking
ymkiux May 17, 2026
7cae095
chore: bump version to 0.0.32
ymkiux May 17, 2026
495e9a1
fix(test): add appVersion to parity baseline allowed keys
ymkiux May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions cli/openai-bridge-session.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use strict';

const crypto = require('crypto');

// 模型 reasoning_content 必回放。
class OpenaiBridgeSessionStore {
constructor() {
this.reasoning = new Map();
this.turnReasoning = new Map();
this.history = new Map();
}

storeReasoning(callId, reasoning) {
if (typeof callId !== 'string' || !callId) return;
if (typeof reasoning !== 'string' || !reasoning) return;
this.reasoning.set(callId, reasoning);
}

getReasoning(callId) {
if (typeof callId !== 'string' || !callId) return null;
return this.reasoning.has(callId) ? this.reasoning.get(callId) : null;
}

storeTurnReasoning(assistantMessage, reasoning) {
if (!assistantMessage || typeof assistantMessage !== 'object') return;
if (typeof reasoning !== 'string' || !reasoning) return;
const content = OpenaiBridgeSessionStore.textOfContent(assistantMessage.content);
if (content) {
this.turnReasoning.set(OpenaiBridgeSessionStore.contentKey(content), reasoning);
}
if (Array.isArray(assistantMessage.tool_calls)) {
for (const call of assistantMessage.tool_calls) {
const id = call && typeof call === 'object' && typeof call.id === 'string' ? call.id : '';
this.storeReasoning(id, reasoning);
}
}
}

getTurnReasoning(assistantMessage) {
if (!assistantMessage || typeof assistantMessage !== 'object') return null;
const content = OpenaiBridgeSessionStore.textOfContent(assistantMessage.content);
if (!content) return null;
const key = OpenaiBridgeSessionStore.contentKey(content);
return this.turnReasoning.has(key) ? this.turnReasoning.get(key) : null;
}

getHistory(responseId) {
if (typeof responseId !== 'string' || !responseId) return [];
const cached = this.history.get(responseId);
return Array.isArray(cached) ? cached.slice() : [];
}

newId() {
return `resp_${crypto.randomBytes(10).toString('hex')}`;
}

saveWithId(responseId, messages) {
if (typeof responseId !== 'string' || !responseId) return;
this.history.set(responseId, Array.isArray(messages) ? messages.slice() : []);
}

save(messages) {
const id = this.newId();
this.saveWithId(id, messages);
return id;
}

static textOfContent(content) {
if (typeof content === 'string') return content;
if (Array.isArray(content)) {
return content
.map((part) => (part && typeof part === 'object' && typeof part.text === 'string' ? part.text : ''))
.filter(Boolean)
.join('');
}
return '';
}

static contentKey(text) {
return crypto.createHash('sha1').update(String(text || ''), 'utf-8').digest('hex');
}
}

module.exports = { OpenaiBridgeSessionStore };
Loading
Loading