@bitkyc08/opencodex 2.0.2 → 2.1.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/README.ko.md +42 -2
- package/README.md +43 -3
- package/README.zh-CN.md +21 -0
- package/gui/dist/assets/index-34pGgy8q.js +9 -0
- package/gui/dist/assets/{index-cEIM1XWY.css → index-dCS-lwCM.css} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +7 -3
- package/src/adapters/azure.ts +7 -7
- package/src/adapters/google.ts +4 -3
- package/src/adapters/openai-chat.ts +2 -1
- package/src/adapters/openai-responses.ts +2 -1
- package/src/bridge.ts +142 -26
- package/src/cli.ts +166 -13
- package/src/codex-catalog.ts +1 -0
- package/src/codex-history-provider.ts +86 -0
- package/src/codex-inject.ts +9 -1
- package/src/codex-shim.ts +76 -32
- package/src/config.ts +31 -5
- package/src/init.ts +11 -0
- package/src/oauth/store.ts +10 -4
- package/src/open-url.ts +7 -3
- package/src/ports.ts +30 -0
- package/src/providers/registry.ts +1 -1
- package/src/responses/parser.ts +9 -6
- package/src/responses/schema.ts +1 -0
- package/src/server.ts +208 -43
- package/src/service.ts +29 -2
- package/src/types.ts +10 -0
- package/src/update.ts +12 -2
- package/src/web-search/loop.ts +9 -1
- package/src/ws-bridge.ts +1 -1
- package/gui/dist/assets/index-PrH8v83W.js +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--bg:var(--lightningcss-light,#f6f7f9)var(--lightningcss-dark,#0c0d11);--rail:var(--lightningcss-light,#fff)var(--lightningcss-dark,#101218);--surface:var(--lightningcss-light,#fff)var(--lightningcss-dark,#15171d);--raised:var(--lightningcss-light,#f1f2f5)var(--lightningcss-dark,#1c1f27);--raised-hover:var(--lightningcss-light,#e8eaee)var(--lightningcss-dark,#242833);--border:var(--lightningcss-light,#e2e4e9)var(--lightningcss-dark,#2a2e39);--border-soft:var(--lightningcss-light,#ededf1)var(--lightningcss-dark,#20242d);--hover:var(--lightningcss-light,#11131c09)var(--lightningcss-dark,#ffffff06);--text:var(--lightningcss-light,#16181d)var(--lightningcss-dark,#edeef2);--muted:var(--lightningcss-light,#5b6270)var(--lightningcss-dark,#a3a9b5);--faint:var(--lightningcss-light,#868d9b)var(--lightningcss-dark,#6b7280);--accent:var(--lightningcss-light,#4f46e5)var(--lightningcss-dark,#6366f1);--accent-hover:var(--lightningcss-light,#4338ca)var(--lightningcss-dark,#818cf8);--accent-ink:#fff;--accent-soft:var(--lightningcss-light,#4f46e51a)var(--lightningcss-dark,#6366f129);--accent-ring:var(--lightningcss-light,#4f46e566)var(--lightningcss-dark,#6366f180);--green:var(--lightningcss-light,#047857)var(--lightningcss-dark,#34d399);--green-soft:var(--lightningcss-light,#0596691a)var(--lightningcss-dark,#34d39921);--red:var(--lightningcss-light,#b91c1c)var(--lightningcss-dark,#f87171);--red-soft:var(--lightningcss-light,#b91c1c17)var(--lightningcss-dark,#f8717121);--amber:var(--lightningcss-light,#b45309)var(--lightningcss-dark,#fbbf24);--amber-soft:var(--lightningcss-light,#b453091a)var(--lightningcss-dark,#fbbf2421);--radius:8px;--radius-sm:5px;--radius-xs:4px;--font:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, "Helvetica Neue", sans-serif;--mono:ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;--shadow:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#00000080), 0 10px 28px var(--lightningcss-light,#10182812)var(--lightningcss-dark,#0000004d);--shadow-sm:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#0006)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}:root[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;margin:0;font-size:14px;line-height:1.5}a{color:var(--accent-hover);text-decoration:none}a:hover{text-decoration:underline}code,.mono{font-family:var(--mono);font-size:.92em}h1,h2,h3,h4{letter-spacing:-.01em;margin:0;font-weight:650}::selection{background:var(--accent-soft)}input[type=checkbox],input[type=radio]{accent-color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--border);border:2px solid var(--bg);border-radius:99px}::-webkit-scrollbar-thumb:hover{background:var(--faint)}:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px;border-radius:4px}.app{grid-template-columns:232px 1fr;min-height:100dvh;display:grid}.sidebar{border-right:1px solid var(--border);background:var(--rail);flex-direction:column;align-self:start;gap:4px;height:100dvh;padding:18px 14px;display:flex;position:sticky;top:0}.brand{align-items:center;gap:10px;padding:6px 8px 14px;display:flex}.brand-logo{background:var(--text);flex-shrink:0;width:26px;height:26px;-webkit-mask:url(/logo.png) 50%/contain no-repeat;mask:url(/logo.png) 50%/contain no-repeat}.brand .name{letter-spacing:-.02em;font-size:15px;font-weight:700;line-height:26px}.brand .ver{font-family:var(--mono);color:var(--muted);background:var(--raised);border:1px solid var(--border);border-radius:99px;align-self:center;padding:2px 6px;font-size:10px;line-height:1}.nav-item{border-radius:var(--radius-sm);text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;background:0 0;border:none;align-items:center;gap:10px;padding:8px 10px;font-size:13.5px;font-weight:500;transition:background .12s,color .12s;display:flex}.nav-item:hover{background:var(--raised);color:var(--text)}.nav-item.active{background:var(--accent-soft);color:var(--text)}.nav-item svg{width:17px;height:17px;color:var(--faint);flex-shrink:0}.nav-item.active svg{color:var(--accent)}.sidebar-foot{flex-direction:column;gap:2px;margin-top:auto;padding-top:12px;display:flex}.sidebar-link{color:var(--muted);border-radius:var(--radius-sm);align-items:center;gap:9px;padding:8px 10px;font-size:13px;display:flex}.sidebar-link:hover{background:var(--raised);color:var(--text);text-decoration:none}.sidebar-link svg{width:16px;height:16px}.theme-toggle{text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;border-radius:var(--radius-sm);background:0 0;border:none;align-items:center;gap:9px;padding:8px 10px;font-size:13px;transition:background .12s,color .12s;display:flex}.theme-toggle:hover{background:var(--raised);color:var(--text)}.theme-toggle svg{flex-shrink:0;width:16px;height:16px}.theme-toggle .mode{text-transform:capitalize}.stop-toggle{color:var(--red)}.stop-toggle:hover{background:var(--red-soft);color:var(--red)}.stop-toggle:disabled{opacity:.5;cursor:default}.main{min-width:0}.main-inner{max-width:980px;margin:0 auto;padding:32px 36px 64px}.page-head{justify-content:space-between;align-items:center;gap:16px;margin-bottom:6px;display:flex}.page-head h2{font-size:19px}.page-sub{color:var(--muted);max-width:70ch;margin:4px 0 22px;font-size:13.5px}.page-sub b{color:var(--text);font-weight:600}.btn{border-radius:var(--radius-sm);font:inherit;cursor:pointer;white-space:nowrap;border:1px solid #0000;justify-content:center;align-items:center;gap:7px;padding:7px 14px;font-size:13px;font-weight:550;transition:background .12s,border-color .12s,opacity .12s;display:inline-flex}.btn svg{width:15px;height:15px}.btn:disabled{opacity:.55;cursor:default}.btn-primary{background:var(--accent);color:var(--accent-ink)}.btn-primary:hover:not(:disabled){background:var(--accent-hover)}.btn-ghost{background:var(--raised);color:var(--text);border-color:var(--border)}.btn-ghost:hover:not(:disabled){background:var(--raised-hover)}.btn-danger{color:var(--red);background:0 0;border-color:#f871714d}.btn-danger:hover:not(:disabled){background:var(--red-soft)}.btn-sm{border-radius:var(--radius-xs);padding:4px 9px;font-size:12px}.btn-icon{padding:5px}.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius)}.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:18px}.panel-accent{background:linear-gradient(180deg, var(--accent-soft), transparent 120%), var(--surface);border-color:#7c5cff47}.stat-row{grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:28px;display:grid}.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;transition:border-color .12s}.stat:hover{border-color:var(--accent-ring)}.stat .label{color:var(--muted);text-transform:uppercase;letter-spacing:.05em;align-items:center;gap:6px;margin-bottom:9px;font-size:11px;font-weight:600;display:flex}.stat .label svg{width:14px;height:14px}.stat .value{letter-spacing:-.02em;font-size:24px;font-weight:700;line-height:1.1}.stat .value.mono{font-family:var(--mono);font-size:19px}.model-group-head{color:var(--muted);text-transform:uppercase;letter-spacing:.04em;align-items:baseline;gap:8px;margin:0 0 8px;font-size:12px;font-weight:600;display:flex}.model-group-head .count{font-family:var(--mono);text-transform:none;letter-spacing:0;color:var(--faint);font-weight:500}.model-grid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;display:grid}.model-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;transition:border-color .12s,background .12s}.model-card:hover{border-color:var(--accent-ring);background:var(--hover)}.model-card .id{font-family:var(--mono);letter-spacing:-.01em;color:var(--text);font-size:13px;font-weight:600}.badge{font-size:11px;font-weight:600;font-family:var(--mono);letter-spacing:.01em;border-radius:99px;align-items:center;gap:5px;padding:2px 8px;display:inline-flex}.badge-accent{background:var(--accent-soft);color:var(--accent-hover)}.badge-green{background:var(--green-soft);color:var(--green)}.badge-amber{background:var(--amber-soft);color:var(--amber)}.badge-muted{background:var(--raised);color:var(--muted);border:1px solid var(--border)}.dot{border-radius:50%;flex-shrink:0;width:7px;height:7px}.dot-green{background:var(--green);box-shadow:0 0 0 3px var(--green-soft)}.dot-red{background:var(--red);box-shadow:0 0 0 3px var(--red-soft)}.tbl{border-collapse:collapse;width:100%;font-size:13px}.tbl thead th{text-align:left;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--border);padding:9px 12px;font-size:11.5px;font-weight:600}.tbl tbody td{border-bottom:1px solid var(--border-soft);padding:10px 12px}.tbl tbody tr:last-child td{border-bottom:none}.tbl tbody tr:hover td{background:var(--hover)}.tbl .num{text-align:right;font-family:var(--mono)}.tbl-wrap{border:1px solid var(--border);border-radius:var(--radius);overflow-x:auto}.input,textarea.input{border-radius:var(--radius-sm);background:var(--raised);border:1px solid var(--border);width:100%;color:var(--text);font:inherit;padding:8px 11px;font-size:13px;transition:border-color .12s}.input::placeholder{color:var(--faint)}.input:focus{border-color:var(--accent);outline:none}textarea.input{resize:vertical;font-family:var(--mono);line-height:1.55}.field-label{color:var(--muted);margin-bottom:5px;font-size:12px;font-weight:500;display:block}select.input{appearance:none}.switch{cursor:pointer;background:var(--lightningcss-light,#c5c9d2)var(--lightningcss-dark,#3a3f4b);border:none;border-radius:99px;flex-shrink:0;width:34px;height:19px;padding:0;transition:background .15s;position:relative}.switch.on{background:var(--accent)}.switch:disabled{opacity:.6;cursor:default}.switch .knob{background:#fff;border-radius:50%;width:15px;height:15px;transition:left .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #1018284d}.switch.on .knob{left:17px}.muted{color:var(--muted)}.faint{color:var(--faint)}.row{align-items:center;gap:10px;display:flex}.spread{justify-content:space-between;align-items:center;gap:12px;display:flex}.stack{flex-direction:column;display:flex}.chip{font-family:var(--mono);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-xs);color:var(--text);padding:1px 7px;font-size:12px}.empty{text-align:center;border:1px dashed var(--border);border-radius:var(--radius);color:var(--muted);padding:56px 20px}.empty svg{width:30px;height:30px;color:var(--faint);margin-bottom:12px}.empty .title{color:var(--text);margin-bottom:6px;font-weight:600}.notice{border-radius:var(--radius-sm);align-items:center;gap:8px;margin-bottom:14px;padding:9px 12px;font-size:13px;display:flex}.notice svg{flex-shrink:0;width:15px;height:15px}.notice-ok{background:var(--green-soft);color:var(--green)}.notice-err{background:var(--red-soft);color:var(--red)}.h-section{color:var(--text);align-items:center;gap:8px;margin:30px 0 12px;font-size:13px;font-weight:600;display:flex}.h-section .count{color:var(--muted);font-weight:500;font-family:var(--mono);font-size:12px}.spin{border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;width:14px;height:14px;animation:.7s linear infinite spin;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}.modal-overlay{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:50;background:var(--lightningcss-light,#11131c73)var(--lightningcss-dark,#0009);justify-content:center;align-items:flex-start;padding:8vh 16px;display:flex;position:fixed;inset:0}.modal-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);width:100%;max-width:520px;box-shadow:var(--shadow);max-height:84vh;padding:20px;overflow-y:auto}.modal-head{justify-content:space-between;align-items:center;margin-bottom:16px;display:flex}.modal-head h3{font-size:16px}.setup-guide{border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:4px;padding:8px 12px;font-size:13px}.setup-guide summary{cursor:pointer;color:var(--accent-hover);font-weight:500}.setup-guide summary:hover{text-decoration:underline}.setup-guide a{color:var(--accent-hover)}.list-row{text-align:left;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--raised);cursor:pointer;width:100%;color:var(--text);font:inherit;justify-content:space-between;align-items:center;gap:10px;padding:11px 13px;transition:background .12s,border-color .12s;display:flex}.list-row:hover{background:var(--raised-hover);border-color:var(--accent-ring)}.list-row .title{font-size:14px;font-weight:600}.list-row .sub{color:var(--muted);margin-top:2px;font-size:12px}.prov-card{justify-content:space-between;align-items:flex-start;gap:12px;padding:15px 16px;display:flex}.link-btn{color:var(--accent-hover);font:inherit;cursor:pointer;background:0 0;border:none;padding:6px 2px;font-size:13px;text-decoration:underline}@media (width<=760px){.app{grid-template-columns:1fr}.sidebar{z-index:20;border-right:none;border-bottom:1px solid var(--border);background:var(--rail);flex-flow:wrap;align-items:center;gap:0;min-width:0;height:auto;padding:0 10px;position:sticky;top:0}.brand{flex:auto;order:1;width:auto;padding:10px 4px}.sidebar-foot{flex-direction:row;flex:none;order:2;gap:4px;margin:0;padding:0}.sidebar-foot .sidebar-link{display:none}.theme-toggle{justify-content:center;min-width:44px;min-height:44px;padding:8px}.theme-toggle .mode{display:none}.sidebar nav{overscroll-behavior-x:contain;border-top:1px solid var(--border-soft);scrollbar-width:none;flex-direction:row;flex:100%;order:3;gap:2px;min-width:0;margin:0;padding:4px 0 8px;display:flex;overflow-x:auto}.sidebar nav::-webkit-scrollbar{display:none}.nav-item{white-space:nowrap;width:auto;min-height:44px;padding:9px 14px;font-size:14px}.main-inner{padding:22px 18px 48px}.stat-row{grid-template-columns:repeat(2,minmax(0,1fr))}.tbl{min-width:460px}}
|
|
1
|
+
:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--bg:var(--lightningcss-light,#f6f7f9)var(--lightningcss-dark,#0c0d11);--rail:var(--lightningcss-light,#fff)var(--lightningcss-dark,#101218);--surface:var(--lightningcss-light,#fff)var(--lightningcss-dark,#15171d);--raised:var(--lightningcss-light,#f1f2f5)var(--lightningcss-dark,#1c1f27);--raised-hover:var(--lightningcss-light,#e8eaee)var(--lightningcss-dark,#242833);--border:var(--lightningcss-light,#e2e4e9)var(--lightningcss-dark,#2a2e39);--border-soft:var(--lightningcss-light,#ededf1)var(--lightningcss-dark,#20242d);--hover:var(--lightningcss-light,#11131c09)var(--lightningcss-dark,#ffffff06);--text:var(--lightningcss-light,#16181d)var(--lightningcss-dark,#edeef2);--muted:var(--lightningcss-light,#5b6270)var(--lightningcss-dark,#a3a9b5);--faint:var(--lightningcss-light,#868d9b)var(--lightningcss-dark,#6b7280);--accent:var(--lightningcss-light,#4f46e5)var(--lightningcss-dark,#6366f1);--accent-hover:var(--lightningcss-light,#4338ca)var(--lightningcss-dark,#818cf8);--accent-ink:#fff;--accent-soft:var(--lightningcss-light,#4f46e51a)var(--lightningcss-dark,#6366f129);--accent-ring:var(--lightningcss-light,#4f46e566)var(--lightningcss-dark,#6366f180);--green:var(--lightningcss-light,#047857)var(--lightningcss-dark,#34d399);--green-soft:var(--lightningcss-light,#0596691a)var(--lightningcss-dark,#34d39921);--red:var(--lightningcss-light,#b91c1c)var(--lightningcss-dark,#f87171);--red-soft:var(--lightningcss-light,#b91c1c17)var(--lightningcss-dark,#f8717121);--amber:var(--lightningcss-light,#b45309)var(--lightningcss-dark,#fbbf24);--amber-soft:var(--lightningcss-light,#b453091a)var(--lightningcss-dark,#fbbf2421);--radius:8px;--radius-sm:5px;--radius-xs:4px;--font:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, "Helvetica Neue", sans-serif;--mono:ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;--shadow:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#00000080), 0 10px 28px var(--lightningcss-light,#10182812)var(--lightningcss-dark,#0000004d);--shadow-sm:0 1px 2px var(--lightningcss-light,#1018280f)var(--lightningcss-dark,#0006)}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}:root[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}:root[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;margin:0;font-size:14px;line-height:1.5}a{color:var(--accent-hover);text-decoration:none}a:hover{text-decoration:underline}code,.mono{font-family:var(--mono);font-size:.92em}h1,h2,h3,h4{letter-spacing:-.01em;margin:0;font-weight:650}::selection{background:var(--accent-soft)}input[type=checkbox],input[type=radio]{accent-color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--border);border:2px solid var(--bg);border-radius:99px}::-webkit-scrollbar-thumb:hover{background:var(--faint)}:focus-visible{outline:2px solid var(--accent-ring);outline-offset:2px;border-radius:4px}.app{grid-template-columns:232px 1fr;min-height:100dvh;display:grid}.sidebar{border-right:1px solid var(--border);background:var(--rail);flex-direction:column;align-self:start;gap:4px;height:100dvh;padding:18px 14px;display:flex;position:sticky;top:0}.brand{align-items:center;gap:10px;padding:6px 8px 14px;display:flex}.brand-logo{background:var(--text);flex-shrink:0;width:26px;height:26px;-webkit-mask:url(/logo.png) 50%/contain no-repeat;mask:url(/logo.png) 50%/contain no-repeat}.brand .name{letter-spacing:-.02em;font-size:15px;font-weight:700;line-height:26px}.brand .ver{font-family:var(--mono);color:var(--muted);background:var(--raised);border:1px solid var(--border);border-radius:99px;align-self:center;padding:2px 6px;font-size:10px;line-height:1}.nav-item{border-radius:var(--radius-sm);text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;background:0 0;border:none;align-items:center;gap:10px;padding:8px 10px;font-size:13.5px;font-weight:500;transition:background .12s,color .12s;display:flex}.nav-item:hover{background:var(--raised);color:var(--text)}.nav-item.active{background:var(--accent-soft);color:var(--text)}.nav-item svg{width:17px;height:17px;color:var(--faint);flex-shrink:0}.nav-item.active svg{color:var(--accent)}.sidebar-foot{flex-direction:column;gap:2px;margin-top:auto;padding-top:12px;display:flex}.sidebar-link{color:var(--muted);border-radius:var(--radius-sm);align-items:center;gap:9px;padding:8px 10px;font-size:13px;display:flex}.sidebar-link:hover{background:var(--raised);color:var(--text);text-decoration:none}.sidebar-link svg{width:16px;height:16px}.theme-toggle{text-align:left;cursor:pointer;width:100%;color:var(--muted);font:inherit;border-radius:var(--radius-sm);background:0 0;border:none;align-items:center;gap:9px;padding:8px 10px;font-size:13px;transition:background .12s,color .12s;display:flex}.theme-toggle:hover{background:var(--raised);color:var(--text)}.theme-toggle svg{flex-shrink:0;width:16px;height:16px}.theme-toggle .mode{text-transform:capitalize}.stop-toggle{color:var(--red)}.stop-toggle:hover{background:var(--red-soft);color:var(--red)}.stop-toggle:disabled{opacity:.5;cursor:default}.main{min-width:0}.main-inner{max-width:980px;margin:0 auto;padding:32px 36px 64px}.page-head{justify-content:space-between;align-items:center;gap:16px;margin-bottom:6px;display:flex}.page-head h2{font-size:19px}.page-sub{color:var(--muted);max-width:70ch;margin:4px 0 22px;font-size:13.5px}.page-sub b{color:var(--text);font-weight:600}.btn{border-radius:var(--radius-sm);font:inherit;cursor:pointer;white-space:nowrap;border:1px solid #0000;justify-content:center;align-items:center;gap:7px;padding:7px 14px;font-size:13px;font-weight:550;transition:background .12s,border-color .12s,opacity .12s;display:inline-flex}.btn svg{width:15px;height:15px}.btn:disabled{opacity:.55;cursor:default}.btn-primary{background:var(--accent);color:var(--accent-ink)}.btn-primary:hover:not(:disabled){background:var(--accent-hover)}.btn-ghost{background:var(--raised);color:var(--text);border-color:var(--border)}.btn-ghost:hover:not(:disabled){background:var(--raised-hover)}.btn-danger{color:var(--red);background:0 0;border-color:#f871714d}.btn-danger:hover:not(:disabled){background:var(--red-soft)}.btn-sm{border-radius:var(--radius-xs);padding:4px 9px;font-size:12px}.btn-icon{padding:5px}.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius)}.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:18px}.panel-accent{background:linear-gradient(180deg, var(--accent-soft), transparent 120%), var(--surface);border-color:#7c5cff47}.stat-row{grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:28px;display:grid}.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;transition:border-color .12s}.stat:hover{border-color:var(--accent-ring)}.stat .label{color:var(--muted);text-transform:uppercase;letter-spacing:.05em;align-items:center;gap:6px;margin-bottom:9px;font-size:11px;font-weight:600;display:flex}.stat .label svg{width:14px;height:14px}.stat .value{letter-spacing:-.02em;font-size:24px;font-weight:700;line-height:1.1}.stat .value.mono{font-family:var(--mono);font-size:19px}.model-group-head{color:var(--muted);text-transform:uppercase;letter-spacing:.04em;align-items:baseline;gap:8px;margin:0 0 8px;font-size:12px;font-weight:600;display:flex}.model-group-head .count{font-family:var(--mono);text-transform:none;letter-spacing:0;color:var(--faint);font-weight:500}.model-grid{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;display:grid}.model-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;transition:border-color .12s,background .12s}.model-card:hover{border-color:var(--accent-ring);background:var(--hover)}.model-card .id{font-family:var(--mono);letter-spacing:-.01em;color:var(--text);font-size:13px;font-weight:600}.badge{font-size:11px;font-weight:600;font-family:var(--mono);letter-spacing:.01em;border-radius:99px;align-items:center;gap:5px;padding:2px 8px;display:inline-flex}.badge-accent{background:var(--accent-soft);color:var(--accent-hover)}.badge-green{background:var(--green-soft);color:var(--green)}.badge-amber{background:var(--amber-soft);color:var(--amber)}.badge-muted{background:var(--raised);color:var(--muted);border:1px solid var(--border)}.dot{border-radius:50%;flex-shrink:0;width:7px;height:7px}.dot-green{background:var(--green);box-shadow:0 0 0 3px var(--green-soft)}.dot-red{background:var(--red);box-shadow:0 0 0 3px var(--red-soft)}.tbl{border-collapse:collapse;width:100%;font-size:13px}.tbl thead th{text-align:left;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--border);padding:9px 12px;font-size:11.5px;font-weight:600}.tbl tbody td{border-bottom:1px solid var(--border-soft);padding:10px 12px}.tbl tbody tr:last-child td{border-bottom:none}.tbl tbody tr:hover td{background:var(--hover)}.tbl .num{text-align:right;font-family:var(--mono)}.tbl-wrap{border:1px solid var(--border);border-radius:var(--radius);overflow-x:auto}.input,textarea.input{border-radius:var(--radius-sm);background:var(--raised);border:1px solid var(--border);width:100%;color:var(--text);font:inherit;padding:8px 11px;font-size:13px;transition:border-color .12s}.input::placeholder{color:var(--faint)}.input:focus{border-color:var(--accent);outline:none}textarea.input{resize:vertical;font-family:var(--mono);line-height:1.55}.field-label{color:var(--muted);margin-bottom:5px;font-size:12px;font-weight:500;display:block}select.input{appearance:none}.select-sm{border-radius:var(--radius-sm);background:var(--raised);border:1px solid var(--border);color:var(--text);font:inherit;cursor:pointer;padding:5px 8px;font-size:13px;transition:border-color .12s}.select-sm:focus{border-color:var(--accent);outline:none}.select-sm:disabled{opacity:.5;cursor:default}.switch{cursor:pointer;background:var(--lightningcss-light,#c5c9d2)var(--lightningcss-dark,#3a3f4b);border:none;border-radius:99px;flex-shrink:0;width:34px;height:19px;padding:0;transition:background .15s;position:relative}.switch.on{background:var(--accent)}.switch:disabled{opacity:.6;cursor:default}.switch .knob{background:#fff;border-radius:50%;width:15px;height:15px;transition:left .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #1018284d}.switch.on .knob{left:17px}.muted{color:var(--muted)}.faint{color:var(--faint)}.row{align-items:center;gap:10px;display:flex}.spread{justify-content:space-between;align-items:center;gap:12px;display:flex}.stack{flex-direction:column;display:flex}.chip{font-family:var(--mono);background:var(--raised);border:1px solid var(--border);border-radius:var(--radius-xs);color:var(--text);padding:1px 7px;font-size:12px}.empty{text-align:center;border:1px dashed var(--border);border-radius:var(--radius);color:var(--muted);padding:56px 20px}.empty svg{width:30px;height:30px;color:var(--faint);margin-bottom:12px}.empty .title{color:var(--text);margin-bottom:6px;font-weight:600}.notice{border-radius:var(--radius-sm);align-items:center;gap:8px;margin-bottom:14px;padding:9px 12px;font-size:13px;display:flex}.notice svg{flex-shrink:0;width:15px;height:15px}.notice-ok{background:var(--green-soft);color:var(--green)}.notice-err{background:var(--red-soft);color:var(--red)}.h-section{color:var(--text);align-items:center;gap:8px;margin:30px 0 12px;font-size:13px;font-weight:600;display:flex}.h-section .count{color:var(--muted);font-weight:500;font-family:var(--mono);font-size:12px}.spin{border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;width:14px;height:14px;animation:.7s linear infinite spin;display:inline-block}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}.modal-overlay{-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:50;background:var(--lightningcss-light,#11131c73)var(--lightningcss-dark,#0009);justify-content:center;align-items:flex-start;padding:8vh 16px;display:flex;position:fixed;inset:0}.modal-card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);width:100%;max-width:520px;box-shadow:var(--shadow);max-height:84vh;padding:20px;overflow-y:auto}.modal-head{justify-content:space-between;align-items:center;margin-bottom:16px;display:flex}.modal-head h3{font-size:16px}.setup-guide{border:1px solid var(--border);border-radius:var(--radius-sm);margin-bottom:4px;padding:8px 12px;font-size:13px}.setup-guide summary{cursor:pointer;color:var(--accent-hover);font-weight:500}.setup-guide summary:hover{text-decoration:underline}.setup-guide a{color:var(--accent-hover)}.list-row{text-align:left;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--raised);cursor:pointer;width:100%;color:var(--text);font:inherit;justify-content:space-between;align-items:center;gap:10px;padding:11px 13px;transition:background .12s,border-color .12s;display:flex}.list-row:hover{background:var(--raised-hover);border-color:var(--accent-ring)}.list-row .title{font-size:14px;font-weight:600}.list-row .sub{color:var(--muted);margin-top:2px;font-size:12px}.prov-card{justify-content:space-between;align-items:flex-start;gap:12px;padding:15px 16px;display:flex}.link-btn{color:var(--accent-hover);font:inherit;cursor:pointer;background:0 0;border:none;padding:6px 2px;font-size:13px;text-decoration:underline}@media (width<=760px){.app{grid-template-columns:1fr}.sidebar{z-index:20;border-right:none;border-bottom:1px solid var(--border);background:var(--rail);flex-flow:wrap;align-items:center;gap:0;min-width:0;height:auto;padding:0 10px;position:sticky;top:0}.brand{flex:auto;order:1;width:auto;padding:10px 4px}.sidebar-foot{flex-direction:row;flex:none;order:2;gap:4px;margin:0;padding:0}.sidebar-foot .sidebar-link{display:none}.theme-toggle{justify-content:center;min-width:44px;min-height:44px;padding:8px}.theme-toggle .mode{display:none}.sidebar nav{overscroll-behavior-x:contain;border-top:1px solid var(--border-soft);scrollbar-width:none;flex-direction:row;flex:100%;order:3;gap:2px;min-width:0;margin:0;padding:4px 0 8px;display:flex;overflow-x:auto}.sidebar nav::-webkit-scrollbar{display:none}.nav-item{white-space:nowrap;width:auto;min-height:44px;padding:9px 14px;font-size:14px}.main-inner{padding:22px 18px 48px}.stat-row{grid-template-columns:repeat(2,minmax(0,1fr))}.tbl{min-width:460px}}
|
package/gui/dist/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-34pGgy8q.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-dCS-lwCM.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
OcxToolCall,
|
|
13
13
|
OcxUsage,
|
|
14
14
|
} from "../types";
|
|
15
|
+
import { namespacedToolName } from "../types";
|
|
15
16
|
import { ANTHROPIC_OAUTH_BETA, CLAUDE_CODE_SYSTEM_INSTRUCTION, applyClaudeToolPrefix, stripClaudeToolPrefix } from "../oauth/anthropic";
|
|
16
17
|
import { parseDataUrl } from "./image";
|
|
17
18
|
|
|
@@ -85,7 +86,8 @@ function messagesToAnthropicFormat(parsed: OcxParsedRequest, isOAuth: boolean):
|
|
|
85
86
|
content.push({ type: "thinking", thinking: t.thinking, ...(t.signature ? { signature: t.signature } : {}) });
|
|
86
87
|
} else if (part.type === "toolCall") {
|
|
87
88
|
const tc = part as OcxToolCall;
|
|
88
|
-
|
|
89
|
+
const flatName = namespacedToolName(tc.namespace, tc.name);
|
|
90
|
+
content.push({ type: "tool_use", id: tc.id, name: isOAuth ? applyClaudeToolPrefix(flatName) : flatName, input: tc.arguments });
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
messages.push({ role: "assistant", content });
|
|
@@ -116,7 +118,7 @@ function messagesToAnthropicFormat(parsed: OcxParsedRequest, isOAuth: boolean):
|
|
|
116
118
|
function toolsToAnthropicFormat(parsed: OcxParsedRequest, isOAuth: boolean): unknown[] | undefined {
|
|
117
119
|
if (!parsed.context.tools || parsed.context.tools.length === 0) return undefined;
|
|
118
120
|
return parsed.context.tools.map(t => ({
|
|
119
|
-
name: isOAuth ? applyClaudeToolPrefix(t.name) : t.name,
|
|
121
|
+
name: isOAuth ? applyClaudeToolPrefix(namespacedToolName(t.namespace, t.name)) : namespacedToolName(t.namespace, t.name),
|
|
120
122
|
description: t.description,
|
|
121
123
|
input_schema: t.parameters,
|
|
122
124
|
}));
|
|
@@ -175,7 +177,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig): ProviderAda
|
|
|
175
177
|
else if (typeof tc === "object" && "name" in tc) body.tool_choice = { type: "tool", name: isOAuth ? applyClaudeToolPrefix(tc.name) : tc.name };
|
|
176
178
|
}
|
|
177
179
|
|
|
178
|
-
const
|
|
180
|
+
const base = provider.baseUrl.replace(/\/v1\/?$/, "");
|
|
181
|
+
const url = `${base}/v1/messages`;
|
|
179
182
|
const headers: Record<string, string> = {
|
|
180
183
|
"Content-Type": "application/json",
|
|
181
184
|
"anthropic-version": "2023-06-01",
|
|
@@ -312,5 +315,6 @@ export function createAnthropicAdapter(provider: OcxProviderConfig): ProviderAda
|
|
|
312
315
|
});
|
|
313
316
|
return events;
|
|
314
317
|
},
|
|
318
|
+
|
|
315
319
|
};
|
|
316
320
|
}
|
package/src/adapters/azure.ts
CHANGED
|
@@ -19,13 +19,13 @@ export function createAzureAdapter(provider: OcxProviderConfig): ProviderAdapter
|
|
|
19
19
|
headers["api-key"] = provider.apiKey;
|
|
20
20
|
delete headers["Authorization"];
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
url
|
|
27
|
-
|
|
28
|
-
};
|
|
22
|
+
let url = request.url;
|
|
23
|
+
if (!url.includes("/v1/")) {
|
|
24
|
+
const apiVersion = (provider.headers?.["api-version"]) ?? "2025-04-01-preview";
|
|
25
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
26
|
+
url = `${url}${separator}api-version=${apiVersion}`;
|
|
27
|
+
}
|
|
28
|
+
return { ...request, url, headers };
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
}
|
package/src/adapters/google.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
OcxToolCall,
|
|
11
11
|
OcxUsage,
|
|
12
12
|
} from "../types";
|
|
13
|
+
import { namespacedToolName } from "../types";
|
|
13
14
|
import { contentPartsToText, parseDataUrl } from "./image";
|
|
14
15
|
|
|
15
16
|
function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?: unknown; contents: unknown[] } {
|
|
@@ -46,7 +47,7 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
46
47
|
if (p.type === "text") parts.push({ text: (p as OcxTextContent).text });
|
|
47
48
|
else if (p.type === "toolCall") {
|
|
48
49
|
const tc = p as OcxToolCall;
|
|
49
|
-
parts.push({ functionCall: { name: tc.name, args: tc.arguments } });
|
|
50
|
+
parts.push({ functionCall: { name: namespacedToolName(tc.namespace, tc.name), args: tc.arguments } });
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
contents.push({ role: "model", parts });
|
|
@@ -55,7 +56,7 @@ function messagesToGeminiFormat(parsed: OcxParsedRequest): { systemInstruction?:
|
|
|
55
56
|
case "toolResult": {
|
|
56
57
|
contents.push({
|
|
57
58
|
role: "user",
|
|
58
|
-
parts: [{ functionResponse: { name: msg.toolName, response: { result: contentPartsToText(msg.content) } } }],
|
|
59
|
+
parts: [{ functionResponse: { name: namespacedToolName(msg.toolNamespace, msg.toolName), response: { result: contentPartsToText(msg.content) } } }],
|
|
59
60
|
});
|
|
60
61
|
break;
|
|
61
62
|
}
|
|
@@ -69,7 +70,7 @@ function toolsToGeminiFormat(parsed: OcxParsedRequest): unknown[] | undefined {
|
|
|
69
70
|
if (!parsed.context.tools?.length) return undefined;
|
|
70
71
|
return [{
|
|
71
72
|
functionDeclarations: parsed.context.tools.map(t => ({
|
|
72
|
-
name: t.name,
|
|
73
|
+
name: namespacedToolName(t.namespace, t.name),
|
|
73
74
|
description: t.description,
|
|
74
75
|
parameters: t.parameters,
|
|
75
76
|
})),
|
|
@@ -160,7 +160,7 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
|
|
|
160
160
|
stream: parsed.stream,
|
|
161
161
|
};
|
|
162
162
|
if (tools) body.tools = tools;
|
|
163
|
-
if (toolChoice !== undefined) {
|
|
163
|
+
if (tools && toolChoice !== undefined) {
|
|
164
164
|
body.tool_choice = modelInList(provider.autoToolChoiceOnlyModels, parsed.modelId)
|
|
165
165
|
? (toolChoice === "none" ? "none" : "auto")
|
|
166
166
|
: toolChoice;
|
|
@@ -182,6 +182,7 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
|
|
|
182
182
|
body.frequency_penalty = parsed.options.frequencyPenalty;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
if (tools) body.parallel_tool_calls = false;
|
|
185
186
|
if (parsed.stream) {
|
|
186
187
|
body.stream_options = { include_usage: true };
|
|
187
188
|
}
|
|
@@ -60,7 +60,8 @@ export function createResponsesPassthroughAdapter(provider: OcxProviderConfig):
|
|
|
60
60
|
if (v) headers[h] = v; // …so forwarded auth always wins.
|
|
61
61
|
}
|
|
62
62
|
} else {
|
|
63
|
-
|
|
63
|
+
const base = provider.baseUrl.replace(/\/v1\/?$/, "");
|
|
64
|
+
url = `${base}/v1/responses`;
|
|
64
65
|
if (provider.apiKey) headers["Authorization"] = `Bearer ${provider.apiKey}`;
|
|
65
66
|
if (provider.headers) Object.assign(headers, provider.headers);
|
|
66
67
|
}
|
package/src/bridge.ts
CHANGED
|
@@ -43,7 +43,7 @@ export function bridgeToResponsesSSE(
|
|
|
43
43
|
toolSearchToolNames?: Set<string>,
|
|
44
44
|
onCancel?: () => void,
|
|
45
45
|
heartbeatMs = 2_000,
|
|
46
|
-
options?: { responseId?: string },
|
|
46
|
+
options?: { responseId?: string; stallTimeoutSec?: number; hideThinkingSummary?: boolean },
|
|
47
47
|
): ReadableStream<Uint8Array> {
|
|
48
48
|
// Freeform/custom tools (apply_patch) carry their body in `input`; the model is given a
|
|
49
49
|
// function with `{input:string}`, so unwrap it here when relaying back as a custom_tool_call.
|
|
@@ -104,11 +104,23 @@ export function bridgeToResponsesSSE(
|
|
|
104
104
|
// whenever a real event was emitted since the last tick, so it only fires on a genuine stall.
|
|
105
105
|
const heartbeatFrame = encoder.encode('event: response.heartbeat\ndata: {"type":"response.heartbeat"}\n\n');
|
|
106
106
|
let stallTicks = 0;
|
|
107
|
-
const
|
|
107
|
+
const stallSec = Math.max(1, options?.stallTimeoutSec ?? 90);
|
|
108
|
+
const maxStallTicks = Math.ceil((stallSec * 1000) / heartbeatMs);
|
|
108
109
|
beat = setInterval(() => {
|
|
109
110
|
if (closed) return;
|
|
110
111
|
if (activity) { activity = false; stallTicks = 0; return; }
|
|
111
112
|
if (++stallTicks >= maxStallTicks) {
|
|
113
|
+
if (currentMsg) closeCurrentMessage();
|
|
114
|
+
if (currentReasoning) closeCurrentReasoning();
|
|
115
|
+
if (currentRawReasoning) closeCurrentRawReasoning();
|
|
116
|
+
if (currentToolCall) closeCurrentToolCall();
|
|
117
|
+
emit("response.incomplete", {
|
|
118
|
+
response: {
|
|
119
|
+
...responseSnapshot("incomplete", finishedItems),
|
|
120
|
+
incomplete_details: { reason: "upstream_stall_timeout" },
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
terminated = true;
|
|
112
124
|
closed = true;
|
|
113
125
|
clearInterval(beat!);
|
|
114
126
|
beat = undefined;
|
|
@@ -219,6 +231,8 @@ export function bridgeToResponsesSSE(
|
|
|
219
231
|
|
|
220
232
|
try {
|
|
221
233
|
for await (const event of events) {
|
|
234
|
+
activity = true;
|
|
235
|
+
stallTicks = 0;
|
|
222
236
|
switch (event.type) {
|
|
223
237
|
case "text_delta": {
|
|
224
238
|
if (currentReasoning) closeCurrentReasoning();
|
|
@@ -245,6 +259,7 @@ export function bridgeToResponsesSSE(
|
|
|
245
259
|
break;
|
|
246
260
|
}
|
|
247
261
|
case "thinking_delta": {
|
|
262
|
+
if (options?.hideThinkingSummary) break;
|
|
248
263
|
if (currentMsg) closeCurrentMessage();
|
|
249
264
|
if (currentRawReasoning) closeCurrentRawReasoning();
|
|
250
265
|
if (currentToolCall) closeCurrentToolCall();
|
|
@@ -366,8 +381,12 @@ export function bridgeToResponsesSSE(
|
|
|
366
381
|
if (currentReasoning) closeCurrentReasoning();
|
|
367
382
|
if (currentRawReasoning) closeCurrentRawReasoning();
|
|
368
383
|
if (currentToolCall) closeCurrentToolCall();
|
|
369
|
-
emit("response.
|
|
370
|
-
response: {
|
|
384
|
+
emit("response.incomplete", {
|
|
385
|
+
response: {
|
|
386
|
+
...responseSnapshot("incomplete", finishedItems),
|
|
387
|
+
usage: responsesUsage(undefined),
|
|
388
|
+
incomplete_details: { reason: "adapter_eof" },
|
|
389
|
+
},
|
|
371
390
|
});
|
|
372
391
|
}
|
|
373
392
|
|
|
@@ -391,46 +410,143 @@ export function bridgeToResponsesSSE(
|
|
|
391
410
|
export function buildResponseJSON(
|
|
392
411
|
events: AdapterEvent[],
|
|
393
412
|
modelId: string,
|
|
413
|
+
options?: {
|
|
414
|
+
hideThinkingSummary?: boolean;
|
|
415
|
+
toolNsMap?: Map<string, { namespace: string; name: string }>;
|
|
416
|
+
freeformToolNames?: Set<string>;
|
|
417
|
+
toolSearchToolNames?: Set<string>;
|
|
418
|
+
},
|
|
394
419
|
): Record<string, unknown> {
|
|
395
420
|
const responseId = `resp_${uuid()}`;
|
|
396
421
|
const output: OutputItem[] = [];
|
|
397
|
-
let text = "";
|
|
398
|
-
let summaryReasoning = "";
|
|
399
|
-
let rawReasoning = "";
|
|
400
422
|
let usage: OcxUsage | undefined;
|
|
423
|
+
let errorMessage: string | undefined;
|
|
401
424
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
425
|
+
let currentText = "";
|
|
426
|
+
let currentSummaryReasoning = "";
|
|
427
|
+
let currentRawReasoning = "";
|
|
428
|
+
let currentToolCallId = "";
|
|
429
|
+
let currentToolCallName = "";
|
|
430
|
+
let currentToolCallArgs = "";
|
|
408
431
|
|
|
409
|
-
|
|
432
|
+
const freeformInput = (args: string): string => {
|
|
433
|
+
try { const o = JSON.parse(args); if (o && typeof o.input === "string") return o.input; } catch { /* raw */ }
|
|
434
|
+
return args;
|
|
435
|
+
};
|
|
436
|
+
const parseArgsObj = (args: string): Record<string, unknown> => {
|
|
437
|
+
try { const o = JSON.parse(args); return o && typeof o === "object" ? o : {}; } catch { return {}; }
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const flushText = () => {
|
|
441
|
+
if (!currentText) return;
|
|
410
442
|
output.push({
|
|
411
|
-
type: "
|
|
412
|
-
content: [{ type: "
|
|
443
|
+
type: "message", id: `msg_${uuid()}`, role: "assistant", status: "completed",
|
|
444
|
+
content: [{ type: "output_text", text: currentText, annotations: [] }],
|
|
413
445
|
});
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
446
|
+
currentText = "";
|
|
447
|
+
};
|
|
448
|
+
const flushSummaryReasoning = () => {
|
|
449
|
+
if (!currentSummaryReasoning || options?.hideThinkingSummary) { currentSummaryReasoning = ""; return; }
|
|
417
450
|
output.push({
|
|
418
451
|
type: "reasoning", id: `rs_${uuid()}`,
|
|
419
|
-
summary: [{ type: "summary_text", text:
|
|
452
|
+
summary: [{ type: "summary_text", text: currentSummaryReasoning }],
|
|
420
453
|
});
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
454
|
+
currentSummaryReasoning = "";
|
|
455
|
+
};
|
|
456
|
+
const flushRawReasoning = () => {
|
|
457
|
+
if (!currentRawReasoning) return;
|
|
424
458
|
output.push({
|
|
425
|
-
type: "
|
|
426
|
-
content: [{ type: "
|
|
459
|
+
type: "reasoning", id: `rs_${uuid()}`, summary: [],
|
|
460
|
+
content: [{ type: "reasoning_text", text: currentRawReasoning }],
|
|
427
461
|
});
|
|
462
|
+
currentRawReasoning = "";
|
|
463
|
+
};
|
|
464
|
+
const flushToolCall = () => {
|
|
465
|
+
if (!currentToolCallId) return;
|
|
466
|
+
const mapped = options?.toolNsMap?.get(currentToolCallName);
|
|
467
|
+
const realName = mapped?.name ?? currentToolCallName;
|
|
468
|
+
const ns = mapped?.namespace;
|
|
469
|
+
const toolSearch = options?.toolSearchToolNames?.has(realName) ?? false;
|
|
470
|
+
const freeform = !toolSearch && (options?.freeformToolNames?.has(realName) ?? false);
|
|
471
|
+
if (toolSearch) {
|
|
472
|
+
output.push({
|
|
473
|
+
type: "tool_search_call", id: `fc_${uuid()}`,
|
|
474
|
+
call_id: currentToolCallId, execution: "client",
|
|
475
|
+
arguments: parseArgsObj(currentToolCallArgs), status: "completed",
|
|
476
|
+
});
|
|
477
|
+
} else if (freeform) {
|
|
478
|
+
output.push({
|
|
479
|
+
type: "custom_tool_call", id: `fc_${uuid()}`,
|
|
480
|
+
call_id: currentToolCallId, name: realName,
|
|
481
|
+
input: freeformInput(currentToolCallArgs), status: "completed",
|
|
482
|
+
});
|
|
483
|
+
} else {
|
|
484
|
+
output.push({
|
|
485
|
+
type: "function_call", id: `fc_${uuid()}`,
|
|
486
|
+
call_id: currentToolCallId, name: realName,
|
|
487
|
+
arguments: currentToolCallArgs || "{}", status: "completed",
|
|
488
|
+
...(ns ? { namespace: ns } : {}),
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
currentToolCallId = "";
|
|
492
|
+
currentToolCallName = "";
|
|
493
|
+
currentToolCallArgs = "";
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
for (const e of events) {
|
|
497
|
+
switch (e.type) {
|
|
498
|
+
case "text_delta":
|
|
499
|
+
if (currentSummaryReasoning) flushSummaryReasoning();
|
|
500
|
+
if (currentRawReasoning) flushRawReasoning();
|
|
501
|
+
if (currentToolCallId) flushToolCall();
|
|
502
|
+
currentText += e.text;
|
|
503
|
+
break;
|
|
504
|
+
case "thinking_delta":
|
|
505
|
+
if (currentText) flushText();
|
|
506
|
+
if (currentRawReasoning) flushRawReasoning();
|
|
507
|
+
if (currentToolCallId) flushToolCall();
|
|
508
|
+
currentSummaryReasoning += e.thinking;
|
|
509
|
+
break;
|
|
510
|
+
case "reasoning_raw_delta":
|
|
511
|
+
if (currentText) flushText();
|
|
512
|
+
if (currentSummaryReasoning) flushSummaryReasoning();
|
|
513
|
+
if (currentToolCallId) flushToolCall();
|
|
514
|
+
currentRawReasoning += e.text;
|
|
515
|
+
break;
|
|
516
|
+
case "tool_call_start":
|
|
517
|
+
if (currentText) flushText();
|
|
518
|
+
if (currentSummaryReasoning) flushSummaryReasoning();
|
|
519
|
+
if (currentRawReasoning) flushRawReasoning();
|
|
520
|
+
flushToolCall();
|
|
521
|
+
currentToolCallId = e.id;
|
|
522
|
+
currentToolCallName = e.name;
|
|
523
|
+
currentToolCallArgs = "";
|
|
524
|
+
break;
|
|
525
|
+
case "tool_call_delta":
|
|
526
|
+
currentToolCallArgs += e.arguments;
|
|
527
|
+
break;
|
|
528
|
+
case "tool_call_end":
|
|
529
|
+
flushToolCall();
|
|
530
|
+
break;
|
|
531
|
+
case "error":
|
|
532
|
+
errorMessage = e.message;
|
|
533
|
+
break;
|
|
534
|
+
case "done":
|
|
535
|
+
usage = e.usage;
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
428
538
|
}
|
|
539
|
+
flushText();
|
|
540
|
+
flushSummaryReasoning();
|
|
541
|
+
flushRawReasoning();
|
|
542
|
+
flushToolCall();
|
|
429
543
|
|
|
430
544
|
return {
|
|
431
545
|
id: responseId, object: "response",
|
|
432
546
|
created_at: Math.floor(Date.now() / 1000),
|
|
433
|
-
status: "
|
|
547
|
+
status: errorMessage ? "failed" : "completed",
|
|
548
|
+
model: modelId, output,
|
|
549
|
+
...(errorMessage ? { error: { message: errorMessage } } : {}),
|
|
434
550
|
usage: responsesUsage(usage),
|
|
435
551
|
};
|
|
436
552
|
}
|