dsh-cline-pass 0.2.11 → 0.2.13
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/lib/adapter.js +1 -11
- package/lib/catalog.js +21 -2
- package/lib/client.js +85 -3
- package/lib/index.js +12 -1
- package/lib/panel.js +37 -0
- package/lib/protocol.js +9 -1
- package/package.json +1 -1
package/lib/adapter.js
CHANGED
|
@@ -54,17 +54,7 @@ export const DEFAULT_MAX_CONCURRENT_REQUESTS = 16
|
|
|
54
54
|
* unknown ones; raise it per model in configuration when a new model ships.
|
|
55
55
|
*/
|
|
56
56
|
export const DEFAULT_CONTEXT_WINDOW = 128000
|
|
57
|
-
|
|
58
|
-
* Per-request output budget for a model whose caller names no `maxTokens`.
|
|
59
|
-
*
|
|
60
|
-
* A budget, not a ceiling: the harness materializes it into requests that omit
|
|
61
|
-
* `maxTokens` and reserves the same number as completion room before it compacts,
|
|
62
|
-
* so this is the number that decides how much of the window stays available to the
|
|
63
|
-
* conversation. 64k is far past any single response a tool-calling agent emits
|
|
64
|
-
* while keeping the reserve well under the point where it would start displacing
|
|
65
|
-
* the compaction ratio. The published ceiling clamps it per model.
|
|
66
|
-
*/
|
|
67
|
-
export const DEFAULT_MAX_TOKENS = 64000
|
|
57
|
+
export { DEFAULT_MAX_TOKENS } from './catalog.js'
|
|
68
58
|
/**
|
|
69
59
|
* Request-image budget applied when the caller names none.
|
|
70
60
|
*
|
package/lib/catalog.js
CHANGED
|
@@ -167,6 +167,22 @@ function pick(configured, published, fallback) {
|
|
|
167
167
|
return fallback
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Per-request output budget used when nothing else names one.
|
|
172
|
+
*
|
|
173
|
+
* A budget, not a ceiling: the harness materializes it into requests that omit
|
|
174
|
+
* `maxTokens`, and reserves the same number as completion room before it compacts, so
|
|
175
|
+
* this is the number that decides how much of the window stays available to the
|
|
176
|
+
* conversation.
|
|
177
|
+
*
|
|
178
|
+
* 128k doubles the room a long reasoning pass gets without moving that point on a 1M
|
|
179
|
+
* window: the 80% rule stays the binding one until the reserve passes ~144k. It is
|
|
180
|
+
* not applied flat, though — a 128k reserve on a 256k window would leave almost
|
|
181
|
+
* nothing to compact into — so the shipped default scales to the window while a
|
|
182
|
+
* configured value does not, because that one is a choice rather than a default.
|
|
183
|
+
*/
|
|
184
|
+
export const DEFAULT_MAX_TOKENS = 131072
|
|
185
|
+
|
|
170
186
|
/**
|
|
171
187
|
* The seam's whole `ModelModality` vocabulary. A catalog entry may list more
|
|
172
188
|
* than this (models.dev reports `audio` for mimo-v2.5); the seam would reject
|
|
@@ -219,8 +235,11 @@ function resolveOutputBudget(budget, ceiling, contextWindow) {
|
|
|
219
235
|
const most = Number.isFinite(ceiling) && ceiling > 0 ? ceiling : undefined
|
|
220
236
|
const chosen = wanted === undefined ? most : most === undefined ? wanted : Math.min(wanted, most)
|
|
221
237
|
if (chosen === undefined) return undefined
|
|
222
|
-
|
|
223
|
-
|
|
238
|
+
if (!Number.isFinite(contextWindow) || contextWindow <= 0) return chosen
|
|
239
|
+
// The shipped default follows the window; a configured value is the user's choice
|
|
240
|
+
// and is only held back from reserving the window outright.
|
|
241
|
+
const share = wanted === DEFAULT_MAX_TOKENS ? 8 : 2
|
|
242
|
+
return Math.min(chosen, Math.floor(contextWindow / share))
|
|
224
243
|
}
|
|
225
244
|
|
|
226
245
|
/**
|
package/lib/client.js
CHANGED
|
@@ -77,6 +77,7 @@ window.__ModuleLoader__.load({
|
|
|
77
77
|
'.cp-input,.cp-select{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;padding:6px 8px;font-size:13px;min-width:0}',
|
|
78
78
|
'.cp-input:focus-visible,.cp-select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}',
|
|
79
79
|
'.cp-btn{border:0.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border-radius:6px;padding:5px 10px;font-size:12px;cursor:pointer}',
|
|
80
|
+
'.cp-btn-on{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-brand-primary)}',
|
|
80
81
|
'.cp-btn:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary)}',
|
|
81
82
|
'.cp-btn:disabled{opacity:.5;cursor:default}',
|
|
82
83
|
'.cp-btn-primary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-base);font-weight:600}',
|
|
@@ -199,6 +200,7 @@ window.__ModuleLoader__.load({
|
|
|
199
200
|
'.cp-history-load-row>span{white-space:nowrap}',
|
|
200
201
|
'.cp-history-load-row>span:first-child{flex:none}',
|
|
201
202
|
'.cp-history-load-row>span:last-child{min-width:0;overflow:hidden;text-overflow:ellipsis;text-align:right}',
|
|
203
|
+
'.cp-history-token-stack{display:flex;flex-direction:column;gap:1px;align-items:center}',
|
|
202
204
|
'.cp-history-meta{display:flex;align-items:center;justify-content:center;gap:6px;min-width:0;overflow:hidden}',
|
|
203
205
|
// A failure gets its own row under the entry rather than widening it: the
|
|
204
206
|
// gateway's messages are long enough to wreck a one-line layout.
|
|
@@ -360,6 +362,7 @@ window.__ModuleLoader__.load({
|
|
|
360
362
|
historyUpstream: '上游',
|
|
361
363
|
historyLoad: '延迟',
|
|
362
364
|
historyTokens: 'TOKEN',
|
|
365
|
+
historyCacheHit: '缓存',
|
|
363
366
|
historyFirstChunk: '首字',
|
|
364
367
|
historyTotal: '总耗时',
|
|
365
368
|
historyRate: '输出速率',
|
|
@@ -381,6 +384,11 @@ window.__ModuleLoader__.load({
|
|
|
381
384
|
refresh: '刷新',
|
|
382
385
|
channels: '渠道(点选=钉住顺序,⊘=排除)',
|
|
383
386
|
channelPlaceholder: '输入渠道名,回车添加',
|
|
387
|
+
budget: '输出预算',
|
|
388
|
+
budgetCurrent: '{n} tok',
|
|
389
|
+
budgetRecommended: '128K(推荐)',
|
|
390
|
+
budgetOfficial: '256K(对齐官方)',
|
|
391
|
+
budgetCustom: '自定义 token 数',
|
|
384
392
|
channelAdd: '添加',
|
|
385
393
|
channelUnverified: '未验证',
|
|
386
394
|
channelsKnown: '已探测:{list}',
|
|
@@ -466,6 +474,7 @@ window.__ModuleLoader__.load({
|
|
|
466
474
|
historyUpstream: 'Upstream',
|
|
467
475
|
historyLoad: 'Latency',
|
|
468
476
|
historyTokens: 'Tokens',
|
|
477
|
+
historyCacheHit: 'cache',
|
|
469
478
|
historyFirstChunk: 'first',
|
|
470
479
|
historyTotal: 'total',
|
|
471
480
|
historyRate: 'rate',
|
|
@@ -487,6 +496,11 @@ window.__ModuleLoader__.load({
|
|
|
487
496
|
refresh: 'Refresh',
|
|
488
497
|
channels: 'Channels (click = pin order, ⊘ = exclude)',
|
|
489
498
|
channelPlaceholder: 'Channel name, Enter to add',
|
|
499
|
+
budget: 'Output budget',
|
|
500
|
+
budgetCurrent: '{n} tok',
|
|
501
|
+
budgetRecommended: '128K (recommended)',
|
|
502
|
+
budgetOfficial: '256K (matches official)',
|
|
503
|
+
budgetCustom: 'Custom token count',
|
|
490
504
|
channelAdd: 'Add',
|
|
491
505
|
channelUnverified: 'unverified',
|
|
492
506
|
channelsKnown: 'Probed: {list}',
|
|
@@ -784,6 +798,7 @@ window.__ModuleLoader__.load({
|
|
|
784
798
|
pinModel: (payload) => controller.pinModel(payload),
|
|
785
799
|
setModelVisible: (model, visible) => controller.setModelVisible(model, visible),
|
|
786
800
|
setToolsExposed: (value) => controller.setToolsExposed(value),
|
|
801
|
+
setBudget: (value) => controller.setBudget(value),
|
|
787
802
|
setModelsVisibility: (mode) => controller.setModelsVisibility(mode),
|
|
788
803
|
probeModel: (model) => controller.probeModel(model),
|
|
789
804
|
validateModel: (model) => controller.validateModel(model),
|
|
@@ -974,6 +989,13 @@ window.__ModuleLoader__.load({
|
|
|
974
989
|
return result
|
|
975
990
|
}
|
|
976
991
|
|
|
992
|
+
/** Set the per-request output budget, in tokens. */
|
|
993
|
+
async setBudget(value) {
|
|
994
|
+
const result = await this.run('budget', async () => await this.call('budget.set', { value }))
|
|
995
|
+
if (result !== undefined) this.applyState(result)
|
|
996
|
+
return result
|
|
997
|
+
}
|
|
998
|
+
|
|
977
999
|
/**
|
|
978
1000
|
* Show, hide or swap every subscription model at once.
|
|
979
1001
|
*
|
|
@@ -1601,6 +1623,60 @@ window.__ModuleLoader__.load({
|
|
|
1601
1623
|
])
|
|
1602
1624
|
}
|
|
1603
1625
|
|
|
1626
|
+
/**
|
|
1627
|
+
* The per-request output budget.
|
|
1628
|
+
*
|
|
1629
|
+
* One number for the whole route: the harness reserves it as completion room on
|
|
1630
|
+
* every request, so it decides where compaction fires as much as how long one
|
|
1631
|
+
* response may be. The two presets are the shipped default and the figure
|
|
1632
|
+
* DeepSeek's own provider uses; anything else is typed.
|
|
1633
|
+
*/
|
|
1634
|
+
function BudgetCard(props) {
|
|
1635
|
+
const { t, data, disabled, actions } = props
|
|
1636
|
+
const current = Number(data.defaultMaxTokens ?? 0)
|
|
1637
|
+
const [draft, setDraft] = React.useState('')
|
|
1638
|
+
const write = (value) => {
|
|
1639
|
+
if (disabled) return
|
|
1640
|
+
actions.setBudget(value)
|
|
1641
|
+
}
|
|
1642
|
+
const custom = () => {
|
|
1643
|
+
const value = Number(draft.trim())
|
|
1644
|
+
if (!Number.isSafeInteger(value) || value < 1024) return
|
|
1645
|
+
setDraft('')
|
|
1646
|
+
write(value)
|
|
1647
|
+
}
|
|
1648
|
+
return h('div', { className: 'cp-card' }, [
|
|
1649
|
+
h('div', { key: 'title', className: 'cp-card-title' }, `${t('budget')} · ${fill(t('budgetCurrent'), { n: current.toLocaleString('en-US') })}`),
|
|
1650
|
+
h('div', { key: 'row', className: 'cp-row' }, [
|
|
1651
|
+
h('button', {
|
|
1652
|
+
key: 'recommended', type: 'button',
|
|
1653
|
+
className: `cp-btn${current === 131072 ? ' cp-btn-on' : ''}`,
|
|
1654
|
+
disabled, onClick: () => write(131072),
|
|
1655
|
+
}, t('budgetRecommended')),
|
|
1656
|
+
h('button', {
|
|
1657
|
+
key: 'official', type: 'button',
|
|
1658
|
+
className: `cp-btn${current === 256000 ? ' cp-btn-on' : ''}`,
|
|
1659
|
+
disabled, onClick: () => write(256000),
|
|
1660
|
+
}, t('budgetOfficial')),
|
|
1661
|
+
]),
|
|
1662
|
+
h('div', { key: 'custom', className: 'cp-row' }, [
|
|
1663
|
+
h('input', {
|
|
1664
|
+
key: 'in', type: 'text', className: 'cp-input cp-grow',
|
|
1665
|
+
value: draft, disabled,
|
|
1666
|
+
placeholder: t('budgetCustom'),
|
|
1667
|
+
'aria-label': t('budget'),
|
|
1668
|
+
onChange: (event) => setDraft(event.target.value),
|
|
1669
|
+
onKeyDown: (event) => {
|
|
1670
|
+
if (event.key !== 'Enter') return
|
|
1671
|
+
event.preventDefault()
|
|
1672
|
+
custom()
|
|
1673
|
+
},
|
|
1674
|
+
}),
|
|
1675
|
+
h('button', { key: 'b', type: 'button', className: 'cp-btn', disabled, onClick: custom }, t('channelAdd')),
|
|
1676
|
+
]),
|
|
1677
|
+
])
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1604
1680
|
/**
|
|
1605
1681
|
* The models card: a fold-away section, like the request history.
|
|
1606
1682
|
*
|
|
@@ -1666,6 +1742,7 @@ window.__ModuleLoader__.load({
|
|
|
1666
1742
|
// — centred text that overflows loses BOTH ends, not just the tail.
|
|
1667
1743
|
const label = String(entry.model).replace(/^cline-pass\//, '')
|
|
1668
1744
|
const figures = latency(entry)
|
|
1745
|
+
const cacheHit = entry.cacheHit === undefined ? null : entry.cacheHit
|
|
1669
1746
|
const row = h('tr', {
|
|
1670
1747
|
key: 'row',
|
|
1671
1748
|
// The whole row restates itself on hover, including the figures the three
|
|
@@ -1699,8 +1776,11 @@ window.__ModuleLoader__.load({
|
|
|
1699
1776
|
h('td', {
|
|
1700
1777
|
key: 'tokens',
|
|
1701
1778
|
className: 'cp-history-tokens',
|
|
1702
|
-
title: `${tokenSummaryExact(entry)}\n${t('historyTokensHint')}`,
|
|
1703
|
-
},
|
|
1779
|
+
title: `${tokenSummaryExact(entry)}\n${cacheHit === null ? '' : `${t('historyCacheHit')} ${cacheHit.toFixed(2)}%\n`}${t('historyTokensHint')}`,
|
|
1780
|
+
}, h('div', { className: 'cp-history-token-stack' }, [
|
|
1781
|
+
h('span', { key: 'sum' }, tokenSummary(entry)),
|
|
1782
|
+
cacheHit === null ? null : h('span', { key: 'cache', className: 'cp-muted cp-small' }, `${t('historyCacheHit')} ${cacheHit.toFixed(2)}%`),
|
|
1783
|
+
])),
|
|
1704
1784
|
h('td', { key: 'load', className: 'cp-history-load' }, [
|
|
1705
1785
|
h('span', { key: 'first', className: 'cp-history-load-row' }, [
|
|
1706
1786
|
h('span', { key: 'k', className: 'cp-muted' }, t('historyFirstChunk')),
|
|
@@ -1953,6 +2033,7 @@ window.__ModuleLoader__.load({
|
|
|
1953
2033
|
pinModel: props.pinModel,
|
|
1954
2034
|
setModelVisible: props.setModelVisible,
|
|
1955
2035
|
setToolsExposed: props.setToolsExposed,
|
|
2036
|
+
setBudget: props.setBudget,
|
|
1956
2037
|
setModelsVisibility: props.setModelsVisibility,
|
|
1957
2038
|
probeModel: props.probeModel,
|
|
1958
2039
|
validateModel: props.validateModel,
|
|
@@ -2010,8 +2091,9 @@ window.__ModuleLoader__.load({
|
|
|
2010
2091
|
// Everything below the accounts card reads through the key that card
|
|
2011
2092
|
// stores, so none of it exists until there is one.
|
|
2012
2093
|
data === null || !ready ? null : h(ModelsCard, { key: 'models', t, data, disabled, busy: state.busy, actions }),
|
|
2013
|
-
// Route-wide
|
|
2094
|
+
// Route-wide settings last: they are not about one model or account, and
|
|
2014
2095
|
// nothing below them depends on their value.
|
|
2096
|
+
data === null ? null : h(BudgetCard, { key: 'budget', t, data, disabled: state.busy !== null || data.settingsAvailable === false, actions }),
|
|
2015
2097
|
data === null ? null : h('div', { key: 'tools', className: 'cp-card' }, [
|
|
2016
2098
|
h('label', { key: 'head', className: 'cp-row cp-tools-label' }, [
|
|
2017
2099
|
h('input', {
|
package/lib/index.js
CHANGED
|
@@ -160,8 +160,19 @@ export const Config = z.object({
|
|
|
160
160
|
* larger, and reporting that here reserves it on every request — at the shipped
|
|
161
161
|
* 384k figure a 1M window compacts at 55% instead of the 80% the threshold ratio
|
|
162
162
|
* asks for. Each model's published ceiling clamps whatever is set here.
|
|
163
|
+
*
|
|
164
|
+
* Nothing here may reserve more than half the window. The shipped default goes
|
|
165
|
+
* further and scales to an eighth on a small window, because a flat 128k reserve
|
|
166
|
+
* leaves a 256k model almost nothing to compact into; an explicit value counts as a
|
|
167
|
+
* choice and only gets the half-window limit.
|
|
168
|
+
*/
|
|
169
|
+
/*
|
|
170
|
+
* Volatile because the panel writes it: the settings service refuses a write to any
|
|
171
|
+
* field the schema does not mark live, which is the same refusal that made the tools
|
|
172
|
+
* switch unclickable before it was marked. Everything downstream reads it through
|
|
173
|
+
* the unwrapped snapshot, so the reference form never escapes this schema.
|
|
163
174
|
*/
|
|
164
|
-
defaultMaxTokens: z.number().default(DEFAULT_MAX_TOKENS),
|
|
175
|
+
defaultMaxTokens: markVolatile(z.number().default(DEFAULT_MAX_TOKENS)),
|
|
165
176
|
streamIdleTimeoutMs: z.number().default(DEFAULT_STREAM_IDLE_TIMEOUT_MS),
|
|
166
177
|
/**
|
|
167
178
|
* Streams one account may keep open to the gateway at once.
|
package/lib/panel.js
CHANGED
|
@@ -130,6 +130,9 @@ export function createPanel({ control, engine, store }) {
|
|
|
130
130
|
provider: control.providerName,
|
|
131
131
|
displayName: control.displayName,
|
|
132
132
|
baseURL: String(config.baseURL ?? ''),
|
|
133
|
+
// The per-request output budget: one number for the whole route, because it
|
|
134
|
+
// decides how much of every window the harness holds back as completion room.
|
|
135
|
+
defaultMaxTokens: Number(config.defaultMaxTokens ?? 0),
|
|
133
136
|
settingsAvailable: control.settingsAvailable(),
|
|
134
137
|
accountMode: config.accountMode === 'roundrobin' ? 'roundrobin' : 'single',
|
|
135
138
|
activeAccount: String(config.activeAccount ?? ''),
|
|
@@ -449,6 +452,21 @@ export function createPanel({ control, engine, store }) {
|
|
|
449
452
|
return await modelPin({ model: modelOf(payload), upstreams: [], exclude: [], sort: 'none', pinMode: 'preferred' })
|
|
450
453
|
}
|
|
451
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Cache reads as a share of billed prompt tokens, or null when nothing was measured.
|
|
457
|
+
*
|
|
458
|
+
* A ratio over zero is not a reading, and 0% would claim "nothing cached" for a
|
|
459
|
+
* request the gateway never reported usage for.
|
|
460
|
+
*/
|
|
461
|
+
function cacheHitOf(usage) {
|
|
462
|
+
if (usage === null || usage === undefined) return null
|
|
463
|
+
const cached = Number(usage.cacheReadTokens ?? 0)
|
|
464
|
+
const billed = cached + Number(usage.inputTokens ?? 0)
|
|
465
|
+
// Two decimals: an integer round turns 99.6% into a flat 100%, which reads as a
|
|
466
|
+
// claim the numbers do not support.
|
|
467
|
+
return billed <= 0 ? null : Math.round((cached / billed) * 10000) / 100
|
|
468
|
+
}
|
|
469
|
+
|
|
452
470
|
/** The live request history, newest first. */
|
|
453
471
|
async function history(payload) {
|
|
454
472
|
const limit = Number.isSafeInteger(payload?.limit) && payload.limit > 0 ? Math.min(payload.limit, 100) : 25
|
|
@@ -473,6 +491,7 @@ export function createPanel({ control, engine, store }) {
|
|
|
473
491
|
cacheReadTokens: Number(entry.usage?.cacheReadTokens ?? 0),
|
|
474
492
|
reasoningTokens: Number(entry.usage?.reasoningTokens ?? 0),
|
|
475
493
|
},
|
|
494
|
+
cacheHit: cacheHitOf(entry.usage),
|
|
476
495
|
effort: String(entry.effort ?? ''),
|
|
477
496
|
stream: entry.stream === true,
|
|
478
497
|
error: firstLine(entry.error, 200),
|
|
@@ -490,6 +509,23 @@ export function createPanel({ control, engine, store }) {
|
|
|
490
509
|
* The response carries `restartRequired` so the panel can say so instead of
|
|
491
510
|
* implying the switch already took effect.
|
|
492
511
|
*/
|
|
512
|
+
/**
|
|
513
|
+
* Set the per-request output budget.
|
|
514
|
+
*
|
|
515
|
+
* The panel offers the two numbers that matter — the shipped default, and the one
|
|
516
|
+
* DeepSeek's own provider uses — plus whatever a user types. It is a route-wide
|
|
517
|
+
* setting rather than a per-model one because it is the same policy for every
|
|
518
|
+
* model: how much of a window to hold back for one response.
|
|
519
|
+
*/
|
|
520
|
+
async function budgetSet(payload) {
|
|
521
|
+
const value = Number(payload?.value)
|
|
522
|
+
if (!Number.isSafeInteger(value) || value < 1024 || value > 2000000) {
|
|
523
|
+
throw new Error(`the output budget must be a whole number of tokens between 1024 and 2000000 (got ${JSON.stringify(payload?.value)})`)
|
|
524
|
+
}
|
|
525
|
+
await control.updateConfig({ defaultMaxTokens: value })
|
|
526
|
+
return await state()
|
|
527
|
+
}
|
|
528
|
+
|
|
493
529
|
async function toolsExpose(payload) {
|
|
494
530
|
if (typeof payload?.value !== 'boolean') throw new Error('this action needs a boolean `value`')
|
|
495
531
|
await control.updateConfig({ exposeTools: payload.value })
|
|
@@ -514,6 +550,7 @@ export function createPanel({ control, engine, store }) {
|
|
|
514
550
|
'model.reset': modelReset,
|
|
515
551
|
'models.refresh': modelsRefresh,
|
|
516
552
|
'tools.expose': toolsExpose,
|
|
553
|
+
'budget.set': budgetSet,
|
|
517
554
|
history,
|
|
518
555
|
}
|
|
519
556
|
}
|
package/lib/protocol.js
CHANGED
|
@@ -59,7 +59,15 @@ export function isAuthenticationError(message, status) {
|
|
|
59
59
|
export function parseRouting(json) {
|
|
60
60
|
const payload = unwrapEnvelope(json)
|
|
61
61
|
const message = payload?.choices?.[0]?.message
|
|
62
|
-
|
|
62
|
+
// A non-streaming answer carries routing on the message; a stream carries the same
|
|
63
|
+
// object on the delta instead. Reading only the message left every streamed request
|
|
64
|
+
// with no upstream at all, which the history then filled in with the pinned name —
|
|
65
|
+
// reporting a pin the gateway may never have adopted.
|
|
66
|
+
const delta = payload?.choices?.[0]?.delta
|
|
67
|
+
const routing = message?.provider_metadata?.gateway?.routing
|
|
68
|
+
?? delta?.provider_metadata?.gateway?.routing
|
|
69
|
+
?? payload?.provider_metadata?.gateway?.routing
|
|
70
|
+
?? {}
|
|
63
71
|
const direct = typeof payload?.provider === 'string' ? payload.provider : null
|
|
64
72
|
return {
|
|
65
73
|
content: typeof message?.content === 'string' ? message.content : null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-cline-pass",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "Self-contained Cline Pass provider for dsh: register Cline Pass subscription models on the harness LLM seam, enumerate and validate the upstream channels behind each model, pin or exclude them with failover, and drive an account pool. No proxy process and no external cline-pass-switcher install required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|