@dotobokuri/fleet-console 1.45.0 → 1.47.0
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/dist/cli.d.ts +4 -0
- package/dist/cli.mjs +416 -899
- package/dist/client/assets/{_baseUniq-DtJH2bh8.js → _baseUniq-kGlxZURL.js} +1 -1
- package/dist/client/assets/{arc-DHCKMqqF.js → arc-0MFZHiK0.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-BOuyINL8.js → architectureDiagram-Q4EWVU46--RIddBvw.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-cIre3_5n.js → blockDiagram-DXYQGD6D-BeAbiibf.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-DTX-qjSW.js → c4Diagram-AHTNJAMY-DRkTrRQf.js} +1 -1
- package/dist/client/assets/channel-Ba1lW0bI.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-DiBwpozK.js → chunk-4BX2VUAB-BpSILXNJ.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-uCZ-B3-y.js → chunk-4TB4RGXK-ghYBwdri.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-CmBu2sf0.js → chunk-55IACEB6-D-DtPH2C.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-BXpw2VyB.js → chunk-EDXVE4YY-59RlsQG_.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-Cn9sKTn5.js → chunk-FMBD7UC4-Hi26IR8N.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-BDgH1zlW.js → chunk-OYMX7WX6-BRgJcTlv.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-BOdvRibu.js → chunk-QZHKN3VN-BRc2Mimo.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-BDIEapcU.js → chunk-YZCP3GAM-CpPUsJ-2.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-CrjH2VLS.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-CrjH2VLS.js +1 -0
- package/dist/client/assets/clone-CSapyzZ9.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-BVlc3Dad.js → cose-bilkent-S5V4N54A-CU7M4-h6.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-raV4BK6w.js → dagre-KV5264BT-DsP2pvSV.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-BMAh1LJt.js → diagram-5BDNPKRD-BIsHIEFX.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-AM5t2f3j.js → diagram-G4DWMVQ6-kszOBtB4.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-DMw_UwWR.js → diagram-MMDJMWI5-Cn5sUEtw.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-CiDAD3e9.js → diagram-TYMM5635-CDdfKXq-.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-D1IXSwFZ.js → erDiagram-SMLLAGMA-CI6i4IOF.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-pEq1L6HP.js → flowDiagram-DWJPFMVM-7foBBYZ0.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-BAXTU16v.js → ganttDiagram-T4ZO3ILL-BtCT8Kyl.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-PkEvpSio.js → gitGraphDiagram-UUTBAWPF-BnG43YXm.js} +1 -1
- package/dist/client/assets/{graph-OOLam9NE.js → graph-BJfoQM9L.js} +1 -1
- package/dist/client/assets/index-BQvUTYMt.js +482 -0
- package/dist/client/assets/index-DpllFOQw.css +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-CcLveXnw.js → infoDiagram-42DDH7IO-fSjQnpO3.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-D-p_eX0W.js → ishikawaDiagram-UXIWVN3A-CikjAzZU.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-D81ht6ZY.js → journeyDiagram-VCZTEJTY-CXlhn41B.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-D8SIIBWy.js → kanban-definition-6JOO6SKY-ZSgxxWjz.js} +1 -1
- package/dist/client/assets/{layout-CeMy87tl.js → layout-Cn9VNxzb.js} +1 -1
- package/dist/client/assets/{linear-C0Txkuhf.js → linear-D-4NsXnb.js} +1 -1
- package/dist/client/assets/{mermaid.core-zdTcCzmD.js → mermaid.core-DIF6Bqhc.js} +4 -4
- package/dist/client/assets/{min-BPp_9Vnv.js → min-BO2TWSJi.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-DRJbMf8W.js → mindmap-definition-QFDTVHPH-Bmigbv3o.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-CqPISwE-.js → pieDiagram-DEJITSTG-56EjQ8_u.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-BGLaujDD.js → quadrantDiagram-34T5L4WZ-B-mdpysI.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-DWF6sFQ_.js → requirementDiagram-MS252O5E-C-16L-rK.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-Dv2O23aj.js → sankeyDiagram-XADWPNL6-Dpi8Xvd6.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-BXgYtweg.js → sequenceDiagram-FGHM5R23-Bb2L9XDw.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-COtDK2gC.js → stateDiagram-FHFEXIEX-z1AMjFur.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CKmEKJLy.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-B_-QYLHK.js → timeline-definition-GMOUNBTQ-DHXjAJin.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-BNVDRgAa.js → vennDiagram-DHZGUBPP-Cw9QDGZk.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-B3XwoW1A.js → wardley-RL74JXVD-CDHq7H5N.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-B6-OKLa-.js → wardleyDiagram-NUSXRM2D-B0P1pItE.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-DepfDqrZ.js → xychartDiagram-5P7HB3ND-B5jXRxLe.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/fleet-plugins/ledger/routes.mjs +45 -105
- package/dist/fleet-plugins/quota/routes.mjs +455 -64
- package/dist/fleet-plugins/repository/routes.mjs +26 -9
- package/dist/fleet-plugins/scuttlebutt/routes.mjs +150 -703
- package/dist/fleet-plugins/skills/routes.mjs +45 -105
- package/dist/fleet-plugins/terminal/routes.mjs +1436 -1076
- package/package.json +1 -1
- package/dist/client/assets/channel-BhciS8jR.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-BjRUnHce.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-BjRUnHce.js +0 -1
- package/dist/client/assets/clone-DygBt67n.js +0 -1
- package/dist/client/assets/index-BgHFwZy9.css +0 -1
- package/dist/client/assets/index-CvXOp1di.js +0 -452
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BzCFtEfV.js +0 -1
|
@@ -20150,225 +20150,6 @@ function inferBinName(packageName) {
|
|
|
20150
20150
|
return lastSegment.replace(/@[^@/]+$/, "");
|
|
20151
20151
|
}
|
|
20152
20152
|
|
|
20153
|
-
// ../../packages/core-unified-agent/models.json
|
|
20154
|
-
var models_default = {
|
|
20155
|
-
version: 1,
|
|
20156
|
-
updatedAt: "2026-07-25T00:00:00Z",
|
|
20157
|
-
providers: {
|
|
20158
|
-
claude: {
|
|
20159
|
-
name: "Claude Code",
|
|
20160
|
-
defaultModel: "opus[1m]",
|
|
20161
|
-
models: [
|
|
20162
|
-
{ modelId: "haiku", name: "Claude Haiku", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "low" } },
|
|
20163
|
-
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20164
|
-
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20165
|
-
{ modelId: "opus[1m]", name: "Claude Opus [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20166
|
-
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20167
|
-
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20168
|
-
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
20169
|
-
]
|
|
20170
|
-
},
|
|
20171
|
-
codex: {
|
|
20172
|
-
name: "Codex",
|
|
20173
|
-
defaultModel: "gpt-5.6-sol",
|
|
20174
|
-
models: [
|
|
20175
|
-
{ modelId: "gpt-5.6-sol", name: "GPT-5.6-Sol", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "low" } },
|
|
20176
|
-
{ modelId: "gpt-5.6-sol-fast", name: "GPT-5.6-Sol Fast", providerModelId: "gpt-5.6-sol", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "low" } },
|
|
20177
|
-
{ modelId: "gpt-5.6-terra", name: "GPT-5.6-Terra", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "medium" } },
|
|
20178
|
-
{ modelId: "gpt-5.6-terra-fast", name: "GPT-5.6-Terra Fast", providerModelId: "gpt-5.6-terra", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "medium" } },
|
|
20179
|
-
{ modelId: "gpt-5.6-luna", name: "GPT-5.6-Luna", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20180
|
-
{ modelId: "gpt-5.6-luna-fast", name: "GPT-5.6-Luna Fast", providerModelId: "gpt-5.6-luna", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20181
|
-
{ modelId: "gpt-5.5", name: "GPT-5.5", effort: { supported: true, levels: ["low", "medium", "high", "xhigh"], default: "high" } },
|
|
20182
|
-
{ modelId: "gpt-5.5-fast", name: "GPT-5.5 Fast", providerModelId: "gpt-5.5", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh"], default: "high" } }
|
|
20183
|
-
]
|
|
20184
|
-
},
|
|
20185
|
-
cursor: {
|
|
20186
|
-
name: "Cursor Agent",
|
|
20187
|
-
defaultModel: "auto",
|
|
20188
|
-
models: [
|
|
20189
|
-
{ modelId: "auto", name: "Auto", effort: { supported: false } },
|
|
20190
|
-
{ modelId: "composer-2.5", name: "Composer 2.5", effort: { supported: false } },
|
|
20191
|
-
{ modelId: "composer-2.5-fast", name: "Composer 2.5 Fast", effort: { supported: false } },
|
|
20192
|
-
{ modelId: "gpt-5.6-sol", name: "GPT-5.6 Sol", spawnModelTemplate: "gpt-5.6-sol-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20193
|
-
{ modelId: "gpt-5.6-sol-fast", name: "GPT-5.6 Sol Fast", spawnModelTemplate: "gpt-5.6-sol-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20194
|
-
{ modelId: "gpt-5.6-sol-none", name: "GPT-5.6 Sol None", effort: { supported: false } },
|
|
20195
|
-
{ modelId: "gpt-5.6-sol-none-fast", name: "GPT-5.6 Sol None Fast", effort: { supported: false } },
|
|
20196
|
-
{ modelId: "gpt-5.6-luna", name: "GPT-5.6 Luna", spawnModelTemplate: "gpt-5.6-luna-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20197
|
-
{ modelId: "gpt-5.6-luna-fast", name: "GPT-5.6 Luna Fast", spawnModelTemplate: "gpt-5.6-luna-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20198
|
-
{ modelId: "gpt-5.6-luna-none", name: "GPT-5.6 Luna None", effort: { supported: false } },
|
|
20199
|
-
{ modelId: "gpt-5.6-luna-none-fast", name: "GPT-5.6 Luna None Fast", effort: { supported: false } },
|
|
20200
|
-
{ modelId: "gpt-5.6-terra", name: "GPT-5.6 Terra", spawnModelTemplate: "gpt-5.6-terra-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20201
|
-
{ modelId: "gpt-5.6-terra-fast", name: "GPT-5.6 Terra Fast", spawnModelTemplate: "gpt-5.6-terra-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20202
|
-
{ modelId: "gpt-5.6-terra-none", name: "GPT-5.6 Terra None", effort: { supported: false } },
|
|
20203
|
-
{ modelId: "gpt-5.6-terra-none-fast", name: "GPT-5.6 Terra None Fast", effort: { supported: false } },
|
|
20204
|
-
{ modelId: "cursor-grok-4.5", name: "Cursor Grok 4.5", spawnModelTemplate: "cursor-grok-4.5-{effort}", effort: { supported: true, levels: ["low", "medium", "high"], default: "high" } },
|
|
20205
|
-
{ modelId: "cursor-grok-4.5-fast", name: "Cursor Grok 4.5 Fast", spawnModelTemplate: "cursor-grok-4.5-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high"], default: "high" } },
|
|
20206
|
-
{ modelId: "claude-opus-4-8", name: "Claude Opus 4.8", spawnModelTemplate: "claude-opus-4-8-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20207
|
-
{ modelId: "claude-opus-4-8-fast", name: "Claude Opus 4.8 Fast", spawnModelTemplate: "claude-opus-4-8-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20208
|
-
{ modelId: "claude-opus-4-8-thinking", name: "Claude Opus 4.8 Thinking", spawnModelTemplate: "claude-opus-4-8-thinking-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20209
|
-
{ modelId: "claude-opus-4-8-thinking-fast", name: "Claude Opus 4.8 Thinking Fast", spawnModelTemplate: "claude-opus-4-8-thinking-{effort}-fast", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20210
|
-
{ modelId: "claude-sonnet-5", name: "Claude Sonnet 5", spawnModelTemplate: "claude-sonnet-5-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20211
|
-
{ modelId: "claude-sonnet-5-thinking", name: "Claude Sonnet 5 Thinking", spawnModelTemplate: "claude-sonnet-5-thinking-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20212
|
-
{ modelId: "claude-fable-5", name: "Claude Fable 5", description: "NO ZDR per cursor-agent model list", spawnModelTemplate: "claude-fable-5-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20213
|
-
{ modelId: "claude-fable-5-thinking", name: "Claude Fable 5 Thinking", description: "NO ZDR per cursor-agent model list", spawnModelTemplate: "claude-fable-5-thinking-{effort}", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20214
|
-
{ modelId: "gemini-3.1-pro", name: "Gemini 3.1 Pro", effort: { supported: false } },
|
|
20215
|
-
{ modelId: "gemini-3.5-flash", name: "Gemini 3.5 Flash", effort: { supported: false } },
|
|
20216
|
-
{ modelId: "kimi-k2.7-code", name: "Kimi K2.7 Code", effort: { supported: false } },
|
|
20217
|
-
{ modelId: "glm-5.2", name: "GLM 5.2", spawnModelTemplate: "glm-5.2-{effort}", effort: { supported: true, levels: ["high", "max"], default: "max" } }
|
|
20218
|
-
]
|
|
20219
|
-
}
|
|
20220
|
-
}
|
|
20221
|
-
};
|
|
20222
|
-
|
|
20223
|
-
// ../../packages/core-unified-agent/src/models/registry.ts
|
|
20224
|
-
var EffortLevelSchema = external_exports.enum([
|
|
20225
|
-
"low",
|
|
20226
|
-
"medium",
|
|
20227
|
-
"high",
|
|
20228
|
-
"xhigh",
|
|
20229
|
-
"max",
|
|
20230
|
-
"ultra"
|
|
20231
|
-
]);
|
|
20232
|
-
var EffortSchema = external_exports.union([
|
|
20233
|
-
external_exports.object({
|
|
20234
|
-
supported: external_exports.literal(true),
|
|
20235
|
-
levels: external_exports.array(EffortLevelSchema).min(1),
|
|
20236
|
-
default: EffortLevelSchema
|
|
20237
|
-
}).strict(),
|
|
20238
|
-
external_exports.object({
|
|
20239
|
-
supported: external_exports.literal(false)
|
|
20240
|
-
}).strict()
|
|
20241
|
-
]);
|
|
20242
|
-
var ModelEntrySchema = external_exports.object({
|
|
20243
|
-
/** 모델 고유 식별자 (session/set_model에 전달되는 값) */
|
|
20244
|
-
modelId: external_exports.string(),
|
|
20245
|
-
/** 사람이 읽을 수 있는 모델 이름 */
|
|
20246
|
-
name: external_exports.string(),
|
|
20247
|
-
/** 모델 설명 (선택) */
|
|
20248
|
-
description: external_exports.string().optional(),
|
|
20249
|
-
/** spawn 시 실제 CLI 모델 ID를 조립해야 하는 경우의 템플릿 */
|
|
20250
|
-
spawnModelTemplate: external_exports.string().optional(),
|
|
20251
|
-
/** 카탈로그 ID와 실제 provider 모델 ID가 다른 경우의 원본 모델 ID */
|
|
20252
|
-
providerModelId: external_exports.string().optional(),
|
|
20253
|
-
/** provider가 모델과 별도로 받는 서비스 티어 */
|
|
20254
|
-
serviceTier: external_exports.string().optional(),
|
|
20255
|
-
/** 모델의 컨텍스트 윈도우 크기 (토큰) */
|
|
20256
|
-
contextWindow: external_exports.number().int().positive().optional(),
|
|
20257
|
-
/** 모델별 effort 설정 */
|
|
20258
|
-
effort: EffortSchema
|
|
20259
|
-
}).check((ctx) => {
|
|
20260
|
-
const effort = ctx.value.effort;
|
|
20261
|
-
if (effort.supported && !effort.levels.includes(effort.default)) {
|
|
20262
|
-
ctx.issues.push({
|
|
20263
|
-
code: "custom",
|
|
20264
|
-
input: effort.default,
|
|
20265
|
-
message: `effort.default "${effort.default}"\uC740(\uB294) levels \uBAA9\uB85D\uC5D0 \uC874\uC7AC\uD574\uC57C \uD569\uB2C8\uB2E4`,
|
|
20266
|
-
path: ["effort", "default"]
|
|
20267
|
-
});
|
|
20268
|
-
}
|
|
20269
|
-
if (effort.supported && ctx.value.spawnModelTemplate && !ctx.value.spawnModelTemplate.includes("{effort}")) {
|
|
20270
|
-
ctx.issues.push({
|
|
20271
|
-
code: "custom",
|
|
20272
|
-
input: ctx.value.spawnModelTemplate,
|
|
20273
|
-
message: 'effort \uC9C0\uC6D0 \uBAA8\uB378\uC758 spawnModelTemplate\uC740 "{effort}" \uD50C\uB808\uC774\uC2A4\uD640\uB354\uB97C \uD3EC\uD568\uD574\uC57C \uD569\uB2C8\uB2E4',
|
|
20274
|
-
path: ["spawnModelTemplate"]
|
|
20275
|
-
});
|
|
20276
|
-
}
|
|
20277
|
-
if (ctx.value.serviceTier && !ctx.value.providerModelId) {
|
|
20278
|
-
ctx.issues.push({
|
|
20279
|
-
code: "custom",
|
|
20280
|
-
input: ctx.value.serviceTier,
|
|
20281
|
-
message: "serviceTier\uB97C \uC9C0\uC815\uD55C \uBAA8\uB378\uC740 providerModelId\uB3C4 \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4",
|
|
20282
|
-
path: ["serviceTier"]
|
|
20283
|
-
});
|
|
20284
|
-
}
|
|
20285
|
-
});
|
|
20286
|
-
var ProviderSchema = external_exports.object({
|
|
20287
|
-
/** 프로바이더 표시 이름 */
|
|
20288
|
-
name: external_exports.string(),
|
|
20289
|
-
/** 기본 모델 ID */
|
|
20290
|
-
defaultModel: external_exports.string(),
|
|
20291
|
-
/** 사용 가능한 모델 목록 */
|
|
20292
|
-
models: external_exports.array(ModelEntrySchema).min(1)
|
|
20293
|
-
}).check((ctx) => {
|
|
20294
|
-
const ids = new Set(ctx.value.models.map((m) => m.modelId));
|
|
20295
|
-
if (!ids.has(ctx.value.defaultModel)) {
|
|
20296
|
-
ctx.issues.push({
|
|
20297
|
-
code: "custom",
|
|
20298
|
-
input: ctx.value.defaultModel,
|
|
20299
|
-
message: `defaultModel "${ctx.value.defaultModel}"\uC740(\uB294) models \uBAA9\uB85D\uC5D0 \uC874\uC7AC\uD574\uC57C \uD569\uB2C8\uB2E4`,
|
|
20300
|
-
path: ["defaultModel"]
|
|
20301
|
-
});
|
|
20302
|
-
}
|
|
20303
|
-
});
|
|
20304
|
-
var ModelMappingSchema = external_exports.record(external_exports.string(), external_exports.string());
|
|
20305
|
-
var ModelsMapperEntrySchema = external_exports.object({
|
|
20306
|
-
/** modelId와 연관된 매핑 모델 */
|
|
20307
|
-
modelMapping: ModelMappingSchema,
|
|
20308
|
-
/** 추가 환경변수 (선택) */
|
|
20309
|
-
env: external_exports.record(external_exports.string(), external_exports.string()).optional()
|
|
20310
|
-
});
|
|
20311
|
-
external_exports.record(external_exports.string(), ModelsMapperEntrySchema);
|
|
20312
|
-
var ModelsRegistrySchema = external_exports.object({
|
|
20313
|
-
/** 스키마 버전 */
|
|
20314
|
-
version: external_exports.number().int().positive(),
|
|
20315
|
-
/** 최종 업데이트 시각 */
|
|
20316
|
-
updatedAt: external_exports.string(),
|
|
20317
|
-
/** 프로바이더별 모델 정보 */
|
|
20318
|
-
providers: external_exports.record(external_exports.string(), ProviderSchema)
|
|
20319
|
-
});
|
|
20320
|
-
var registry2 = Object.freeze(ModelsRegistrySchema.parse(models_default));
|
|
20321
|
-
function getProviderModels(cli) {
|
|
20322
|
-
const provider = registry2.providers[cli];
|
|
20323
|
-
if (!provider) {
|
|
20324
|
-
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uD504\uB85C\uBC14\uC774\uB354: "${cli}"`);
|
|
20325
|
-
}
|
|
20326
|
-
return structuredClone(provider);
|
|
20327
|
-
}
|
|
20328
|
-
function getEffort(cli, modelId) {
|
|
20329
|
-
const model = findProviderModel(cli, modelId);
|
|
20330
|
-
return structuredClone(model.effort);
|
|
20331
|
-
}
|
|
20332
|
-
function getCursorSpawnEffortInfo(modelId) {
|
|
20333
|
-
const model = findProviderModel("cursor", modelId);
|
|
20334
|
-
if (!model.spawnModelTemplate || !model.effort.supported) {
|
|
20335
|
-
return { supported: false, levels: [], default: null };
|
|
20336
|
-
}
|
|
20337
|
-
return {
|
|
20338
|
-
supported: true,
|
|
20339
|
-
levels: [...model.effort.levels],
|
|
20340
|
-
default: model.effort.default
|
|
20341
|
-
};
|
|
20342
|
-
}
|
|
20343
|
-
function resolveCursorSpawnModel(modelId, effort) {
|
|
20344
|
-
const model = findProviderModel("cursor", modelId);
|
|
20345
|
-
if (!model.spawnModelTemplate) {
|
|
20346
|
-
return model.modelId;
|
|
20347
|
-
}
|
|
20348
|
-
if (!model.effort.supported) {
|
|
20349
|
-
return model.spawnModelTemplate;
|
|
20350
|
-
}
|
|
20351
|
-
const level = effort ?? model.effort.default;
|
|
20352
|
-
const resolvedLevel = model.effort.levels.includes(level) ? level : model.effort.default;
|
|
20353
|
-
if (!model.effort.levels.includes(resolvedLevel)) {
|
|
20354
|
-
throw new Error(
|
|
20355
|
-
`cursor/${modelId} \uBAA8\uB378\uC740 effort "${level}"\uC744(\uB97C) \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC0AC\uC6A9 \uAC00\uB2A5: ${model.effort.levels.join(", ")}`
|
|
20356
|
-
);
|
|
20357
|
-
}
|
|
20358
|
-
return model.spawnModelTemplate.replace("{effort}", resolvedLevel);
|
|
20359
|
-
}
|
|
20360
|
-
function findProviderModel(cli, modelId) {
|
|
20361
|
-
const provider = registry2.providers[cli];
|
|
20362
|
-
if (!provider) {
|
|
20363
|
-
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uD504\uB85C\uBC14\uC774\uB354: "${cli}"`);
|
|
20364
|
-
}
|
|
20365
|
-
const model = provider.models.find((m) => m.modelId === modelId);
|
|
20366
|
-
if (!model) {
|
|
20367
|
-
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uBAA8\uB378: "${cli}/${modelId}"`);
|
|
20368
|
-
}
|
|
20369
|
-
return model;
|
|
20370
|
-
}
|
|
20371
|
-
|
|
20372
20153
|
// ../../packages/core-unified-agent/src/config/CliConfigs.ts
|
|
20373
20154
|
var CLI_BACKENDS = {
|
|
20374
20155
|
claude: {
|
|
@@ -20404,21 +20185,6 @@ var CLI_BACKENDS = {
|
|
|
20404
20185
|
requiresModelAtSpawn: false,
|
|
20405
20186
|
usesNpxBridge: false,
|
|
20406
20187
|
defaultMaxTokens: 1e5
|
|
20407
|
-
},
|
|
20408
|
-
cursor: {
|
|
20409
|
-
id: "cursor",
|
|
20410
|
-
cliCommand: "cursor-agent",
|
|
20411
|
-
protocol: "acp",
|
|
20412
|
-
authRequired: true,
|
|
20413
|
-
acpArgs: ["acp"],
|
|
20414
|
-
modes: [
|
|
20415
|
-
{ id: "agent", label: "Agent" }
|
|
20416
|
-
],
|
|
20417
|
-
supportsSessionClose: false,
|
|
20418
|
-
supportsSessionLoad: true,
|
|
20419
|
-
requiresModelAtSpawn: true,
|
|
20420
|
-
usesNpxBridge: false,
|
|
20421
|
-
defaultMaxTokens: 2e5
|
|
20422
20188
|
}
|
|
20423
20189
|
};
|
|
20424
20190
|
function createSpawnConfig(cli, options) {
|
|
@@ -20449,9 +20215,6 @@ function createSpawnConfig(cli, options) {
|
|
|
20449
20215
|
}
|
|
20450
20216
|
const command = options.cliPath ?? backend.cliCommand;
|
|
20451
20217
|
const args = backend.acpArgs ? [...backend.acpArgs] : [];
|
|
20452
|
-
if (cli === "cursor" && options.model) {
|
|
20453
|
-
args.unshift("--model", resolveCursorSpawnModel(options.model, options.effort));
|
|
20454
|
-
}
|
|
20455
20218
|
return {
|
|
20456
20219
|
command,
|
|
20457
20220
|
args,
|
|
@@ -20465,8 +20228,6 @@ function getYoloModeId(cli) {
|
|
|
20465
20228
|
switch (cli) {
|
|
20466
20229
|
case "claude":
|
|
20467
20230
|
return "bypassPermissions";
|
|
20468
|
-
case "cursor":
|
|
20469
|
-
return "agent";
|
|
20470
20231
|
case "codex":
|
|
20471
20232
|
return "yolo";
|
|
20472
20233
|
}
|
|
@@ -20665,6 +20426,152 @@ var CliDetector = class {
|
|
|
20665
20426
|
}
|
|
20666
20427
|
};
|
|
20667
20428
|
|
|
20429
|
+
// ../../packages/core-unified-agent/models.json
|
|
20430
|
+
var models_default = {
|
|
20431
|
+
version: 1,
|
|
20432
|
+
updatedAt: "2026-07-25T00:00:00Z",
|
|
20433
|
+
providers: {
|
|
20434
|
+
claude: {
|
|
20435
|
+
name: "Claude Code",
|
|
20436
|
+
defaultModel: "opus[1m]",
|
|
20437
|
+
models: [
|
|
20438
|
+
{ modelId: "haiku", name: "Claude Haiku", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "low" } },
|
|
20439
|
+
{ modelId: "sonnet", name: "Claude Sonnet", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20440
|
+
{ modelId: "opus", name: "Claude Opus", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20441
|
+
{ modelId: "opus[1m]", name: "Claude Opus [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "xhigh" } },
|
|
20442
|
+
{ modelId: "claude-opus-4-6[1m]", name: "Claude Opus 4.6 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20443
|
+
{ modelId: "claude-opus-4-7[1m]", name: "Claude Opus 4.7 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } },
|
|
20444
|
+
{ modelId: "claude-opus-4-8[1m]", name: "Claude Opus 4.8 [1M]", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "high" } }
|
|
20445
|
+
]
|
|
20446
|
+
},
|
|
20447
|
+
codex: {
|
|
20448
|
+
name: "Codex",
|
|
20449
|
+
defaultModel: "gpt-5.6-sol",
|
|
20450
|
+
models: [
|
|
20451
|
+
{ modelId: "gpt-5.6-sol", name: "GPT-5.6-Sol", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "low" } },
|
|
20452
|
+
{ modelId: "gpt-5.6-sol-fast", name: "GPT-5.6-Sol Fast", providerModelId: "gpt-5.6-sol", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "low" } },
|
|
20453
|
+
{ modelId: "gpt-5.6-terra", name: "GPT-5.6-Terra", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "medium" } },
|
|
20454
|
+
{ modelId: "gpt-5.6-terra-fast", name: "GPT-5.6-Terra Fast", providerModelId: "gpt-5.6-terra", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max", "ultra"], default: "medium" } },
|
|
20455
|
+
{ modelId: "gpt-5.6-luna", name: "GPT-5.6-Luna", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20456
|
+
{ modelId: "gpt-5.6-luna-fast", name: "GPT-5.6-Luna Fast", providerModelId: "gpt-5.6-luna", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh", "max"], default: "medium" } },
|
|
20457
|
+
{ modelId: "gpt-5.5", name: "GPT-5.5", effort: { supported: true, levels: ["low", "medium", "high", "xhigh"], default: "high" } },
|
|
20458
|
+
{ modelId: "gpt-5.5-fast", name: "GPT-5.5 Fast", providerModelId: "gpt-5.5", serviceTier: "priority", effort: { supported: true, levels: ["low", "medium", "high", "xhigh"], default: "high" } }
|
|
20459
|
+
]
|
|
20460
|
+
}
|
|
20461
|
+
}
|
|
20462
|
+
};
|
|
20463
|
+
|
|
20464
|
+
// ../../packages/core-unified-agent/src/models/registry.ts
|
|
20465
|
+
var EffortLevelSchema = external_exports.enum([
|
|
20466
|
+
"low",
|
|
20467
|
+
"medium",
|
|
20468
|
+
"high",
|
|
20469
|
+
"xhigh",
|
|
20470
|
+
"max",
|
|
20471
|
+
"ultra"
|
|
20472
|
+
]);
|
|
20473
|
+
var EffortSchema = external_exports.union([
|
|
20474
|
+
external_exports.object({
|
|
20475
|
+
supported: external_exports.literal(true),
|
|
20476
|
+
levels: external_exports.array(EffortLevelSchema).min(1),
|
|
20477
|
+
default: EffortLevelSchema
|
|
20478
|
+
}).strict(),
|
|
20479
|
+
external_exports.object({
|
|
20480
|
+
supported: external_exports.literal(false)
|
|
20481
|
+
}).strict()
|
|
20482
|
+
]);
|
|
20483
|
+
var ModelEntrySchema = external_exports.object({
|
|
20484
|
+
/** 모델 고유 식별자 (session/set_model에 전달되는 값) */
|
|
20485
|
+
modelId: external_exports.string(),
|
|
20486
|
+
/** 사람이 읽을 수 있는 모델 이름 */
|
|
20487
|
+
name: external_exports.string(),
|
|
20488
|
+
/** 모델 설명 (선택) */
|
|
20489
|
+
description: external_exports.string().optional(),
|
|
20490
|
+
/** 카탈로그 ID와 실제 provider 모델 ID가 다른 경우의 원본 모델 ID */
|
|
20491
|
+
providerModelId: external_exports.string().optional(),
|
|
20492
|
+
/** provider가 모델과 별도로 받는 서비스 티어 */
|
|
20493
|
+
serviceTier: external_exports.string().optional(),
|
|
20494
|
+
/** 모델의 컨텍스트 윈도우 크기 (토큰) */
|
|
20495
|
+
contextWindow: external_exports.number().int().positive().optional(),
|
|
20496
|
+
/** 모델별 effort 설정 */
|
|
20497
|
+
effort: EffortSchema
|
|
20498
|
+
}).check((ctx) => {
|
|
20499
|
+
const effort = ctx.value.effort;
|
|
20500
|
+
if (effort.supported && !effort.levels.includes(effort.default)) {
|
|
20501
|
+
ctx.issues.push({
|
|
20502
|
+
code: "custom",
|
|
20503
|
+
input: effort.default,
|
|
20504
|
+
message: `effort.default "${effort.default}"\uC740(\uB294) levels \uBAA9\uB85D\uC5D0 \uC874\uC7AC\uD574\uC57C \uD569\uB2C8\uB2E4`,
|
|
20505
|
+
path: ["effort", "default"]
|
|
20506
|
+
});
|
|
20507
|
+
}
|
|
20508
|
+
if (ctx.value.serviceTier && !ctx.value.providerModelId) {
|
|
20509
|
+
ctx.issues.push({
|
|
20510
|
+
code: "custom",
|
|
20511
|
+
input: ctx.value.serviceTier,
|
|
20512
|
+
message: "serviceTier\uB97C \uC9C0\uC815\uD55C \uBAA8\uB378\uC740 providerModelId\uB3C4 \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4",
|
|
20513
|
+
path: ["serviceTier"]
|
|
20514
|
+
});
|
|
20515
|
+
}
|
|
20516
|
+
});
|
|
20517
|
+
var ProviderSchema = external_exports.object({
|
|
20518
|
+
/** 프로바이더 표시 이름 */
|
|
20519
|
+
name: external_exports.string(),
|
|
20520
|
+
/** 기본 모델 ID */
|
|
20521
|
+
defaultModel: external_exports.string(),
|
|
20522
|
+
/** 사용 가능한 모델 목록 */
|
|
20523
|
+
models: external_exports.array(ModelEntrySchema).min(1)
|
|
20524
|
+
}).check((ctx) => {
|
|
20525
|
+
const ids = new Set(ctx.value.models.map((m) => m.modelId));
|
|
20526
|
+
if (!ids.has(ctx.value.defaultModel)) {
|
|
20527
|
+
ctx.issues.push({
|
|
20528
|
+
code: "custom",
|
|
20529
|
+
input: ctx.value.defaultModel,
|
|
20530
|
+
message: `defaultModel "${ctx.value.defaultModel}"\uC740(\uB294) models \uBAA9\uB85D\uC5D0 \uC874\uC7AC\uD574\uC57C \uD569\uB2C8\uB2E4`,
|
|
20531
|
+
path: ["defaultModel"]
|
|
20532
|
+
});
|
|
20533
|
+
}
|
|
20534
|
+
});
|
|
20535
|
+
var ModelMappingSchema = external_exports.record(external_exports.string(), external_exports.string());
|
|
20536
|
+
var ModelsMapperEntrySchema = external_exports.object({
|
|
20537
|
+
/** modelId와 연관된 매핑 모델 */
|
|
20538
|
+
modelMapping: ModelMappingSchema,
|
|
20539
|
+
/** 추가 환경변수 (선택) */
|
|
20540
|
+
env: external_exports.record(external_exports.string(), external_exports.string()).optional()
|
|
20541
|
+
});
|
|
20542
|
+
external_exports.record(external_exports.string(), ModelsMapperEntrySchema);
|
|
20543
|
+
var ModelsRegistrySchema = external_exports.object({
|
|
20544
|
+
/** 스키마 버전 */
|
|
20545
|
+
version: external_exports.number().int().positive(),
|
|
20546
|
+
/** 최종 업데이트 시각 */
|
|
20547
|
+
updatedAt: external_exports.string(),
|
|
20548
|
+
/** 프로바이더별 모델 정보 */
|
|
20549
|
+
providers: external_exports.record(external_exports.string(), ProviderSchema)
|
|
20550
|
+
});
|
|
20551
|
+
var registry2 = Object.freeze(ModelsRegistrySchema.parse(models_default));
|
|
20552
|
+
function getProviderModels(cli) {
|
|
20553
|
+
const provider = registry2.providers[cli];
|
|
20554
|
+
if (!provider) {
|
|
20555
|
+
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uD504\uB85C\uBC14\uC774\uB354: "${cli}"`);
|
|
20556
|
+
}
|
|
20557
|
+
return structuredClone(provider);
|
|
20558
|
+
}
|
|
20559
|
+
function getEffort(cli, modelId) {
|
|
20560
|
+
const model = findProviderModel(cli, modelId);
|
|
20561
|
+
return structuredClone(model.effort);
|
|
20562
|
+
}
|
|
20563
|
+
function findProviderModel(cli, modelId) {
|
|
20564
|
+
const provider = registry2.providers[cli];
|
|
20565
|
+
if (!provider) {
|
|
20566
|
+
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uD504\uB85C\uBC14\uC774\uB354: "${cli}"`);
|
|
20567
|
+
}
|
|
20568
|
+
const model = provider.models.find((m) => m.modelId === modelId);
|
|
20569
|
+
if (!model) {
|
|
20570
|
+
throw new Error(`\uC54C \uC218 \uC5C6\uB294 \uBAA8\uB378: "${cli}/${modelId}"`);
|
|
20571
|
+
}
|
|
20572
|
+
return model;
|
|
20573
|
+
}
|
|
20574
|
+
|
|
20668
20575
|
// ../../packages/core-unified-agent/src/client/UnifiedClaudeAgentClient.ts
|
|
20669
20576
|
var UnifiedClaudeAgentClient = class extends EventEmitter {
|
|
20670
20577
|
connection = null;
|
|
@@ -22396,453 +22303,6 @@ var UnifiedCodexAgentClient = class extends EventEmitter {
|
|
|
22396
22303
|
};
|
|
22397
22304
|
}
|
|
22398
22305
|
};
|
|
22399
|
-
var UnifiedCursorAgentClient = class extends EventEmitter {
|
|
22400
|
-
connection = null;
|
|
22401
|
-
sessionId = null;
|
|
22402
|
-
sessionCwd = null;
|
|
22403
|
-
currentSystemPrompt = null;
|
|
22404
|
-
firstPromptPending = null;
|
|
22405
|
-
currentConnectOptions = null;
|
|
22406
|
-
detector = new CliDetector();
|
|
22407
|
-
on(event, listener) {
|
|
22408
|
-
return super.on(event, listener);
|
|
22409
|
-
}
|
|
22410
|
-
once(event, listener) {
|
|
22411
|
-
return super.once(event, listener);
|
|
22412
|
-
}
|
|
22413
|
-
off(event, listener) {
|
|
22414
|
-
return super.off(event, listener);
|
|
22415
|
-
}
|
|
22416
|
-
emitTyped(event, ...args) {
|
|
22417
|
-
return super.emit(event, ...args);
|
|
22418
|
-
}
|
|
22419
|
-
async connect(options) {
|
|
22420
|
-
await this.disconnect();
|
|
22421
|
-
if (options.cli && options.cli !== "cursor") {
|
|
22422
|
-
throw new Error("UnifiedCursorAgentClient\uB294 cursor CLI\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4.");
|
|
22423
|
-
}
|
|
22424
|
-
const acpMcpServers = this.resolveMcpServers(options.mcpServers);
|
|
22425
|
-
const spawnConfig = createSpawnConfig("cursor", options);
|
|
22426
|
-
const cleanEnv = cleanEnvironment(process.env, options.env);
|
|
22427
|
-
const env = { ...cleanEnv };
|
|
22428
|
-
const connection = new AcpConnection({
|
|
22429
|
-
command: spawnConfig.command,
|
|
22430
|
-
args: spawnConfig.args,
|
|
22431
|
-
cliType: "cursor",
|
|
22432
|
-
cwd: options.cwd,
|
|
22433
|
-
env,
|
|
22434
|
-
requestTimeout: options.timeout,
|
|
22435
|
-
initTimeout: options.timeout,
|
|
22436
|
-
promptIdleTimeout: options.promptIdleTimeout,
|
|
22437
|
-
clientInfo: options.clientInfo,
|
|
22438
|
-
autoApprove: options.autoApprove,
|
|
22439
|
-
fsAccess: options.fsAccess
|
|
22440
|
-
});
|
|
22441
|
-
this.connection = connection;
|
|
22442
|
-
this.setupEventForwarding();
|
|
22443
|
-
const recentLogs = [];
|
|
22444
|
-
const collectLog = (message) => {
|
|
22445
|
-
recentLogs.push(message);
|
|
22446
|
-
if (recentLogs.length > 30) {
|
|
22447
|
-
recentLogs.shift();
|
|
22448
|
-
}
|
|
22449
|
-
};
|
|
22450
|
-
connection.on("log", collectLog);
|
|
22451
|
-
let session;
|
|
22452
|
-
try {
|
|
22453
|
-
session = await connection.connect(
|
|
22454
|
-
options.cwd,
|
|
22455
|
-
options.sessionId,
|
|
22456
|
-
acpMcpServers,
|
|
22457
|
-
options.systemPrompt
|
|
22458
|
-
);
|
|
22459
|
-
} catch (error51) {
|
|
22460
|
-
const connectionError = this.buildConnectionError(error51, recentLogs);
|
|
22461
|
-
await this.cleanupFailedConnection();
|
|
22462
|
-
throw connectionError;
|
|
22463
|
-
} finally {
|
|
22464
|
-
connection.off("log", collectLog);
|
|
22465
|
-
}
|
|
22466
|
-
return this.finalizeConnect(options, session);
|
|
22467
|
-
}
|
|
22468
|
-
async disconnect() {
|
|
22469
|
-
if (!this.connection) {
|
|
22470
|
-
this.clearSessionState();
|
|
22471
|
-
return;
|
|
22472
|
-
}
|
|
22473
|
-
const conn = this.connection;
|
|
22474
|
-
if (this.sessionId && conn.canResetSession) {
|
|
22475
|
-
try {
|
|
22476
|
-
await conn.endSession(this.sessionId);
|
|
22477
|
-
} catch {
|
|
22478
|
-
}
|
|
22479
|
-
}
|
|
22480
|
-
await conn.disconnect();
|
|
22481
|
-
conn.removeAllListeners();
|
|
22482
|
-
this.connection = null;
|
|
22483
|
-
this.clearSessionState();
|
|
22484
|
-
}
|
|
22485
|
-
async endSession() {
|
|
22486
|
-
if (!this.connection || !this.sessionId) {
|
|
22487
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22488
|
-
}
|
|
22489
|
-
await this.connection.endSession(this.sessionId);
|
|
22490
|
-
this.sessionId = null;
|
|
22491
|
-
}
|
|
22492
|
-
getConnectionInfo() {
|
|
22493
|
-
return {
|
|
22494
|
-
cli: this.connection ? "cursor" : null,
|
|
22495
|
-
protocol: this.connection ? "acp" : null,
|
|
22496
|
-
sessionId: this.sessionId,
|
|
22497
|
-
state: this.connection ? this.connection.connectionState : "disconnected"
|
|
22498
|
-
};
|
|
22499
|
-
}
|
|
22500
|
-
async detectClis() {
|
|
22501
|
-
return this.detector.detectAll(true);
|
|
22502
|
-
}
|
|
22503
|
-
async sendMessage(content) {
|
|
22504
|
-
if (!this.connection || !this.sessionId) {
|
|
22505
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22506
|
-
}
|
|
22507
|
-
const systemPrompt = this.firstPromptPending;
|
|
22508
|
-
if (!systemPrompt) {
|
|
22509
|
-
return this.connection.sendPrompt(this.sessionId, content);
|
|
22510
|
-
}
|
|
22511
|
-
const userBlocks = typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
22512
|
-
const response = await this.connection.sendPrompt(this.sessionId, [
|
|
22513
|
-
{ type: "text", text: systemPrompt },
|
|
22514
|
-
...userBlocks
|
|
22515
|
-
]);
|
|
22516
|
-
this.firstPromptPending = null;
|
|
22517
|
-
return response;
|
|
22518
|
-
}
|
|
22519
|
-
async cancelPrompt() {
|
|
22520
|
-
if (!this.connection || !this.sessionId) {
|
|
22521
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22522
|
-
}
|
|
22523
|
-
await this.connection.cancelSession(this.sessionId);
|
|
22524
|
-
}
|
|
22525
|
-
async setModel(model) {
|
|
22526
|
-
if (!this.connection || !this.sessionId) {
|
|
22527
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22528
|
-
}
|
|
22529
|
-
const reconnectOptions = this.buildReconnectOptions(model);
|
|
22530
|
-
await this.reconnectWithRestore(reconnectOptions, "\uBAA8\uB378 \uBCC0\uACBD");
|
|
22531
|
-
}
|
|
22532
|
-
async setConfigOption(configId, value) {
|
|
22533
|
-
if (!this.connection || !this.sessionId) {
|
|
22534
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22535
|
-
}
|
|
22536
|
-
if (configId === "effort" || configId === "reasoning_effort") {
|
|
22537
|
-
const reconnectOptions = this.buildEffortReconnectOptions(value);
|
|
22538
|
-
if (!reconnectOptions) {
|
|
22539
|
-
return;
|
|
22540
|
-
}
|
|
22541
|
-
await this.reconnectWithRestore(reconnectOptions, "effort \uBCC0\uACBD");
|
|
22542
|
-
return;
|
|
22543
|
-
}
|
|
22544
|
-
if (configId === "model") {
|
|
22545
|
-
return this.setModel(value);
|
|
22546
|
-
}
|
|
22547
|
-
await this.connection.setConfigOption(this.sessionId, configId, value);
|
|
22548
|
-
}
|
|
22549
|
-
async setMode(mode) {
|
|
22550
|
-
if (!this.connection || !this.sessionId) {
|
|
22551
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22552
|
-
}
|
|
22553
|
-
await this.connection.setMode(this.sessionId, mode);
|
|
22554
|
-
}
|
|
22555
|
-
async setYoloMode(enabled) {
|
|
22556
|
-
return this.setMode(enabled ? getYoloModeId("cursor") : "default");
|
|
22557
|
-
}
|
|
22558
|
-
getAvailableModes() {
|
|
22559
|
-
return getBackendConfig("cursor").modes ?? [];
|
|
22560
|
-
}
|
|
22561
|
-
getAvailableModels() {
|
|
22562
|
-
return getProviderModels("cursor");
|
|
22563
|
-
}
|
|
22564
|
-
getCurrentSystemPrompt() {
|
|
22565
|
-
return this.currentSystemPrompt;
|
|
22566
|
-
}
|
|
22567
|
-
async loadSession(sessionId, mcpServers) {
|
|
22568
|
-
if (!this.connection) {
|
|
22569
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22570
|
-
}
|
|
22571
|
-
await this.connection.loadSession({
|
|
22572
|
-
sessionId,
|
|
22573
|
-
cwd: this.sessionCwd ?? process.cwd(),
|
|
22574
|
-
mcpServers: this.resolveMcpServers(mcpServers)
|
|
22575
|
-
});
|
|
22576
|
-
this.sessionId = sessionId;
|
|
22577
|
-
this.currentSystemPrompt = null;
|
|
22578
|
-
this.firstPromptPending = null;
|
|
22579
|
-
}
|
|
22580
|
-
async resetSession(cwd) {
|
|
22581
|
-
if (!this.connection || !this.sessionId) {
|
|
22582
|
-
throw new Error("\uC5F0\uACB0\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
22583
|
-
}
|
|
22584
|
-
const targetCwd = cwd ?? this.sessionCwd ?? process.cwd();
|
|
22585
|
-
if (!this.connection.canResetSession) {
|
|
22586
|
-
throw new Error("[cursor] \uC138\uC158 \uB9AC\uC14B\uC744 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. disconnect() \uD6C4 \uC7AC\uC5F0\uACB0\uD558\uC138\uC694.");
|
|
22587
|
-
}
|
|
22588
|
-
await this.connection.endSession(this.sessionId);
|
|
22589
|
-
this.sessionId = null;
|
|
22590
|
-
const session = this.currentSystemPrompt ? await this.connection.reconnectSession(
|
|
22591
|
-
targetCwd,
|
|
22592
|
-
void 0,
|
|
22593
|
-
void 0,
|
|
22594
|
-
this.currentSystemPrompt
|
|
22595
|
-
) : await this.connection.reconnectSession(targetCwd);
|
|
22596
|
-
this.sessionId = session.sessionId;
|
|
22597
|
-
this.sessionCwd = targetCwd;
|
|
22598
|
-
this.firstPromptPending = this.currentSystemPrompt;
|
|
22599
|
-
return {
|
|
22600
|
-
cli: "cursor",
|
|
22601
|
-
protocol: "acp",
|
|
22602
|
-
session
|
|
22603
|
-
};
|
|
22604
|
-
}
|
|
22605
|
-
resolveMcpServers(servers) {
|
|
22606
|
-
return servers?.length ? mcpServerConfigsToAcp(servers) : [];
|
|
22607
|
-
}
|
|
22608
|
-
async finalizeConnect(options, session) {
|
|
22609
|
-
if (options.yoloMode && session.sessionId) {
|
|
22610
|
-
try {
|
|
22611
|
-
await this.connection.setMode(session.sessionId, getYoloModeId("cursor"));
|
|
22612
|
-
} catch {
|
|
22613
|
-
}
|
|
22614
|
-
}
|
|
22615
|
-
this.sessionId = session.sessionId;
|
|
22616
|
-
this.sessionCwd = options.cwd;
|
|
22617
|
-
this.currentSystemPrompt = options.systemPrompt ?? null;
|
|
22618
|
-
this.firstPromptPending = options.sessionId ? null : this.currentSystemPrompt;
|
|
22619
|
-
this.currentConnectOptions = this.cloneConnectOptions(options);
|
|
22620
|
-
return {
|
|
22621
|
-
cli: "cursor",
|
|
22622
|
-
protocol: "acp",
|
|
22623
|
-
session
|
|
22624
|
-
};
|
|
22625
|
-
}
|
|
22626
|
-
clearSessionState() {
|
|
22627
|
-
this.sessionId = null;
|
|
22628
|
-
this.sessionCwd = null;
|
|
22629
|
-
this.currentSystemPrompt = null;
|
|
22630
|
-
this.firstPromptPending = null;
|
|
22631
|
-
this.currentConnectOptions = null;
|
|
22632
|
-
}
|
|
22633
|
-
buildReconnectOptions(model) {
|
|
22634
|
-
if (!this.currentConnectOptions) {
|
|
22635
|
-
throw new Error("[cursor] \uBAA8\uB378 \uC804\uD658\uC744 \uC704\uD55C \uAE30\uC874 \uC5F0\uACB0 \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. connect()\uB85C \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.");
|
|
22636
|
-
}
|
|
22637
|
-
const options = this.cloneConnectOptions(this.currentConnectOptions);
|
|
22638
|
-
const effort = this.resolveEffortForModel(model, options.effort);
|
|
22639
|
-
delete options.sessionId;
|
|
22640
|
-
if (effort) {
|
|
22641
|
-
options.effort = effort;
|
|
22642
|
-
} else {
|
|
22643
|
-
delete options.effort;
|
|
22644
|
-
}
|
|
22645
|
-
return {
|
|
22646
|
-
...options,
|
|
22647
|
-
cli: "cursor",
|
|
22648
|
-
model
|
|
22649
|
-
};
|
|
22650
|
-
}
|
|
22651
|
-
buildEffortReconnectOptions(effort) {
|
|
22652
|
-
if (!this.currentConnectOptions) {
|
|
22653
|
-
throw new Error("[cursor] effort \uC804\uD658\uC744 \uC704\uD55C \uAE30\uC874 \uC5F0\uACB0 \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. connect()\uB85C \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.");
|
|
22654
|
-
}
|
|
22655
|
-
if (!this.currentConnectOptions.model) {
|
|
22656
|
-
throw new Error("[cursor] effort \uC804\uD658\uC744 \uC704\uD55C \uD604\uC7AC \uBAA8\uB378 \uC815\uBCF4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uBAA8\uB378\uC744 \uC9C0\uC815\uD574 \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.");
|
|
22657
|
-
}
|
|
22658
|
-
if (this.currentConnectOptions.effort === effort) {
|
|
22659
|
-
return null;
|
|
22660
|
-
}
|
|
22661
|
-
const effortInfo = getCursorSpawnEffortInfo(this.currentConnectOptions.model);
|
|
22662
|
-
if (!effortInfo.supported) {
|
|
22663
|
-
return null;
|
|
22664
|
-
}
|
|
22665
|
-
if (!effortInfo.levels.includes(effort)) {
|
|
22666
|
-
throw new Error(
|
|
22667
|
-
`[cursor] ${this.currentConnectOptions.model} \uBAA8\uB378\uC740 effort "${effort}"\uC744(\uB97C) \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC0AC\uC6A9 \uAC00\uB2A5: ${effortInfo.levels.join(", ")}`
|
|
22668
|
-
);
|
|
22669
|
-
}
|
|
22670
|
-
const options = this.cloneConnectOptions(this.currentConnectOptions);
|
|
22671
|
-
delete options.sessionId;
|
|
22672
|
-
return {
|
|
22673
|
-
...options,
|
|
22674
|
-
cli: "cursor",
|
|
22675
|
-
effort
|
|
22676
|
-
};
|
|
22677
|
-
}
|
|
22678
|
-
resolveEffortForModel(model, effort) {
|
|
22679
|
-
const effortInfo = getCursorSpawnEffortInfo(model);
|
|
22680
|
-
if (!effortInfo.supported) {
|
|
22681
|
-
return void 0;
|
|
22682
|
-
}
|
|
22683
|
-
if (effort && effortInfo.levels.includes(effort)) {
|
|
22684
|
-
return effort;
|
|
22685
|
-
}
|
|
22686
|
-
return effortInfo.default ?? void 0;
|
|
22687
|
-
}
|
|
22688
|
-
async reconnectWithRestore(nextOptions, label) {
|
|
22689
|
-
if (!this.currentConnectOptions) {
|
|
22690
|
-
throw new Error(`[cursor] ${label}\uC744 \uC704\uD55C \uAE30\uC874 \uC5F0\uACB0 \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. connect()\uB85C \uB2E4\uC2DC \uC5F0\uACB0\uD558\uC138\uC694.`);
|
|
22691
|
-
}
|
|
22692
|
-
const previousOptions = this.cloneConnectOptions(this.currentConnectOptions);
|
|
22693
|
-
try {
|
|
22694
|
-
await this.connect(nextOptions);
|
|
22695
|
-
} catch (error51) {
|
|
22696
|
-
try {
|
|
22697
|
-
await this.connect(previousOptions);
|
|
22698
|
-
} catch (restoreError) {
|
|
22699
|
-
throw new Error(
|
|
22700
|
-
`[cursor] ${label} \uC2E4\uD328 \uD6C4 \uC774\uC804 \uC5F0\uACB0 \uBCF5\uAD6C\uB3C4 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. ${label} \uC624\uB958: ${this.formatErrorMessage(error51)} / \uBCF5\uAD6C \uC624\uB958: ${this.formatErrorMessage(restoreError)}`
|
|
22701
|
-
);
|
|
22702
|
-
}
|
|
22703
|
-
throw new Error(
|
|
22704
|
-
`[cursor] ${label} \uC2E4\uD328\uB85C \uC774\uC804 \uC5F0\uACB0\uC744 \uBCF5\uAD6C\uD588\uC2B5\uB2C8\uB2E4. ${label} \uC624\uB958: ${this.formatErrorMessage(error51)}`
|
|
22705
|
-
);
|
|
22706
|
-
}
|
|
22707
|
-
}
|
|
22708
|
-
formatErrorMessage(error51) {
|
|
22709
|
-
if (error51 instanceof Error) {
|
|
22710
|
-
return error51.message;
|
|
22711
|
-
}
|
|
22712
|
-
return String(error51);
|
|
22713
|
-
}
|
|
22714
|
-
cloneConnectOptions(options) {
|
|
22715
|
-
return {
|
|
22716
|
-
...options,
|
|
22717
|
-
cli: "cursor",
|
|
22718
|
-
env: options.env ? { ...options.env } : void 0,
|
|
22719
|
-
clientInfo: options.clientInfo ? { ...options.clientInfo } : void 0,
|
|
22720
|
-
mcpServers: options.mcpServers?.map((server) => ({
|
|
22721
|
-
...server,
|
|
22722
|
-
headers: server.headers?.map((header) => ({ ...header }))
|
|
22723
|
-
}))
|
|
22724
|
-
};
|
|
22725
|
-
}
|
|
22726
|
-
setupEventForwarding() {
|
|
22727
|
-
if (!this.connection) return;
|
|
22728
|
-
this.connection.on("stateChange", (state) => {
|
|
22729
|
-
this.emitTyped("stateChange", state);
|
|
22730
|
-
});
|
|
22731
|
-
this.connection.on("userMessageChunk", (text2, sessionId) => {
|
|
22732
|
-
this.emitTyped("userMessageChunk", text2, sessionId);
|
|
22733
|
-
});
|
|
22734
|
-
this.connection.on("messageChunk", (text2, sessionId) => {
|
|
22735
|
-
this.emitTyped("messageChunk", text2, sessionId);
|
|
22736
|
-
});
|
|
22737
|
-
this.connection.on("thoughtChunk", (text2, sessionId) => {
|
|
22738
|
-
this.emitTyped("thoughtChunk", text2, sessionId);
|
|
22739
|
-
});
|
|
22740
|
-
this.connection.on("toolCall", (title, status, sessionId, data) => {
|
|
22741
|
-
this.emitTyped("toolCall", title, status, sessionId, data);
|
|
22742
|
-
});
|
|
22743
|
-
this.connection.on("toolCallUpdate", (title, status, sessionId, data) => {
|
|
22744
|
-
this.emitTyped("toolCallUpdate", title, status, sessionId, data);
|
|
22745
|
-
});
|
|
22746
|
-
this.connection.on("plan", (plan, sessionId) => {
|
|
22747
|
-
this.emitTyped("plan", plan, sessionId);
|
|
22748
|
-
});
|
|
22749
|
-
this.connection.on("availableCommandsUpdate", (commands, sessionId) => {
|
|
22750
|
-
this.emitTyped("availableCommandsUpdate", commands, sessionId);
|
|
22751
|
-
});
|
|
22752
|
-
this.connection.on("sessionUpdate", (update) => {
|
|
22753
|
-
this.emitTyped("sessionUpdate", update);
|
|
22754
|
-
});
|
|
22755
|
-
this.connection.on("permissionRequest", (params, resolve3) => {
|
|
22756
|
-
this.emitTyped("permissionRequest", params, resolve3);
|
|
22757
|
-
});
|
|
22758
|
-
this.connection.on("fileRead", (params, resolve3) => {
|
|
22759
|
-
this.emitTyped("fileRead", params, resolve3);
|
|
22760
|
-
});
|
|
22761
|
-
this.connection.on("fileWrite", (params, resolve3) => {
|
|
22762
|
-
this.emitTyped("fileWrite", params, resolve3);
|
|
22763
|
-
});
|
|
22764
|
-
this.connection.on("promptComplete", (sessionId) => {
|
|
22765
|
-
this.emitTyped("promptComplete", sessionId);
|
|
22766
|
-
});
|
|
22767
|
-
this.connection.on("error", (err) => {
|
|
22768
|
-
this.emitTyped("error", err);
|
|
22769
|
-
});
|
|
22770
|
-
this.connection.on("exit", (code, signal) => {
|
|
22771
|
-
this.emitTyped("exit", code, signal);
|
|
22772
|
-
});
|
|
22773
|
-
this.connection.on("log", (msg) => {
|
|
22774
|
-
this.emitTyped("log", msg);
|
|
22775
|
-
});
|
|
22776
|
-
this.connection.on("logEntry", (entry) => {
|
|
22777
|
-
this.emitTyped("logEntry", entry);
|
|
22778
|
-
});
|
|
22779
|
-
}
|
|
22780
|
-
async cleanupFailedConnection() {
|
|
22781
|
-
if (!this.connection) {
|
|
22782
|
-
return;
|
|
22783
|
-
}
|
|
22784
|
-
try {
|
|
22785
|
-
await this.connection.disconnect();
|
|
22786
|
-
} catch {
|
|
22787
|
-
}
|
|
22788
|
-
this.connection.removeAllListeners();
|
|
22789
|
-
this.connection = null;
|
|
22790
|
-
this.clearSessionState();
|
|
22791
|
-
}
|
|
22792
|
-
buildConnectionError(error51, recentLogs) {
|
|
22793
|
-
if (getBackendConfig("cursor").authRequired && this.isAuthenticationError(error51, recentLogs)) {
|
|
22794
|
-
return new Error(
|
|
22795
|
-
"[cursor] \uC778\uC99D\uC774 \uD544\uC694\uD558\uAC70\uB098 \uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 \uD574\uB2F9 CLI\uC5D0\uC11C \uB85C\uADF8\uC778/\uC778\uC99D\uC744 \uC644\uB8CC\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694."
|
|
22796
|
-
);
|
|
22797
|
-
}
|
|
22798
|
-
if (error51 instanceof Error) {
|
|
22799
|
-
return error51;
|
|
22800
|
-
}
|
|
22801
|
-
if (typeof error51 === "object" && error51 !== null) {
|
|
22802
|
-
const obj = error51;
|
|
22803
|
-
if (typeof obj.message === "string") {
|
|
22804
|
-
const code = typeof obj.code === "number" ? ` (code: ${obj.code})` : "";
|
|
22805
|
-
const data = obj.data ? ` \u2014 ${JSON.stringify(obj.data)}` : "";
|
|
22806
|
-
return new Error(`${obj.message}${code}${data}`);
|
|
22807
|
-
}
|
|
22808
|
-
return new Error(JSON.stringify(error51));
|
|
22809
|
-
}
|
|
22810
|
-
return new Error(String(error51));
|
|
22811
|
-
}
|
|
22812
|
-
isAuthenticationError(error51, recentLogs) {
|
|
22813
|
-
const authPatterns = [
|
|
22814
|
-
/auth_required/i,
|
|
22815
|
-
/authentication required/i,
|
|
22816
|
-
/not authenticated/i,
|
|
22817
|
-
/please login/i,
|
|
22818
|
-
/please log in/i,
|
|
22819
|
-
/sign in/i,
|
|
22820
|
-
/reauth/i,
|
|
22821
|
-
/unauthorized/i,
|
|
22822
|
-
/invalid api key/i
|
|
22823
|
-
];
|
|
22824
|
-
if (this.matchAnyPattern(this.extractErrorText(error51), authPatterns)) {
|
|
22825
|
-
return true;
|
|
22826
|
-
}
|
|
22827
|
-
return recentLogs.some((log) => this.matchAnyPattern(log, authPatterns));
|
|
22828
|
-
}
|
|
22829
|
-
extractErrorText(error51) {
|
|
22830
|
-
if (error51 instanceof Error) {
|
|
22831
|
-
const code = error51.code;
|
|
22832
|
-
if (code === -32e3) {
|
|
22833
|
-
return `auth_required ${error51.message}`;
|
|
22834
|
-
}
|
|
22835
|
-
return error51.message;
|
|
22836
|
-
}
|
|
22837
|
-
if (typeof error51 === "string") {
|
|
22838
|
-
return error51;
|
|
22839
|
-
}
|
|
22840
|
-
return String(error51);
|
|
22841
|
-
}
|
|
22842
|
-
matchAnyPattern(text2, patterns) {
|
|
22843
|
-
return patterns.some((pattern) => pattern.test(text2));
|
|
22844
|
-
}
|
|
22845
|
-
};
|
|
22846
22306
|
|
|
22847
22307
|
// ../../packages/core-unified-agent/src/client/UnifiedAgent.ts
|
|
22848
22308
|
var UnifiedAgent = {
|
|
@@ -22852,8 +22312,6 @@ var UnifiedAgent = {
|
|
|
22852
22312
|
return new UnifiedClaudeAgentClient();
|
|
22853
22313
|
case "codex":
|
|
22854
22314
|
return new UnifiedCodexAgentClient();
|
|
22855
|
-
case "cursor":
|
|
22856
|
-
return new UnifiedCursorAgentClient();
|
|
22857
22315
|
}
|
|
22858
22316
|
},
|
|
22859
22317
|
async build(options = {}) {
|
|
@@ -22866,7 +22324,7 @@ var UnifiedAgent = {
|
|
|
22866
22324
|
const preferred = await new CliDetector().getPreferred();
|
|
22867
22325
|
if (!preferred) {
|
|
22868
22326
|
throw new Error(
|
|
22869
|
-
"\uC0AC\uC6A9 \uAC00\uB2A5\uD55C CLI\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. claude, codex
|
|
22327
|
+
"\uC0AC\uC6A9 \uAC00\uB2A5\uD55C CLI\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. claude, codex \uC911 \uD558\uB098\uB97C \uC124\uCE58\uD574\uC8FC\uC138\uC694."
|
|
22870
22328
|
);
|
|
22871
22329
|
}
|
|
22872
22330
|
return this.createClient(preferred.cli);
|
|
@@ -32753,7 +32211,7 @@ Both surfaces require the user's request. When the one the work needs is gated,
|
|
|
32753
32211
|
### Model Loadout
|
|
32754
32212
|
Which model and effort a run uses is routing, so it stays with the host agent. Call the ${"`"}gateway_models${"`"} MCP tool before every run on either surface, then pick the identity this work needs — a measured role fit first, and the model's own allowance wherever measurement is silent. Never let the session's own model be the default answer; it is the most expensive way to obtain what any identity produces equally well, and an unpinned run spends that allowance too.
|
|
32755
32213
|
|
|
32756
|
-
A staged workflow spreads its stages across identities and balances them against provider allowances instead of inheriting one model for every stage. The ${"`"}workflow${"`"} skill owns that procedure; what each roster field means stays in the tool's own metadata.
|
|
32214
|
+
A staged workflow spreads its stages across identities and balances them against provider allowances instead of inheriting one model for every stage — reading each allowance's own reported verdict rather than comparing raw percentages across windows that reset on different clocks. The ${"`"}workflow${"`"} skill owns that procedure; what each roster field means stays in the tool's own metadata.
|
|
32757
32215
|
|
|
32758
32216
|
### Skill Routing
|
|
32759
32217
|
Load the ${"`"}workflow${"`"} skill before executing a stage skeleton or assigning models across runs. The skeleton itself belongs to the skill matching the work: ${"`"}architecture-review${"`"} to decide, ${"`"}codebase-research${"`"} to establish facts, ${"`"}implementation-run${"`"} to change files, ${"`"}quality-review${"`"} to judge what exists.`
|
|
@@ -32763,15 +32221,15 @@ var DEEP_DIVE2 = {
|
|
|
32763
32221
|
name: "Deep Dive",
|
|
32764
32222
|
prompt: String.raw`## Deep Dive Standing Order
|
|
32765
32223
|
|
|
32766
|
-
A cross-cutting verification procedure
|
|
32224
|
+
A cross-cutting verification procedure. It is not a phase of its own — it interrupts the current step, runs to completion, and then resumes that step. Throughout, never flatten uncertainty into confident-sounding summaries — preserve and surface ambiguity honestly.
|
|
32767
32225
|
|
|
32768
32226
|
### Trigger
|
|
32769
|
-
|
|
32227
|
+
Entry is routed by the Result Integrity trigger mapping table. This order owns unverified claims only; ambiguity or thin evidence is a confidence gap and re-enters Context Confidence instead.
|
|
32770
32228
|
|
|
32771
32229
|
### Procedure
|
|
32772
|
-
1. **
|
|
32773
|
-
2. **
|
|
32774
|
-
-
|
|
32230
|
+
1. **Choose the scan.** Scan it yourself when the result is short and confined to ground already read this session; give it its own run otherwise. These are alternatives, not steps.
|
|
32231
|
+
2. **Run that scan.** Yours sweeps for speculation markers (e.g., "likely", "probably", "I think", "may be", "not sure but…"). Its own run gets explicit instructions:
|
|
32232
|
+
- *"Review the following analysis for speculative, assumed, or unverified claims. Flag each with evidence of why it is speculative and what verification is needed."*
|
|
32775
32233
|
3. **Follow-up verification** — For each identified speculative element, start a verification run that seeks independent confirmation or refutation.
|
|
32776
32234
|
4. **Repeat** until all speculative elements are either **confirmed with evidence** or explicitly flagged as **unresolvable unknowns**.
|
|
32777
32235
|
|
|
@@ -37524,7 +36982,9 @@ function projectClaudeContextInputTokens(inputTokens, advertisedContextWindow, u
|
|
|
37524
36982
|
);
|
|
37525
36983
|
}
|
|
37526
36984
|
async function* projectAnthropicResponseUsage(chunks, options) {
|
|
37527
|
-
|
|
36985
|
+
const contextWindow = canProjectClaudeContextWindow(options.contextWindow) ? options.contextWindow : void 0;
|
|
36986
|
+
const responseModel = typeof options.responseModel === "string" && options.responseModel.length > 0 ? options.responseModel : void 0;
|
|
36987
|
+
if (contextWindow === void 0 && responseModel === void 0) {
|
|
37528
36988
|
yield* chunks;
|
|
37529
36989
|
return;
|
|
37530
36990
|
}
|
|
@@ -37532,7 +36992,8 @@ async function* projectAnthropicResponseUsage(chunks, options) {
|
|
|
37532
36992
|
if (mediaType === "text/event-stream") {
|
|
37533
36993
|
yield* projectSseUsage(
|
|
37534
36994
|
chunks,
|
|
37535
|
-
|
|
36995
|
+
contextWindow,
|
|
36996
|
+
responseModel,
|
|
37536
36997
|
positiveLimit(options.maxSseFrameBytes, DEFAULT_MAX_SSE_FRAME_BYTES)
|
|
37537
36998
|
);
|
|
37538
36999
|
return;
|
|
@@ -37540,14 +37001,15 @@ async function* projectAnthropicResponseUsage(chunks, options) {
|
|
|
37540
37001
|
if (mediaType === "application/json" || mediaType?.endsWith("+json")) {
|
|
37541
37002
|
yield* projectJsonUsage(
|
|
37542
37003
|
chunks,
|
|
37543
|
-
|
|
37004
|
+
contextWindow,
|
|
37005
|
+
responseModel,
|
|
37544
37006
|
positiveLimit(options.maxJsonBytes, DEFAULT_MAX_JSON_BYTES)
|
|
37545
37007
|
);
|
|
37546
37008
|
return;
|
|
37547
37009
|
}
|
|
37548
37010
|
yield* chunks;
|
|
37549
37011
|
}
|
|
37550
|
-
async function* projectJsonUsage(chunks, contextWindow, maxBytes) {
|
|
37012
|
+
async function* projectJsonUsage(chunks, contextWindow, responseModel, maxBytes) {
|
|
37551
37013
|
const buffered = [];
|
|
37552
37014
|
let bufferedBytes = 0;
|
|
37553
37015
|
let passthrough = false;
|
|
@@ -37567,10 +37029,10 @@ async function* projectJsonUsage(chunks, contextWindow, maxBytes) {
|
|
|
37567
37029
|
}
|
|
37568
37030
|
if (passthrough || bufferedBytes === 0) return;
|
|
37569
37031
|
const original = concatChunks(buffered, bufferedBytes);
|
|
37570
|
-
const projected = projectJsonBytes(original, contextWindow);
|
|
37032
|
+
const projected = projectJsonBytes(original, contextWindow, responseModel);
|
|
37571
37033
|
yield projected ?? original;
|
|
37572
37034
|
}
|
|
37573
|
-
async function* projectSseUsage(chunks, contextWindow, maxFrameBytes) {
|
|
37035
|
+
async function* projectSseUsage(chunks, contextWindow, responseModel, maxFrameBytes) {
|
|
37574
37036
|
let buffered = new Uint8Array(0);
|
|
37575
37037
|
let oversizedFrame = false;
|
|
37576
37038
|
for await (const chunk of chunks) {
|
|
@@ -37597,7 +37059,7 @@ async function* projectSseUsage(chunks, contextWindow, maxFrameBytes) {
|
|
|
37597
37059
|
const frame = buffered.slice(0, separator.index);
|
|
37598
37060
|
const separatorBytes = buffered.slice(separator.index, separator.index + separator.length);
|
|
37599
37061
|
const originalFrame = buffered.slice(0, separator.index + separator.length);
|
|
37600
|
-
const projectedFrame = frame.byteLength > maxFrameBytes ? void 0 : projectSseFrame(frame, contextWindow);
|
|
37062
|
+
const projectedFrame = frame.byteLength > maxFrameBytes ? void 0 : projectSseFrame(frame, contextWindow, responseModel);
|
|
37601
37063
|
yield projectedFrame === void 0 ? originalFrame : concatBytes(projectedFrame, separatorBytes);
|
|
37602
37064
|
buffered = buffered.slice(separator.index + separator.length);
|
|
37603
37065
|
}
|
|
@@ -37611,17 +37073,17 @@ async function* projectSseUsage(chunks, contextWindow, maxFrameBytes) {
|
|
|
37611
37073
|
}
|
|
37612
37074
|
if (buffered.byteLength > 0) yield buffered;
|
|
37613
37075
|
}
|
|
37614
|
-
function projectJsonBytes(bytes, contextWindow) {
|
|
37076
|
+
function projectJsonBytes(bytes, contextWindow, responseModel) {
|
|
37615
37077
|
let parsed;
|
|
37616
37078
|
try {
|
|
37617
37079
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
37618
37080
|
} catch {
|
|
37619
37081
|
return void 0;
|
|
37620
37082
|
}
|
|
37621
|
-
const projected = projectAnthropicUsageEnvelope(parsed, contextWindow);
|
|
37083
|
+
const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel);
|
|
37622
37084
|
return projected.changed ? new TextEncoder().encode(JSON.stringify(projected.value)) : void 0;
|
|
37623
37085
|
}
|
|
37624
|
-
function projectSseFrame(frame, contextWindow) {
|
|
37086
|
+
function projectSseFrame(frame, contextWindow, responseModel) {
|
|
37625
37087
|
let text2;
|
|
37626
37088
|
try {
|
|
37627
37089
|
text2 = new TextDecoder("utf-8", { fatal: true }).decode(frame);
|
|
@@ -37647,7 +37109,7 @@ function projectSseFrame(frame, contextWindow) {
|
|
|
37647
37109
|
} catch {
|
|
37648
37110
|
return void 0;
|
|
37649
37111
|
}
|
|
37650
|
-
const projected = projectAnthropicUsageEnvelope(parsed, contextWindow);
|
|
37112
|
+
const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel);
|
|
37651
37113
|
if (!projected.changed) return void 0;
|
|
37652
37114
|
const firstDataIndex = dataIndexes[0];
|
|
37653
37115
|
const dataIndexSet = new Set(dataIndexes);
|
|
@@ -37661,20 +37123,33 @@ function projectSseFrame(frame, contextWindow) {
|
|
|
37661
37123
|
}
|
|
37662
37124
|
return new TextEncoder().encode(outputLines.join(newline2));
|
|
37663
37125
|
}
|
|
37664
|
-
function projectAnthropicUsageEnvelope(value, contextWindow) {
|
|
37126
|
+
function projectAnthropicUsageEnvelope(value, contextWindow, responseModel) {
|
|
37665
37127
|
if (!isRecord4(value)) return { changed: false, value };
|
|
37666
37128
|
let projectedValue = value;
|
|
37667
37129
|
let changed = false;
|
|
37668
|
-
|
|
37669
|
-
|
|
37670
|
-
|
|
37671
|
-
|
|
37130
|
+
if (contextWindow !== void 0) {
|
|
37131
|
+
const topLevelUsage = projectUsageProperty(projectedValue, "usage", contextWindow);
|
|
37132
|
+
if (topLevelUsage.changed) {
|
|
37133
|
+
projectedValue = topLevelUsage.value;
|
|
37134
|
+
changed = true;
|
|
37135
|
+
}
|
|
37136
|
+
const message = projectedValue.message;
|
|
37137
|
+
if (isRecord4(message)) {
|
|
37138
|
+
const messageUsage = projectUsageProperty(message, "usage", contextWindow);
|
|
37139
|
+
if (messageUsage.changed) {
|
|
37140
|
+
projectedValue = { ...projectedValue, message: messageUsage.value };
|
|
37141
|
+
changed = true;
|
|
37142
|
+
}
|
|
37143
|
+
}
|
|
37672
37144
|
}
|
|
37673
|
-
|
|
37674
|
-
|
|
37675
|
-
|
|
37676
|
-
|
|
37677
|
-
|
|
37145
|
+
if (responseModel !== void 0) {
|
|
37146
|
+
if (typeof projectedValue.model === "string" && projectedValue.model !== responseModel) {
|
|
37147
|
+
projectedValue = { ...projectedValue, model: responseModel };
|
|
37148
|
+
changed = true;
|
|
37149
|
+
}
|
|
37150
|
+
const message = projectedValue.message;
|
|
37151
|
+
if (isRecord4(message) && typeof message.model === "string" && message.model !== responseModel) {
|
|
37152
|
+
projectedValue = { ...projectedValue, message: { ...message, model: responseModel } };
|
|
37678
37153
|
changed = true;
|
|
37679
37154
|
}
|
|
37680
37155
|
}
|
|
@@ -37740,7 +37215,7 @@ function isRecord4(value) {
|
|
|
37740
37215
|
}
|
|
37741
37216
|
var models_default2 = {
|
|
37742
37217
|
version: 1,
|
|
37743
|
-
updatedAt: "2026-08-
|
|
37218
|
+
updatedAt: "2026-08-03T00:00:00Z",
|
|
37744
37219
|
providers: {
|
|
37745
37220
|
codex: {
|
|
37746
37221
|
name: "Codex",
|
|
@@ -38025,13 +37500,167 @@ var models_default2 = {
|
|
|
38025
37500
|
]
|
|
38026
37501
|
}
|
|
38027
37502
|
]
|
|
37503
|
+
},
|
|
37504
|
+
opencode: {
|
|
37505
|
+
name: "OpenCode",
|
|
37506
|
+
defaultModel: "minimax-m3",
|
|
37507
|
+
source: "live GET https://opencode.ai/zen/go/v1/models + per-model wire probes on /messages, /responses, /chat/completions (2026-08-03); contextWindow cross-checked against models.dev api.json opencode-go entries and oh-my-pi packages/catalog/src/models.json (2026-08-03, both agree). Excluded: mimo-v2-pro/mimo-v2-omni (upstream server_error), hy3-preview (listed but Router.ModelNotFound)",
|
|
37508
|
+
models: [
|
|
37509
|
+
{
|
|
37510
|
+
modelId: "minimax-m3",
|
|
37511
|
+
name: "MiniMax-M3",
|
|
37512
|
+
contextWindow: 1e6
|
|
37513
|
+
},
|
|
37514
|
+
{
|
|
37515
|
+
modelId: "minimax-m2.7",
|
|
37516
|
+
name: "MiniMax-M2.7",
|
|
37517
|
+
contextWindow: 204800
|
|
37518
|
+
},
|
|
37519
|
+
{
|
|
37520
|
+
modelId: "minimax-m2.5",
|
|
37521
|
+
name: "MiniMax-M2.5",
|
|
37522
|
+
contextWindow: 204800
|
|
37523
|
+
},
|
|
37524
|
+
{
|
|
37525
|
+
modelId: "qwen3.8-max",
|
|
37526
|
+
name: "Qwen3.8-Max",
|
|
37527
|
+
contextWindow: 1e6
|
|
37528
|
+
},
|
|
37529
|
+
{
|
|
37530
|
+
modelId: "qwen3.7-max",
|
|
37531
|
+
name: "Qwen3.7-Max",
|
|
37532
|
+
contextWindow: 1e6
|
|
37533
|
+
},
|
|
37534
|
+
{
|
|
37535
|
+
modelId: "qwen3.7-plus",
|
|
37536
|
+
name: "Qwen3.7-Plus",
|
|
37537
|
+
contextWindow: 1e6
|
|
37538
|
+
},
|
|
37539
|
+
{
|
|
37540
|
+
modelId: "qwen3.6-plus",
|
|
37541
|
+
name: "Qwen3.6-Plus",
|
|
37542
|
+
contextWindow: 1e6
|
|
37543
|
+
},
|
|
37544
|
+
{
|
|
37545
|
+
modelId: "qwen3.5-plus",
|
|
37546
|
+
name: "Qwen3.5-Plus",
|
|
37547
|
+
contextWindow: 262144
|
|
37548
|
+
},
|
|
37549
|
+
{
|
|
37550
|
+
modelId: "gpt-5.6-luna",
|
|
37551
|
+
name: "GPT-5.6-Luna",
|
|
37552
|
+
wire: "responses",
|
|
37553
|
+
contextWindow: 105e4,
|
|
37554
|
+
effort: {
|
|
37555
|
+
supported: true,
|
|
37556
|
+
levels: [
|
|
37557
|
+
"low",
|
|
37558
|
+
"medium",
|
|
37559
|
+
"high",
|
|
37560
|
+
"xhigh",
|
|
37561
|
+
"max"
|
|
37562
|
+
]
|
|
37563
|
+
}
|
|
37564
|
+
},
|
|
37565
|
+
{
|
|
37566
|
+
modelId: "grok-4.5",
|
|
37567
|
+
name: "Grok-4.5",
|
|
37568
|
+
wire: "responses",
|
|
37569
|
+
contextWindow: 5e5,
|
|
37570
|
+
effort: {
|
|
37571
|
+
supported: true,
|
|
37572
|
+
levels: [
|
|
37573
|
+
"low",
|
|
37574
|
+
"medium",
|
|
37575
|
+
"high"
|
|
37576
|
+
]
|
|
37577
|
+
}
|
|
37578
|
+
},
|
|
37579
|
+
{
|
|
37580
|
+
modelId: "deepseek-v4-flash",
|
|
37581
|
+
name: "DeepSeek-V4-Flash",
|
|
37582
|
+
wire: "chat-completions",
|
|
37583
|
+
contextWindow: 1e6
|
|
37584
|
+
},
|
|
37585
|
+
{
|
|
37586
|
+
modelId: "deepseek-v4-pro",
|
|
37587
|
+
name: "DeepSeek-V4-Pro",
|
|
37588
|
+
wire: "chat-completions",
|
|
37589
|
+
contextWindow: 1e6
|
|
37590
|
+
},
|
|
37591
|
+
{
|
|
37592
|
+
modelId: "glm-5.2",
|
|
37593
|
+
name: "GLM-5.2",
|
|
37594
|
+
wire: "chat-completions",
|
|
37595
|
+
contextWindow: 1e6
|
|
37596
|
+
},
|
|
37597
|
+
{
|
|
37598
|
+
modelId: "glm-5.1",
|
|
37599
|
+
name: "GLM-5.1",
|
|
37600
|
+
wire: "chat-completions",
|
|
37601
|
+
contextWindow: 202752
|
|
37602
|
+
},
|
|
37603
|
+
{
|
|
37604
|
+
modelId: "glm-5",
|
|
37605
|
+
name: "GLM-5",
|
|
37606
|
+
wire: "chat-completions",
|
|
37607
|
+
contextWindow: 202752
|
|
37608
|
+
},
|
|
37609
|
+
{
|
|
37610
|
+
modelId: "kimi-k3",
|
|
37611
|
+
name: "Kimi-K3",
|
|
37612
|
+
wire: "chat-completions",
|
|
37613
|
+
contextWindow: 1048576
|
|
37614
|
+
},
|
|
37615
|
+
{
|
|
37616
|
+
modelId: "kimi-k2.7-code",
|
|
37617
|
+
name: "Kimi-K2.7-Code",
|
|
37618
|
+
wire: "chat-completions",
|
|
37619
|
+
contextWindow: 262144
|
|
37620
|
+
},
|
|
37621
|
+
{
|
|
37622
|
+
modelId: "kimi-k2.6",
|
|
37623
|
+
name: "Kimi-K2.6",
|
|
37624
|
+
wire: "chat-completions",
|
|
37625
|
+
contextWindow: 262144
|
|
37626
|
+
},
|
|
37627
|
+
{
|
|
37628
|
+
modelId: "kimi-k2.5",
|
|
37629
|
+
name: "Kimi-K2.5",
|
|
37630
|
+
wire: "chat-completions",
|
|
37631
|
+
contextWindow: 262144
|
|
37632
|
+
},
|
|
37633
|
+
{
|
|
37634
|
+
modelId: "mimo-v2.5-pro",
|
|
37635
|
+
name: "MiMo-V2.5-Pro",
|
|
37636
|
+
wire: "chat-completions",
|
|
37637
|
+
contextWindow: 1048576
|
|
37638
|
+
},
|
|
37639
|
+
{
|
|
37640
|
+
modelId: "mimo-v2.5",
|
|
37641
|
+
name: "MiMo-V2.5",
|
|
37642
|
+
wire: "chat-completions",
|
|
37643
|
+
contextWindow: 1e6
|
|
37644
|
+
},
|
|
37645
|
+
{
|
|
37646
|
+
modelId: "hy3",
|
|
37647
|
+
name: "HY3",
|
|
37648
|
+
wire: "chat-completions",
|
|
37649
|
+
contextWindow: 256e3
|
|
37650
|
+
}
|
|
37651
|
+
]
|
|
38028
37652
|
}
|
|
38029
37653
|
}
|
|
38030
37654
|
};
|
|
38031
37655
|
var KIMI_AUTH_PROVIDER_ID = "Claude Code with Moonshot Kimi";
|
|
38032
37656
|
var KIMI_CODE_API_BASE_URL = "https://api.kimi.com/coding";
|
|
38033
37657
|
var KIMI_CODE_MODEL = "k3";
|
|
38034
|
-
var GATEWAY_PROVIDERS = ["codex", "cursor", "kimi"];
|
|
37658
|
+
var GATEWAY_PROVIDERS = ["codex", "cursor", "kimi", "opencode"];
|
|
37659
|
+
var GATEWAY_MODEL_WIRES = ["anthropic", "responses", "chat-completions"];
|
|
37660
|
+
function isAnthropicPassthroughModel(model) {
|
|
37661
|
+
if (model.provider === "kimi") return true;
|
|
37662
|
+
return model.provider === "opencode" && (model.wire ?? "anthropic") === "anthropic";
|
|
37663
|
+
}
|
|
38035
37664
|
var GATEWAY_REASONING_EFFORTS = [
|
|
38036
37665
|
"low",
|
|
38037
37666
|
"medium",
|
|
@@ -38064,6 +37693,7 @@ var GatewayModelEntrySchema = external_exports.object({
|
|
|
38064
37693
|
serviceTier: external_exports.literal("priority").optional(),
|
|
38065
37694
|
cursorMaxMode: external_exports.literal(true).optional(),
|
|
38066
37695
|
quotaScope: external_exports.enum(GATEWAY_QUOTA_SCOPES).optional(),
|
|
37696
|
+
wire: external_exports.enum(GATEWAY_MODEL_WIRES).optional(),
|
|
38067
37697
|
aliases: external_exports.array(external_exports.string().min(1)).optional(),
|
|
38068
37698
|
contextWindow: external_exports.number().int().positive().optional(),
|
|
38069
37699
|
effort: GatewayModelEffortSchema.optional()
|
|
@@ -38080,7 +37710,8 @@ var GatewayModelsRegistrySchema = external_exports.object({
|
|
|
38080
37710
|
providers: external_exports.object({
|
|
38081
37711
|
codex: GatewayProviderSchema,
|
|
38082
37712
|
cursor: GatewayProviderSchema,
|
|
38083
|
-
kimi: GatewayProviderSchema
|
|
37713
|
+
kimi: GatewayProviderSchema,
|
|
37714
|
+
opencode: GatewayProviderSchema
|
|
38084
37715
|
}).strict()
|
|
38085
37716
|
}).strict();
|
|
38086
37717
|
var UNSUPPORTED_GATEWAY_MODEL_EFFORT = Object.freeze({ supported: false });
|
|
@@ -38105,6 +37736,7 @@ var GATEWAY_MODELS = Object.freeze(
|
|
|
38105
37736
|
providerModels("codex");
|
|
38106
37737
|
var CURSOR_SUBSCRIPTION_MODELS = providerModels("cursor");
|
|
38107
37738
|
providerModels("kimi");
|
|
37739
|
+
providerModels("opencode");
|
|
38108
37740
|
var GATEWAY_MODEL_ALIAS_PREFIX = "claude-gateway--";
|
|
38109
37741
|
var CLAUDE_ONE_MILLION_MARKER = "[1m]";
|
|
38110
37742
|
var CLAUDE_ONE_MILLION_DISPLAY_SUFFIX = " (1M Context)";
|
|
@@ -38113,7 +37745,7 @@ function toGatewayModelAlias(modelId) {
|
|
|
38113
37745
|
}
|
|
38114
37746
|
function toClaudeGatewayModelId(model) {
|
|
38115
37747
|
const alias = toGatewayModelAlias(model.id);
|
|
38116
|
-
if (canProjectClaudeContextWindow(model.contextWindow) && (model
|
|
37748
|
+
if (canProjectClaudeContextWindow(model.contextWindow) && (!isAnthropicPassthroughModel(model) || isClaudeOneMillionContextWindow(model.contextWindow))) {
|
|
38117
37749
|
return `${alias}${CLAUDE_ONE_MILLION_MARKER}`;
|
|
38118
37750
|
}
|
|
38119
37751
|
return alias;
|
|
@@ -38139,7 +37771,6 @@ function gatewayModelIdentity(model) {
|
|
|
38139
37771
|
function buildGatewayModelConstraints(model) {
|
|
38140
37772
|
const ladder = model.effort.supported ? model.effort.levels.filter((level) => ANTHROPIC_EFFORT_RUNGS.has(level)) : [];
|
|
38141
37773
|
return {
|
|
38142
|
-
identity: gatewayModelIdentity(model),
|
|
38143
37774
|
provider: model.provider,
|
|
38144
37775
|
...model.contextWindow !== void 0 ? { contextWindow: model.contextWindow } : {},
|
|
38145
37776
|
effortLadder: Object.freeze([...ladder]),
|
|
@@ -38213,6 +37844,7 @@ function toGatewayModel(provider, providerName, entry) {
|
|
|
38213
37844
|
...entry.serviceTier ? { serviceTier: entry.serviceTier } : {},
|
|
38214
37845
|
...entry.cursorMaxMode ? { cursorMaxMode: entry.cursorMaxMode } : {},
|
|
38215
37846
|
...entry.quotaScope ? { quotaScope: entry.quotaScope } : {},
|
|
37847
|
+
...entry.wire ? { wire: entry.wire } : {},
|
|
38216
37848
|
...entry.description ? { description: entry.description } : {},
|
|
38217
37849
|
...entry.contextWindow ? { contextWindow: entry.contextWindow } : {},
|
|
38218
37850
|
effort: freezeGatewayModelEffort(entry.effort),
|
|
@@ -38247,6 +37879,9 @@ function validateRegistry(value) {
|
|
|
38247
37879
|
if (model.quotaScope && provider !== "cursor") {
|
|
38248
37880
|
throw new Error(`Gateway quota scope is only supported by Cursor: ${provider}/${model.modelId}`);
|
|
38249
37881
|
}
|
|
37882
|
+
if (model.wire && provider !== "opencode") {
|
|
37883
|
+
throw new Error(`Gateway model wire is only supported by OpenCode: ${provider}/${model.modelId}`);
|
|
37884
|
+
}
|
|
38250
37885
|
if (model.effort?.supported) {
|
|
38251
37886
|
if (new Set(model.effort.levels).size !== model.effort.levels.length) {
|
|
38252
37887
|
throw new Error(`Gateway effort levels contain duplicates: ${provider}/${model.modelId}`);
|
|
@@ -40216,21 +39851,9 @@ var AgentServerMessageSchema = messageDesc(cursorAgentFile, 119);
|
|
|
40216
39851
|
var ConversationStepSchema = messageDesc(cursorAgentFile, 53);
|
|
40217
39852
|
var UserMessageSchema = messageDesc(cursorAgentFile, 63);
|
|
40218
39853
|
var ConversationTurnStructureSchema = messageDesc(cursorAgentFile, 70);
|
|
40219
|
-
var OPENAI_RESPONSES_URL = "https://api.openai.com/v1/responses";
|
|
40220
|
-
var CHATGPT_CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
40221
|
-
var DEFAULT_MAX_UPSTREAM_BODY_BYTES = 64 * 1024 * 1024;
|
|
40222
|
-
var DEFAULT_UPSTREAM_IDLE_TIMEOUT_MS = 3e4;
|
|
40223
|
-
var CHATGPT_UNSUPPORTED_FIELDS = [
|
|
40224
|
-
"max_output_tokens",
|
|
40225
|
-
"temperature",
|
|
40226
|
-
"top_p",
|
|
40227
|
-
"stop",
|
|
40228
|
-
"user",
|
|
40229
|
-
"metadata"
|
|
40230
|
-
];
|
|
40231
39854
|
var UpstreamBodyLimitError = class extends Error {
|
|
40232
39855
|
constructor(maxBodyBytes) {
|
|
40233
|
-
super(`
|
|
39856
|
+
super(`Upstream response exceeded ${maxBodyBytes} bytes`);
|
|
40234
39857
|
this.maxBodyBytes = maxBodyBytes;
|
|
40235
39858
|
this.name = "UpstreamBodyLimitError";
|
|
40236
39859
|
}
|
|
@@ -40238,7 +39861,7 @@ var UpstreamBodyLimitError = class extends Error {
|
|
|
40238
39861
|
};
|
|
40239
39862
|
var UpstreamIdleTimeoutError = class extends Error {
|
|
40240
39863
|
constructor(idleTimeoutMs) {
|
|
40241
|
-
super(`
|
|
39864
|
+
super(`Upstream response was idle for ${idleTimeoutMs}ms`);
|
|
40242
39865
|
this.idleTimeoutMs = idleTimeoutMs;
|
|
40243
39866
|
this.name = "UpstreamIdleTimeoutError";
|
|
40244
39867
|
}
|
|
@@ -40250,6 +39873,132 @@ var UpstreamProtocolError = class extends Error {
|
|
|
40250
39873
|
this.name = "UpstreamProtocolError";
|
|
40251
39874
|
}
|
|
40252
39875
|
};
|
|
39876
|
+
async function readBoundedBody(body, options) {
|
|
39877
|
+
if (body === null) {
|
|
39878
|
+
return new Uint8Array();
|
|
39879
|
+
}
|
|
39880
|
+
const reader = body.getReader();
|
|
39881
|
+
const chunks = [];
|
|
39882
|
+
let byteLength3 = 0;
|
|
39883
|
+
try {
|
|
39884
|
+
while (true) {
|
|
39885
|
+
const result = await readWithIdleTimeout(reader, options);
|
|
39886
|
+
if (result.done) {
|
|
39887
|
+
break;
|
|
39888
|
+
}
|
|
39889
|
+
byteLength3 += result.value.byteLength;
|
|
39890
|
+
if (byteLength3 > options.maxBodyBytes) {
|
|
39891
|
+
const error51 = new UpstreamBodyLimitError(options.maxBodyBytes);
|
|
39892
|
+
options.controller.abort(error51);
|
|
39893
|
+
throw error51;
|
|
39894
|
+
}
|
|
39895
|
+
chunks.push(result.value);
|
|
39896
|
+
}
|
|
39897
|
+
} finally {
|
|
39898
|
+
await reader.cancel().catch(() => void 0);
|
|
39899
|
+
}
|
|
39900
|
+
const bodyBytes = new Uint8Array(byteLength3);
|
|
39901
|
+
let offset = 0;
|
|
39902
|
+
for (const chunk of chunks) {
|
|
39903
|
+
bodyBytes.set(chunk, offset);
|
|
39904
|
+
offset += chunk.byteLength;
|
|
39905
|
+
}
|
|
39906
|
+
return bodyBytes;
|
|
39907
|
+
}
|
|
39908
|
+
async function readWithIdleTimeout(reader, options) {
|
|
39909
|
+
return await new Promise((resolve3, reject) => {
|
|
39910
|
+
let settled = false;
|
|
39911
|
+
const finish = (callback, value) => {
|
|
39912
|
+
if (settled) {
|
|
39913
|
+
return;
|
|
39914
|
+
}
|
|
39915
|
+
settled = true;
|
|
39916
|
+
clearTimeout(timeout);
|
|
39917
|
+
options.controller.signal.removeEventListener("abort", abort);
|
|
39918
|
+
callback(value);
|
|
39919
|
+
};
|
|
39920
|
+
const abort = () => {
|
|
39921
|
+
const reason = options.controller.signal.reason instanceof Error ? options.controller.signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
39922
|
+
void reader.cancel(reason).catch(() => void 0);
|
|
39923
|
+
finish(reject, reason);
|
|
39924
|
+
};
|
|
39925
|
+
const timeout = setTimeout(() => {
|
|
39926
|
+
const error51 = new UpstreamIdleTimeoutError(options.idleTimeoutMs);
|
|
39927
|
+
options.controller.abort(error51);
|
|
39928
|
+
}, options.idleTimeoutMs);
|
|
39929
|
+
options.controller.signal.addEventListener("abort", abort, { once: true });
|
|
39930
|
+
if (options.controller.signal.aborted) {
|
|
39931
|
+
abort();
|
|
39932
|
+
return;
|
|
39933
|
+
}
|
|
39934
|
+
reader.read().then(
|
|
39935
|
+
(result) => {
|
|
39936
|
+
finish(resolve3, result);
|
|
39937
|
+
},
|
|
39938
|
+
(error51) => {
|
|
39939
|
+
finish(reject, error51);
|
|
39940
|
+
}
|
|
39941
|
+
);
|
|
39942
|
+
});
|
|
39943
|
+
}
|
|
39944
|
+
function nextEventBoundary(buffer) {
|
|
39945
|
+
const match = /\r\n\r\n|\n\n|\r\r/.exec(buffer);
|
|
39946
|
+
return match === null ? void 0 : { index: match.index, length: match[0].length };
|
|
39947
|
+
}
|
|
39948
|
+
function parseSseFrameFields(frame) {
|
|
39949
|
+
let eventName;
|
|
39950
|
+
const data = [];
|
|
39951
|
+
for (const line of frame.split(/\r\n|\n|\r/)) {
|
|
39952
|
+
if (line.startsWith(":")) {
|
|
39953
|
+
continue;
|
|
39954
|
+
}
|
|
39955
|
+
const separator = line.indexOf(":");
|
|
39956
|
+
const field = separator === -1 ? line : line.slice(0, separator);
|
|
39957
|
+
let value = separator === -1 ? "" : line.slice(separator + 1);
|
|
39958
|
+
if (value.startsWith(" ")) {
|
|
39959
|
+
value = value.slice(1);
|
|
39960
|
+
}
|
|
39961
|
+
if (field === "event") {
|
|
39962
|
+
eventName = value;
|
|
39963
|
+
} else if (field === "data") {
|
|
39964
|
+
data.push(value);
|
|
39965
|
+
}
|
|
39966
|
+
}
|
|
39967
|
+
return {
|
|
39968
|
+
...eventName === void 0 ? {} : { event: eventName },
|
|
39969
|
+
data: data.join("\n")
|
|
39970
|
+
};
|
|
39971
|
+
}
|
|
39972
|
+
function linkAbortSignal(signal, controller) {
|
|
39973
|
+
if (signal === void 0) {
|
|
39974
|
+
return () => void 0;
|
|
39975
|
+
}
|
|
39976
|
+
const abort = () => controller.abort(signal.reason);
|
|
39977
|
+
if (signal.aborted) {
|
|
39978
|
+
abort();
|
|
39979
|
+
return () => void 0;
|
|
39980
|
+
}
|
|
39981
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
39982
|
+
return () => signal.removeEventListener("abort", abort);
|
|
39983
|
+
}
|
|
39984
|
+
function positiveInteger(value, name) {
|
|
39985
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
39986
|
+
throw new TypeError(`${name} must be a positive integer`);
|
|
39987
|
+
}
|
|
39988
|
+
return value;
|
|
39989
|
+
}
|
|
39990
|
+
var OPENAI_RESPONSES_URL = "https://api.openai.com/v1/responses";
|
|
39991
|
+
var CHATGPT_CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
39992
|
+
var DEFAULT_MAX_UPSTREAM_BODY_BYTES = 64 * 1024 * 1024;
|
|
39993
|
+
var DEFAULT_UPSTREAM_IDLE_TIMEOUT_MS = 3e4;
|
|
39994
|
+
var CHATGPT_UNSUPPORTED_FIELDS = [
|
|
39995
|
+
"max_output_tokens",
|
|
39996
|
+
"temperature",
|
|
39997
|
+
"top_p",
|
|
39998
|
+
"stop",
|
|
39999
|
+
"user",
|
|
40000
|
+
"metadata"
|
|
40001
|
+
];
|
|
40253
40002
|
var OpenAIResponsesAdapter = class {
|
|
40254
40003
|
capabilities = { nativeTools: ["web_search"] };
|
|
40255
40004
|
fetchImpl;
|
|
@@ -40396,38 +40145,6 @@ function forChatGptBackend(request) {
|
|
|
40396
40145
|
copy.store = false;
|
|
40397
40146
|
return copy;
|
|
40398
40147
|
}
|
|
40399
|
-
async function readBoundedBody(body, options) {
|
|
40400
|
-
if (body === null) {
|
|
40401
|
-
return new Uint8Array();
|
|
40402
|
-
}
|
|
40403
|
-
const reader = body.getReader();
|
|
40404
|
-
const chunks = [];
|
|
40405
|
-
let byteLength3 = 0;
|
|
40406
|
-
try {
|
|
40407
|
-
while (true) {
|
|
40408
|
-
const result = await readWithIdleTimeout(reader, options);
|
|
40409
|
-
if (result.done) {
|
|
40410
|
-
break;
|
|
40411
|
-
}
|
|
40412
|
-
byteLength3 += result.value.byteLength;
|
|
40413
|
-
if (byteLength3 > options.maxBodyBytes) {
|
|
40414
|
-
const error51 = new UpstreamBodyLimitError(options.maxBodyBytes);
|
|
40415
|
-
options.controller.abort(error51);
|
|
40416
|
-
throw error51;
|
|
40417
|
-
}
|
|
40418
|
-
chunks.push(result.value);
|
|
40419
|
-
}
|
|
40420
|
-
} finally {
|
|
40421
|
-
await reader.cancel().catch(() => void 0);
|
|
40422
|
-
}
|
|
40423
|
-
const bodyBytes = new Uint8Array(byteLength3);
|
|
40424
|
-
let offset = 0;
|
|
40425
|
-
for (const chunk of chunks) {
|
|
40426
|
-
bodyBytes.set(chunk, offset);
|
|
40427
|
-
offset += chunk.byteLength;
|
|
40428
|
-
}
|
|
40429
|
-
return bodyBytes;
|
|
40430
|
-
}
|
|
40431
40148
|
async function* parseOpenAIEventStream(body, options) {
|
|
40432
40149
|
if (body === null) {
|
|
40433
40150
|
options.onClose();
|
|
@@ -40473,71 +40190,14 @@ async function* parseOpenAIEventStream(body, options) {
|
|
|
40473
40190
|
options.onClose();
|
|
40474
40191
|
}
|
|
40475
40192
|
}
|
|
40476
|
-
async function readWithIdleTimeout(reader, options) {
|
|
40477
|
-
return await new Promise((resolve3, reject) => {
|
|
40478
|
-
let settled = false;
|
|
40479
|
-
const finish = (callback, value) => {
|
|
40480
|
-
if (settled) {
|
|
40481
|
-
return;
|
|
40482
|
-
}
|
|
40483
|
-
settled = true;
|
|
40484
|
-
clearTimeout(timeout);
|
|
40485
|
-
options.controller.signal.removeEventListener("abort", abort);
|
|
40486
|
-
callback(value);
|
|
40487
|
-
};
|
|
40488
|
-
const abort = () => {
|
|
40489
|
-
const reason = options.controller.signal.reason instanceof Error ? options.controller.signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
40490
|
-
void reader.cancel(reason).catch(() => void 0);
|
|
40491
|
-
finish(reject, reason);
|
|
40492
|
-
};
|
|
40493
|
-
const timeout = setTimeout(() => {
|
|
40494
|
-
const error51 = new UpstreamIdleTimeoutError(options.idleTimeoutMs);
|
|
40495
|
-
options.controller.abort(error51);
|
|
40496
|
-
}, options.idleTimeoutMs);
|
|
40497
|
-
options.controller.signal.addEventListener("abort", abort, { once: true });
|
|
40498
|
-
if (options.controller.signal.aborted) {
|
|
40499
|
-
abort();
|
|
40500
|
-
return;
|
|
40501
|
-
}
|
|
40502
|
-
reader.read().then(
|
|
40503
|
-
(result) => {
|
|
40504
|
-
finish(resolve3, result);
|
|
40505
|
-
},
|
|
40506
|
-
(error51) => {
|
|
40507
|
-
finish(reject, error51);
|
|
40508
|
-
}
|
|
40509
|
-
);
|
|
40510
|
-
});
|
|
40511
|
-
}
|
|
40512
|
-
function nextEventBoundary(buffer) {
|
|
40513
|
-
const match = /\r\n\r\n|\n\n|\r\r/.exec(buffer);
|
|
40514
|
-
return match === null ? void 0 : { index: match.index, length: match[0].length };
|
|
40515
|
-
}
|
|
40516
40193
|
function parseEventFrame(frame) {
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
for (const line of frame.split(/\r\n|\n|\r/)) {
|
|
40520
|
-
if (line.startsWith(":")) {
|
|
40521
|
-
continue;
|
|
40522
|
-
}
|
|
40523
|
-
const separator = line.indexOf(":");
|
|
40524
|
-
const field = separator === -1 ? line : line.slice(0, separator);
|
|
40525
|
-
let value = separator === -1 ? "" : line.slice(separator + 1);
|
|
40526
|
-
if (value.startsWith(" ")) {
|
|
40527
|
-
value = value.slice(1);
|
|
40528
|
-
}
|
|
40529
|
-
if (field === "event") {
|
|
40530
|
-
eventName = value;
|
|
40531
|
-
} else if (field === "data") {
|
|
40532
|
-
data.push(value);
|
|
40533
|
-
}
|
|
40534
|
-
}
|
|
40535
|
-
if (data.length === 0 || data.join("\n") === "[DONE]") {
|
|
40194
|
+
const { event: eventName, data } = parseSseFrameFields(frame);
|
|
40195
|
+
if (data.length === 0 || data === "[DONE]") {
|
|
40536
40196
|
return void 0;
|
|
40537
40197
|
}
|
|
40538
40198
|
let parsed;
|
|
40539
40199
|
try {
|
|
40540
|
-
parsed = JSON.parse(data
|
|
40200
|
+
parsed = JSON.parse(data);
|
|
40541
40201
|
} catch (error51) {
|
|
40542
40202
|
throw new UpstreamProtocolError(
|
|
40543
40203
|
`OpenAI SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
@@ -40669,7 +40329,6 @@ var STRICT_ALLOWED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
40669
40329
|
"$ref",
|
|
40670
40330
|
"description",
|
|
40671
40331
|
"title",
|
|
40672
|
-
"format",
|
|
40673
40332
|
"pattern",
|
|
40674
40333
|
"minimum",
|
|
40675
40334
|
"maximum",
|
|
@@ -40682,7 +40341,8 @@ var STRICT_ALLOWED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
40682
40341
|
"maxItems",
|
|
40683
40342
|
// Dropped by `strictSchema` before the schema reaches the wire.
|
|
40684
40343
|
"$schema",
|
|
40685
|
-
"default"
|
|
40344
|
+
"default",
|
|
40345
|
+
"format"
|
|
40686
40346
|
]);
|
|
40687
40347
|
function strictCompatible(schema) {
|
|
40688
40348
|
if (!isRecord42(schema)) return true;
|
|
@@ -40721,11 +40381,19 @@ function strictSchema(schema) {
|
|
|
40721
40381
|
const next = { ...schema };
|
|
40722
40382
|
delete next.$schema;
|
|
40723
40383
|
delete next.default;
|
|
40384
|
+
delete next.format;
|
|
40724
40385
|
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
40725
40386
|
const branches = next[key];
|
|
40726
40387
|
if (Array.isArray(branches)) next[key] = branches.map(strictSchema);
|
|
40727
40388
|
}
|
|
40728
40389
|
if (isRecord42(next.items)) next.items = strictSchema(next.items);
|
|
40390
|
+
if (isRecord42(next.$defs)) {
|
|
40391
|
+
const rewrittenDefs = {};
|
|
40392
|
+
for (const [name, value] of Object.entries(next.$defs)) {
|
|
40393
|
+
rewrittenDefs[name] = strictSchema(value);
|
|
40394
|
+
}
|
|
40395
|
+
next.$defs = rewrittenDefs;
|
|
40396
|
+
}
|
|
40729
40397
|
const properties = next.properties;
|
|
40730
40398
|
if (isRecord42(properties)) {
|
|
40731
40399
|
const required2 = new Set(
|
|
@@ -40775,10 +40443,15 @@ function withoutNulls(value) {
|
|
|
40775
40443
|
const out = {};
|
|
40776
40444
|
for (const [key, entry] of Object.entries(value)) {
|
|
40777
40445
|
if (entry === null) continue;
|
|
40778
|
-
out[key] =
|
|
40446
|
+
out[key] = withoutNullMembers(entry);
|
|
40779
40447
|
}
|
|
40780
40448
|
return out;
|
|
40781
40449
|
}
|
|
40450
|
+
function withoutNullMembers(entry) {
|
|
40451
|
+
if (isRecord42(entry)) return withoutNulls(entry);
|
|
40452
|
+
if (Array.isArray(entry)) return entry.map(withoutNullMembers);
|
|
40453
|
+
return entry;
|
|
40454
|
+
}
|
|
40782
40455
|
function outputItem(value) {
|
|
40783
40456
|
const item = record2(value, "item");
|
|
40784
40457
|
if (item.type === "message") {
|
|
@@ -40866,24 +40539,6 @@ function canonicalError(value) {
|
|
|
40866
40539
|
const type = typeof error51.type === "string" && error51.type !== "error" ? error51.type : typeof error51.code === "string" ? error51.code : "api_error";
|
|
40867
40540
|
return { type, message };
|
|
40868
40541
|
}
|
|
40869
|
-
function linkAbortSignal(signal, controller) {
|
|
40870
|
-
if (signal === void 0) {
|
|
40871
|
-
return () => void 0;
|
|
40872
|
-
}
|
|
40873
|
-
const abort = () => controller.abort(signal.reason);
|
|
40874
|
-
if (signal.aborted) {
|
|
40875
|
-
abort();
|
|
40876
|
-
return () => void 0;
|
|
40877
|
-
}
|
|
40878
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
40879
|
-
return () => signal.removeEventListener("abort", abort);
|
|
40880
|
-
}
|
|
40881
|
-
function positiveInteger(value, name) {
|
|
40882
|
-
if (!Number.isInteger(value) || value <= 0) {
|
|
40883
|
-
throw new TypeError(`${name} must be a positive integer`);
|
|
40884
|
-
}
|
|
40885
|
-
return value;
|
|
40886
|
-
}
|
|
40887
40542
|
function isRecord42(value) {
|
|
40888
40543
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40889
40544
|
}
|
|
@@ -43297,6 +42952,478 @@ async function resolveCodexCredentials(deps) {
|
|
|
43297
42952
|
return null;
|
|
43298
42953
|
}
|
|
43299
42954
|
}
|
|
42955
|
+
var DEFAULT_CHAT_MAX_UPSTREAM_BODY_BYTES = 64 * 1024 * 1024;
|
|
42956
|
+
var DEFAULT_CHAT_UPSTREAM_IDLE_TIMEOUT_MS = 3e4;
|
|
42957
|
+
var OpenAIChatCompletionsAdapter = class {
|
|
42958
|
+
fetchImpl;
|
|
42959
|
+
maxBodyBytes;
|
|
42960
|
+
idleTimeoutMs;
|
|
42961
|
+
url;
|
|
42962
|
+
extraHeaders;
|
|
42963
|
+
constructor(options) {
|
|
42964
|
+
this.url = options.url;
|
|
42965
|
+
this.extraHeaders = options.headers ?? {};
|
|
42966
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
42967
|
+
this.maxBodyBytes = positiveInteger(
|
|
42968
|
+
options.maxBodyBytes ?? DEFAULT_CHAT_MAX_UPSTREAM_BODY_BYTES,
|
|
42969
|
+
"maxBodyBytes"
|
|
42970
|
+
);
|
|
42971
|
+
this.idleTimeoutMs = positiveInteger(
|
|
42972
|
+
options.idleTimeoutMs ?? DEFAULT_CHAT_UPSTREAM_IDLE_TIMEOUT_MS,
|
|
42973
|
+
"idleTimeoutMs"
|
|
42974
|
+
);
|
|
42975
|
+
}
|
|
42976
|
+
async stream(request, options) {
|
|
42977
|
+
if (options.apiKey.length === 0) {
|
|
42978
|
+
throw new TypeError("apiKey must not be empty");
|
|
42979
|
+
}
|
|
42980
|
+
const controller = new AbortController();
|
|
42981
|
+
const unlinkAbort = linkAbortSignal(options.signal, controller);
|
|
42982
|
+
const payload = forChatCompletionsBackend(request);
|
|
42983
|
+
wireLog("openai-chat.wire.request", { url: this.url, payload });
|
|
42984
|
+
let response;
|
|
42985
|
+
try {
|
|
42986
|
+
response = await this.fetchImpl(this.url, {
|
|
42987
|
+
method: "POST",
|
|
42988
|
+
headers: {
|
|
42989
|
+
accept: "text/event-stream",
|
|
42990
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
42991
|
+
"content-type": "application/json",
|
|
42992
|
+
...this.extraHeaders
|
|
42993
|
+
},
|
|
42994
|
+
body: JSON.stringify(payload),
|
|
42995
|
+
signal: controller.signal
|
|
42996
|
+
});
|
|
42997
|
+
} catch (error51) {
|
|
42998
|
+
unlinkAbort();
|
|
42999
|
+
throw error51;
|
|
43000
|
+
}
|
|
43001
|
+
const readOptions = {
|
|
43002
|
+
controller,
|
|
43003
|
+
idleTimeoutMs: this.idleTimeoutMs,
|
|
43004
|
+
maxBodyBytes: this.maxBodyBytes
|
|
43005
|
+
};
|
|
43006
|
+
if (!response.ok) {
|
|
43007
|
+
try {
|
|
43008
|
+
const body = await readBoundedBody(response.body, readOptions);
|
|
43009
|
+
return { ok: false, status: response.status, headers: response.headers, body };
|
|
43010
|
+
} finally {
|
|
43011
|
+
unlinkAbort();
|
|
43012
|
+
}
|
|
43013
|
+
}
|
|
43014
|
+
return {
|
|
43015
|
+
ok: true,
|
|
43016
|
+
status: response.status,
|
|
43017
|
+
headers: response.headers,
|
|
43018
|
+
events: translateChatCompletionsStream(response.body, {
|
|
43019
|
+
...readOptions,
|
|
43020
|
+
onClose: unlinkAbort
|
|
43021
|
+
})
|
|
43022
|
+
};
|
|
43023
|
+
}
|
|
43024
|
+
};
|
|
43025
|
+
function forChatCompletionsBackend(request) {
|
|
43026
|
+
const messages = [];
|
|
43027
|
+
if (request.instructions !== void 0 && request.instructions.length > 0) {
|
|
43028
|
+
messages.push({ role: "system", content: request.instructions });
|
|
43029
|
+
}
|
|
43030
|
+
let pendingToolCalls = [];
|
|
43031
|
+
let pendingAssistantText;
|
|
43032
|
+
let deferredMessages = [];
|
|
43033
|
+
const flushToolCalls = () => {
|
|
43034
|
+
if (pendingToolCalls.length === 0) return;
|
|
43035
|
+
messages.push({
|
|
43036
|
+
role: "assistant",
|
|
43037
|
+
content: pendingAssistantText ?? null,
|
|
43038
|
+
tool_calls: pendingToolCalls
|
|
43039
|
+
});
|
|
43040
|
+
pendingToolCalls = [];
|
|
43041
|
+
pendingAssistantText = void 0;
|
|
43042
|
+
};
|
|
43043
|
+
const flushDeferredMessages = () => {
|
|
43044
|
+
if (deferredMessages.length === 0) return;
|
|
43045
|
+
messages.push(...deferredMessages);
|
|
43046
|
+
deferredMessages = [];
|
|
43047
|
+
};
|
|
43048
|
+
for (const item of request.input) {
|
|
43049
|
+
if (item.type === "function_call") {
|
|
43050
|
+
flushDeferredMessages();
|
|
43051
|
+
pendingToolCalls.push({
|
|
43052
|
+
id: item.call_id,
|
|
43053
|
+
type: "function",
|
|
43054
|
+
function: { name: item.name, arguments: item.arguments }
|
|
43055
|
+
});
|
|
43056
|
+
continue;
|
|
43057
|
+
}
|
|
43058
|
+
if (item.type === "function_call_output") {
|
|
43059
|
+
flushToolCalls();
|
|
43060
|
+
messages.push({ role: "tool", tool_call_id: item.call_id, content: item.output });
|
|
43061
|
+
continue;
|
|
43062
|
+
}
|
|
43063
|
+
if (pendingToolCalls.length > 0) {
|
|
43064
|
+
if (item.role === "assistant") {
|
|
43065
|
+
const text2 = canonicalMessageText(item.content);
|
|
43066
|
+
if (text2.length > 0) {
|
|
43067
|
+
pendingAssistantText = pendingAssistantText === void 0 ? text2 : `${pendingAssistantText}
|
|
43068
|
+
|
|
43069
|
+
${text2}`;
|
|
43070
|
+
}
|
|
43071
|
+
} else {
|
|
43072
|
+
deferredMessages.push(chatWireMessage(item));
|
|
43073
|
+
}
|
|
43074
|
+
continue;
|
|
43075
|
+
}
|
|
43076
|
+
flushDeferredMessages();
|
|
43077
|
+
messages.push(chatWireMessage(item));
|
|
43078
|
+
}
|
|
43079
|
+
flushToolCalls();
|
|
43080
|
+
flushDeferredMessages();
|
|
43081
|
+
const payload = {
|
|
43082
|
+
model: request.model,
|
|
43083
|
+
messages,
|
|
43084
|
+
stream: true,
|
|
43085
|
+
stream_options: { include_usage: true }
|
|
43086
|
+
};
|
|
43087
|
+
const tools = (request.tools ?? []).map((tool) => ({
|
|
43088
|
+
type: "function",
|
|
43089
|
+
function: {
|
|
43090
|
+
name: tool.name,
|
|
43091
|
+
...tool.description === void 0 ? {} : { description: tool.description },
|
|
43092
|
+
parameters: tool.parameters
|
|
43093
|
+
}
|
|
43094
|
+
}));
|
|
43095
|
+
if (tools.length > 0) {
|
|
43096
|
+
payload.tools = tools;
|
|
43097
|
+
}
|
|
43098
|
+
const toolChoice = request.tool_choice;
|
|
43099
|
+
if (toolChoice !== void 0) {
|
|
43100
|
+
payload.tool_choice = typeof toolChoice === "string" ? toolChoice : { type: "function", function: { name: toolChoice.name } };
|
|
43101
|
+
}
|
|
43102
|
+
if (request.parallel_tool_calls !== void 0 && tools.length > 0) {
|
|
43103
|
+
payload.parallel_tool_calls = request.parallel_tool_calls;
|
|
43104
|
+
}
|
|
43105
|
+
if (request.max_output_tokens !== void 0) {
|
|
43106
|
+
payload.max_tokens = request.max_output_tokens;
|
|
43107
|
+
}
|
|
43108
|
+
return payload;
|
|
43109
|
+
}
|
|
43110
|
+
function chatWireMessage(item) {
|
|
43111
|
+
const role = item.role === "developer" ? "system" : item.role;
|
|
43112
|
+
if (typeof item.content === "string") {
|
|
43113
|
+
return { role, content: item.content };
|
|
43114
|
+
}
|
|
43115
|
+
if (role !== "user") {
|
|
43116
|
+
return { role, content: canonicalMessageText(item.content) };
|
|
43117
|
+
}
|
|
43118
|
+
const parts = item.content.map((part) => {
|
|
43119
|
+
if (part.type === "input_text") {
|
|
43120
|
+
return { type: "text", text: part.text };
|
|
43121
|
+
}
|
|
43122
|
+
return {
|
|
43123
|
+
type: "image_url",
|
|
43124
|
+
image_url: {
|
|
43125
|
+
url: part.image_url,
|
|
43126
|
+
// Chat 와이어의 detail 집합에는 original이 없다. 축소 없이 보내는 데 가장
|
|
43127
|
+
// 가까운 값은 high다.
|
|
43128
|
+
...part.detail === void 0 ? {} : { detail: part.detail === "original" ? "high" : part.detail }
|
|
43129
|
+
}
|
|
43130
|
+
};
|
|
43131
|
+
});
|
|
43132
|
+
return { role, content: parts };
|
|
43133
|
+
}
|
|
43134
|
+
async function* translateChatCompletionsStream(body, options) {
|
|
43135
|
+
if (body === null) {
|
|
43136
|
+
options.onClose();
|
|
43137
|
+
throw new UpstreamProtocolError("Chat Completions streaming response had no body");
|
|
43138
|
+
}
|
|
43139
|
+
const reader = body.getReader();
|
|
43140
|
+
const decoder = new TextDecoder();
|
|
43141
|
+
let buffer = "";
|
|
43142
|
+
let byteLength3 = 0;
|
|
43143
|
+
let responseId;
|
|
43144
|
+
let responseModel;
|
|
43145
|
+
let createdEmitted = false;
|
|
43146
|
+
let textSeen = false;
|
|
43147
|
+
let accumulatedText = "";
|
|
43148
|
+
let usage2 = null;
|
|
43149
|
+
let failed = false;
|
|
43150
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
43151
|
+
const MESSAGE_ITEM_ID = "chat_message_0";
|
|
43152
|
+
function* consumeChunk(value) {
|
|
43153
|
+
if (!isRecord7(value)) {
|
|
43154
|
+
throw new UpstreamProtocolError("Chat Completions SSE event was not an object");
|
|
43155
|
+
}
|
|
43156
|
+
if (isRecord7(value.error)) {
|
|
43157
|
+
failed = true;
|
|
43158
|
+
yield { type: "error", error: chatCanonicalError(value.error) };
|
|
43159
|
+
return;
|
|
43160
|
+
}
|
|
43161
|
+
if (typeof value.id === "string" && responseId === void 0) {
|
|
43162
|
+
responseId = value.id;
|
|
43163
|
+
}
|
|
43164
|
+
if (typeof value.model === "string" && responseModel === void 0) {
|
|
43165
|
+
responseModel = value.model;
|
|
43166
|
+
}
|
|
43167
|
+
if (!createdEmitted) {
|
|
43168
|
+
createdEmitted = true;
|
|
43169
|
+
yield {
|
|
43170
|
+
type: "response.created",
|
|
43171
|
+
response: {
|
|
43172
|
+
id: responseId ?? "chat_response",
|
|
43173
|
+
model: responseModel ?? "",
|
|
43174
|
+
usage: null
|
|
43175
|
+
}
|
|
43176
|
+
};
|
|
43177
|
+
}
|
|
43178
|
+
if (isRecord7(value.usage)) {
|
|
43179
|
+
usage2 = chatUsage(value.usage);
|
|
43180
|
+
}
|
|
43181
|
+
const choices = Array.isArray(value.choices) ? value.choices : [];
|
|
43182
|
+
for (const choice of choices) {
|
|
43183
|
+
if (!isRecord7(choice)) continue;
|
|
43184
|
+
const delta = isRecord7(choice.delta) ? choice.delta : {};
|
|
43185
|
+
if (typeof delta.content === "string" && delta.content.length > 0) {
|
|
43186
|
+
textSeen = true;
|
|
43187
|
+
accumulatedText += delta.content;
|
|
43188
|
+
yield {
|
|
43189
|
+
type: "response.output_text.delta",
|
|
43190
|
+
item_id: MESSAGE_ITEM_ID,
|
|
43191
|
+
output_index: 0,
|
|
43192
|
+
content_index: 0,
|
|
43193
|
+
delta: delta.content
|
|
43194
|
+
};
|
|
43195
|
+
}
|
|
43196
|
+
const wireToolCalls = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
43197
|
+
for (const call of wireToolCalls) {
|
|
43198
|
+
if (!isRecord7(call)) continue;
|
|
43199
|
+
const index = typeof call.index === "number" ? call.index : 0;
|
|
43200
|
+
const pending = toolCalls.get(index) ?? { arguments: "" };
|
|
43201
|
+
if (typeof call.id === "string" && call.id.length > 0) {
|
|
43202
|
+
pending.id ??= call.id;
|
|
43203
|
+
}
|
|
43204
|
+
const fn = isRecord7(call.function) ? call.function : {};
|
|
43205
|
+
if (typeof fn.name === "string" && fn.name.length > 0) {
|
|
43206
|
+
pending.name ??= fn.name;
|
|
43207
|
+
}
|
|
43208
|
+
if (typeof fn.arguments === "string") {
|
|
43209
|
+
pending.arguments += fn.arguments;
|
|
43210
|
+
}
|
|
43211
|
+
toolCalls.set(index, pending);
|
|
43212
|
+
}
|
|
43213
|
+
}
|
|
43214
|
+
}
|
|
43215
|
+
function* finish() {
|
|
43216
|
+
if (failed) return;
|
|
43217
|
+
if (!createdEmitted) {
|
|
43218
|
+
createdEmitted = true;
|
|
43219
|
+
yield {
|
|
43220
|
+
type: "response.created",
|
|
43221
|
+
response: { id: responseId ?? "chat_response", model: responseModel ?? "", usage: null }
|
|
43222
|
+
};
|
|
43223
|
+
}
|
|
43224
|
+
if (textSeen) {
|
|
43225
|
+
yield {
|
|
43226
|
+
type: "response.output_text.done",
|
|
43227
|
+
item_id: MESSAGE_ITEM_ID,
|
|
43228
|
+
output_index: 0,
|
|
43229
|
+
content_index: 0,
|
|
43230
|
+
text: accumulatedText
|
|
43231
|
+
};
|
|
43232
|
+
}
|
|
43233
|
+
let outputIndex = 1;
|
|
43234
|
+
for (const [index, pending] of [...toolCalls.entries()].sort(([a], [b]) => a - b)) {
|
|
43235
|
+
if (pending.name === void 0) {
|
|
43236
|
+
throw new UpstreamProtocolError(`Chat Completions tool call ${index} ended without a name`);
|
|
43237
|
+
}
|
|
43238
|
+
const id = pending.id ?? `chat_call_${index}`;
|
|
43239
|
+
const item = {
|
|
43240
|
+
id,
|
|
43241
|
+
type: "function_call",
|
|
43242
|
+
call_id: id,
|
|
43243
|
+
name: pending.name,
|
|
43244
|
+
arguments: pending.arguments
|
|
43245
|
+
};
|
|
43246
|
+
yield { type: "response.output_item.added", output_index: outputIndex, item: { ...item, arguments: "" } };
|
|
43247
|
+
yield {
|
|
43248
|
+
type: "response.function_call_arguments.done",
|
|
43249
|
+
item_id: id,
|
|
43250
|
+
output_index: outputIndex,
|
|
43251
|
+
arguments: pending.arguments
|
|
43252
|
+
};
|
|
43253
|
+
yield { type: "response.output_item.done", output_index: outputIndex, item };
|
|
43254
|
+
outputIndex += 1;
|
|
43255
|
+
}
|
|
43256
|
+
yield {
|
|
43257
|
+
type: "response.completed",
|
|
43258
|
+
response: {
|
|
43259
|
+
id: responseId ?? "chat_response",
|
|
43260
|
+
model: responseModel ?? "",
|
|
43261
|
+
// 하류 message_delta는 usage가 필수다. include_usage에도 usage 청크를 주지
|
|
43262
|
+
// 않는 백엔드에서는 0-usage로 완결하고, 실제 회계는 provider 콘솔이 맡는다.
|
|
43263
|
+
usage: usage2 ?? { input_tokens: 0, output_tokens: 0 }
|
|
43264
|
+
}
|
|
43265
|
+
};
|
|
43266
|
+
}
|
|
43267
|
+
try {
|
|
43268
|
+
while (true) {
|
|
43269
|
+
const result = await readWithIdleTimeout(reader, options);
|
|
43270
|
+
if (result.done) {
|
|
43271
|
+
buffer += decoder.decode();
|
|
43272
|
+
break;
|
|
43273
|
+
}
|
|
43274
|
+
byteLength3 += result.value.byteLength;
|
|
43275
|
+
if (byteLength3 > options.maxBodyBytes) {
|
|
43276
|
+
const error51 = new UpstreamBodyLimitError(options.maxBodyBytes);
|
|
43277
|
+
options.controller.abort(error51);
|
|
43278
|
+
throw error51;
|
|
43279
|
+
}
|
|
43280
|
+
buffer += decoder.decode(result.value, { stream: true });
|
|
43281
|
+
let boundary = nextEventBoundary(buffer);
|
|
43282
|
+
while (boundary !== void 0) {
|
|
43283
|
+
const frame = buffer.slice(0, boundary.index);
|
|
43284
|
+
buffer = buffer.slice(boundary.index + boundary.length);
|
|
43285
|
+
const data = chatFrameData(frame);
|
|
43286
|
+
if (data !== void 0) {
|
|
43287
|
+
yield* consumeChunk(data);
|
|
43288
|
+
}
|
|
43289
|
+
boundary = nextEventBoundary(buffer);
|
|
43290
|
+
}
|
|
43291
|
+
}
|
|
43292
|
+
if (buffer.trim().length > 0) {
|
|
43293
|
+
const data = chatFrameData(buffer);
|
|
43294
|
+
if (data !== void 0) {
|
|
43295
|
+
yield* consumeChunk(data);
|
|
43296
|
+
}
|
|
43297
|
+
}
|
|
43298
|
+
yield* finish();
|
|
43299
|
+
} finally {
|
|
43300
|
+
await reader.cancel().catch(() => void 0);
|
|
43301
|
+
options.onClose();
|
|
43302
|
+
}
|
|
43303
|
+
}
|
|
43304
|
+
function chatFrameData(frame) {
|
|
43305
|
+
const { data } = parseSseFrameFields(frame);
|
|
43306
|
+
if (data.length === 0 || data === "[DONE]") {
|
|
43307
|
+
return void 0;
|
|
43308
|
+
}
|
|
43309
|
+
try {
|
|
43310
|
+
return JSON.parse(data);
|
|
43311
|
+
} catch (error51) {
|
|
43312
|
+
throw new UpstreamProtocolError(
|
|
43313
|
+
`Chat Completions SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
43314
|
+
);
|
|
43315
|
+
}
|
|
43316
|
+
}
|
|
43317
|
+
function chatUsage(value) {
|
|
43318
|
+
const inputTokens = nonNegativeOrZero(value.prompt_tokens);
|
|
43319
|
+
const outputTokens = nonNegativeOrZero(value.completion_tokens);
|
|
43320
|
+
const promptDetails = isRecord7(value.prompt_tokens_details) ? value.prompt_tokens_details : void 0;
|
|
43321
|
+
const completionDetails = isRecord7(value.completion_tokens_details) ? value.completion_tokens_details : void 0;
|
|
43322
|
+
const cachedInputTokens = promptDetails === void 0 ? void 0 : optionalNonNegative(promptDetails.cached_tokens);
|
|
43323
|
+
const reasoningOutputTokens = completionDetails === void 0 ? void 0 : optionalNonNegative(completionDetails.reasoning_tokens);
|
|
43324
|
+
const totalTokens = optionalNonNegative(value.total_tokens);
|
|
43325
|
+
return {
|
|
43326
|
+
input_tokens: inputTokens,
|
|
43327
|
+
output_tokens: outputTokens,
|
|
43328
|
+
...cachedInputTokens === void 0 ? {} : { cached_input_tokens: cachedInputTokens },
|
|
43329
|
+
...reasoningOutputTokens === void 0 ? {} : { reasoning_output_tokens: reasoningOutputTokens },
|
|
43330
|
+
...totalTokens === void 0 ? {} : { total_tokens: totalTokens }
|
|
43331
|
+
};
|
|
43332
|
+
}
|
|
43333
|
+
function chatCanonicalError(error51) {
|
|
43334
|
+
const message = typeof error51.message === "string" ? error51.message : JSON.stringify(error51);
|
|
43335
|
+
const type = typeof error51.type === "string" && error51.type !== "error" ? error51.type : typeof error51.code === "string" ? error51.code : "api_error";
|
|
43336
|
+
return { type, message };
|
|
43337
|
+
}
|
|
43338
|
+
function nonNegativeOrZero(value) {
|
|
43339
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
43340
|
+
}
|
|
43341
|
+
function optionalNonNegative(value) {
|
|
43342
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
43343
|
+
}
|
|
43344
|
+
function isRecord7(value) {
|
|
43345
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43346
|
+
}
|
|
43347
|
+
var OPENCODE_AUTH_PROVIDER_ID = "Claude Code with OpenCode Go";
|
|
43348
|
+
var OPENCODE_GO_API_BASE_URL = "https://opencode.ai/zen/go";
|
|
43349
|
+
var OPENCODE_GO_MODEL = "minimax-m2.5";
|
|
43350
|
+
var OPENCODE_GO_MESSAGES_URL = `${OPENCODE_GO_API_BASE_URL}/v1/messages`;
|
|
43351
|
+
var OPENCODE_GO_RESPONSES_URL = `${OPENCODE_GO_API_BASE_URL}/v1/responses`;
|
|
43352
|
+
var OPENCODE_GO_CHAT_COMPLETIONS_URL = `${OPENCODE_GO_API_BASE_URL}/v1/chat/completions`;
|
|
43353
|
+
function opencodeGoWire(model) {
|
|
43354
|
+
return model.wire ?? "anthropic";
|
|
43355
|
+
}
|
|
43356
|
+
function createOpencodeGoAdapter(wire, options = {}) {
|
|
43357
|
+
if (wire === "responses") {
|
|
43358
|
+
return new OpenAIResponsesAdapter({
|
|
43359
|
+
url: OPENCODE_GO_RESPONSES_URL,
|
|
43360
|
+
...options.fetch ? { fetch: options.fetch } : {}
|
|
43361
|
+
});
|
|
43362
|
+
}
|
|
43363
|
+
return new OpenAIChatCompletionsAdapter({
|
|
43364
|
+
url: OPENCODE_GO_CHAT_COMPLETIONS_URL,
|
|
43365
|
+
...options.fetch ? { fetch: options.fetch } : {}
|
|
43366
|
+
});
|
|
43367
|
+
}
|
|
43368
|
+
|
|
43369
|
+
// ../../packages/fleet-admiral/src/agent-cli/gateway-agents.ts
|
|
43370
|
+
var GENERAL_PURPOSE_AGENT_PROMPT = [
|
|
43371
|
+
"You are a Fleet execution agent. Do the assigned work directly; do not re-delegate the whole assignment.",
|
|
43372
|
+
'Treat host objective/scope/constraints/references as binding contracts. Do not silently re-plan, expand scope, or substitute a "cleaner" design \u2014 finish as instructed, then optionally suggest alternatives. On ambiguity or conflict, stop and report the blocker instead of guessing.',
|
|
43373
|
+
"",
|
|
43374
|
+
"Pick ONE mode from the task and stay in it:",
|
|
43375
|
+
"- recon: read-only facts; least-invasive evidence path; cite path:line",
|
|
43376
|
+
"- decide: read-only; one simplest viable recommendation; no implementation checklist",
|
|
43377
|
+
"- implement: edit within scope; verify what you changed; report compliance and any deviations",
|
|
43378
|
+
"- verify: hunt real defects with evidence+impact; PASS/FAIL; fix only if asked",
|
|
43379
|
+
"",
|
|
43380
|
+
"Search only as needed for the chosen mode. Prefer known paths over broad sweeps. Do not default to exhaustive multi-strategy hunting.",
|
|
43381
|
+
"NEVER create files unless they are absolutely necessary. ALWAYS prefer editing an existing file to creating a new one.",
|
|
43382
|
+
"NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested.",
|
|
43383
|
+
"Final reply: concise essentials only \u2014 mode, what changed or found, key evidence (path:line when relevant), and blockers/deviations."
|
|
43384
|
+
].join("\n");
|
|
43385
|
+
function buildGatewayCustomAgents(exposed) {
|
|
43386
|
+
const agents = {};
|
|
43387
|
+
for (const model of exposed) {
|
|
43388
|
+
const modelId = toClaudeGatewayModelId(model);
|
|
43389
|
+
const constraints = buildGatewayModelConstraints(model);
|
|
43390
|
+
if (constraints.effortSupported) {
|
|
43391
|
+
for (const effort of constraints.effortLadder) {
|
|
43392
|
+
const name2 = toGatewayAgentName(modelId, effort);
|
|
43393
|
+
agents[name2] = {
|
|
43394
|
+
description: gatewayAgentDescription(modelId, name2, effort),
|
|
43395
|
+
prompt: GENERAL_PURPOSE_AGENT_PROMPT,
|
|
43396
|
+
model: modelId,
|
|
43397
|
+
effort
|
|
43398
|
+
};
|
|
43399
|
+
}
|
|
43400
|
+
continue;
|
|
43401
|
+
}
|
|
43402
|
+
const name = toGatewayAgentName(modelId);
|
|
43403
|
+
agents[name] = {
|
|
43404
|
+
description: gatewayAgentDescription(modelId, name),
|
|
43405
|
+
prompt: GENERAL_PURPOSE_AGENT_PROMPT,
|
|
43406
|
+
model: modelId
|
|
43407
|
+
};
|
|
43408
|
+
}
|
|
43409
|
+
return agents;
|
|
43410
|
+
}
|
|
43411
|
+
function toGatewayAgentName(modelId, effort) {
|
|
43412
|
+
const stripped = modelId.startsWith("claude-gateway--") ? modelId.slice("claude-gateway--".length) : modelId;
|
|
43413
|
+
const base = stripped.replace(/\[1m\]/g, "-1m").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
43414
|
+
const stem = base.length > 0 ? base : "model";
|
|
43415
|
+
return effort === void 0 ? stem : `${stem}-${effort}`;
|
|
43416
|
+
}
|
|
43417
|
+
function gatewayAgentDescription(modelId, name, effort) {
|
|
43418
|
+
const effortPart = effort === void 0 ? "no effort control" : `effort ${effort}`;
|
|
43419
|
+
return [
|
|
43420
|
+
`Gateway model ${modelId}, ${effortPart}.`,
|
|
43421
|
+
"Fleet execution agent that runs one mode \u2014 recon, decide, implement, or verify. Name the mode in the task.",
|
|
43422
|
+
"Use after calling gateway_models when this roster entry fits the stage.",
|
|
43423
|
+
`Select this identity by the agent type name ${name}. The model id above is a value for a model field and is rejected wherever a name is expected.`,
|
|
43424
|
+
...effort === void 0 ? [] : [`That name already carries ${effort}, so pinning a reasoning effort alongside it is redundant.`]
|
|
43425
|
+
].join(" ");
|
|
43426
|
+
}
|
|
43300
43427
|
|
|
43301
43428
|
// ../../packages/fleet-admiral/src/ai-gateway/role-fit.ts
|
|
43302
43429
|
var ROLE_FIT = Object.freeze({
|
|
@@ -43363,37 +43490,115 @@ function gatewayRoleFit(identity) {
|
|
|
43363
43490
|
var UNSUPPORTED_QUOTA = Object.freeze({ status: "unsupported" });
|
|
43364
43491
|
var PARENT_PROVIDER_ID = "claude";
|
|
43365
43492
|
function buildGatewayLoadout(input) {
|
|
43366
|
-
const
|
|
43493
|
+
const placed = input.exposed.map((model) => ({
|
|
43494
|
+
provider: model.provider,
|
|
43495
|
+
entry: toLoadoutModel(model, input.defaultModel)
|
|
43496
|
+
}));
|
|
43367
43497
|
return {
|
|
43368
|
-
revision: loadoutRevision(
|
|
43498
|
+
revision: loadoutRevision(placed.map(({ entry }) => entry)),
|
|
43369
43499
|
catalogUpdatedAt: GATEWAY_MODELS_UPDATED_AT,
|
|
43370
|
-
|
|
43371
|
-
providers: buildProviders(input.exposed, input.quota)
|
|
43500
|
+
providers: buildProviders(placed, input.quota, input.now ?? Date.now)
|
|
43372
43501
|
};
|
|
43373
43502
|
}
|
|
43374
43503
|
function toLoadoutModel(model, defaultModel) {
|
|
43504
|
+
const modelId = toClaudeGatewayModelId(model);
|
|
43505
|
+
const { provider: _provider, ...constraints } = buildGatewayModelConstraints(model);
|
|
43375
43506
|
return {
|
|
43376
|
-
|
|
43377
|
-
|
|
43378
|
-
constraints
|
|
43507
|
+
agentTypes: toAgentTypeSelectors(modelId, constraints),
|
|
43508
|
+
modelId,
|
|
43509
|
+
constraints,
|
|
43379
43510
|
roleFit: gatewayRoleFit(gatewayModelIdentity(model)) ?? null,
|
|
43380
43511
|
isSessionDefault: defaultModel !== void 0 && defaultModel.id === model.id
|
|
43381
43512
|
};
|
|
43382
43513
|
}
|
|
43383
|
-
function
|
|
43514
|
+
function toAgentTypeSelectors(id, constraints) {
|
|
43515
|
+
if (!constraints.effortSupported) {
|
|
43516
|
+
return Object.freeze({ none: toGatewayAgentName(id) });
|
|
43517
|
+
}
|
|
43518
|
+
return Object.freeze(Object.fromEntries(
|
|
43519
|
+
constraints.effortLadder.map((effort) => [effort, toGatewayAgentName(id, effort)])
|
|
43520
|
+
));
|
|
43521
|
+
}
|
|
43522
|
+
function buildProviders(placed, quota, now) {
|
|
43384
43523
|
const ids = [PARENT_PROVIDER_ID];
|
|
43385
|
-
for (const
|
|
43386
|
-
if (!ids.includes(
|
|
43524
|
+
for (const { provider } of placed) {
|
|
43525
|
+
if (!ids.includes(provider)) ids.push(provider);
|
|
43387
43526
|
}
|
|
43388
43527
|
for (const id of Object.keys(quota ?? {})) {
|
|
43389
43528
|
if (!ids.includes(id)) ids.push(id);
|
|
43390
43529
|
}
|
|
43391
|
-
return ids.map((id) =>
|
|
43530
|
+
return Object.freeze(Object.fromEntries(ids.map((id) => [id, {
|
|
43531
|
+
quota: enrichProviderQuota(quota?.[id], now) ?? UNSUPPORTED_QUOTA,
|
|
43532
|
+
models: Object.freeze(
|
|
43533
|
+
placed.filter((candidate) => candidate.provider === id).map(({ entry }) => entry)
|
|
43534
|
+
)
|
|
43535
|
+
}])));
|
|
43536
|
+
}
|
|
43537
|
+
var MS_PER_HOUR = 36e5;
|
|
43538
|
+
var CADENCE_SESSION_MAX_MS = 20 * MS_PER_HOUR;
|
|
43539
|
+
var CADENCE_DAILY_MAX_MS = 3 * 24 * MS_PER_HOUR;
|
|
43540
|
+
var CADENCE_WEEKLY_MAX_MS = 20 * 24 * MS_PER_HOUR;
|
|
43541
|
+
var MIN_ELAPSED_FRACTION = 0.05;
|
|
43542
|
+
var PACE_CRITICAL = 1.5;
|
|
43543
|
+
var PACE_ELEVATED = 1.1;
|
|
43544
|
+
var USED_CRITICAL_PERCENT = 95;
|
|
43545
|
+
var USED_ELEVATED_PERCENT = 80;
|
|
43546
|
+
function enrichProviderQuota(quota, now) {
|
|
43547
|
+
if (!quota) return void 0;
|
|
43548
|
+
const { windows, ...rest } = quota;
|
|
43549
|
+
if (!windows || windows.length === 0) return rest;
|
|
43550
|
+
const at = typeof quota.fetchedAt === "number" && Number.isFinite(quota.fetchedAt) ? quota.fetchedAt : now();
|
|
43551
|
+
return { ...rest, windows: windows.map((window) => enrichQuotaWindow(window, at)) };
|
|
43552
|
+
}
|
|
43553
|
+
function windowCadence(durationMs) {
|
|
43554
|
+
if (durationMs <= CADENCE_SESSION_MAX_MS) return "session";
|
|
43555
|
+
if (durationMs <= CADENCE_DAILY_MAX_MS) return "daily";
|
|
43556
|
+
if (durationMs <= CADENCE_WEEKLY_MAX_MS) return "weekly";
|
|
43557
|
+
return "monthly";
|
|
43558
|
+
}
|
|
43559
|
+
function windowPressure(usedPercent, paceRatio) {
|
|
43560
|
+
if (usedPercent >= USED_CRITICAL_PERCENT || paceRatio !== void 0 && paceRatio >= PACE_CRITICAL) {
|
|
43561
|
+
return "critical";
|
|
43562
|
+
}
|
|
43563
|
+
if (usedPercent >= USED_ELEVATED_PERCENT || paceRatio !== void 0 && paceRatio >= PACE_ELEVATED) {
|
|
43564
|
+
return "elevated";
|
|
43565
|
+
}
|
|
43566
|
+
return "ok";
|
|
43567
|
+
}
|
|
43568
|
+
function enrichQuotaWindow(window, at) {
|
|
43569
|
+
const durationMs = window.period?.durationMs;
|
|
43570
|
+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs <= 0) {
|
|
43571
|
+
return { ...window, pressure: windowPressure(window.usedPercent, void 0) };
|
|
43572
|
+
}
|
|
43573
|
+
const startsAt = window.period?.startsAt ?? (window.resetsAt !== void 0 && window.resetsAt > durationMs ? window.resetsAt - durationMs : void 0);
|
|
43574
|
+
const resetBoundary = window.resetsAt ?? (startsAt !== void 0 ? startsAt + durationMs : void 0);
|
|
43575
|
+
const stale = resetBoundary !== void 0 && at > resetBoundary;
|
|
43576
|
+
let paceRatio;
|
|
43577
|
+
let projectedExhaustionAt;
|
|
43578
|
+
if (startsAt !== void 0 && resetBoundary !== void 0 && !stale && at > startsAt) {
|
|
43579
|
+
const elapsed = Math.min(1, (at - startsAt) / durationMs);
|
|
43580
|
+
if (elapsed >= MIN_ELAPSED_FRACTION) {
|
|
43581
|
+
const used = Math.min(1, Math.max(0, window.usedPercent / 100));
|
|
43582
|
+
paceRatio = Math.round(used / elapsed * 100) / 100;
|
|
43583
|
+
if (used > 0) {
|
|
43584
|
+
const exhaustionAt = startsAt + Math.round((at - startsAt) / used);
|
|
43585
|
+
if (exhaustionAt < resetBoundary) projectedExhaustionAt = exhaustionAt;
|
|
43586
|
+
}
|
|
43587
|
+
}
|
|
43588
|
+
}
|
|
43589
|
+
return {
|
|
43590
|
+
...window,
|
|
43591
|
+
cadence: windowCadence(durationMs),
|
|
43592
|
+
...paceRatio !== void 0 ? { paceRatio } : {},
|
|
43593
|
+
...projectedExhaustionAt !== void 0 ? { projectedExhaustionAt } : {},
|
|
43594
|
+
recoveryHalfLifeMs: Math.round(durationMs / 2),
|
|
43595
|
+
pressure: windowPressure(window.usedPercent, paceRatio)
|
|
43596
|
+
};
|
|
43392
43597
|
}
|
|
43393
43598
|
function loadoutRevision(models) {
|
|
43394
43599
|
const material = [
|
|
43395
43600
|
GATEWAY_MODELS_UPDATED_AT,
|
|
43396
|
-
...models.map((model) => `${model.
|
|
43601
|
+
...models.map((model) => `${model.modelId}:${model.isSessionDefault ? "1" : "0"}`).sort()
|
|
43397
43602
|
].join("\n");
|
|
43398
43603
|
return createHash("sha256").update(material).digest("hex").slice(0, 12);
|
|
43399
43604
|
}
|
|
@@ -43414,16 +43619,17 @@ var GATEWAY_MODELS_DOCTRINE = {
|
|
|
43414
43619
|
`Do not carry an earlier read forward as if it were still current. The revision tracks roster and default changes only, never allowance movement, so equal revisions do not mean equal quotas.`,
|
|
43415
43620
|
`Do not treat the response as a recommendation to act on unread. It reports facts; the choice and its justification stay with you.`
|
|
43416
43621
|
],
|
|
43622
|
+
// 이 목록은 필드 사전이 아니라 판정 규칙이다. 응답을 보면 알 수 있는 것은 빼고,
|
|
43623
|
+
// 틀리면 조용히 실패하는 것만 남긴다 — 길어질수록 읽히지 않고, 읽히지 않으면 없는 것과 같다.
|
|
43417
43624
|
usageGuidelines: [
|
|
43418
|
-
`
|
|
43419
|
-
`
|
|
43420
|
-
`
|
|
43421
|
-
`
|
|
43422
|
-
`
|
|
43423
|
-
`
|
|
43424
|
-
`
|
|
43425
|
-
`
|
|
43426
|
-
`constraints.identity collapses service-tier siblings, so a measurement recorded against one covers the other.`
|
|
43625
|
+
`Two spellings, never interchangeable. agentTypes names this identity once per reasoning rung, so selecting by name already carries the level and nothing further pins effort; modelId is the model as a value. Neither derives from the other \u2014 the transform behind a name collapses ".", "[1m]", and "--" all into "-". Prefer a name: a wrong name fails loudly, while modelId reaches whatever the catalog holds, including a model the user turned off, in silence.`,
|
|
43626
|
+
`Names are registered once at session start; this roster is re-read live. A model exposed mid-session therefore appears here under a name that will not resolve until a new session \u2014 that, and not a stale roster, is what an unknown-name failure means.`,
|
|
43627
|
+
`Each provider entry pairs one allowance with the exposed models it serves, so the window to read against a model is in the same entry. claude serves none by design: it is what an unpinned run spends, and the baseline an offload is measured against. A model in no entry is one the user turned off.`,
|
|
43628
|
+
`effortLadder is the whole set of levels that survive \u2014 anything outside it is clamped upstream with no signal, and some models have no effort control at all.`,
|
|
43629
|
+
`roleFit null means unmeasured, never unsuitable: quality then gives no reason to prefer an identity, so the choice falls to allowance and never back to this session's own model. homolineage marks shared lineage with that session \u2014 useful for moving spend, useless where independent judgement is the product.`,
|
|
43630
|
+
`Read pressure before doing arithmetic of your own; it is the verdict on one window, combining headroom with burn pace against that window's own clock, and it never says which model to choose. Compare usedPercent only within one cadence \u2014 a shared window id does not mean a shared length. Where a provider splits into pools, quotaScope picks the window that applies and the isAggregate one stays out of headroom math. recoveryHalfLifeMs prices the drain: weeks of lockout for a monthly window, hours for a session one.`,
|
|
43631
|
+
`Absence is never safety. A missing derived field means the reading could not support it, and status "unsupported" means the allowance could not be read at all.`,
|
|
43632
|
+
`The roster cannot tell which provider this session itself runs on \u2014 it is registered once per runtime \u2014 so make that match yourself and read that window. isSessionDefault reflects Settings as it stands now, not what an already-running session launched with.`
|
|
43427
43633
|
]
|
|
43428
43634
|
};
|
|
43429
43635
|
function buildGatewayModelsToolSpec(deps) {
|
|
@@ -43496,17 +43702,31 @@ function getExecutorMcpTools(registry4, carrierRuntime, carrierId) {
|
|
|
43496
43702
|
|
|
43497
43703
|
// ../../packages/fleet-admiral/src/ai-gateway/auth.ts
|
|
43498
43704
|
async function validateKimiAuthKey(apiKey) {
|
|
43499
|
-
|
|
43705
|
+
return validateAnthropicCompatibleAuthKey(apiKey, {
|
|
43500
43706
|
providerId: KIMI_AUTH_PROVIDER_ID,
|
|
43501
|
-
apiKey,
|
|
43502
43707
|
baseUrl: KIMI_CODE_API_BASE_URL,
|
|
43503
43708
|
model: KIMI_CODE_MODEL
|
|
43504
43709
|
});
|
|
43710
|
+
}
|
|
43711
|
+
async function validateOpencodeGoAuthKey(apiKey) {
|
|
43712
|
+
return validateAnthropicCompatibleAuthKey(apiKey, {
|
|
43713
|
+
providerId: OPENCODE_AUTH_PROVIDER_ID,
|
|
43714
|
+
baseUrl: OPENCODE_GO_API_BASE_URL,
|
|
43715
|
+
model: OPENCODE_GO_MODEL
|
|
43716
|
+
});
|
|
43717
|
+
}
|
|
43718
|
+
async function validateAnthropicCompatibleAuthKey(apiKey, coordinates) {
|
|
43719
|
+
const validation = await validateAnthropicCompatibleApiKey({
|
|
43720
|
+
providerId: coordinates.providerId,
|
|
43721
|
+
apiKey,
|
|
43722
|
+
baseUrl: coordinates.baseUrl,
|
|
43723
|
+
model: coordinates.model
|
|
43724
|
+
});
|
|
43505
43725
|
if (isAuthValidationSuccess(validation)) {
|
|
43506
|
-
return { providerId:
|
|
43726
|
+
return { providerId: coordinates.providerId, status: "success" };
|
|
43507
43727
|
}
|
|
43508
43728
|
return {
|
|
43509
|
-
providerId:
|
|
43729
|
+
providerId: coordinates.providerId,
|
|
43510
43730
|
status: validation.status,
|
|
43511
43731
|
detail: validation.detail
|
|
43512
43732
|
};
|
|
@@ -43676,63 +43896,6 @@ function buildClaudeMcpConfig(servers) {
|
|
|
43676
43896
|
});
|
|
43677
43897
|
}
|
|
43678
43898
|
|
|
43679
|
-
// ../../packages/fleet-admiral/src/agent-cli/gateway-agents.ts
|
|
43680
|
-
var GENERAL_PURPOSE_AGENT_PROMPT = [
|
|
43681
|
-
"You are a Fleet execution agent. Do the assigned work directly; do not re-delegate the whole assignment.",
|
|
43682
|
-
'Treat host objective/scope/constraints/references as binding contracts. Do not silently re-plan, expand scope, or substitute a "cleaner" design \u2014 finish as instructed, then optionally suggest alternatives. On ambiguity or conflict, stop and report the blocker instead of guessing.',
|
|
43683
|
-
"",
|
|
43684
|
-
"Pick ONE mode from the task and stay in it:",
|
|
43685
|
-
"- recon: read-only facts; least-invasive evidence path; cite path:line",
|
|
43686
|
-
"- decide: read-only; one simplest viable recommendation; no implementation checklist",
|
|
43687
|
-
"- implement: edit within scope; verify what you changed; report compliance and any deviations",
|
|
43688
|
-
"- verify: hunt real defects with evidence+impact; PASS/FAIL; fix only if asked",
|
|
43689
|
-
"",
|
|
43690
|
-
"Search only as needed for the chosen mode. Prefer known paths over broad sweeps. Do not default to exhaustive multi-strategy hunting.",
|
|
43691
|
-
"NEVER create files unless they are absolutely necessary. ALWAYS prefer editing an existing file to creating a new one.",
|
|
43692
|
-
"NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested.",
|
|
43693
|
-
"Final reply: concise essentials only \u2014 mode, what changed or found, key evidence (path:line when relevant), and blockers/deviations."
|
|
43694
|
-
].join("\n");
|
|
43695
|
-
function buildGatewayCustomAgents(exposed) {
|
|
43696
|
-
const agents = {};
|
|
43697
|
-
for (const model of exposed) {
|
|
43698
|
-
const modelId = toClaudeGatewayModelId(model);
|
|
43699
|
-
const constraints = buildGatewayModelConstraints(model);
|
|
43700
|
-
if (constraints.effortSupported) {
|
|
43701
|
-
for (const effort of constraints.effortLadder) {
|
|
43702
|
-
const name2 = toGatewayAgentName(modelId, effort);
|
|
43703
|
-
agents[name2] = {
|
|
43704
|
-
description: gatewayAgentDescription(model, modelId, effort),
|
|
43705
|
-
prompt: GENERAL_PURPOSE_AGENT_PROMPT,
|
|
43706
|
-
model: modelId,
|
|
43707
|
-
effort
|
|
43708
|
-
};
|
|
43709
|
-
}
|
|
43710
|
-
continue;
|
|
43711
|
-
}
|
|
43712
|
-
const name = toGatewayAgentName(modelId);
|
|
43713
|
-
agents[name] = {
|
|
43714
|
-
description: gatewayAgentDescription(model, modelId),
|
|
43715
|
-
prompt: GENERAL_PURPOSE_AGENT_PROMPT,
|
|
43716
|
-
model: modelId
|
|
43717
|
-
};
|
|
43718
|
-
}
|
|
43719
|
-
return agents;
|
|
43720
|
-
}
|
|
43721
|
-
function toGatewayAgentName(modelId, effort) {
|
|
43722
|
-
const stripped = modelId.startsWith("claude-gateway--") ? modelId.slice("claude-gateway--".length) : modelId;
|
|
43723
|
-
const base = stripped.replace(/\[1m\]/g, "-1m").replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
|
|
43724
|
-
const stem = base.length > 0 ? base : "model";
|
|
43725
|
-
return effort === void 0 ? stem : `${stem}-${effort}`;
|
|
43726
|
-
}
|
|
43727
|
-
function gatewayAgentDescription(model, modelId, effort) {
|
|
43728
|
-
const effortPart = effort === void 0 ? "no effort control" : `effort ${effort}`;
|
|
43729
|
-
return [
|
|
43730
|
-
`Gateway model ${model.displayName} (${modelId}), ${effortPart}.`,
|
|
43731
|
-
"Fleet execution agent that runs one mode \u2014 recon, decide, implement, or verify. Name the mode in the task.",
|
|
43732
|
-
"Use after calling gateway_models when this roster entry fits the stage."
|
|
43733
|
-
].join(" ");
|
|
43734
|
-
}
|
|
43735
|
-
|
|
43736
43899
|
// ../../packages/fleet-admiral/src/agent-cli/assets.generated.ts
|
|
43737
43900
|
var EMBEDDED_AGENT_CLI_SKILL_ASSETS = [
|
|
43738
43901
|
{ relativePath: "assumption-audit/SKILL.md", content: "---\nname: assumption-audit\ndescription: Resolve decision-shaped blocking gaps one at a time \u2014 Context Confidence gate failures during an active protocol, or pre-engagement requirements ambiguity routed by the Command Integrity Standing Order.\n---\n\nUse this auxiliary skill only when a decision-shaped blocking gap has been found: either the active protocol or Context Confidence re-entry path surfaced it, or the Command Integrity Standing Order routed a pre-engagement requirements ambiguity here before a protocol mode loads. This skill is not a protocol mode, does not replace the active protocol, and cannot declare the planning boundary passed by itself.\n\nFor each unresolved blocking gap, triage the gap before questioning:\n\n- **Scout-shaped**: the answer should come from direct file reads, focused reconnaissance, carrier scouting, or another verifiable evidence source. Send the workflow back to that evidence-gathering path instead of asking the user to decide.\n- **Decision-shaped**: the answer depends on preference, scope, risk appetite, product intent, or authority that evidence alone cannot settle. Ask exactly one question for this gap.\n- **Escalation-shaped**: the answer requires authority beyond the current operator, changes the mission boundary, repeatedly fails to resolve, or would weaken the active protocol's required gate. Escalate to the user.\n\nWhen a gap is decision-shaped, ask one question at a time. Present your recommended answer first, then give one or two concrete alternatives when useful. Walk decision dependencies one branch at a time until the current gap is resolved; do not bundle unrelated gaps into the same question.\n\nAfter the gap is answered, report the resolved decision in one short line and return control to the caller: the active protocol or Context Confidence Standing Order on re-entry, or the Protocol Gate when invoked pre-engagement. An active workflow must re-evaluate confidence and re-apply the required planning boundary gate before planning proceeds.\n" },
|
|
@@ -43809,7 +43972,7 @@ If the intended Carrier is unavailable or carrier_dispatch rejects the requested
|
|
|
43809
43972
|
{ relativePath: "gateway/codebase-research/SKILL.md", content: "---\nname: codebase-research\ndescription: Answer a question about a codebase or an external subject by fanning out independent searches, reading sources directly, and separating what was verified from what was only claimed. Load before orchestrating reconnaissance across many files, subsystems, or external sources. Skip for a single lookup you can perform directly.\n---\n\n# Codebase Research\n\nReconnaissance whose product is **evidence, not a summary**. The run's value comes from covering angles a single reader would miss and from being explicit about what it failed to establish.\n\nExecuting this skeleton \u2014 the surface it runs on, the wiring between stages, and model and effort assignment \u2014 belongs to `workflow`; this skill owns the shape of the run.\n\n## When Not To Use\n\n- A fact one grep or one file read settles. Fanning out costs more than the answer is worth.\n- Work that will change files. Use `implementation-run`.\n- Judging code that already exists against a standard. Use `quality-review`.\n\n## Stage Skeleton\n\n| Stage | Role | Fan | Returns |\n|---|---|---|---|\n| Scope | decompose | 1 | 3-6 angles, each a distinct search strategy \u2014 not paraphrases of one query |\n| Sweep | scan | one per angle | Located candidates with a path or URL and why each is relevant |\n| Read | extract | one per surviving candidate | Claims, each with a verbatim quote and its exact source |\n| Reconcile | synthesize | 1 | Merged findings, ranked, with contradictions kept visible |\n\nRun Sweep and Read as a pipeline. A barrier between them buys nothing: each candidate can be read the moment its angle finds it. Insert a barrier only before Reconcile, which genuinely needs the whole set.\n\n## Rules\n\n- **Angles must differ in method, not wording.** By-name, by-caller, by-test, by-history, by-config are different angles. Three rephrasings of one query is one angle run three times.\n- **A claim without a quote is a lead, not a finding.** Require the source and the literal text; report the count of leads that never became findings.\n- **Deduplicate before reading, not after.** Deduplicate on a normalized identity (path, or host plus path for a URL) so the same source is not read once per angle.\n- **Contradictions survive to the report.** When two sources disagree, say so and name both. Collapsing them into whichever sounds more confident destroys the run's most valuable output.\n- **Name what you failed to reach.** Blocked networks, unreadable files, and truncated searches are results. A report that omits them reads as exhaustive when it is not.\n\n## Stopping\n\nStop when a full sweep round adds no source you had not already read. Do not keep spawning searchers because the subject is large \u2014 spawn them because the last round found something new.\n\n## Gotchas\n\n- **Symptom:** The report is confident and short, and every finding traces to one or two sources.\n **Action:** Check whether the angles actually differed. Re-run with methods, not phrasings.\n **Why:** Similar queries return the same top results, so the fan-out produced redundancy that reads as corroboration.\n\n- **Symptom:** A cited file path or symbol does not exist.\n **Action:** Treat the whole finding as unverified and re-read the source before keeping it.\n **Why:** A stage that could not reach a source may still produce a plausible path; requiring a verbatim quote is what makes this detectable.\n" },
|
|
43810
43973
|
{ relativePath: "gateway/implementation-run/SKILL.md", content: '---\nname: implementation-run\ndescription: Apply one decided change across many files, packages, or call sites by discovering the sites, transforming each in isolation, and inspecting the artifacts rather than the reports. Load before a migration, a sweeping refactor, or a multi-package edit. Skip when the change fits in a few files you will edit directly, or when the approach is not yet decided.\n---\n\n# Implementation Run\n\nThe only stage shape here that **writes**. Its risk is not failure \u2014 a failed edit is visible \u2014 but convergence: many branches each producing something reasonable that together do not match the codebase.\n\nExecuting this skeleton \u2014 the surface it runs on, the wiring between stages, and model and effort assignment \u2014 belongs to `workflow`; this skill owns the shape of the run.\n\n## When Not To Use\n\n- The approach is undecided. Decide first with `architecture-review`; a stage handed an open decision will close it for you, differently in each branch.\n- A handful of files you can edit directly. The per-stage overhead exceeds the work.\n- Judging existing code. Use `quality-review`.\n\n## Stage Skeleton\n\n| Stage | Role | Fan | Returns |\n|---|---|---|---|\n| Discover | map | 1-3 | Every site that must change, each with a path and why it qualifies |\n| **Decide** | \u2014 | **host only** | The literal values every site will use. Decided here, never in a stage. |\n| Apply | implement | one per site or coherent group, `isolation: \'worktree\'` | Files changed, and which existing conventions were matched |\n| Inspect | verify | host reads the diff | Accept or reject per site |\n\nDiscover and Apply pipeline naturally, but **Decide is a barrier by necessity** \u2014 the literals must exist before any site is touched, or each branch invents its own.\n\n## Decisions Travel as Literals\n\nBefore starting any branch, close every judgment gap. Ask both:\n\n1. Must the stage choose a concrete value?\n2. Does it lack the doctrine or convention context to justify that choice?\n\nIf both are yes, **the host chooses the value and passes it verbatim**. This covers design tokens, API paths, setting keys, protocol tokens, names, error message text, thresholds, and constants \u2014 not an exhaustive list.\n\nNever leave a choice to a stage behind phrases like "match the existing style", "pick a consistent name", "follow the convention", or "\uC801\uC808\uD788". A stage on another model has no feel for this repository and will produce something defensible but foreign.\n\n## Rules\n\n- **Isolate every writing branch.** Parallel edits to a shared tree corrupt each other. Worktree isolation costs setup time and disk; pay it whenever more than one branch writes.\n- **Inspect artifacts, never narratives.** Read the actual diff for each site. A stage\'s summary of what it did is evidence of what it believed, not of what it wrote.\n- **Verbatim match or defect.** A literal you sent must appear exactly. An equivalent-looking substitution \u2014 a synonym token, a reformatted path, a renamed key \u2014 is a defect, not a variation.\n- **A site that needs a new decision stops.** When Apply discovers a case Decide did not cover, it returns that fact instead of choosing. Resolve it on the host and start that branch again with the value; do not let one branch set precedent for the rest.\n- **Reject rather than patch.** A branch whose output drifted is re-run with a sharper prompt. Fixing its output by hand hides that the prompt was insufficient, and the next site will drift the same way.\n\n## Scope Warning\n\nMeasurement covered only **local, well-precedented edits** \u2014 a couple of files with an obvious existing pattern to follow. Every model tested handled those correctly. Nothing establishes that this holds for sweeping or cross-package work, where convention drift compounds and each branch sees only its own slice. Treat wide runs as unproven: keep groups small, inspect every diff, and keep a structural change on the host rather than spreading it across branches that each see one slice.\n\n## Stopping\n\nStop when every discovered site is either accepted or explicitly deferred with a reason. Do not accept a run with unexamined sites because the count is large \u2014 an unexamined site is an unknown edit.\n\n## Gotchas\n\n- **Symptom:** Tests pass and the build is green, but the change reads as foreign to the surrounding code.\n **Action:** Diff the produced values against the literals you sent. Re-run the drifted sites with the literal spelled out.\n **Why:** Green checks confirm the code runs, not that it belongs; convention is invisible to a compiler.\n\n- **Symptom:** Different sites solved the same sub-problem differently.\n **Action:** That sub-problem belonged in Decide. Choose once on the host and re-run the affected sites with the value.\n **Why:** Each branch resolved an open decision independently, which is exactly what the Decide barrier exists to prevent.\n\n- **Symptom:** A branch reports success but changed nothing.\n **Action:** Check the returned file list against the actual diff before accepting.\n **Why:** A branch that could not find its target may report the intent as done; only the artifact settles it.\n' },
|
|
43811
43974
|
{ relativePath: "gateway/quality-review/SKILL.md", content: "---\nname: quality-review\ndescription: Review existing code or a change set by splitting the work into independent dimensions, hunting within each, then adversarially verifying every finding before it is reported. Load before a correctness, security, or quality pass over a diff or subsystem. Skip when you already know the defect and only need it fixed.\n---\n\n# Quality Review\n\nThe output is a **judged finding list, not a fix list**. A reviewer that also repairs what it finds loses the independence that made the finding worth having, and repairs things that were never broken.\n\nExecuting this skeleton \u2014 the surface it runs on, the wiring between stages, and model and effort assignment \u2014 belongs to `workflow`; this skill owns the shape of the run.\n\n## When Not To Use\n\n- The defect is known and only the repair remains. Use `implementation-run`.\n- Deciding between designs. Use `architecture-review`.\n- Establishing facts with no standard to judge against. Use `codebase-research`.\n\n## Stage Skeleton\n\n| Stage | Role | Fan | Returns |\n|---|---|---|---|\n| Split | decompose | 1 | The dimensions this review will cover, each with its own standard |\n| Hunt | scan | one per dimension | Candidate findings, each with a file, a line, and a concrete failing scenario |\n| Verify | verify | 2-3 per finding, mixed lineage, prompted to refute | Refuted or survived, with the specific evidence |\n| Adjudicate | \u2014 | **host only** | Confirmed / declined / deferred, with the reason |\n\nPipeline Hunt into Verify \u2014 a dimension's findings can be verified while another dimension is still hunting. Nothing here needs a global barrier.\n\n## Dimensions Stay Separate\n\nNever combine security auditing with functional or end-to-end review in one hunt. Measured outcome: the combined run drops the functional pass \u2014 security findings are more legible, so the agent spends its budget there and reports the run as complete. Give each dimension its own hunter with its own standard.\n\nTypical dimensions, chosen per target rather than run wholesale: correctness, security and input trust, boundary and ownership rules, error and failure handling, test coverage, and convention conformance.\n\n## Verify Is Adversarial\n\nVerifiers are prompted to **refute**, not to confirm. A finding survives only when the refutation attempt fails.\n\n- Default to refuted when uncertain. An unreproduced finding is a hypothesis.\n- Require a concrete failing scenario: inputs or state, and the wrong result. \"This could break\" is not a finding.\n- Distinguish three outcomes. Survived, refuted on merit, and **unverifiable because the verifier errored** are different; collapsing the third into \"refuted\" silently discards real findings when infrastructure fails.\n- Mix lineage across a finding's verifiers. Identical models produce correlated verdicts, which reads as agreement.\n\n## Adjudication Stays on the Host\n\nA surviving finding is evidence, not an instruction. For each one the host decides:\n\n- **Confirm** when it occurs on a path a real workflow reaches, is in scope, and the repair costs less than the defect.\n- **Decline** when it is hypothetical, overfit to the reviewer's reading, outside scope, or contradicts an intended trade-off. Record the reason; a silent skip is indistinguishable from an oversight.\n- **Defer** when it is real but belongs to different work. Say why it is real and why not here.\n\nSeverity never decides disposition. A reviewer's P1 on a path nothing reaches is still a decline.\n\n## Stopping\n\nStop when a hunting round produces no finding that survives verification. Two consecutive dry rounds end the run. A reviewer can always generate another suggestion, so waiting for it to fall silent is an unbounded loop.\n\n## Gotchas\n\n- **Symptom:** The run reports many findings and all of them survived.\n **Action:** Check that verifiers were prompted to refute rather than to assess. A confirming verifier confirms.\n **Why:** Adversarial framing is the entire mechanism; without it the verify stage is a second opinion that agrees by default.\n\n- **Symptom:** Fixing one finding produced the next round's findings.\n **Action:** Roll back the fix rather than widening it. That is evidence the repair was over-scoped.\n **Why:** A repair that breeds findings changed more than the defect required.\n\n- **Symptom:** The security dimension is thorough and the functional one is a sentence.\n **Action:** Re-run the functional dimension on its own hunter.\n **Why:** Combined dimensions do not split budget evenly; the more legible one absorbs it.\n" },
|
|
43812
|
-
{ relativePath: "gateway/workflow/SKILL.md", content: "---\nname: workflow\ndescription: Run a staged multi-agent operation \u2014 map a stage skeleton onto the workflow execution surface, choose pipeline or barrier between stages, keep failures visible, and assign each stage its model and reasoning effort. Load before executing any skeleton from architecture-review, codebase-research, implementation-run, or quality-review, and before pinning a model or effort anywhere. Skip when the work is one stage you will perform directly.\n---\n\n# Workflow\n\nThe other gateway skills each own the *shape* of a run \u2014 which stages exist, what each returns, where the judgment stays on the host. This skill owns **turning that shape into an actual run**: the surface it executes on, how stages are wired to each other, and what each stage runs on.\n\nA skeleton that is never executed as stages is not a cheaper version of the run. It is a single reader doing every job in one context, which is the failure mode the skeleton exists to prevent.\n\n## Execution Surface\n\nStaged execution requires the workflow execution surface \u2014 the one that runs a script of stages, wires them together, and lets each stage carry its own model and effort. Inspect the live tool surface before concluding anything about it; tools may be lazy-loaded.\n\nThis skill covers that surface only, and that surface is not the default. An Agent \u2014 one run, or a named teammate you can continue \u2014 carries work that needs no wiring between its parts, and the Orchestration Policy Standing Order makes it the default for exactly that reason. A staged run is what the user asks for on top of it, and what it buys is the wiring: data flowing between stages, barriers, fan-out, and a fleet of different models working the same problem at once. Model and effort assignment below applies to both surfaces.\n\n**A surface gated behind user opt-in is unavailable until that opt-in exists.** Some workflow surfaces refuse to run unless the user explicitly asked for a multi-agent run. That refusal is not a defect and it is not a reason to quietly do the whole thing yourself in one context. Report the gate, say what the staged run would cost and what it would buy, and wait \u2014 the same way you would report any unavailable surface.\n\nTwo things stay out of this skill on purpose:\n\n- **Call mechanics.** Argument names, script syntax, return shapes, and which values a field accepts live in the live tool description. Read them there every time. Anything restated here would be a copy that goes stale silently.\n- **Whether to run at all.** That is the Orchestration Policy Standing Order's call, not this skill's.\n\n## Reading a Stage Skeleton\n\nEvery gateway skeleton is a table of `Stage | Role | Fan | Returns`. Read it as an execution plan:\n\n- **Role** is the one-word job \u2014 map, propose, implement, verify, synthesize, transform. It is also the input to model assignment below.\n- **Fan** is how many parallel branches that stage runs. `1` is one branch. `one per <item>` is a fan-out sized by the previous stage's output, not by a number you pick. **`host only` is not a stage you hand off** \u2014 it is a barrier where you do the work yourself, and handing it off defeats the skeleton.\n- **Returns** is the contract. When a stage returns structured data, declare the schema rather than parsing prose; a stage that must fill a shape will retry against it, while a stage asked to write prose will improvise.\n\n## Pipeline by Default\n\nBetween two stages, the choice is pipeline or barrier, and **pipeline is the default**.\n\nA barrier \u2014 waiting for every branch of stage N before starting stage N+1 \u2014 is correct only when stage N+1 genuinely needs the whole set at once: deduplicating across all results before expensive downstream work, deciding literals every later branch must share, early-exit when the total is zero, or a prompt that compares one result against the others.\n\nA barrier is **not** justified by needing to flatten, map, or filter between stages \u2014 do that inside a stage \u2014 nor by the stages feeling conceptually separate, nor by the script reading more cleanly. Each unjustified barrier costs the difference between the slowest branch and the fastest, on every item, for nothing.\n\nEach skill's skeleton already names its own barriers, and they are the load-bearing part of that shape. `implementation-run`'s Decide barrier and `quality-review`'s Adjudicate barrier are the two places the run stops being parallel because a single decision must exist before anything downstream. Do not optimize them away.\n\n## Failures Must Be Loud\n\nFan-out helpers routinely turn a failed branch into an empty result rather than an error. A run that lost three of eight branches then looks like a run that found less, which is indistinguishable from a thorough run over a quiet subject.\n\n- Have each stage **return its failure as a value** \u2014 a result that says it failed and why \u2014 instead of throwing into the helper.\n- Before synthesizing, check the branch count against what you started. A missing branch is a finding.\n- Never report coverage you did not verify. If the run capped, sampled, or dropped anything, say so in the report; silent truncation reads as completeness.\n\n## Model and Effort Assignment\n\nDistribution is the default. Concentrating a run on the model this session happens to run on is the exception, and the exception carries the burden of proof \u2014 the binding rule is in the Orchestration Policy Standing Order. This is the procedure that discharges it.\n\n**Call `gateway_models` first, every time.** Not once per session: allowances move while work is in flight, and a roster entry can be enabled or disabled between two runs.\n\nWork through these in order.\n\n1. **Name the role.** Take it from the skeleton's Role column. If you cannot name it in one word, the stage boundary is wrong; fix the split before choosing a model.\n2. **Name the dominant risk.** What would ruin *this* stage: too little context, unreliable tool use, correlated judgment, drift from repository convention, or incomplete coverage. One risk, not a list.\n3. **Look for a measured fit.** Read `roleFit` for that risk. A declared `fit` is a reason to prefer an identity and a declared `unfit` a reason to avoid it. `null` means unmeasured: it says nothing about quality, and it is never a reason to fall back to the session model.\n4. **Spread the rest by allowance.** For every stage with no measured fit, choose by cost. Read the window that belongs to the model \u2014 the one whose `scope` matches `constraints.quotaScope` when the model declares one, and the provider's scope-less window when it does not \u2014 then send stages toward the lower `usedPercent`. A scope is declared only where one subscription splits into pools; there, and only there, the scope-less figure is a sum that can read healthy while the model's own pool is spent. Move off a provider as it approaches exhaustion instead of discovering it mid-run.\n5. **Re-pick effort for the model you chose.** Ladders differ between identities. A level a model does not advertise is clamped down to the next rung below it with no signal to you, and rejected outright when nothing is below. Take a rung the target's `effortLadder` actually lists, and check the stage's input against the target's `contextWindow`.\n6. **Diversify where disagreement is the product.** A majority-vote or judging stage wants different lineages \u2014 a verifier sharing its subject's lineage inherits the same blind spots. `homolineage: true` marks an identity sharing the parent Claude session's lineage: useful for moving spend, useless for independence.\n7. **Confirm the name exists on both sides.** Roster membership resolves live, but Agent names were fixed when the session started. Pick only a name present in both; a model enabled mid-session is unreachable until restart. `400 unknown model` means re-read the roster.\n8. **Do not choose the load-bearing stage by allowance alone.** When everything downstream rests on one stage \u2014 the contract survey, the final synthesis, the integrating judgment \u2014 let measured fit and lineage independence decide it, and let cost break ties only after those.\n9. **Record the split.** One line per run: which identities carried which stages, and what decided it. A distribution nobody can audit is indistinguishable from a random one.\n\n### What Measurement Actually Showed\n\nTwo measurements, both on 2026-08-02.\n\nThree models against seven stage roles were **indistinguishable on five of them**: structured output, repository search, adversarial judgment, mechanical transformation, and a small implementation task.\n\nTwelve identities were then given one identical mapping task \u2014 twelve files, exact line counts, exact export symbols. **All twelve answered it perfectly**: full coverage, no fabricated file, and every one caught the trap entry whose correct answer was an empty list. What separated them was spend. The cheapest finished on 176k total tokens over 5 tool calls; the most expensive spent 5.20M over 29 for the same answer. Output tokens alone ran 1.7k to 20.3k, so this is not a cache-read artifact.\n\nRead the two together. Quality parity is the prior \u2014 and parity is exactly what makes cost the deciding axis. **Indistinguishable never meant \"inherit\"; it means the expensive choice buys nothing.** The roster declares fit only where a measurement separated the models, and reports `null` everywhere else \u2014 `null` means unmeasured, never unsuitable.\n\n### Rules That Measurement Refuted\n\n- **A larger context window does not mean better reading.** Asked to map a 22-file subsystem, the 1M-window model opened 16 files and a 372k-window model opened all 22. What separated them was thoroughness in tool use, which no catalog field predicts. Use the window as a floor \u2014 can this model hold the input at all \u2014 not as a ranking.\n- **Raising effort does not reliably improve judgment.** The same verification task at the lowest and highest rungs produced the same verdict with equal reasoning quality. Effort pays only once a task is hard enough to need it; raising it by habit buys nothing and costs throughput.\n- **A local, well-precedented edit does not need the session model.** Every model tested landed the change in the right files, found the package's existing export pattern instead of inventing one, and matched the surrounding comment language. This does **not** generalize to sweeping or multi-package work, where convention drift compounds and goes unseen.\n\n### Handing Work to a Different Model\n\nA stage running on another model has no feel for this repository's conventions, so decisions must travel as literal values, not as descriptions. Name the exact token, path, setting key, or constant; never write \"match the existing style\" or \"pick something consistent\". On return, check the artifacts against the literals you sent \u2014 an equivalent-looking substitution is a defect, not a variation.\n\n## Gotchas\n\n- **Symptom:** A run that pinned several models produced uniform-looking results, or one stage's output is missing with no error.\n **Action:** Check whether that branch failed rather than ran. Confirm each pinned id is still in the roster and return branch failures as values instead of letting the helper collapse them.\n **Why:** A de-selected or mistyped id fails at the gateway, but the fan-out helper turns a failed branch into an empty slot, so a heterogeneous run silently becomes a partial one.\n\n- **Symptom:** A stage ran at a different reasoning level than the one requested.\n **Action:** Read that model's ladder from the roster and request a level it actually advertises.\n **Why:** Ladders are not uniform \u2014 some models have no `medium`, others no effort control at all \u2014 and an off-ladder level is clamped upstream without any signal.\n\n- **Symptom:** A provider looked like it had room, but its requests began failing.\n **Action:** Read the window whose `scope` matches the model's `quotaScope`, not the provider's combined figure.\n **Why:** One subscription can bill through separate pools; the sum can read comfortable while the pool a given model draws from is nearly spent.\n\n- **Symptom:** A stage returned nothing at all \u2014 no result, no error you can quote \u2014 while other stages on the same provider succeeded.\n **Action:** Treat a high `usedPercent` on that model's own window as the explanation and move those stages to another provider. Do not wait for a message that says exhausted.\n **Why:** There is no exhaustion status. `status` distinguishes *reading* failures \u2014 not connected, signed out, expired, no subscription, stale, error \u2014 and a spent pool is visible only as `usedPercent` near 100. A stage dying after retries with an empty return is what exhaustion actually looks like from here.\n\n- **Symptom:** A model you just enabled is in `gateway_models` but every attempt to run a stage on it fails as an unknown Agent.\n **Action:** Use only names present in both the live roster and the Agent names this session started with. Reaching a newly enabled model requires a new session.\n **Why:** The roster re-reads the user's selection on every call, but Agent names were serialized once at session start. The two drift apart the moment settings change mid-session.\n\n- **Symptom:** The run took as long as doing it yourself, with the same total cost.\n **Action:** Count the barriers. Each one that no stage actually needed becomes wall-clock spent waiting for the slowest branch.\n **Why:** Staging buys overlap; a skeleton executed as a sequence of barriers pays the coordination cost and collects none of it back.\n\n- **Symptom:** A stage came back asking what to do, or made a choice the skeleton reserved for the host.\n **Action:** Move that decision to the preceding host-only barrier and run the stage again with the value spelled out.\n **Why:** A stage handed an open decision always closes it, differently in each branch \u2014 which is the failure the barrier was placed there to prevent.\n" },
|
|
43975
|
+
{ relativePath: "gateway/workflow/SKILL.md", content: "---\nname: workflow\ndescription: Run a staged multi-agent operation \u2014 map a stage skeleton onto the workflow execution surface, choose pipeline or barrier between stages, keep failures visible, and assign each stage its model and reasoning effort. Load before executing any skeleton from architecture-review, codebase-research, implementation-run, or quality-review, and before pinning a model or effort anywhere. Skip when the work is one stage you will perform directly.\n---\n\n# Workflow\n\nThe other gateway skills each own the *shape* of a run \u2014 which stages exist, what each returns, where the judgment stays on the host. This skill owns **turning that shape into an actual run**: the surface it executes on, how stages are wired to each other, and what each stage runs on.\n\nA skeleton that is never executed as stages is not a cheaper version of the run. It is a single reader doing every job in one context, which is the failure mode the skeleton exists to prevent.\n\n## Execution Surface\n\nStaged execution requires the workflow execution surface \u2014 the one that runs a script of stages, wires them together, and lets each stage carry its own model and effort. Inspect the live tool surface before concluding anything about it; tools may be lazy-loaded.\n\nThis skill covers that surface only, and that surface is not the default. An Agent \u2014 one run, or a named teammate you can continue \u2014 carries work that needs no wiring between its parts, and the Orchestration Policy Standing Order makes it the default for exactly that reason. A staged run is what the user asks for on top of it, and what it buys is the wiring: data flowing between stages, barriers, fan-out, and a fleet of different models working the same problem at once. Model and effort assignment below applies to both surfaces.\n\n**A surface gated behind user opt-in is unavailable until that opt-in exists.** Some workflow surfaces refuse to run unless the user explicitly asked for a multi-agent run. That refusal is not a defect and it is not a reason to quietly do the whole thing yourself in one context. Report the gate, say what the staged run would cost and what it would buy, and wait \u2014 the same way you would report any unavailable surface.\n\nTwo things stay out of this skill on purpose:\n\n- **Call mechanics.** Argument names, script syntax, return shapes, and which values a field accepts live in the live tool description. Read them there every time. Anything restated here would be a copy that goes stale silently.\n- **Whether to run at all.** That is the Orchestration Policy Standing Order's call, not this skill's.\n\n## Reading a Stage Skeleton\n\nEvery gateway skeleton is a table of `Stage | Role | Fan | Returns`. Read it as an execution plan:\n\n- **Role** is the one-word job \u2014 map, propose, implement, verify, synthesize, transform. It is also the input to model assignment below.\n- **Fan** is how many parallel branches that stage runs. `1` is one branch. `one per <item>` is a fan-out sized by the previous stage's output, not by a number you pick. **`host only` is not a stage you hand off** \u2014 it is a barrier where you do the work yourself, and handing it off defeats the skeleton.\n- **Returns** is the contract. When a stage returns structured data, declare the schema rather than parsing prose; a stage that must fill a shape will retry against it, while a stage asked to write prose will improvise.\n\n## Pipeline by Default\n\nBetween two stages, the choice is pipeline or barrier, and **pipeline is the default**.\n\nA barrier \u2014 waiting for every branch of stage N before starting stage N+1 \u2014 is correct only when stage N+1 genuinely needs the whole set at once: deduplicating across all results before expensive downstream work, deciding literals every later branch must share, early-exit when the total is zero, or a prompt that compares one result against the others.\n\nA barrier is **not** justified by needing to flatten, map, or filter between stages \u2014 do that inside a stage \u2014 nor by the stages feeling conceptually separate, nor by the script reading more cleanly. Each unjustified barrier costs the difference between the slowest branch and the fastest, on every item, for nothing.\n\nEach skill's skeleton already names its own barriers, and they are the load-bearing part of that shape. `implementation-run`'s Decide barrier and `quality-review`'s Adjudicate barrier are the two places the run stops being parallel because a single decision must exist before anything downstream. Do not optimize them away.\n\n## Failures Must Be Loud\n\nFan-out helpers routinely turn a failed branch into an empty result rather than an error. A run that lost three of eight branches then looks like a run that found less, which is indistinguishable from a thorough run over a quiet subject.\n\n- Have each stage **return its failure as a value** \u2014 a result that says it failed and why \u2014 instead of throwing into the helper.\n- Before synthesizing, check the branch count against what you started. A missing branch is a finding.\n- Never report coverage you did not verify. If the run capped, sampled, or dropped anything, say so in the report; silent truncation reads as completeness.\n\n## Model and Effort Assignment\n\nDistribution is the default. Concentrating a run on the model this session happens to run on is the exception, and the exception carries the burden of proof \u2014 the binding rule is in the Orchestration Policy Standing Order. This is the procedure that discharges it.\n\n**Call `gateway_models` first, every time.** Not once per session: allowances move while work is in flight, and a roster entry can be enabled or disabled between two runs.\n\nWork through these in order.\n\n1. **Name the role.** Take it from the skeleton's Role column. If you cannot name it in one word, the stage boundary is wrong; fix the split before choosing a model.\n2. **Name the dominant risk.** What would ruin *this* stage: too little context, unreliable tool use, correlated judgment, drift from repository convention, or incomplete coverage. One risk, not a list.\n3. **Look for a measured fit.** Read `roleFit` for that risk. A declared `fit` is a reason to prefer an identity and a declared `unfit` a reason to avoid it. `null` means unmeasured: it says nothing about quality, and it is never a reason to fall back to the session model.\n4. **Spread the rest by allowance.** For every stage with no measured fit, choose by cost. Read the window that belongs to the model \u2014 the one whose `scope` matches `constraints.quotaScope` when the model declares one, and the provider's scope-less window when it does not \u2014 and let the roster's own verdict lead: prefer windows at `pressure: \"ok\"`, treat `\"elevated\"` as a reason to route elsewhere, and send nothing to `\"critical\"` unless every alternative is worse. Break a tie between windows that share a `cadence` by the lower `usedPercent`, and never compare percentages across cadences \u2014 a weekly window at 49% early in its week burns hotter than a monthly one at 78% near its reset, and `paceRatio` above 1.0 says so directly. On an older reading that carries none of the derived fields, treat percentages as comparable only within a single provider's windows \u2014 a shared id like `cycle` does not mean a shared length \u2014 and across providers trust only the extreme: a window near 100 is spent whatever its clock. A scope is declared only where one subscription splits into pools; there the scope-less figure is marked `isAggregate` \u2014 a sum that can read healthy while the model's own pool is spent, and one that stays out of headroom math. Move off a provider as its windows go elevated instead of discovering exhaustion mid-run.\n5. **Re-pick effort for the model you chose.** Ladders differ between identities. A level a model does not advertise is clamped down to the next rung below it with no signal to you, and rejected outright when nothing is below. Take a rung the target's `effortLadder` actually lists, and check the stage's input against the target's `contextWindow`.\n6. **Diversify where disagreement is the product.** A majority-vote or judging stage wants different lineages \u2014 a verifier sharing its subject's lineage inherits the same blind spots. `homolineage: true` marks an identity sharing the parent Claude session's lineage: useful for moving spend, useless for independence.\n7. **Confirm the name exists on both sides.** Roster membership resolves live, but Agent names were fixed when the session started. Pick only a name present in both; a model enabled mid-session is unreachable until restart. `400 unknown model` means re-read the roster.\n8. **Do not choose the load-bearing stage by allowance alone.** When everything downstream rests on one stage \u2014 the contract survey, the final synthesis, the integrating judgment \u2014 let measured fit and lineage independence decide it, and let cost break ties only after those.\n9. **Record the split.** One line per run: which identities carried which stages, and what decided it. A distribution nobody can audit is indistinguishable from a random one.\n\n### What Measurement Actually Showed\n\nTwo measurements, both on 2026-08-02.\n\nThree models against seven stage roles were **indistinguishable on five of them**: structured output, repository search, adversarial judgment, mechanical transformation, and a small implementation task.\n\nTwelve identities were then given one identical mapping task \u2014 twelve files, exact line counts, exact export symbols. **All twelve answered it perfectly**: full coverage, no fabricated file, and every one caught the trap entry whose correct answer was an empty list. What separated them was spend. The cheapest finished on 176k total tokens over 5 tool calls; the most expensive spent 5.20M over 29 for the same answer. Output tokens alone ran 1.7k to 20.3k, so this is not a cache-read artifact.\n\nRead the two together. Quality parity is the prior \u2014 and parity is exactly what makes cost the deciding axis. **Indistinguishable never meant \"inherit\"; it means the expensive choice buys nothing.** The roster declares fit only where a measurement separated the models, and reports `null` everywhere else \u2014 `null` means unmeasured, never unsuitable.\n\n### Rules That Measurement Refuted\n\n- **A larger context window does not mean better reading.** Asked to map a 22-file subsystem, the 1M-window model opened 16 files and a 372k-window model opened all 22. What separated them was thoroughness in tool use, which no catalog field predicts. Use the window as a floor \u2014 can this model hold the input at all \u2014 not as a ranking.\n- **Raising effort does not reliably improve judgment.** The same verification task at the lowest and highest rungs produced the same verdict with equal reasoning quality. Effort pays only once a task is hard enough to need it; raising it by habit buys nothing and costs throughput.\n- **A local, well-precedented edit does not need the session model.** Every model tested landed the change in the right files, found the package's existing export pattern instead of inventing one, and matched the surrounding comment language. This does **not** generalize to sweeping or multi-package work, where convention drift compounds and goes unseen.\n\n### Handing Work to a Different Model\n\nA stage running on another model has no feel for this repository's conventions, so decisions must travel as literal values, not as descriptions. Name the exact token, path, setting key, or constant; never write \"match the existing style\" or \"pick something consistent\". On return, check the artifacts against the literals you sent \u2014 an equivalent-looking substitution is a defect, not a variation.\n\n## Gotchas\n\n- **Symptom:** A run that pinned several models produced uniform-looking results, or one stage's output is missing with no error.\n **Action:** Check whether that branch failed rather than ran. Confirm each pinned id is still in the roster and return branch failures as values instead of letting the helper collapse them.\n **Why:** A de-selected or mistyped id fails at the gateway, but the fan-out helper turns a failed branch into an empty slot, so a heterogeneous run silently becomes a partial one.\n\n- **Symptom:** A stage ran at a different reasoning level than the one requested.\n **Action:** Read that model's ladder from the roster and request a level it actually advertises.\n **Why:** Ladders are not uniform \u2014 some models have no `medium`, others no effort control at all \u2014 and an off-ladder level is clamped upstream without any signal.\n\n- **Symptom:** A provider looked like it had room, but its requests began failing.\n **Action:** Read the window whose `scope` matches the model's `quotaScope`, not the provider's combined figure.\n **Why:** One subscription can bill through separate pools; the sum can read comfortable while the pool a given model draws from is nearly spent.\n\n- **Symptom:** A stage returned nothing at all \u2014 no result, no error you can quote \u2014 while other stages on the same provider succeeded.\n **Action:** Treat a `\"critical\"` pressure \u2014 or a `usedPercent` near 100 \u2014 on that model's own window as the explanation and move those stages to another provider. Do not wait for a message that says exhausted.\n **Why:** There is no exhaustion status. `status` distinguishes *reading* failures \u2014 not connected, signed out, expired, no subscription, stale, error \u2014 and a spent pool is visible only in its own window's figures. A stage dying after retries with an empty return is what exhaustion actually looks like from here.\n\n- **Symptom:** A model you just enabled is in `gateway_models` but every attempt to run a stage on it fails as an unknown Agent.\n **Action:** Use only names present in both the live roster and the Agent names this session started with. Reaching a newly enabled model requires a new session.\n **Why:** The roster re-reads the user's selection on every call, but Agent names were serialized once at session start. The two drift apart the moment settings change mid-session.\n\n- **Symptom:** The run took as long as doing it yourself, with the same total cost.\n **Action:** Count the barriers. Each one that no stage actually needed becomes wall-clock spent waiting for the slowest branch.\n **Why:** Staging buys overlap; a skeleton executed as a sequence of barriers pays the coordination cost and collects none of it back.\n\n- **Symptom:** A stage came back asking what to do, or made a choice the skeleton reserved for the host.\n **Action:** Move that decision to the preceding host-only barrier and run the stage again with the value spelled out.\n **Why:** A stage handed an open decision always closes it, differently in each branch \u2014 which is the failure the barrier was placed there to prevent.\n" },
|
|
43813
43976
|
{ relativePath: "protocol-baseline/SKILL.md", content: "---\nname: protocol-baseline\ndescription: Use the compact Fleet protocol mode for simple, reversible, single-surface work.\n---\n\n# Fleet Protocol: Baseline\n\nUse this mode only for simple, reversible, single-surface operational work.\n\nAt any point during the work, if a Downward Guard trigger appears, stop and re-classify.\n\n## Checkpoints\n\nNone. Selecting baseline implies Mission Anchor Compact Mode.\n\n## Reporting Cadence\n\nAs you move through this protocol, report progress to the user in order.\n\n1. Brief in one line how the Procedure will proceed. \u2192 report `brief: <\u2026>`\n2. State that execution is beginning and run the Procedure. \u2192 report `status: executing`\n\n## General Quarters\n\nConfirm each readiness check below before the Procedure. Work through them in order and report each as you confirm it, then proceed to the Objective anchor. These checks prepare the work; they do not gate entry.\n\n- [ ] **Common** \u2014 objective stated (Mission Anchor), mode-fit holds (Mode Gate), Standing Orders binding. \u2192 report `common: ready`\n- [ ] **Single surface** \u2014 the exact file, command, or fact is identified. \u2192 report `surface: <x>`\n- [ ] **Reversibility** \u2014 the change is trivially reversible. \u2192 report `reversible: yes`\n\n## Procedure\n\n1. Objective statement: state the Mission Anchor objective in one line.\n2. Exact fact/file verification: verify the exact file, command, or fact needed for the request.\n3. Execution: make the smallest reversible change or run the exact requested command.\n4. Result verification: check the touched surface or command result.\n5. One-line report: report what changed, verification, and any skipped escalation trigger.\n" },
|
|
43814
43977
|
{ relativePath: "protocol-frontline/SKILL.md", content: "---\nname: protocol-frontline\ndescription: Use the coordinated Fleet protocol mode for multi-carrier or parallel ownership work.\n---\n\n# Fleet Protocol: Frontline\n\nUse this mode when operational work requires multiple Carriers, independent parallel workstreams, cross-carrier review loops, or file ownership coordination. If the work is high risk but single-owner, use `protocol-redline` instead.\n\n## Checkpoints\n\nDecomposition, Dispatch, Integration, Verification.\n\n## Reporting Cadence\n\nAs you move through this protocol, report progress to the user in order \u2014 each step on its own line with its report token.\n\n1. Brief how the Procedure will proceed \u2014 name (a) the Procedure steps that will run, (b) each carrier's file or responsibility ownership, and (c) the dispatch wave sequencing. \u2192 report `brief: <\u2026>`\n2. State that execution is beginning and run the Procedure. \u2192 report `status: executing`\n\n## General Quarters\n\nConfirm each readiness check below before the Procedure. Work through them in order and report each as you confirm it, then proceed to reconnaissance and decomposition. These checks prepare the work; they do not gate entry.\n\n- [ ] **Common** \u2014 objective stated (Mission Anchor), mode-fit holds (Mode Gate), Standing Orders binding. \u2192 report `common: ready`\n- [ ] **Impact radius** \u2014 flag public-surface or API impact, irreversibility, and any security-sensitive surface. \u2192 report `impact: <\u2026>`\n- [ ] **Rollback** \u2014 identify a rollback-safe checkpoint and any user approval point before execution begins. \u2192 report `rollback: <\u2026>`\n- [ ] **Carrier availability** \u2014 confirm the intended carriers are actually exposed and available this session. \u2192 report `carriers: <\u2026>`\n- [ ] **Ownership** \u2014 pre-sketch each carrier's file or responsibility boundary. \u2192 report `ownership: <\u2026>`\n- [ ] **Shared resources** \u2014 flag shared mutable resources (same files, lock files, or a singleton test environment). \u2192 report `shared: <\u2026|none>`\n- [ ] **Dependencies** \u2014 pre-classify parallel versus sequential work before decomposition and dispatch. \u2192 report `dependencies: <parallel|sequenced: \u2026>`\n\n## Procedure\n\n1. Reconnaissance and decomposition: audit known facts, identify gaps, map affected surfaces, and split work into independently verifiable missions.\n2. Ownership graph: assign each Carrier a clear file or responsibility boundary, note dependencies, and identify shared mutable resources.\n3. Host-authored structured planning boundary: `Apply the Context Confidence Standing Order \u2014 entry requires complete`. Resolve all blocking and confirmatory gaps before the host authors the dispatch plan.\n4. Parallel dispatch: use the `carrier-operations` skill's sequencing rules to launch independent Carrier work in parallel; sequence only for explicit dependencies or shared resources.\n5. Integration: re-read files before editing or accepting Carrier output, reconcile overlaps, and preserve unrelated user or Carrier changes.\n6. Cross-carrier review loop: route implementation outputs to review Carriers, send actionable findings back to owners, and re-review changed surfaces.\n7. Verification: run integrated tests and apply Deep Dive to speculative or conflicting Carrier claims.\n8. Documentation and completion report: update directly affected docs and report executed waves, Carrier ownership, QA, unresolved risks, and final Result Integrity checks.\n\n## Cross-Carrier Feedback Patterns\n\nWhen composing waves and review loops, select the structured feedback pattern that fits the task:\n\n| Pattern | Flow | When |\n|---------|------|------|\n| **Build \u2192 Review** | implementation carrier \u2192 review carrier \u2192 findings back to implementation carrier \u2192 re-review | Standard implementation cycle |\n| **Analyze \u2192 Execute** | implementation or refactoring carrier \u2192 review carrier verifies | Refactoring workflow |\n| **Decide \u2192 Host Planning \u2192 Execute** | optional judgment carrier \u2192 host-authored plan \u2192 execution carrier | Complex features |\n| **Research \u2192 Act** | reconnaissance carrier \u2192 appropriate follow-up carrier from the active roster | Unknown scope tasks |\n" },
|
|
43815
43978
|
{ relativePath: "protocol-midline/SKILL.md", content: "---\nname: protocol-midline\ndescription: Use the normal Fleet protocol mode for bounded operational work without downward-guard triggers.\n---\n\n# Fleet Protocol: Midline\n\nUse this mode for ordinary bounded operational work.\n\nAt any point during the work, if a Downward Guard trigger appears, stop and re-classify.\n\n## Checkpoints\n\nReconnaissance, Plan, Execution, Verification.\n\n## Reporting Cadence\n\nAs you move through this protocol, report progress to the user in order \u2014 each step on its own line with its report token.\n\n1. Brief how the Procedure will proceed \u2014 name (a) the Procedure steps that will run, (b) the target surfaces, and (c) the verification command. \u2192 report `brief: <\u2026>`\n2. State that execution is beginning and run the Procedure. \u2192 report `status: executing`\n\n## General Quarters\n\nConfirm each readiness check below before the Procedure. Work through them in order and report each as you confirm it, then proceed to focused reconnaissance. These checks prepare the work; they do not gate entry.\n\n- [ ] **Common** \u2014 objective stated (Mission Anchor), mode-fit holds (Mode Gate), Standing Orders binding. \u2192 report `common: ready`\n- [ ] **Target surfaces** \u2014 provisionally name the minimal modules or files reconnaissance will touch; confirm or revise in the brief after reconnaissance. \u2192 report `surfaces: <\u2026>`\n- [ ] **Verification** \u2014 provisionally pre-load the test, build, or check command that will prove the work done; confirm or revise in the brief after reconnaissance. \u2192 report `verify: <cmd>`\n- [ ] **Carrier** \u2014 declare whether a carrier dispatch is needed. \u2192 report `carrier: <none|\u2026>`\n\n## Procedure\n\n1. Focused reconnaissance: audit known facts, identify blocking and confirmatory gaps, and inspect the minimal relevant surfaces.\n2. Host-authored planning boundary: `Apply the Context Confidence Standing Order \u2014 entry requires sufficient`. Resolve all blocking gaps before the host plans.\n3. Host-authored inline plan: state objective, targets, execution steps, and done criteria.\n4. Execution: implement the plan in narrow batches, using Carrier Operations Policy when delegation is appropriate.\n5. Verification and review: run targeted checks, apply Deep Dive to speculative results, and fix actionable issues.\n6. Documentation and final report: update directly affected docs only when behavior or operator guidance changed, then summarize changes and QA.\n" },
|
|
@@ -43999,6 +44162,16 @@ function claudeHooks(options) {
|
|
|
43999
44162
|
const userPromptSubmitExecs = [options.captureSessionHookExec, options.turnStartHookExec, options.autoNameHookExec].filter((exec2) => exec2 !== void 0);
|
|
44000
44163
|
const stopExecs = [options.turnEndHookExec].filter((exec2) => exec2 !== void 0);
|
|
44001
44164
|
const inputWaitingExec = options.inputWaitingHookExec;
|
|
44165
|
+
const preToolUse = [
|
|
44166
|
+
...inputWaitingExec ? [{
|
|
44167
|
+
matcher: "AskUserQuestion",
|
|
44168
|
+
hooks: [claudeCommandHook(inputWaitingExec)]
|
|
44169
|
+
}] : [],
|
|
44170
|
+
...options.backgroundSpawnHookExec ? [{
|
|
44171
|
+
matcher: "Task|Agent|Workflow",
|
|
44172
|
+
hooks: [claudeCommandHook(options.backgroundSpawnHookExec)]
|
|
44173
|
+
}] : []
|
|
44174
|
+
];
|
|
44002
44175
|
return {
|
|
44003
44176
|
hooks: {
|
|
44004
44177
|
...userPromptSubmitExecs.length > 0 ? {
|
|
@@ -44011,15 +44184,17 @@ function claudeHooks(options) {
|
|
|
44011
44184
|
hooks: stopExecs.map(claudeCommandHook)
|
|
44012
44185
|
}]
|
|
44013
44186
|
} : {},
|
|
44187
|
+
...preToolUse.length > 0 ? { PreToolUse: preToolUse } : {},
|
|
44014
44188
|
...inputWaitingExec ? {
|
|
44015
|
-
PreToolUse: [{
|
|
44016
|
-
matcher: "AskUserQuestion",
|
|
44017
|
-
hooks: [claudeCommandHook(inputWaitingExec)]
|
|
44018
|
-
}],
|
|
44019
44189
|
Notification: [{
|
|
44020
44190
|
matcher: "permission_prompt|elicitation_dialog",
|
|
44021
44191
|
hooks: [claudeCommandHook(inputWaitingExec)]
|
|
44022
44192
|
}]
|
|
44193
|
+
} : {},
|
|
44194
|
+
...options.backgroundStopHookExec ? {
|
|
44195
|
+
SubagentStop: [{
|
|
44196
|
+
hooks: [claudeCommandHook(options.backgroundStopHookExec)]
|
|
44197
|
+
}]
|
|
44023
44198
|
} : {}
|
|
44024
44199
|
}
|
|
44025
44200
|
};
|
|
@@ -44267,6 +44442,8 @@ async function injectAgentCliProfile(profile, options) {
|
|
|
44267
44442
|
turnStartHookExec: options.turnStartHookExec,
|
|
44268
44443
|
turnEndHookExec: options.turnEndHookExec,
|
|
44269
44444
|
inputWaitingHookExec: options.inputWaitingHookExec,
|
|
44445
|
+
backgroundSpawnHookExec: options.backgroundSpawnHookExec,
|
|
44446
|
+
backgroundStopHookExec: options.backgroundStopHookExec,
|
|
44270
44447
|
autoNameHookExec: options.autoNameHookExec,
|
|
44271
44448
|
withMarketplaceLock: options.withMarketplaceLock
|
|
44272
44449
|
});
|
|
@@ -51351,6 +51528,9 @@ function createTerminalSessionManager(deps) {
|
|
|
51351
51528
|
touchActivity(session);
|
|
51352
51529
|
session.pty.resize(session.cols, session.rows);
|
|
51353
51530
|
replayScrollback(session, socket);
|
|
51531
|
+
if (socket.readyState === WS_OPEN_STATE) {
|
|
51532
|
+
socket.send(Buffer.from(JSON.stringify({ type: "replay_end" }), "utf8"), { binary: false });
|
|
51533
|
+
}
|
|
51354
51534
|
socket.on("message", (data, isBinary) => handleSocketMessage(session, data, isBinary));
|
|
51355
51535
|
socket.once("close", () => detachSocket(session, socket));
|
|
51356
51536
|
}
|
|
@@ -51485,13 +51665,15 @@ function createTerminalSessionManager(deps) {
|
|
|
51485
51665
|
function handlePtyData(session, data) {
|
|
51486
51666
|
touchActivity(session);
|
|
51487
51667
|
const buffer = Buffer.from(data, "utf8");
|
|
51488
|
-
|
|
51668
|
+
const liveSocket = session.activeSocket?.readyState === WS_OPEN_STATE ? session.activeSocket : null;
|
|
51669
|
+
const queryResponses = scanTerminalQueries(session, buffer);
|
|
51670
|
+
if (!liveSocket) {
|
|
51671
|
+
for (const response of queryResponses) writeTerminalQueryResponse(session, response);
|
|
51672
|
+
}
|
|
51489
51673
|
observeOscTitles(session, buffer);
|
|
51490
51674
|
session.scrollback.push(buffer);
|
|
51491
51675
|
while (session.scrollback.length > scrollbackLimit) session.scrollback.shift();
|
|
51492
|
-
|
|
51493
|
-
session.activeSocket.send(buffer, { binary: true });
|
|
51494
|
-
}
|
|
51676
|
+
liveSocket?.send(buffer, { binary: true });
|
|
51495
51677
|
}
|
|
51496
51678
|
function observeOscTitles(session, buffer) {
|
|
51497
51679
|
if (!session.titleParser || !session.titleListener) return;
|
|
@@ -51637,8 +51819,9 @@ function clearGraceTimer(session) {
|
|
|
51637
51819
|
clearTimeout(session.graceTimer);
|
|
51638
51820
|
session.graceTimer = null;
|
|
51639
51821
|
}
|
|
51640
|
-
function
|
|
51822
|
+
function scanTerminalQueries(session, buffer) {
|
|
51641
51823
|
const text2 = `${session.terminalQueryResidual}${buffer.toString("utf8")}`;
|
|
51824
|
+
const responses = [];
|
|
51642
51825
|
session.terminalQueryResidual = "";
|
|
51643
51826
|
let cursor = 0;
|
|
51644
51827
|
while (cursor < text2.length) {
|
|
@@ -51652,9 +51835,11 @@ function respondToTerminalQueries(session, buffer) {
|
|
|
51652
51835
|
session.terminalQueryResidual = trimTerminalQueryResidual(text2.slice(start));
|
|
51653
51836
|
break;
|
|
51654
51837
|
}
|
|
51655
|
-
|
|
51838
|
+
const response = resolveTerminalQueryResponse(session, text2.slice(start, end + 1));
|
|
51839
|
+
if (response) responses.push(response);
|
|
51656
51840
|
cursor = end + 1;
|
|
51657
51841
|
}
|
|
51842
|
+
return responses;
|
|
51658
51843
|
}
|
|
51659
51844
|
function readTrailingEscape(text2) {
|
|
51660
51845
|
return text2.endsWith(ANSI_ESCAPE) ? ANSI_ESCAPE : "";
|
|
@@ -51926,12 +52111,11 @@ function hashablePath(entry) {
|
|
|
51926
52111
|
return filePath;
|
|
51927
52112
|
}
|
|
51928
52113
|
var AGENT_CLI_PATHS_STORAGE_KEY = "agent-cli-paths";
|
|
51929
|
-
var AGENT_CLI_COMMANDS = ["claude"
|
|
51930
|
-
var STORED_AGENT_CLI_COMMANDS = ["claude", "codex"
|
|
52114
|
+
var AGENT_CLI_COMMANDS = ["claude"];
|
|
52115
|
+
var STORED_AGENT_CLI_COMMANDS = ["claude", "codex"];
|
|
51931
52116
|
var OVERRIDE_ENV_BY_COMMAND = {
|
|
51932
52117
|
claude: "CLAUDE_BIN",
|
|
51933
|
-
codex: "CODEX_BIN"
|
|
51934
|
-
"cursor-agent": "CURSOR_AGENT_BIN"
|
|
52118
|
+
codex: "CODEX_BIN"
|
|
51935
52119
|
};
|
|
51936
52120
|
var agentCliPathsWriteTail = Promise.resolve();
|
|
51937
52121
|
function createAgentCliPathStore(storage, pluginId) {
|
|
@@ -51960,7 +52144,7 @@ function serializeAgentCliPathsWrite(write) {
|
|
|
51960
52144
|
return result;
|
|
51961
52145
|
}
|
|
51962
52146
|
function normalizeAgentCliPaths(value) {
|
|
51963
|
-
if (!
|
|
52147
|
+
if (!isRecord8(value) || value.version !== 1 || !isRecord8(value.paths)) {
|
|
51964
52148
|
return { version: 1, paths: {} };
|
|
51965
52149
|
}
|
|
51966
52150
|
const paths = {};
|
|
@@ -52006,7 +52190,6 @@ function validateUserAgentCliPath(executablePath, env, platform = process.platfo
|
|
|
52006
52190
|
}
|
|
52007
52191
|
function agentCliCommandForId(cliId) {
|
|
52008
52192
|
if (cliId === "claude" || cliId === "claude-native" || cliId === "claude-gateway") return "claude";
|
|
52009
|
-
if (cliId === "cursor") return "cursor-agent";
|
|
52010
52193
|
return null;
|
|
52011
52194
|
}
|
|
52012
52195
|
function applyAgentCliPathEnvOverlay(env, cliId, userPaths) {
|
|
@@ -52084,7 +52267,7 @@ function readPathEntries(env, platform) {
|
|
|
52084
52267
|
const separator = platform === "win32" ? ";" : path23__default.delimiter;
|
|
52085
52268
|
return value.split(separator).filter((entry) => entry.length > 0);
|
|
52086
52269
|
}
|
|
52087
|
-
function
|
|
52270
|
+
function isRecord8(value) {
|
|
52088
52271
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52089
52272
|
}
|
|
52090
52273
|
function isNodeError(error51) {
|
|
@@ -52093,8 +52276,7 @@ function isNodeError(error51) {
|
|
|
52093
52276
|
|
|
52094
52277
|
// ../fleet-plugins/terminal/server/agent-api/agent-cli-detect.ts
|
|
52095
52278
|
var BINARY_DISPLAY_NAMES = {
|
|
52096
|
-
claude: "Claude Code"
|
|
52097
|
-
"cursor-agent": "Cursor Agent"
|
|
52279
|
+
claude: "Claude Code"
|
|
52098
52280
|
};
|
|
52099
52281
|
var VERSION_PROBE_TIMEOUT_MS = 5e3;
|
|
52100
52282
|
var SEMVER_PATTERN = /(\d+\.\d+\.\d+)/;
|
|
@@ -52241,6 +52423,36 @@ async function readConsoleQuotaSnapshot(origin, fetchImpl = fetch) {
|
|
|
52241
52423
|
function record3(value) {
|
|
52242
52424
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
52243
52425
|
}
|
|
52426
|
+
var AMOUNT_PATTERN = /^\d{1,15}$/;
|
|
52427
|
+
var MAX_WINDOW_DURATION_MS = 400 * 24 * 36e5;
|
|
52428
|
+
var DURATION_BASES = /* @__PURE__ */ new Set(["upstream", "catalog"]);
|
|
52429
|
+
var START_BASES = /* @__PURE__ */ new Set(["upstream", "derived"]);
|
|
52430
|
+
function toWindowPeriod(value) {
|
|
52431
|
+
const period = record3(value);
|
|
52432
|
+
if (!period) return void 0;
|
|
52433
|
+
const durationMs = period.durationMs;
|
|
52434
|
+
const durationBasis = period.durationBasis;
|
|
52435
|
+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs <= 0) return void 0;
|
|
52436
|
+
if (durationMs > MAX_WINDOW_DURATION_MS) return void 0;
|
|
52437
|
+
if (typeof durationBasis !== "string" || !DURATION_BASES.has(durationBasis)) return void 0;
|
|
52438
|
+
const startsAt = typeof period.startsAt === "number" && Number.isFinite(period.startsAt) ? period.startsAt : void 0;
|
|
52439
|
+
const startsAtBasis = typeof period.startsAtBasis === "string" && START_BASES.has(period.startsAtBasis) ? period.startsAtBasis : void 0;
|
|
52440
|
+
return {
|
|
52441
|
+
durationMs,
|
|
52442
|
+
durationBasis,
|
|
52443
|
+
...startsAt !== void 0 ? { startsAt } : {},
|
|
52444
|
+
...startsAt !== void 0 && startsAtBasis !== void 0 ? { startsAtBasis } : {}
|
|
52445
|
+
};
|
|
52446
|
+
}
|
|
52447
|
+
function toWindowAmounts(value) {
|
|
52448
|
+
const amounts = record3(value);
|
|
52449
|
+
if (!amounts) return void 0;
|
|
52450
|
+
const used = amounts.used;
|
|
52451
|
+
const limit = amounts.limit;
|
|
52452
|
+
if (typeof used !== "string" || typeof limit !== "string") return void 0;
|
|
52453
|
+
if (!AMOUNT_PATTERN.test(used) || !AMOUNT_PATTERN.test(limit)) return void 0;
|
|
52454
|
+
return { used, limit };
|
|
52455
|
+
}
|
|
52244
52456
|
function toQuotaSnapshot(payload) {
|
|
52245
52457
|
const providers = record3(record3(payload)?.providers);
|
|
52246
52458
|
if (!providers) return void 0;
|
|
@@ -52251,11 +52463,17 @@ function toQuotaSnapshot(payload) {
|
|
|
52251
52463
|
const windows = Array.isArray(provider.windows) ? provider.windows.flatMap((entry) => {
|
|
52252
52464
|
const window = record3(entry);
|
|
52253
52465
|
if (!window || typeof window.id !== "string" || typeof window.usedPercent !== "number") return [];
|
|
52466
|
+
const period = toWindowPeriod(window.period);
|
|
52467
|
+
const amounts = toWindowAmounts(window.amounts);
|
|
52254
52468
|
return [{
|
|
52255
52469
|
id: window.id,
|
|
52256
52470
|
...typeof window.scope === "string" ? { scope: window.scope } : {},
|
|
52471
|
+
...typeof window.label === "string" ? { label: window.label } : {},
|
|
52257
52472
|
usedPercent: window.usedPercent,
|
|
52258
|
-
...typeof window.resetsAt === "number" ? { resetsAt: window.resetsAt } : {}
|
|
52473
|
+
...typeof window.resetsAt === "number" ? { resetsAt: window.resetsAt } : {},
|
|
52474
|
+
...period ? { period } : {},
|
|
52475
|
+
...window.isAggregate === true ? { isAggregate: true } : {},
|
|
52476
|
+
...amounts ? { amounts } : {}
|
|
52259
52477
|
}];
|
|
52260
52478
|
}) : void 0;
|
|
52261
52479
|
snapshot[id] = {
|
|
@@ -52270,8 +52488,8 @@ function toQuotaSnapshot(payload) {
|
|
|
52270
52488
|
// ../fleet-plugins/terminal/server/ai-gateway-settings.ts
|
|
52271
52489
|
var AI_GATEWAY_SETTINGS_STORAGE_KEY = "ai-gateway";
|
|
52272
52490
|
function normalizeAiGatewaySettings(value) {
|
|
52273
|
-
if (!
|
|
52274
|
-
const models = Array.isArray(value.models) ? value.models.filter((entry) =>
|
|
52491
|
+
if (!isRecord9(value) || value.version !== 1) return { version: 1 };
|
|
52492
|
+
const models = Array.isArray(value.models) ? value.models.filter((entry) => isRecord9(entry) && typeof entry.id === "string" && entry.id.length > 0).map((entry) => ({ id: entry.id })) : [];
|
|
52275
52493
|
const defaultModel = typeof value.defaultModel === "string" && value.defaultModel.length > 0 ? value.defaultModel : void 0;
|
|
52276
52494
|
return {
|
|
52277
52495
|
version: 1,
|
|
@@ -52316,7 +52534,7 @@ function serializeAiGatewaySettingsWrite(write) {
|
|
|
52316
52534
|
);
|
|
52317
52535
|
return result;
|
|
52318
52536
|
}
|
|
52319
|
-
function
|
|
52537
|
+
function isRecord9(value) {
|
|
52320
52538
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52321
52539
|
}
|
|
52322
52540
|
function resolveAiGatewaySelection(settings2) {
|
|
@@ -52481,6 +52699,9 @@ var MARKETPLACE_LOCK_DIR_SUFFIX = ".lock";
|
|
|
52481
52699
|
function buildConsoleTurnHookCommand(entry, phase) {
|
|
52482
52700
|
return buildConsoleCliHookExec(entry, ["hook", phase === "start" ? "turn-start" : "turn-end"]);
|
|
52483
52701
|
}
|
|
52702
|
+
function buildConsoleBackgroundHookCommand(entry, kind) {
|
|
52703
|
+
return buildConsoleCliHookExec(entry, ["hook", kind === "spawn" ? "background-spawn" : "background-stop"]);
|
|
52704
|
+
}
|
|
52484
52705
|
function buildConsoleAttentionHookCommand(entry) {
|
|
52485
52706
|
return buildConsoleCliHookExec(entry, ["hook", "attention"]);
|
|
52486
52707
|
}
|
|
@@ -52638,6 +52859,8 @@ async function createAgentCliLaunchSpec(options) {
|
|
|
52638
52859
|
),
|
|
52639
52860
|
turnStartHookExec: buildConsoleTurnHookCommand(options.hookEntry, "start"),
|
|
52640
52861
|
turnEndHookExec: buildConsoleTurnHookCommand(options.hookEntry, "end"),
|
|
52862
|
+
backgroundSpawnHookExec: buildConsoleBackgroundHookCommand(options.hookEntry, "spawn"),
|
|
52863
|
+
backgroundStopHookExec: buildConsoleBackgroundHookCommand(options.hookEntry, "stop"),
|
|
52641
52864
|
inputWaitingHookExec: buildConsoleAttentionHookCommand(options.hookEntry),
|
|
52642
52865
|
autoNameHookExec: buildConsoleAutoNameHookCommand(options.hookEntry),
|
|
52643
52866
|
onCleanup: (cleanup) => cleanupStack.push(cleanup),
|
|
@@ -52790,6 +53013,7 @@ var TENANT_EVENT_LIMIT = 1e3;
|
|
|
52790
53013
|
var TENANT_FINALIZED_JOB_LIMIT = 100;
|
|
52791
53014
|
var TENANT_JOB_LIMIT = 200;
|
|
52792
53015
|
var EVENT_TEXT_RETENTION_LIMIT = 8192;
|
|
53016
|
+
var BACKGROUND_PENDING_TTL_MS = 30 * 6e4;
|
|
52793
53017
|
var REDACTED_REQUEST_PATH = "[redacted path]";
|
|
52794
53018
|
function createConsoleObservabilityStore(deps = {}) {
|
|
52795
53019
|
const now = deps.now ?? Date.now;
|
|
@@ -52899,6 +53123,8 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
52899
53123
|
const createdAt = input.createdAt ?? now();
|
|
52900
53124
|
const canonicalCwd = canonicalizeTheaterPath(input.cwd);
|
|
52901
53125
|
const theaterId = workspaceHash(canonicalCwd);
|
|
53126
|
+
const previous = terminalSessionsById.get(input.sessionId);
|
|
53127
|
+
if (previous) clearTerminalSessionBackgroundPending(previous);
|
|
52902
53128
|
const state = {
|
|
52903
53129
|
sessionId: input.sessionId,
|
|
52904
53130
|
cwd: input.cwd,
|
|
@@ -52914,6 +53140,8 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
52914
53140
|
return toTerminalSessionInfo(state);
|
|
52915
53141
|
}
|
|
52916
53142
|
function injectDormantOperation(operation) {
|
|
53143
|
+
const previous = terminalSessionsById.get(operation.sessionId);
|
|
53144
|
+
if (previous) clearTerminalSessionBackgroundPending(previous);
|
|
52917
53145
|
const state = {
|
|
52918
53146
|
sessionId: operation.sessionId,
|
|
52919
53147
|
cwd: operation.cwd,
|
|
@@ -52973,6 +53201,9 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
52973
53201
|
delete session.modelActivity;
|
|
52974
53202
|
delete session.attentionPending;
|
|
52975
53203
|
}
|
|
53204
|
+
if (status === "dormant" || status === "closed" || status === "error") {
|
|
53205
|
+
clearTerminalSessionBackgroundPending(session);
|
|
53206
|
+
}
|
|
52976
53207
|
return toTerminalSessionInfo(session);
|
|
52977
53208
|
}
|
|
52978
53209
|
function setTerminalSessionTurnState(sessionId, turnState) {
|
|
@@ -52983,6 +53214,25 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
52983
53214
|
delete session.attentionPending;
|
|
52984
53215
|
return toTerminalSessionInfo(session);
|
|
52985
53216
|
}
|
|
53217
|
+
function setTerminalSessionBackgroundEvent(sessionId, event) {
|
|
53218
|
+
const session = terminalSessionsById.get(sessionId);
|
|
53219
|
+
if (!session) return null;
|
|
53220
|
+
if (session.status === "dormant" || session.status === "closed" || session.status === "error") return null;
|
|
53221
|
+
const count = session.backgroundPendingCount ?? 0;
|
|
53222
|
+
session.backgroundPendingCount = event === "spawn" ? count + 1 : Math.max(0, count - 1);
|
|
53223
|
+
if (session.backgroundPendingCount === 0) {
|
|
53224
|
+
clearTerminalSessionBackgroundPending(session);
|
|
53225
|
+
return toTerminalSessionInfo(session);
|
|
53226
|
+
}
|
|
53227
|
+
if (session.backgroundPendingExpiry) clearTimeout(session.backgroundPendingExpiry);
|
|
53228
|
+
session.backgroundPendingExpiry = setTimeout(() => {
|
|
53229
|
+
session.backgroundPendingCount = 0;
|
|
53230
|
+
delete session.backgroundPendingExpiry;
|
|
53231
|
+
notifySessionUpdated(toTerminalSessionInfo(session));
|
|
53232
|
+
}, BACKGROUND_PENDING_TTL_MS);
|
|
53233
|
+
if (typeof session.backgroundPendingExpiry.unref === "function") session.backgroundPendingExpiry.unref();
|
|
53234
|
+
return toTerminalSessionInfo(session);
|
|
53235
|
+
}
|
|
52986
53236
|
function setTerminalSessionModelActivity(sessionId, modelActivity) {
|
|
52987
53237
|
const session = terminalSessionsById.get(sessionId);
|
|
52988
53238
|
if (!session) return null;
|
|
@@ -53003,6 +53253,7 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
53003
53253
|
session.status = "dormant";
|
|
53004
53254
|
session.providerSession = providerSession;
|
|
53005
53255
|
delete session.modelActivity;
|
|
53256
|
+
clearTerminalSessionBackgroundPending(session);
|
|
53006
53257
|
return toTerminalSessionInfo(session);
|
|
53007
53258
|
}
|
|
53008
53259
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
@@ -53070,7 +53321,14 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
53070
53321
|
};
|
|
53071
53322
|
for (const listener of allListeners) listener(event);
|
|
53072
53323
|
}
|
|
53324
|
+
function clearTerminalSessionBackgroundPending(session) {
|
|
53325
|
+
if (session.backgroundPendingExpiry) clearTimeout(session.backgroundPendingExpiry);
|
|
53326
|
+
delete session.backgroundPendingExpiry;
|
|
53327
|
+
session.backgroundPendingCount = 0;
|
|
53328
|
+
}
|
|
53073
53329
|
function removeTerminalSession(sessionId) {
|
|
53330
|
+
const session = terminalSessionsById.get(sessionId);
|
|
53331
|
+
if (session) clearTerminalSessionBackgroundPending(session);
|
|
53074
53332
|
const workspace = workspacesByCliRunId.get(sessionId);
|
|
53075
53333
|
if (workspace?.terminalSessionId === sessionId) {
|
|
53076
53334
|
removeWorkspaceIndexes(workspace);
|
|
@@ -53079,6 +53337,7 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
53079
53337
|
return terminalSessionsById.delete(sessionId);
|
|
53080
53338
|
}
|
|
53081
53339
|
function clear() {
|
|
53340
|
+
for (const session of terminalSessionsById.values()) clearTerminalSessionBackgroundPending(session);
|
|
53082
53341
|
workspacesByCliRunId.clear();
|
|
53083
53342
|
workspacesByRegistrationId.clear();
|
|
53084
53343
|
eventsByTenant.clear();
|
|
@@ -53115,6 +53374,7 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
53115
53374
|
clearTerminalSessionProviderSession,
|
|
53116
53375
|
updateTerminalSessionStatus,
|
|
53117
53376
|
setTerminalSessionTurnState,
|
|
53377
|
+
setTerminalSessionBackgroundEvent,
|
|
53118
53378
|
setTerminalSessionModelActivity,
|
|
53119
53379
|
transitionTerminalSessionToDormant,
|
|
53120
53380
|
removeTerminalSession,
|
|
@@ -53189,6 +53449,7 @@ function toTerminalSessionInfo(state) {
|
|
|
53189
53449
|
turnState: state.turnState ?? "none",
|
|
53190
53450
|
...state.modelActivity ? { modelActivity: state.modelActivity } : {},
|
|
53191
53451
|
...state.attentionPending === true ? { attentionPending: true } : {},
|
|
53452
|
+
...state.backgroundPendingCount && state.backgroundPendingCount > 0 ? { backgroundPending: true } : {},
|
|
53192
53453
|
createdAt: state.createdAt,
|
|
53193
53454
|
theaterId: state.theaterId,
|
|
53194
53455
|
registrationId: state.registrationId,
|
|
@@ -53693,6 +53954,7 @@ function sweepIdleAgentSessions(deps) {
|
|
|
53693
53954
|
if (session.status !== "registered" && session.status !== "terminal-only") continue;
|
|
53694
53955
|
if (session.modelActivity === "working") continue;
|
|
53695
53956
|
if (session.modelActivity === void 0 && session.turnState === "running") continue;
|
|
53957
|
+
if (session.backgroundPending === true) continue;
|
|
53696
53958
|
if (deps.hasActiveCarrierJob(session.sessionId)) continue;
|
|
53697
53959
|
if (!deps.hasProviderSessionCapture(session.sessionId)) continue;
|
|
53698
53960
|
const lastActivityAt = deps.getSessionLastActivityAt(session.sessionId);
|
|
@@ -54004,6 +54266,7 @@ function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
54004
54266
|
}
|
|
54005
54267
|
async function handleSessionItem(req, res, sessionId, action) {
|
|
54006
54268
|
if (action === "turn") return handleTurn(req, res, sessionId);
|
|
54269
|
+
if (action === "background") return handleBackground(req, res, sessionId);
|
|
54007
54270
|
if (action === "attention") return handleAttention(req, res, sessionId);
|
|
54008
54271
|
if (action === "auto-name") return handleAutoName(req, res, sessionId);
|
|
54009
54272
|
if (action === "capture") return handleCapture(req, res, sessionId);
|
|
@@ -54142,6 +54405,24 @@ function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
54142
54405
|
if (turnState === "ended") scheduleIdentityRefresh(sessionId);
|
|
54143
54406
|
return true;
|
|
54144
54407
|
}
|
|
54408
|
+
async function handleBackground(req, res, sessionId) {
|
|
54409
|
+
if (req.method !== "POST") return methodNotAllowed2(res);
|
|
54410
|
+
if (!ctx.host.security.isLockAuthorized(req)) return unauthorized(res);
|
|
54411
|
+
const body = await ctx.host.http.readJsonBody(req);
|
|
54412
|
+
const event = body?.event === "spawn" || body?.event === "stop" ? body.event : null;
|
|
54413
|
+
if (event === null) {
|
|
54414
|
+
ctx.host.http.writeJson(res, 400, { error: "invalid_event" });
|
|
54415
|
+
return true;
|
|
54416
|
+
}
|
|
54417
|
+
const updated = observability.setTerminalSessionBackgroundEvent(sessionId, event);
|
|
54418
|
+
if (!updated) {
|
|
54419
|
+
ctx.host.http.writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
54420
|
+
return true;
|
|
54421
|
+
}
|
|
54422
|
+
observability.notifySessionUpdated(updated);
|
|
54423
|
+
ctx.host.http.writeJson(res, 200, { ok: true });
|
|
54424
|
+
return true;
|
|
54425
|
+
}
|
|
54145
54426
|
async function handleAttention(req, res, sessionId) {
|
|
54146
54427
|
if (req.method !== "POST") return methodNotAllowed2(res);
|
|
54147
54428
|
if (!ctx.host.security.isLockAuthorized(req)) return unauthorized(res);
|
|
@@ -55259,8 +55540,7 @@ var ANALYSIS_ERROR_CODES = {
|
|
|
55259
55540
|
sessionBusy: "analysis_session_busy"
|
|
55260
55541
|
};
|
|
55261
55542
|
var ANALYST_CLI_ENTRIES = [
|
|
55262
|
-
{ binaryId: "claude", cliId: "claude" }
|
|
55263
|
-
{ binaryId: "cursor-agent", cliId: "cursor" }
|
|
55543
|
+
{ binaryId: "claude", cliId: "claude" }
|
|
55264
55544
|
];
|
|
55265
55545
|
function buildAnalysisCatalog(statuses, modelsFor) {
|
|
55266
55546
|
const statusById = new Map(statuses.map((status) => [status.id, status]));
|
|
@@ -55285,7 +55565,7 @@ function analysisError(code, message) {
|
|
|
55285
55565
|
return { error: { code, message } };
|
|
55286
55566
|
}
|
|
55287
55567
|
function isAnalysisSelection(catalog, value) {
|
|
55288
|
-
if (!
|
|
55568
|
+
if (!isRecord10(value) || !hasExactKeys(value, ["cliId", "model", "effort", "language"]) || typeof value.cliId !== "string" || typeof value.model !== "string" || value.effort !== void 0 && typeof value.effort !== "string" || value.language !== void 0 && value.language !== "en" && value.language !== "ko") return false;
|
|
55289
55569
|
const cli = catalog.clis.find((candidate) => candidate.cliId === value.cliId);
|
|
55290
55570
|
if (!cli?.available) return false;
|
|
55291
55571
|
const model = cli.models.find((candidate) => candidate.id === value.model);
|
|
@@ -55294,9 +55574,9 @@ function isAnalysisSelection(catalog, value) {
|
|
|
55294
55574
|
return typeof value.effort === "string" && value.effort.length > 0 && model.effortLevels.includes(value.effort);
|
|
55295
55575
|
}
|
|
55296
55576
|
function isMessageBody(value) {
|
|
55297
|
-
return
|
|
55577
|
+
return isRecord10(value) && hasExactKeys(value, ["text"]) && typeof value.text === "string" && value.text.trim().length > 0;
|
|
55298
55578
|
}
|
|
55299
|
-
function
|
|
55579
|
+
function isRecord10(value) {
|
|
55300
55580
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
55301
55581
|
}
|
|
55302
55582
|
function hasExactKeys(value, keys) {
|
|
@@ -55981,6 +56261,146 @@ async function ignoreMissing(operation) {
|
|
|
55981
56261
|
}
|
|
55982
56262
|
}
|
|
55983
56263
|
|
|
56264
|
+
// ../fleet-plugins/terminal/server/ai-gateway-proxy.ts
|
|
56265
|
+
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
56266
|
+
"connection",
|
|
56267
|
+
"content-encoding",
|
|
56268
|
+
"content-length",
|
|
56269
|
+
"keep-alive",
|
|
56270
|
+
"proxy-authenticate",
|
|
56271
|
+
"proxy-authorization",
|
|
56272
|
+
"te",
|
|
56273
|
+
"trailer",
|
|
56274
|
+
"transfer-encoding",
|
|
56275
|
+
"upgrade"
|
|
56276
|
+
]);
|
|
56277
|
+
async function proxyAnthropicMessages(res, body, options) {
|
|
56278
|
+
const upstream = await options.fetchImpl(options.url, {
|
|
56279
|
+
method: "POST",
|
|
56280
|
+
headers: options.headers,
|
|
56281
|
+
body: JSON.stringify(body),
|
|
56282
|
+
signal: options.signal
|
|
56283
|
+
});
|
|
56284
|
+
const responseHeaders = {};
|
|
56285
|
+
upstream.headers.forEach((value, key) => {
|
|
56286
|
+
if (!HOP_BY_HOP_HEADERS.has(key)) responseHeaders[key] = value;
|
|
56287
|
+
});
|
|
56288
|
+
res.writeHead(upstream.status, responseHeaders);
|
|
56289
|
+
if (!upstream.body) {
|
|
56290
|
+
res.end();
|
|
56291
|
+
return;
|
|
56292
|
+
}
|
|
56293
|
+
const rawBody = readResponseBody(upstream.body);
|
|
56294
|
+
const responseBody = options.contextWindow === void 0 && options.responseModel === void 0 ? rawBody : projectAnthropicResponseUsage(rawBody, {
|
|
56295
|
+
contentType: upstream.headers.get("content-type"),
|
|
56296
|
+
contextWindow: options.contextWindow,
|
|
56297
|
+
responseModel: options.responseModel
|
|
56298
|
+
});
|
|
56299
|
+
for await (const chunk of responseBody) {
|
|
56300
|
+
if (!res.write(chunk)) await drain(res);
|
|
56301
|
+
}
|
|
56302
|
+
res.end();
|
|
56303
|
+
}
|
|
56304
|
+
async function* readResponseBody(body) {
|
|
56305
|
+
const reader = body.getReader();
|
|
56306
|
+
try {
|
|
56307
|
+
for (; ; ) {
|
|
56308
|
+
const { done, value } = await reader.read();
|
|
56309
|
+
if (done) return;
|
|
56310
|
+
yield value;
|
|
56311
|
+
}
|
|
56312
|
+
} finally {
|
|
56313
|
+
reader.releaseLock();
|
|
56314
|
+
}
|
|
56315
|
+
}
|
|
56316
|
+
function eagerAnthropicRequestBody(body, model) {
|
|
56317
|
+
return {
|
|
56318
|
+
...body,
|
|
56319
|
+
model,
|
|
56320
|
+
messages: body.messages.map(eagerAnthropicMessage),
|
|
56321
|
+
...body.tools === void 0 ? {} : { tools: body.tools.map(eagerAnthropicTool) }
|
|
56322
|
+
};
|
|
56323
|
+
}
|
|
56324
|
+
function eagerAnthropicTool(tool) {
|
|
56325
|
+
if (!("input_schema" in tool)) return tool;
|
|
56326
|
+
const { defer_loading: _deferLoading, ...eagerTool } = tool;
|
|
56327
|
+
return eagerTool;
|
|
56328
|
+
}
|
|
56329
|
+
function eagerAnthropicMessage(message) {
|
|
56330
|
+
if (typeof message.content === "string") return message;
|
|
56331
|
+
return {
|
|
56332
|
+
...message,
|
|
56333
|
+
content: message.content.map((block) => {
|
|
56334
|
+
if (block.type !== "tool_result" || !Array.isArray(block.content)) return block;
|
|
56335
|
+
return {
|
|
56336
|
+
...block,
|
|
56337
|
+
content: block.content.map((result) => {
|
|
56338
|
+
if (result.type !== "tool_reference") return result;
|
|
56339
|
+
const toolName = typeof result.tool_name === "string" && result.tool_name.length > 0 ? result.tool_name : "(invalid reference)";
|
|
56340
|
+
return { type: "text", text: `Tool available: ${toolName}` };
|
|
56341
|
+
})
|
|
56342
|
+
};
|
|
56343
|
+
})
|
|
56344
|
+
};
|
|
56345
|
+
}
|
|
56346
|
+
async function drain(res) {
|
|
56347
|
+
await new Promise((resolve3) => res.once("drain", resolve3));
|
|
56348
|
+
}
|
|
56349
|
+
function writeAnthropicError(res, status, type, message) {
|
|
56350
|
+
res.writeHead(status, { "content-type": "application/json" });
|
|
56351
|
+
res.end(JSON.stringify({ type: "error", error: { type, message } }));
|
|
56352
|
+
}
|
|
56353
|
+
function writeSseErrorFrame(res, type, message) {
|
|
56354
|
+
try {
|
|
56355
|
+
const data = JSON.stringify({ type: "error", error: { type, message } });
|
|
56356
|
+
res.write(`
|
|
56357
|
+
|
|
56358
|
+
event: error
|
|
56359
|
+
data: ${data}
|
|
56360
|
+
|
|
56361
|
+
`);
|
|
56362
|
+
} catch {
|
|
56363
|
+
}
|
|
56364
|
+
}
|
|
56365
|
+
function errorMessage(error51) {
|
|
56366
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
56367
|
+
}
|
|
56368
|
+
|
|
56369
|
+
// ../fleet-plugins/terminal/server/ai-gateway-opencode.ts
|
|
56370
|
+
function isOpencodeAnthropicPassthrough(model) {
|
|
56371
|
+
return opencodeGoWire(model) === "anthropic";
|
|
56372
|
+
}
|
|
56373
|
+
function createOpencodeGateway(wire) {
|
|
56374
|
+
return new AnthropicMessagesGateway(createOpencodeGoAdapter(wire));
|
|
56375
|
+
}
|
|
56376
|
+
async function proxyToOpencode(requestHeaders, res, body, model, contextWindow, apiKey, fetchImpl, signal) {
|
|
56377
|
+
const headers = {
|
|
56378
|
+
"content-type": "application/json",
|
|
56379
|
+
"anthropic-version": typeof requestHeaders["anthropic-version"] === "string" ? requestHeaders["anthropic-version"] : "2023-06-01",
|
|
56380
|
+
"x-api-key": apiKey
|
|
56381
|
+
};
|
|
56382
|
+
for (const name of ["anthropic-beta", "user-agent"]) {
|
|
56383
|
+
const value = requestHeaders[name];
|
|
56384
|
+
if (typeof value === "string") headers[name] = value;
|
|
56385
|
+
}
|
|
56386
|
+
const responseModel = typeof body.model === "string" ? body.model : void 0;
|
|
56387
|
+
await proxyAnthropicMessages(res, opencodeRequestBody(body, model), {
|
|
56388
|
+
contextWindow,
|
|
56389
|
+
responseModel,
|
|
56390
|
+
fetchImpl,
|
|
56391
|
+
headers,
|
|
56392
|
+
signal,
|
|
56393
|
+
url: OPENCODE_GO_MESSAGES_URL
|
|
56394
|
+
});
|
|
56395
|
+
}
|
|
56396
|
+
function opencodeRequestBody(body, model) {
|
|
56397
|
+
const eagerBody = eagerAnthropicRequestBody(body, model);
|
|
56398
|
+
if (body.output_config === void 0) return eagerBody;
|
|
56399
|
+
const { effort: _effort, ...outputConfig } = body.output_config;
|
|
56400
|
+
const { output_config: _outputConfig, ...withoutOutputConfig } = eagerBody;
|
|
56401
|
+
return Object.keys(outputConfig).length > 0 ? { ...withoutOutputConfig, output_config: outputConfig } : withoutOutputConfig;
|
|
56402
|
+
}
|
|
56403
|
+
|
|
55984
56404
|
// ../fleet-plugins/terminal/server/ai-gateway-routes.ts
|
|
55985
56405
|
var AI_GATEWAY_ROUTE_SEGMENT = "ai-gateway";
|
|
55986
56406
|
var AI_GATEWAY_MODEL_ENV = "FLEET_AI_GATEWAY_MODEL";
|
|
@@ -56083,6 +56503,13 @@ function createAiGatewayRouter(deps = {}) {
|
|
|
56083
56503
|
return true;
|
|
56084
56504
|
}
|
|
56085
56505
|
credential = kimiApiKey;
|
|
56506
|
+
} else if (target2?.provider === "opencode") {
|
|
56507
|
+
const opencodeApiKey = await deps.readOpencodeApiKey?.();
|
|
56508
|
+
if (!opencodeApiKey) {
|
|
56509
|
+
writeAnthropicError(res, 401, "authentication_error", "No OpenCode Go API key was found. Sign in to OpenCode Go first.");
|
|
56510
|
+
return true;
|
|
56511
|
+
}
|
|
56512
|
+
credential = opencodeApiKey;
|
|
56086
56513
|
}
|
|
56087
56514
|
const controller = new AbortController();
|
|
56088
56515
|
const abort = () => controller.abort(new Error("client disconnected"));
|
|
@@ -56106,7 +56533,20 @@ function createAiGatewayRouter(deps = {}) {
|
|
|
56106
56533
|
);
|
|
56107
56534
|
return true;
|
|
56108
56535
|
}
|
|
56109
|
-
|
|
56536
|
+
if (target2.provider === "opencode" && isOpencodeAnthropicPassthrough(target2)) {
|
|
56537
|
+
await proxyToOpencode(
|
|
56538
|
+
req.headers,
|
|
56539
|
+
res,
|
|
56540
|
+
body,
|
|
56541
|
+
upstreamModelId(target2),
|
|
56542
|
+
claudeContextWindow,
|
|
56543
|
+
credential,
|
|
56544
|
+
fetchImpl,
|
|
56545
|
+
controller.signal
|
|
56546
|
+
);
|
|
56547
|
+
return true;
|
|
56548
|
+
}
|
|
56549
|
+
const gateway = deps.gateway ?? (target2.provider === "cursor" ? ownedCursorGateway : target2.provider === "opencode" ? createOpencodeGateway(opencodeGoWire(target2)) : createGatewayFor(target2, chatgptAccountId));
|
|
56110
56550
|
const diagnosticsEnabled = target2.provider === "cursor" ? await cursorDiagnosticsEnabled() : void 0;
|
|
56111
56551
|
const modelContextWindow = typeof target2.contextWindow === "number" && Number.isFinite(target2.contextWindow) && target2.contextWindow > 0 ? target2.contextWindow : void 0;
|
|
56112
56552
|
const upstream = await gateway.stream(body, {
|
|
@@ -56185,8 +56625,10 @@ async function proxyToKimi(requestHeaders, res, body, model, contextWindow, apiK
|
|
|
56185
56625
|
const value = requestHeaders[name];
|
|
56186
56626
|
if (typeof value === "string") headers[name] = value;
|
|
56187
56627
|
}
|
|
56628
|
+
const responseModel = typeof body.model === "string" ? body.model : void 0;
|
|
56188
56629
|
await proxyAnthropicMessages(res, kimiRequestBody(body, model), {
|
|
56189
56630
|
contextWindow,
|
|
56631
|
+
responseModel,
|
|
56190
56632
|
fetchImpl,
|
|
56191
56633
|
headers,
|
|
56192
56634
|
signal,
|
|
@@ -56195,12 +56637,7 @@ async function proxyToKimi(requestHeaders, res, body, model, contextWindow, apiK
|
|
|
56195
56637
|
}
|
|
56196
56638
|
var KIMI_REASONING_EFFORTS = ["low", "high", "max"];
|
|
56197
56639
|
function kimiRequestBody(body, model) {
|
|
56198
|
-
const eagerBody =
|
|
56199
|
-
...body,
|
|
56200
|
-
model,
|
|
56201
|
-
messages: body.messages.map(kimiEagerMessage),
|
|
56202
|
-
...body.tools === void 0 ? {} : { tools: body.tools.map(kimiEagerTool) }
|
|
56203
|
-
};
|
|
56640
|
+
const eagerBody = eagerAnthropicRequestBody(body, model);
|
|
56204
56641
|
const effort = reasoningEffortFromOutputConfig(body.output_config);
|
|
56205
56642
|
if (effort === void 0) {
|
|
56206
56643
|
return eagerBody;
|
|
@@ -56213,78 +56650,6 @@ function kimiRequestBody(body, model) {
|
|
|
56213
56650
|
}
|
|
56214
56651
|
};
|
|
56215
56652
|
}
|
|
56216
|
-
function kimiEagerTool(tool) {
|
|
56217
|
-
if (!("input_schema" in tool)) return tool;
|
|
56218
|
-
const { defer_loading: _deferLoading, ...eagerTool } = tool;
|
|
56219
|
-
return eagerTool;
|
|
56220
|
-
}
|
|
56221
|
-
function kimiEagerMessage(message) {
|
|
56222
|
-
if (typeof message.content === "string") return message;
|
|
56223
|
-
return {
|
|
56224
|
-
...message,
|
|
56225
|
-
content: message.content.map((block) => {
|
|
56226
|
-
if (block.type !== "tool_result" || !Array.isArray(block.content)) return block;
|
|
56227
|
-
return {
|
|
56228
|
-
...block,
|
|
56229
|
-
content: block.content.map((result) => {
|
|
56230
|
-
if (result.type !== "tool_reference") return result;
|
|
56231
|
-
const toolName = typeof result.tool_name === "string" && result.tool_name.length > 0 ? result.tool_name : "(invalid reference)";
|
|
56232
|
-
return { type: "text", text: `Tool available: ${toolName}` };
|
|
56233
|
-
})
|
|
56234
|
-
};
|
|
56235
|
-
})
|
|
56236
|
-
};
|
|
56237
|
-
}
|
|
56238
|
-
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
56239
|
-
"connection",
|
|
56240
|
-
"content-encoding",
|
|
56241
|
-
"content-length",
|
|
56242
|
-
"keep-alive",
|
|
56243
|
-
"proxy-authenticate",
|
|
56244
|
-
"proxy-authorization",
|
|
56245
|
-
"te",
|
|
56246
|
-
"trailer",
|
|
56247
|
-
"transfer-encoding",
|
|
56248
|
-
"upgrade"
|
|
56249
|
-
]);
|
|
56250
|
-
async function proxyAnthropicMessages(res, body, options) {
|
|
56251
|
-
const upstream = await options.fetchImpl(options.url, {
|
|
56252
|
-
method: "POST",
|
|
56253
|
-
headers: options.headers,
|
|
56254
|
-
body: JSON.stringify(body),
|
|
56255
|
-
signal: options.signal
|
|
56256
|
-
});
|
|
56257
|
-
const responseHeaders = {};
|
|
56258
|
-
upstream.headers.forEach((value, key) => {
|
|
56259
|
-
if (!HOP_BY_HOP_HEADERS.has(key)) responseHeaders[key] = value;
|
|
56260
|
-
});
|
|
56261
|
-
res.writeHead(upstream.status, responseHeaders);
|
|
56262
|
-
if (!upstream.body) {
|
|
56263
|
-
res.end();
|
|
56264
|
-
return;
|
|
56265
|
-
}
|
|
56266
|
-
const rawBody = readResponseBody(upstream.body);
|
|
56267
|
-
const responseBody = options.contextWindow === void 0 ? rawBody : projectAnthropicResponseUsage(rawBody, {
|
|
56268
|
-
contentType: upstream.headers.get("content-type"),
|
|
56269
|
-
contextWindow: options.contextWindow
|
|
56270
|
-
});
|
|
56271
|
-
for await (const chunk of responseBody) {
|
|
56272
|
-
if (!res.write(chunk)) await drain(res);
|
|
56273
|
-
}
|
|
56274
|
-
res.end();
|
|
56275
|
-
}
|
|
56276
|
-
async function* readResponseBody(body) {
|
|
56277
|
-
const reader = body.getReader();
|
|
56278
|
-
try {
|
|
56279
|
-
for (; ; ) {
|
|
56280
|
-
const { done, value } = await reader.read();
|
|
56281
|
-
if (done) return;
|
|
56282
|
-
yield value;
|
|
56283
|
-
}
|
|
56284
|
-
} finally {
|
|
56285
|
-
reader.releaseLock();
|
|
56286
|
-
}
|
|
56287
|
-
}
|
|
56288
56653
|
function createGatewayFor(model, chatgptAccountId) {
|
|
56289
56654
|
if (model.provider !== "codex") {
|
|
56290
56655
|
throw new TypeError(`Unsupported translated gateway provider: ${model.provider}`);
|
|
@@ -56321,28 +56686,6 @@ function headerEntries(headers) {
|
|
|
56321
56686
|
});
|
|
56322
56687
|
return entries;
|
|
56323
56688
|
}
|
|
56324
|
-
async function drain(res) {
|
|
56325
|
-
await new Promise((resolve3) => res.once("drain", resolve3));
|
|
56326
|
-
}
|
|
56327
|
-
function writeAnthropicError(res, status, type, message) {
|
|
56328
|
-
res.writeHead(status, { "content-type": "application/json" });
|
|
56329
|
-
res.end(JSON.stringify({ type: "error", error: { type, message } }));
|
|
56330
|
-
}
|
|
56331
|
-
function writeSseErrorFrame(res, type, message) {
|
|
56332
|
-
try {
|
|
56333
|
-
const data = JSON.stringify({ type: "error", error: { type, message } });
|
|
56334
|
-
res.write(`
|
|
56335
|
-
|
|
56336
|
-
event: error
|
|
56337
|
-
data: ${data}
|
|
56338
|
-
|
|
56339
|
-
`);
|
|
56340
|
-
} catch {
|
|
56341
|
-
}
|
|
56342
|
-
}
|
|
56343
|
-
function errorMessage(error51) {
|
|
56344
|
-
return error51 instanceof Error ? error51.message : String(error51);
|
|
56345
|
-
}
|
|
56346
56689
|
|
|
56347
56690
|
// ../fleet-plugins/terminal/server/carrier-settings-routes.ts
|
|
56348
56691
|
var CARRIER_SETTINGS_PRESENTATION_LOCALES = CARRIER_PRESENTATION_LOCALES;
|
|
@@ -56776,23 +57119,38 @@ function registerGlobalShellRoutes(ctx, runtime) {
|
|
|
56776
57119
|
}
|
|
56777
57120
|
|
|
56778
57121
|
// ../fleet-plugins/terminal/server/model-auth-state.ts
|
|
57122
|
+
var MODEL_AUTH_STORE_IDS = Object.freeze({
|
|
57123
|
+
kimi: KIMI_AUTH_PROVIDER_ID,
|
|
57124
|
+
opencode: OPENCODE_AUTH_PROVIDER_ID
|
|
57125
|
+
});
|
|
57126
|
+
var MODEL_AUTH_DISPLAY_NAMES = Object.freeze({
|
|
57127
|
+
kimi: "Kimi for AI Gateway",
|
|
57128
|
+
opencode: "OpenCode Go for AI Gateway"
|
|
57129
|
+
});
|
|
57130
|
+
function isTerminalModelAuthProviderId(value) {
|
|
57131
|
+
return value in MODEL_AUTH_STORE_IDS;
|
|
57132
|
+
}
|
|
56779
57133
|
async function buildModelAuthState(authService) {
|
|
56780
57134
|
const signedInIds = new Set(await authService.listProviderIds());
|
|
56781
57135
|
return {
|
|
56782
|
-
providers:
|
|
56783
|
-
provider
|
|
56784
|
-
displayName:
|
|
56785
|
-
signedIn: signedInIds.has(
|
|
56786
|
-
}
|
|
57136
|
+
providers: Object.keys(MODEL_AUTH_STORE_IDS).map((provider) => ({
|
|
57137
|
+
provider,
|
|
57138
|
+
displayName: MODEL_AUTH_DISPLAY_NAMES[provider],
|
|
57139
|
+
signedIn: signedInIds.has(MODEL_AUTH_STORE_IDS[provider])
|
|
57140
|
+
}))
|
|
56787
57141
|
};
|
|
56788
57142
|
}
|
|
56789
57143
|
|
|
56790
57144
|
// ../fleet-plugins/terminal/server/model-auth-routes.ts
|
|
56791
57145
|
var UPSTREAM_FAILURE_STATUSES = /* @__PURE__ */ new Set(["timeout", "network", "server"]);
|
|
57146
|
+
var MODEL_AUTH_VALIDATORS = {
|
|
57147
|
+
kimi: validateKimiAuthKey,
|
|
57148
|
+
opencode: validateOpencodeGoAuthKey
|
|
57149
|
+
};
|
|
56792
57150
|
function registerTerminalModelAuthRoutes(ctx, deps) {
|
|
56793
57151
|
registerRouter(ctx, "model-auth", createTerminalModelAuthRouter(ctx, {
|
|
56794
57152
|
...deps,
|
|
56795
|
-
validateApiKey:
|
|
57153
|
+
validateApiKey: (provider, apiKey) => MODEL_AUTH_VALIDATORS[provider](apiKey)
|
|
56796
57154
|
}));
|
|
56797
57155
|
}
|
|
56798
57156
|
function createTerminalModelAuthRouter(ctx, deps) {
|
|
@@ -56808,11 +57166,11 @@ function createTerminalModelAuthRouter(ctx, deps) {
|
|
|
56808
57166
|
}
|
|
56809
57167
|
const providerId = parseProviderPath(path44);
|
|
56810
57168
|
if (!providerId) return false;
|
|
56811
|
-
if (providerId
|
|
57169
|
+
if (!isTerminalModelAuthProviderId(providerId)) {
|
|
56812
57170
|
ctx.host.http.writeJson(res, 404, { error: "provider_not_found" });
|
|
56813
57171
|
return true;
|
|
56814
57172
|
}
|
|
56815
|
-
const provider = await findProvider(deps);
|
|
57173
|
+
const provider = await findProvider(deps, providerId);
|
|
56816
57174
|
if (!provider) {
|
|
56817
57175
|
ctx.host.http.writeJson(res, 404, { error: "provider_not_found" });
|
|
56818
57176
|
return true;
|
|
@@ -56822,7 +57180,7 @@ function createTerminalModelAuthRouter(ctx, deps) {
|
|
|
56822
57180
|
return true;
|
|
56823
57181
|
}
|
|
56824
57182
|
if (req.method === "DELETE") {
|
|
56825
|
-
await signOutProvider(ctx, req, res, deps);
|
|
57183
|
+
await signOutProvider(ctx, req, res, deps, provider.provider);
|
|
56826
57184
|
return true;
|
|
56827
57185
|
}
|
|
56828
57186
|
ctx.host.http.writeJson(res, 405, { error: "Method not allowed" });
|
|
@@ -56848,7 +57206,7 @@ async function signInProvider(ctx, req, res, deps, provider) {
|
|
|
56848
57206
|
return;
|
|
56849
57207
|
}
|
|
56850
57208
|
const apiKey = body.apiKey.trim();
|
|
56851
|
-
const validation = await deps.validateApiKey(apiKey);
|
|
57209
|
+
const validation = await deps.validateApiKey(provider.provider, apiKey);
|
|
56852
57210
|
if (validation.status !== "success") {
|
|
56853
57211
|
ctx.host.http.writeJson(res, UPSTREAM_FAILURE_STATUSES.has(validation.status) ? 502 : 400, {
|
|
56854
57212
|
error: formatSignInFailureMessage(provider.displayName, validation.status),
|
|
@@ -56856,22 +57214,23 @@ async function signInProvider(ctx, req, res, deps, provider) {
|
|
|
56856
57214
|
});
|
|
56857
57215
|
return;
|
|
56858
57216
|
}
|
|
56859
|
-
await deps.authService.setApiKey(
|
|
57217
|
+
await deps.authService.setApiKey(MODEL_AUTH_STORE_IDS[provider.provider], apiKey);
|
|
56860
57218
|
await writeMutationState2(ctx, res, deps);
|
|
56861
57219
|
}
|
|
56862
|
-
async function signOutProvider(ctx, req, res, deps) {
|
|
57220
|
+
async function signOutProvider(ctx, req, res, deps, provider) {
|
|
56863
57221
|
if (!ctx.host.security.isTerminalAuthorized(req)) {
|
|
56864
57222
|
ctx.host.http.writeJson(res, 401, { error: "unauthorized" });
|
|
56865
57223
|
return;
|
|
56866
57224
|
}
|
|
56867
|
-
await deps.authService.deleteApiKey(
|
|
57225
|
+
await deps.authService.deleteApiKey(MODEL_AUTH_STORE_IDS[provider]);
|
|
56868
57226
|
await writeMutationState2(ctx, res, deps);
|
|
56869
57227
|
}
|
|
56870
57228
|
async function writeMutationState2(ctx, res, deps) {
|
|
56871
57229
|
ctx.host.http.writeJson(res, 200, { state: await buildModelAuthState(deps.authService) });
|
|
56872
57230
|
}
|
|
56873
|
-
async function findProvider(deps) {
|
|
56874
|
-
|
|
57231
|
+
async function findProvider(deps, providerId) {
|
|
57232
|
+
const state = await buildModelAuthState(deps.authService);
|
|
57233
|
+
return state.providers.find((provider) => provider.provider === providerId) ?? null;
|
|
56875
57234
|
}
|
|
56876
57235
|
function parseProviderPath(path44) {
|
|
56877
57236
|
const parts = path44.split("/").filter(Boolean);
|
|
@@ -57031,7 +57390,8 @@ var routes_default = definePlugin({
|
|
|
57031
57390
|
registerTerminalModelAuthRoutes(ctx, { authService: infraServices.authService });
|
|
57032
57391
|
registerAiGatewayRoutes(ctx, {
|
|
57033
57392
|
readAiGatewaySettings: aiGatewayStore.read,
|
|
57034
|
-
readKimiApiKey: () => infraServices.authService.getApiKey(KIMI_AUTH_PROVIDER_ID)
|
|
57393
|
+
readKimiApiKey: () => infraServices.authService.getApiKey(KIMI_AUTH_PROVIDER_ID),
|
|
57394
|
+
readOpencodeApiKey: () => infraServices.authService.getApiKey(OPENCODE_AUTH_PROVIDER_ID)
|
|
57035
57395
|
});
|
|
57036
57396
|
registerCarrierSettingsRoutes(ctx, { registry: carrierRegistry });
|
|
57037
57397
|
const agentCliPathStore = createAgentCliPathStore(ctx.host.storage, ctx.pluginId);
|