@covro/covro 0.5.1-dev.2 → 0.5.1-dev.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/README.zh-CN.md +11 -1
- package/dist/codex/adapter.js +65 -5
- package/dist/codex/adapter.js.map +2 -2
- package/dist/codex/collaboration.js +28 -0
- package/dist/codex/collaboration.js.map +7 -0
- package/dist/codex/guardian-denials.js +67 -0
- package/dist/codex/guardian-denials.js.map +7 -0
- package/dist/codex/mapping.js +10 -1
- package/dist/codex/mapping.js.map +2 -2
- package/dist/codex/thread-goals.js +15 -0
- package/dist/codex/thread-goals.js.map +7 -0
- package/dist/codex/thread-titles.js +135 -60
- package/dist/codex/thread-titles.js.map +2 -2
- package/dist/server/capacity-retry.js +176 -0
- package/dist/server/capacity-retry.js.map +7 -0
- package/dist/server/db/operations.js +11 -0
- package/dist/server/db/operations.js.map +2 -2
- package/dist/server/http.js +51 -0
- package/dist/server/http.js.map +2 -2
- package/dist/server/project-init.js +28 -0
- package/dist/server/project-init.js.map +7 -0
- package/dist/server/projection.js +11 -3
- package/dist/server/projection.js.map +2 -2
- package/dist/server/service.js +315 -8
- package/dist/server/service.js.map +2 -2
- package/dist/server/thread-recap.js +34 -0
- package/dist/server/thread-recap.js.map +7 -0
- package/dist/server/workspace-diff.js +149 -0
- package/dist/server/workspace-diff.js.map +7 -0
- package/dist/shared/guardian-denials.js +1 -0
- package/dist/shared/guardian-denials.js.map +7 -0
- package/dist/shared/thread-goal.js +1 -0
- package/dist/shared/thread-goal.js.map +7 -0
- package/dist/shared/turn-errors.js +25 -0
- package/dist/shared/turn-errors.js.map +7 -0
- package/dist/shared/validation.js +53 -3
- package/dist/shared/validation.js.map +2 -2
- package/dist/shared/workspace-diff.js +1 -0
- package/dist/shared/workspace-diff.js.map +7 -0
- package/dist/web/assets/{abnfDiagram-WEYOIA3C-DK1b1m5g.js → abnfDiagram-WEYOIA3C-2_00Zp4O.js} +1 -1
- package/dist/web/assets/{arc-0hKPa6cH.js → arc-DAyuVDVU.js} +1 -1
- package/dist/web/assets/{architecture-WOLXFQ4H-DUa2ELbW.js → architecture-WOLXFQ4H-CgR1C4gR.js} +1 -1
- package/dist/web/assets/{architectureDiagram-ZHVYKT53-DfpAMcHI.js → architectureDiagram-ZHVYKT53-Dkb6AWjz.js} +1 -1
- package/dist/web/assets/{blockDiagram-RJAE7QA3-CD8LlPAk.js → blockDiagram-RJAE7QA3-NtOGZdkX.js} +1 -1
- package/dist/web/assets/{c4Diagram-XDPPPE54-KVKGUBPP.js → c4Diagram-XDPPPE54-C1dqWKb1.js} +1 -1
- package/dist/web/assets/channel-Co9_v2dk.js +1 -0
- package/dist/web/assets/{chunk-2E7WHVMD-CPcfaznm.js → chunk-2E7WHVMD-ClzuEiGk.js} +1 -1
- package/dist/web/assets/{chunk-4EMNKR2T-Ba4ZkZos.js → chunk-4EMNKR2T-DyTpkWag.js} +1 -1
- package/dist/web/assets/{chunk-55XCU76K-COU6aQoV.js → chunk-55XCU76K-DXBA4ib1.js} +1 -1
- package/dist/web/assets/{chunk-7S6XSTFO-mof6va94.js → chunk-7S6XSTFO-DA_aq0zc.js} +1 -1
- package/dist/web/assets/{chunk-AQDTSKZB-B9S7XD0k.js → chunk-AQDTSKZB-BWTN3SC_.js} +1 -1
- package/dist/web/assets/{chunk-DSNLSHJZ-DiTTjo21.js → chunk-DSNLSHJZ-DJnLTeE9.js} +1 -1
- package/dist/web/assets/{chunk-HAGFOTED-bBaCv2Gr.js → chunk-HAGFOTED-cDP-g1Eh.js} +1 -1
- package/dist/web/assets/{chunk-HNE4Q36P-COubV5SQ.js → chunk-HNE4Q36P-B3TTIYd_.js} +1 -1
- package/dist/web/assets/{chunk-NQOKRVIF-D7mCDLmx.js → chunk-NQOKRVIF-D8mmhZHq.js} +1 -1
- package/dist/web/assets/{chunk-UHW7PFBP-7E_Y7QMq.js → chunk-UHW7PFBP-DWIIg_jq.js} +1 -1
- package/dist/web/assets/{chunk-VQ5W62QI-DIe2sxBO.js → chunk-VQ5W62QI-Bu3R2cpS.js} +1 -1
- package/dist/web/assets/{chunk-WQQL4CDK-sGc70NW0.js → chunk-WQQL4CDK-BxsR1mXs.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-CnTJfCp_.js → chunk-XXDRQBXY-Ds0JNdm-.js} +1 -1
- package/dist/web/assets/{chunk-YZO67HFG-D1uBxw_D.js → chunk-YZO67HFG-COpqyQaD.js} +1 -1
- package/dist/web/assets/{chunk-ZAUX2LTX-quytYPeh.js → chunk-ZAUX2LTX-BUrGjDuS.js} +1 -1
- package/dist/web/assets/{chunk-ZCHMQSOR-CebhdtBu.js → chunk-ZCHMQSOR-DYMM9mEK.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-4MYWR3UA-_NujQwSa.js → classDiagram-v2-4MYWR3UA-DfJvks0C.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-DltmODTL.js → cose-bilkent-JH36ORCC-CN5mpYIb.js} +1 -1
- package/dist/web/assets/{cynefin-EF2NZ3EQ-CyNUtvfu.js → cynefin-EF2NZ3EQ-DmlCHkY-.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-WF24UDRP-DH1m77PD.js → cynefinDiagram-WF24UDRP-C0aUblC2.js} +1 -1
- package/dist/web/assets/{dagre-NK4GIZVX-DiCwjat3.js → dagre-NK4GIZVX-Ba7RcAgP.js} +1 -1
- package/dist/web/assets/{diagram-CBK3MWTC-DnoBkry8.js → diagram-CBK3MWTC-BYQDjB9i.js} +1 -1
- package/dist/web/assets/{diagram-I5XIIV2D-CIeRHNwj.js → diagram-I5XIIV2D-EV79hoob.js} +1 -1
- package/dist/web/assets/{diagram-ODIL2UCW-BiyJagHP.js → diagram-ODIL2UCW-BvQdwmgA.js} +1 -1
- package/dist/web/assets/{diagram-PFBEJUXE-B6xGLENr.js → diagram-PFBEJUXE-hxwI3F00.js} +1 -1
- package/dist/web/assets/{diagram-RJA3I4VV-DCbGrXsR.js → diagram-RJA3I4VV-DwaHE2iB.js} +1 -1
- package/dist/web/assets/{diagram-TYUNFSNR-BjYXlBMa.js → diagram-TYUNFSNR-BxiOemA0.js} +1 -1
- package/dist/web/assets/{dist-C9Qd1YEe.js → dist-nfRX7L9k.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-V4P3TTPT-CpRXdAa6.js → ebnfDiagram-V4P3TTPT-CzQv5iDM.js} +1 -1
- package/dist/web/assets/{elk-QONTBCTQ-BZa9Vnbc.js → elk-QONTBCTQ-DNR9HWcl.js} +1 -1
- package/dist/web/assets/{erDiagram-KYQIGQAA-7AaYG_a9.js → erDiagram-KYQIGQAA-aJlTdb9w.js} +1 -1
- package/dist/web/assets/{eventmodeling-K75KTNOO-BzIg1KNf.js → eventmodeling-K75KTNOO-D4J-ujy-.js} +1 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-Bq7dmPlS.js +1 -0
- package/dist/web/assets/{ganttDiagram-R7GPNTJY-DeNg-7K2.js → ganttDiagram-R7GPNTJY-DgytSfqO.js} +1 -1
- package/dist/web/assets/{gitGraph-VSP46ZUC-BR-A7hdM.js → gitGraph-VSP46ZUC-BtjueFHB.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-LMyLpeqK.js → gitGraphDiagram-PDYL7XHY-WP0Hjdh9.js} +1 -1
- package/dist/web/assets/index-BesPYgjq.js +156 -0
- package/dist/web/assets/{index-CEM8pkOB.css → index-qYBdGqKM.css} +1 -1
- package/dist/web/assets/{info-OHQRW6UA-CRbCGNnm.js → info-OHQRW6UA-iuP0WTfn.js} +1 -1
- package/dist/web/assets/{infoDiagram-MVDRKAX5-DTUWae1O.js → infoDiagram-MVDRKAX5-CpAtMyKS.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-CE4r0jTM.js → ishikawaDiagram-HPEHV2GE-JTnItv7N.js} +1 -1
- package/dist/web/assets/{journeyDiagram-BOSHW7O7-KcSuVnTV.js → journeyDiagram-BOSHW7O7-B333k1QJ.js} +1 -1
- package/dist/web/assets/{kanban-definition-FNSA4HC5-I0QF1Ftr.js → kanban-definition-FNSA4HC5-DpCk5ZH0.js} +1 -1
- package/dist/web/assets/{line-DLSy1-se.js → line-CLs-qFxt.js} +1 -1
- package/dist/web/assets/{linear-XWNSUdmR.js → linear-E9AWqBNs.js} +1 -1
- package/dist/web/assets/{mermaid-parser.core-BcMfaJSH.js → mermaid-parser.core-D1rEzlb-.js} +3 -3
- package/dist/web/assets/{mermaid.core-CPl3cZ55.js → mermaid.core-D6TNGGsX.js} +4 -4
- package/dist/web/assets/{mindmap-definition-6OY57UG3-BIB4ahHf.js → mindmap-definition-6OY57UG3-DrpuGWuc.js} +1 -1
- package/dist/web/assets/{packet-JDAUHWVQ-UZicf9-F.js → packet-JDAUHWVQ-BpBr3aKk.js} +1 -1
- package/dist/web/assets/{pegDiagram-ECIUJNBX-ckOqIfTt.js → pegDiagram-ECIUJNBX-BrZX1cdv.js} +1 -1
- package/dist/web/assets/{pie-XZMESJXO-DErhKWJX.js → pie-XZMESJXO-CcTpis-K.js} +1 -1
- package/dist/web/assets/{pieDiagram-GNMPY74T-CrnS_2qe.js → pieDiagram-GNMPY74T-CR2em875.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-D57K4MC3-UK4DsDJz.js → quadrantDiagram-D57K4MC3-D-ET5xbH.js} +1 -1
- package/dist/web/assets/{radar-ABXABTNO-BYgJm4I9.js → radar-ABXABTNO-CTFFPCi_.js} +1 -1
- package/dist/web/assets/{railroad-I3PHUGI6-2n6yUb7T.js → railroad-I3PHUGI6-S6MHolw_.js} +1 -1
- package/dist/web/assets/{railroad-abnf-LNEFI6M7-CGAFqTzs.js → railroad-abnf-LNEFI6M7-NWxYLYMN.js} +1 -1
- package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-gJx_FXYW.js → railroad-ebnf-DWYD2UWJ-CRnaPl26.js} +1 -1
- package/dist/web/assets/{railroad-peg-JR7BVNR7-Dm0kEaxK.js → railroad-peg-JR7BVNR7-CB85ffhO.js} +1 -1
- package/dist/web/assets/{railroadDiagram-Y72NRBL7-CqzySn4U.js → railroadDiagram-Y72NRBL7-Ba2xIF7q.js} +1 -1
- package/dist/web/assets/{requirementDiagram-EQYSW5RA-B33Hrc0L.js → requirementDiagram-EQYSW5RA-B7faqgDT.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-SY24JHO5-BA9Smc0j.js → sankeyDiagram-SY24JHO5-IjJVI58S.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-BLEHNHQU-CUA-rKot.js → sequenceDiagram-BLEHNHQU-D-h5jxwQ.js} +1 -1
- package/dist/web/assets/{src-htchAh5W.js → src-hBdSvoFJ.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-kIYMkX3_.js → stateDiagram-v2-A6IESKWZ-rlZaPFqZ.js} +1 -1
- package/dist/web/assets/{swimlanes-B3ENRKFQ-C8Lzsqig.js → swimlanes-B3ENRKFQ-CqgKwSbP.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-BGvWQ2Hp.js +8 -0
- package/dist/web/assets/{timeline-definition-JXYKGLGB-C3uOHb1e.js → timeline-definition-JXYKGLGB-DD76ZtY0.js} +1 -1
- package/dist/web/assets/{treeView-D4JQ5SDB-Dq-ug1SE.js → treeView-D4JQ5SDB-CcwWh4Bw.js} +1 -1
- package/dist/web/assets/{treemap-SAJKECNS-mX01fnXB.js → treemap-SAJKECNS-8lde6V5O.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-WPOLBNNX-DMBep2-D.js → usecaseDiagram-WPOLBNNX-CWowobZv.js} +1 -1
- package/dist/web/assets/{vennDiagram-Q3Y3IDCW-CUardqBP.js → vennDiagram-Q3Y3IDCW-U11W8pHe.js} +1 -1
- package/dist/web/assets/{wardley-7MLQ67FV-CIOqSz29.js → wardley-7MLQ67FV-Dp2EaBmo.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-IVAIDKWA-DtfU2fzi.js → wardleyDiagram-IVAIDKWA-7Qnos8ak.js} +1 -1
- package/dist/web/assets/{xychartDiagram-4URNHDU4-Cb3se94q.js → xychartDiagram-4URNHDU4-BwfHNtsG.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/channel-CpEW0zog.js +0 -1
- package/dist/web/assets/flowDiagram-IUGLLWBU-FDG_7_Jf.js +0 -1
- package/dist/web/assets/index-D2dQZgkr.js +0 -147
- package/dist/web/assets/swimlanesDiagram-AYQRV4AK-CWrPdxiH.js +0 -8
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/codex/guardian-denials.ts"],
|
|
4
|
+
"sourcesContent": ["import type { GuardianDenial } from '../shared/guardian-denials.js';\nimport type { JsonValue } from './generated/serde_json/JsonValue.js';\nimport type { ItemGuardianApprovalReviewCompletedNotification } from './generated/v2/ItemGuardianApprovalReviewCompletedNotification.js';\nimport { mapAutoReview } from './auto-review.js';\nimport { AppError } from '../shared/errors.js';\n\n// v2 uses camelCase; the retry RPC expects the core protocol's snake_case event.\n// Convert keys only: command text, paths, argument values and IDs remain verbatim.\nfunction coreKeys(value: unknown): JsonValue {\n if (Array.isArray(value)) return value.map(coreKeys);\n if (value && typeof value === 'object')\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [\n key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`),\n coreKeys(item),\n ]),\n );\n return value as JsonValue;\n}\nexport class GuardianDenials {\n private readonly entries = new Map<\n string,\n Map<string, { view: GuardianDenial; event: JsonValue }>\n >();\n clear(): void {\n this.entries.clear();\n this.consumed.clear();\n }\n forget(threadId: string): void {\n this.entries.delete(threadId);\n }\n record(p: ItemGuardianApprovalReviewCompletedNotification): void {\n if (p.review.status !== 'denied') return;\n const entries = this.entries.get(p.threadId) ?? new Map();\n const action = coreKeys(p.action) as Record<string, JsonValue>;\n action.type = p.action.type.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n if ('source' in p.action)\n action.source = p.action.source === 'unifiedExec' ? 'unified_exec' : p.action.source;\n const event: JsonValue = {\n id: p.reviewId,\n target_item_id: p.targetItemId,\n turn_id: p.turnId,\n started_at_ms: p.startedAtMs,\n completed_at_ms: p.completedAtMs,\n status: 'denied',\n risk_level: p.review.riskLevel,\n user_authorization: p.review.userAuthorization,\n rationale: p.review.rationale,\n decision_source: p.decisionSource,\n action,\n };\n // Consumed identities cannot be reintroduced by a duplicate notification.\n if (!entries.has(p.reviewId))\n entries.set(p.reviewId, {\n view: { id: p.reviewId, turnId: p.turnId, review: mapAutoReview(p) },\n event,\n });\n while (entries.size > 10) entries.delete(entries.keys().next().value!);\n this.entries.set(p.threadId, entries);\n }\n private readonly consumed = new Set<string>();\n list(threadId: string): GuardianDenial[] {\n return [...(this.entries.get(threadId)?.values() ?? [])]\n .filter((entry) => !this.consumed.has(`${threadId}:${entry.view.id}`))\n .map((entry) => entry.view)\n .reverse();\n }\n take(threadId: string, id: string): JsonValue {\n const key = `${threadId}:${id}`;\n const entry = this.entries.get(threadId)?.get(id);\n if (!entry || this.consumed.has(key))\n throw new AppError('DENIAL_EXPIRED', '\u62D2\u7EDD\u8BB0\u5F55\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD', 409);\n this.consumed.add(key);\n return entry.event;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAGA,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AAIzB,SAAS,SAAS,OAA2B;AAC3C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,QAAQ;AACnD,MAAI,SAAS,OAAO,UAAU;AAC5B,WAAO,OAAO;AAAA,MACZ,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM;AAAA,QACzC,IAAI,QAAQ,UAAU,CAAC,WAAW,IAAI,OAAO,YAAY,CAAC,EAAE;AAAA,QAC5D,SAAS,IAAI;AAAA,MACf,CAAC;AAAA,IACH;AACF,SAAO;AACT;AACO,MAAM,gBAAgB;AAAA,EACV,UAAU,oBAAI,IAG7B;AAAA,EACF,QAAc;AACZ,SAAK,QAAQ,MAAM;AACnB,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EACA,OAAO,UAAwB;AAC7B,SAAK,QAAQ,OAAO,QAAQ;AAAA,EAC9B;AAAA,EACA,OAAO,GAA0D;AAC/D,QAAI,EAAE,OAAO,WAAW,SAAU;AAClC,UAAM,UAAU,KAAK,QAAQ,IAAI,EAAE,QAAQ,KAAK,oBAAI,IAAI;AACxD,UAAM,SAAS,SAAS,EAAE,MAAM;AAChC,WAAO,OAAO,EAAE,OAAO,KAAK,QAAQ,UAAU,CAAC,WAAW,IAAI,OAAO,YAAY,CAAC,EAAE;AACpF,QAAI,YAAY,EAAE;AAChB,aAAO,SAAS,EAAE,OAAO,WAAW,gBAAgB,iBAAiB,EAAE,OAAO;AAChF,UAAM,QAAmB;AAAA,MACvB,IAAI,EAAE;AAAA,MACN,gBAAgB,EAAE;AAAA,MAClB,SAAS,EAAE;AAAA,MACX,eAAe,EAAE;AAAA,MACjB,iBAAiB,EAAE;AAAA,MACnB,QAAQ;AAAA,MACR,YAAY,EAAE,OAAO;AAAA,MACrB,oBAAoB,EAAE,OAAO;AAAA,MAC7B,WAAW,EAAE,OAAO;AAAA,MACpB,iBAAiB,EAAE;AAAA,MACnB;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,IAAI,EAAE,QAAQ;AACzB,cAAQ,IAAI,EAAE,UAAU;AAAA,QACtB,MAAM,EAAE,IAAI,EAAE,UAAU,QAAQ,EAAE,QAAQ,QAAQ,cAAc,CAAC,EAAE;AAAA,QACnE;AAAA,MACF,CAAC;AACH,WAAO,QAAQ,OAAO,GAAI,SAAQ,OAAO,QAAQ,KAAK,EAAE,KAAK,EAAE,KAAM;AACrE,SAAK,QAAQ,IAAI,EAAE,UAAU,OAAO;AAAA,EACtC;AAAA,EACiB,WAAW,oBAAI,IAAY;AAAA,EAC5C,KAAK,UAAoC;AACvC,WAAO,CAAC,GAAI,KAAK,QAAQ,IAAI,QAAQ,GAAG,OAAO,KAAK,CAAC,CAAE,EACpD,OAAO,CAAC,UAAU,CAAC,KAAK,SAAS,IAAI,GAAG,QAAQ,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC,EACpE,IAAI,CAAC,UAAU,MAAM,IAAI,EACzB,QAAQ;AAAA,EACb;AAAA,EACA,KAAK,UAAkB,IAAuB;AAC5C,UAAM,MAAM,GAAG,QAAQ,IAAI,EAAE;AAC7B,UAAM,QAAQ,KAAK,QAAQ,IAAI,QAAQ,GAAG,IAAI,EAAE;AAChD,QAAI,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG;AACjC,YAAM,IAAI,SAAS,kBAAkB,0GAAqB,GAAG;AAC/D,SAAK,SAAS,IAAI,GAAG;AACrB,WAAO,MAAM;AAAA,EACf;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/codex/mapping.js
CHANGED
|
@@ -3,6 +3,14 @@ import { permissionSettings } from "./permissions.js";
|
|
|
3
3
|
import { parseQuestionReplies } from "../shared/async-questions.js";
|
|
4
4
|
import { imageDataBytes, MAX_IMAGES, MAX_IMAGE_BYTES } from "../shared/images.js";
|
|
5
5
|
import { CodexError, isRecord } from "./transport.js";
|
|
6
|
+
function mapTurnError(error) {
|
|
7
|
+
const info = error.codexErrorInfo;
|
|
8
|
+
const code = typeof info === "string" ? info : isRecord(info) ? Object.keys(info)[0] : void 0;
|
|
9
|
+
return {
|
|
10
|
+
...code ? { errorCode: code.slice(0, 100) } : {},
|
|
11
|
+
...error.additionalDetails ? { errorDetails: error.additionalDetails.slice(0, 4096) } : {}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
6
14
|
function taskInput(text, images = []) {
|
|
7
15
|
return [
|
|
8
16
|
...text ? [{ type: "text", text, text_elements: [] }] : [],
|
|
@@ -72,7 +80,7 @@ function mapTurn(threadId, turn) {
|
|
|
72
80
|
...validTiming(turn.completedAt) ? { completedAt: turn.completedAt * 1e3 } : {},
|
|
73
81
|
...validTiming(turn.durationMs) ? { durationMs: turn.durationMs } : {},
|
|
74
82
|
items: turn.items.map(mapItem),
|
|
75
|
-
...turn.error ? { error: turn.error.message } : {}
|
|
83
|
+
...turn.error ? { error: turn.error.message, ...mapTurnError(turn.error) } : {}
|
|
76
84
|
};
|
|
77
85
|
}
|
|
78
86
|
function validTiming(value) {
|
|
@@ -200,6 +208,7 @@ export {
|
|
|
200
208
|
mapItem,
|
|
201
209
|
mapThread,
|
|
202
210
|
mapTurn,
|
|
211
|
+
mapTurnError,
|
|
203
212
|
permissionSettings,
|
|
204
213
|
serviceTierSettings,
|
|
205
214
|
taskInput,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/mapping.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n ItemView,\n RunStatus,\n RuntimeSettings,\n Settings,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport { permissionModes } from '../shared/permissions.js';\nimport type { PermissionSelection } from './permissions.js';\nexport { permissionSettings } from './permissions.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadItem } from './generated/v2/ThreadItem.js';\nimport type { ThreadStatus } from './generated/v2/ThreadStatus.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport type { TurnStartParams } from './generated/v2/TurnStartParams.js';\nimport type { ReasoningEffort } from './generated/ReasoningEffort.js';\nimport type { UserInput } from './generated/v2/UserInput.js';\nimport { parseQuestionReplies } from '../shared/async-questions.js';\nimport { imageDataBytes, MAX_IMAGES, MAX_IMAGE_BYTES } from '../shared/images.js';\nimport { CodexError, isRecord } from './transport.js';\n\nexport function taskInput(text: string, images: string[] = []): UserInput[] {\n return [\n ...(text ? [{ type: 'text' as const, text, text_elements: [] }] : []),\n ...images.map((url) => ({ type: 'image' as const, url })),\n ];\n}\n\n/** Codex 0.164.0 reports Fast as priority and standard speed as default. */\nexport function serviceTierSettings(\n tier: string | null | undefined,\n): Pick<RuntimeSettings, 'serviceTier'> {\n if (tier === undefined) return {};\n return { serviceTier: tier === 'priority' ? 'fast' : tier === 'default' ? null : tier };\n}\n\nexport function threadStatus(status: ThreadStatus): RunStatus {\n if (!isRecord(status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is malformed', true);\n if (status.type === 'notLoaded') return 'unknown';\n if (status.type === 'idle') return 'idle';\n if (status.type === 'systemError') return 'failed';\n if (status.type !== 'active' || !Array.isArray(status.activeFlags))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is not supported', true);\n if (status.activeFlags.includes('waitingOnApproval')) return 'waitingApproval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'waitingInput';\n return 'running';\n}\nexport function mapThread(thread: Thread): ThreadView {\n assertObjectId(thread, 'thread');\n if (typeof thread.cwd !== 'string' || !Array.isArray(thread.turns) || !isRecord(thread.status))\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex thread response is missing required fields',\n true,\n );\n const turns = thread.turns.map((turn) => mapTurn(thread.id, turn));\n let status = threadStatus(thread.status);\n // Persisted history is normally notLoaded after a restart, even when every turn\n // finished. Keep unfinished history uncertain; the gateway separately overlays\n // durable execution markers, including dispatches without a known turn ID.\n if (thread.status.type === 'notLoaded' && !turns.some((turn) => turn.status === 'running'))\n status = turns.at(-1)?.status ?? 'idle';\n return {\n id: thread.id,\n ...(typeof thread.forkedFromId === 'string' ? { forkedFromId: thread.forkedFromId } : {}),\n projectId: '',\n cwd: thread.cwd,\n source: typeof thread.source === 'string' ? thread.source : JSON.stringify(thread.source),\n originator: typeof thread.originator === 'string' ? thread.originator : null,\n title: thread.name || thread.preview || '\u65B0\u4F1A\u8BDD',\n // List/metadata responses omit turns. The native preview is history evidence.\n hasMessages: Boolean(thread.preview) || thread.turns.length > 0,\n status,\n turns,\n managed: false,\n runtimeSettings: {\n model: thread.model ?? null,\n reasoningEffort: thread.reasoningEffort ?? null,\n },\n updatedAt: thread.updatedAt * 1000,\n actions: [],\n };\n}\nexport function mapTurn(threadId: string, turn: Turn): TurnView {\n assertObjectId(turn, 'turn');\n if (!['inProgress', 'completed', 'failed', 'interrupted'].includes(turn.status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn status is not supported', true);\n if (!Array.isArray(turn.items))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn response is missing items', true);\n return {\n id: turn.id,\n threadId,\n status: turn.status === 'inProgress' ? 'running' : turn.status,\n ...(validTiming(turn.startedAt) ? { startedAt: turn.startedAt * 1000 } : {}),\n ...(validTiming(turn.completedAt) ? { completedAt: turn.completedAt * 1000 } : {}),\n ...(validTiming(turn.durationMs) ? { durationMs: turn.durationMs } : {}),\n items: turn.items.map(mapItem),\n ...(turn.error ? { error: turn.error.message } : {}),\n };\n}\nfunction validTiming(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\nexport function mapItem(item: ThreadItem): ItemView {\n assertObjectId(item, 'item');\n if (typeof item.type !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex item has no type', true);\n switch (item.type) {\n case 'userMessage': {\n const content = item.content.filter((input) => !['skill', 'mention'].includes(input.type));\n const replies =\n content.length === 1 && content[0]?.type === 'text'\n ? parseQuestionReplies(content[0].text)\n : undefined;\n const imageInputs = item.content.filter(\n (input) => input.type === 'image' || input.type === 'localImage',\n );\n let bytes = 0;\n const images = imageInputs.slice(0, MAX_IMAGES).flatMap((input) => {\n if (input.type !== 'image' || !('url' in input)) return [];\n const size = imageDataBytes(input.url);\n if (size === undefined || bytes + size > MAX_IMAGE_BYTES) return [];\n bytes += size;\n return [input.url];\n });\n return {\n id: item.id,\n type: item.type,\n text: replies\n ? replies.map((reply) => `${reply.question}\\n${reply.answer}`).join('\\n\\n')\n : item.content\n .filter((input) => input.type !== 'image' && input.type !== 'localImage')\n .map((input) => (input.type === 'text' ? input.text : `[${input.type}]`))\n .join('\\n'),\n ...(replies ? { questionReplies: replies } : {}),\n ...(imageInputs.length ? { images, imageCount: imageInputs.length } : {}),\n };\n }\n case 'agentMessage':\n return {\n id: item.id,\n type: item.type,\n text: item.text,\n ...(item.delivery ? { delivery: item.delivery } : {}),\n ...(item.questions?.length ? { questions: structuredClone(item.questions) } : {}),\n };\n case 'reasoning':\n return { id: item.id, type: item.type, text: [...item.summary, ...item.content].join('\\n') };\n case 'plan':\n return { id: item.id, type: item.type, text: item.text };\n case 'contextCompaction':\n // Lifecycle is carried by notifications, not the persisted item body.\n return { id: item.id, type: item.type };\n case 'enteredReviewMode':\n case 'exitedReviewMode':\n return { id: item.id, type: item.type, text: item.review };\n case 'commandExecution':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n command: item.command,\n cwd: item.cwd,\n output: item.aggregatedOutput ?? '',\n ...(item.exitCode !== null && item.exitCode !== 0\n ? { error: `\u9000\u51FA\u4EE3\u7801 ${item.exitCode}` }\n : {}),\n };\n case 'fileChange':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n changes: item.changes.map((change) => ({\n path: change.path,\n kind: change.kind.type,\n diff: change.diff,\n })),\n };\n default:\n return {\n id: item.id,\n type: item.type,\n ...('status' in item ? { status: String(item.status) } : {}),\n details: item,\n };\n }\n}\nexport function threadSettings(\n settings: Settings = {},\n): Pick<\n ThreadStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandbox' | 'config'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(settings.sandbox === undefined ? {} : { sandbox: settings.sandbox }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { config: { model_reasoning_effort: settings.reasoningEffort } }),\n };\n}\nexport function turnSettings(\n cwd: string,\n settings: Settings = {},\n): Pick<\n TurnStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandboxPolicy' | 'effort'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n const sandboxPolicy: TurnStartParams['sandboxPolicy'] =\n settings.sandbox === 'read-only'\n ? { type: 'readOnly', networkAccess: false }\n : settings.sandbox === 'workspace-write'\n ? {\n type: 'workspaceWrite',\n writableRoots: [cwd],\n networkAccess: false,\n excludeTmpdirEnvVar: false,\n excludeSlashTmp: false,\n }\n : settings.sandbox === 'danger-full-access'\n ? { type: 'dangerFullAccess' }\n : undefined;\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(sandboxPolicy === undefined ? {} : { sandboxPolicy }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { effort: settings.reasoningEffort as ReasoningEffort }),\n };\n}\nfunction assertObjectId(value: unknown, kind: string): void {\n if (!isRecord(value) || typeof value.id !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex ${kind} has no stable id`, true);\n}\n"],
|
|
5
|
-
"mappings": "AAQA,SAAS,uBAAuB;AAEhC,SAAS,0BAA0B;AASnC,SAAS,4BAA4B;AACrC,SAAS,gBAAgB,YAAY,uBAAuB;AAC5D,SAAS,YAAY,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import type {\n ItemView,\n RunStatus,\n RuntimeSettings,\n Settings,\n ThreadView,\n TurnView,\n} from '../shared/types.js';\nimport { permissionModes } from '../shared/permissions.js';\nimport type { PermissionSelection } from './permissions.js';\nexport { permissionSettings } from './permissions.js';\nimport type { Thread } from './generated/v2/Thread.js';\nimport type { ThreadItem } from './generated/v2/ThreadItem.js';\nimport type { ThreadStatus } from './generated/v2/ThreadStatus.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport type { TurnStartParams } from './generated/v2/TurnStartParams.js';\nimport type { ReasoningEffort } from './generated/ReasoningEffort.js';\nimport type { UserInput } from './generated/v2/UserInput.js';\nimport { parseQuestionReplies } from '../shared/async-questions.js';\nimport { imageDataBytes, MAX_IMAGES, MAX_IMAGE_BYTES } from '../shared/images.js';\nimport { CodexError, isRecord } from './transport.js';\n\n/** Keep public diagnostics bounded and independent of upstream protocol types. */\nexport function mapTurnError(error: {\n codexErrorInfo?: unknown;\n additionalDetails?: string | null;\n}) {\n const info = error.codexErrorInfo;\n const code = typeof info === 'string' ? info : isRecord(info) ? Object.keys(info)[0] : undefined;\n return {\n ...(code ? { errorCode: code.slice(0, 100) } : {}),\n ...(error.additionalDetails ? { errorDetails: error.additionalDetails.slice(0, 4096) } : {}),\n };\n}\n\nexport function taskInput(text: string, images: string[] = []): UserInput[] {\n return [\n ...(text ? [{ type: 'text' as const, text, text_elements: [] }] : []),\n ...images.map((url) => ({ type: 'image' as const, url })),\n ];\n}\n\n/** Codex 0.164.0 reports Fast as priority and standard speed as default. */\nexport function serviceTierSettings(\n tier: string | null | undefined,\n): Pick<RuntimeSettings, 'serviceTier'> {\n if (tier === undefined) return {};\n return { serviceTier: tier === 'priority' ? 'fast' : tier === 'default' ? null : tier };\n}\n\nexport function threadStatus(status: ThreadStatus): RunStatus {\n if (!isRecord(status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is malformed', true);\n if (status.type === 'notLoaded') return 'unknown';\n if (status.type === 'idle') return 'idle';\n if (status.type === 'systemError') return 'failed';\n if (status.type !== 'active' || !Array.isArray(status.activeFlags))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex thread status is not supported', true);\n if (status.activeFlags.includes('waitingOnApproval')) return 'waitingApproval';\n if (status.activeFlags.includes('waitingOnUserInput')) return 'waitingInput';\n return 'running';\n}\nexport function mapThread(thread: Thread): ThreadView {\n assertObjectId(thread, 'thread');\n if (typeof thread.cwd !== 'string' || !Array.isArray(thread.turns) || !isRecord(thread.status))\n throw new CodexError(\n 'PROTOCOL_INCOMPATIBLE',\n 'Codex thread response is missing required fields',\n true,\n );\n const turns = thread.turns.map((turn) => mapTurn(thread.id, turn));\n let status = threadStatus(thread.status);\n // Persisted history is normally notLoaded after a restart, even when every turn\n // finished. Keep unfinished history uncertain; the gateway separately overlays\n // durable execution markers, including dispatches without a known turn ID.\n if (thread.status.type === 'notLoaded' && !turns.some((turn) => turn.status === 'running'))\n status = turns.at(-1)?.status ?? 'idle';\n return {\n id: thread.id,\n ...(typeof thread.forkedFromId === 'string' ? { forkedFromId: thread.forkedFromId } : {}),\n projectId: '',\n cwd: thread.cwd,\n source: typeof thread.source === 'string' ? thread.source : JSON.stringify(thread.source),\n originator: typeof thread.originator === 'string' ? thread.originator : null,\n title: thread.name || thread.preview || '\u65B0\u4F1A\u8BDD',\n // List/metadata responses omit turns. The native preview is history evidence.\n hasMessages: Boolean(thread.preview) || thread.turns.length > 0,\n status,\n turns,\n managed: false,\n runtimeSettings: {\n model: thread.model ?? null,\n reasoningEffort: thread.reasoningEffort ?? null,\n },\n updatedAt: thread.updatedAt * 1000,\n actions: [],\n };\n}\nexport function mapTurn(threadId: string, turn: Turn): TurnView {\n assertObjectId(turn, 'turn');\n if (!['inProgress', 'completed', 'failed', 'interrupted'].includes(turn.status))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn status is not supported', true);\n if (!Array.isArray(turn.items))\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex turn response is missing items', true);\n return {\n id: turn.id,\n threadId,\n status: turn.status === 'inProgress' ? 'running' : turn.status,\n ...(validTiming(turn.startedAt) ? { startedAt: turn.startedAt * 1000 } : {}),\n ...(validTiming(turn.completedAt) ? { completedAt: turn.completedAt * 1000 } : {}),\n ...(validTiming(turn.durationMs) ? { durationMs: turn.durationMs } : {}),\n items: turn.items.map(mapItem),\n ...(turn.error ? { error: turn.error.message, ...mapTurnError(turn.error) } : {}),\n };\n}\nfunction validTiming(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\nexport function mapItem(item: ThreadItem): ItemView {\n assertObjectId(item, 'item');\n if (typeof item.type !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex item has no type', true);\n switch (item.type) {\n case 'userMessage': {\n const content = item.content.filter((input) => !['skill', 'mention'].includes(input.type));\n const replies =\n content.length === 1 && content[0]?.type === 'text'\n ? parseQuestionReplies(content[0].text)\n : undefined;\n const imageInputs = item.content.filter(\n (input) => input.type === 'image' || input.type === 'localImage',\n );\n let bytes = 0;\n const images = imageInputs.slice(0, MAX_IMAGES).flatMap((input) => {\n if (input.type !== 'image' || !('url' in input)) return [];\n const size = imageDataBytes(input.url);\n if (size === undefined || bytes + size > MAX_IMAGE_BYTES) return [];\n bytes += size;\n return [input.url];\n });\n return {\n id: item.id,\n type: item.type,\n text: replies\n ? replies.map((reply) => `${reply.question}\\n${reply.answer}`).join('\\n\\n')\n : item.content\n .filter((input) => input.type !== 'image' && input.type !== 'localImage')\n .map((input) => (input.type === 'text' ? input.text : `[${input.type}]`))\n .join('\\n'),\n ...(replies ? { questionReplies: replies } : {}),\n ...(imageInputs.length ? { images, imageCount: imageInputs.length } : {}),\n };\n }\n case 'agentMessage':\n return {\n id: item.id,\n type: item.type,\n text: item.text,\n ...(item.delivery ? { delivery: item.delivery } : {}),\n ...(item.questions?.length ? { questions: structuredClone(item.questions) } : {}),\n };\n case 'reasoning':\n return { id: item.id, type: item.type, text: [...item.summary, ...item.content].join('\\n') };\n case 'plan':\n return { id: item.id, type: item.type, text: item.text };\n case 'contextCompaction':\n // Lifecycle is carried by notifications, not the persisted item body.\n return { id: item.id, type: item.type };\n case 'enteredReviewMode':\n case 'exitedReviewMode':\n return { id: item.id, type: item.type, text: item.review };\n case 'commandExecution':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n command: item.command,\n cwd: item.cwd,\n output: item.aggregatedOutput ?? '',\n ...(item.exitCode !== null && item.exitCode !== 0\n ? { error: `\u9000\u51FA\u4EE3\u7801 ${item.exitCode}` }\n : {}),\n };\n case 'fileChange':\n return {\n id: item.id,\n type: item.type,\n status: item.status,\n changes: item.changes.map((change) => ({\n path: change.path,\n kind: change.kind.type,\n diff: change.diff,\n })),\n };\n default:\n return {\n id: item.id,\n type: item.type,\n ...('status' in item ? { status: String(item.status) } : {}),\n details: item,\n };\n }\n}\nexport function threadSettings(\n settings: Settings = {},\n): Pick<\n ThreadStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandbox' | 'config'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(settings.sandbox === undefined ? {} : { sandbox: settings.sandbox }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { config: { model_reasoning_effort: settings.reasoningEffort } }),\n };\n}\nexport function turnSettings(\n cwd: string,\n settings: Settings = {},\n): Pick<\n TurnStartParams,\n 'model' | 'serviceTier' | 'approvalPolicy' | 'approvalsReviewer' | 'sandboxPolicy' | 'effort'\n> &\n PermissionSelection {\n const preset = settings.permissionMode && permissionModes[settings.permissionMode];\n const sandboxPolicy: TurnStartParams['sandboxPolicy'] =\n settings.sandbox === 'read-only'\n ? { type: 'readOnly', networkAccess: false }\n : settings.sandbox === 'workspace-write'\n ? {\n type: 'workspaceWrite',\n writableRoots: [cwd],\n networkAccess: false,\n excludeTmpdirEnvVar: false,\n excludeSlashTmp: false,\n }\n : settings.sandbox === 'danger-full-access'\n ? { type: 'dangerFullAccess' }\n : undefined;\n return {\n ...(settings.model === undefined ? {} : { model: settings.model }),\n ...(settings.serviceTier === undefined ? {} : { serviceTier: settings.serviceTier }),\n ...(settings.approvalPolicy === undefined ? {} : { approvalPolicy: settings.approvalPolicy }),\n ...(settings.approvalReviewer === undefined\n ? {}\n : { approvalsReviewer: settings.approvalReviewer }),\n ...(sandboxPolicy === undefined ? {} : { sandboxPolicy }),\n ...(preset\n ? {\n permissions: preset.profile,\n approvalPolicy: preset.approvalPolicy,\n approvalsReviewer: preset.approvalReviewer,\n }\n : {}),\n ...(settings.reasoningEffort === undefined\n ? {}\n : { effort: settings.reasoningEffort as ReasoningEffort }),\n };\n}\nfunction assertObjectId(value: unknown, kind: string): void {\n if (!isRecord(value) || typeof value.id !== 'string')\n throw new CodexError('PROTOCOL_INCOMPATIBLE', `Codex ${kind} has no stable id`, true);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CodexError, isRecord } from "./transport.js";
|
|
2
|
+
function readGoal(value, threadId) {
|
|
3
|
+
if (value === null) return null;
|
|
4
|
+
if (!isRecord(value) || value.threadId !== threadId || typeof value.objective !== "string" || !["active", "paused", "blocked", "usageLimited", "budgetLimited", "complete"].includes(
|
|
5
|
+
String(value.status)
|
|
6
|
+
) || !["tokensUsed", "timeUsedSeconds", "createdAt", "updatedAt"].every(
|
|
7
|
+
(key) => typeof value[key] === "number" && Number.isFinite(value[key]) && value[key] >= 0
|
|
8
|
+
) || value.tokenBudget !== null && (typeof value.tokenBudget !== "number" || !Number.isSafeInteger(value.tokenBudget) || value.tokenBudget <= 0))
|
|
9
|
+
throw new CodexError("PROTOCOL_INCOMPATIBLE", "Codex returned an invalid goal snapshot");
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
readGoal
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=thread-goals.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/codex/thread-goals.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ThreadGoal } from '../shared/thread-goal.js';\nimport { CodexError, isRecord } from './transport.js';\nexport function readGoal(value: unknown, threadId: string): ThreadGoal | null {\n if (value === null) return null;\n if (\n !isRecord(value) ||\n value.threadId !== threadId ||\n typeof value.objective !== 'string' ||\n !['active', 'paused', 'blocked', 'usageLimited', 'budgetLimited', 'complete'].includes(\n String(value.status),\n ) ||\n !['tokensUsed', 'timeUsedSeconds', 'createdAt', 'updatedAt'].every(\n (key) => typeof value[key] === 'number' && Number.isFinite(value[key]) && value[key] >= 0,\n ) ||\n (value.tokenBudget !== null &&\n (typeof value.tokenBudget !== 'number' ||\n !Number.isSafeInteger(value.tokenBudget) ||\n value.tokenBudget <= 0))\n )\n throw new CodexError('PROTOCOL_INCOMPATIBLE', 'Codex returned an invalid goal snapshot');\n return value as unknown as ThreadGoal;\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,YAAY,gBAAgB;AAC9B,SAAS,SAAS,OAAgB,UAAqC;AAC5E,MAAI,UAAU,KAAM,QAAO;AAC3B,MACE,CAAC,SAAS,KAAK,KACf,MAAM,aAAa,YACnB,OAAO,MAAM,cAAc,YAC3B,CAAC,CAAC,UAAU,UAAU,WAAW,gBAAgB,iBAAiB,UAAU,EAAE;AAAA,IAC5E,OAAO,MAAM,MAAM;AAAA,EACrB,KACA,CAAC,CAAC,cAAc,mBAAmB,aAAa,WAAW,EAAE;AAAA,IAC3D,CAAC,QAAQ,OAAO,MAAM,GAAG,MAAM,YAAY,OAAO,SAAS,MAAM,GAAG,CAAC,KAAK,MAAM,GAAG,KAAK;AAAA,EAC1F,KACC,MAAM,gBAAgB,SACpB,OAAO,MAAM,gBAAgB,YAC5B,CAAC,OAAO,cAAc,MAAM,WAAW,KACvC,MAAM,eAAe;AAEzB,UAAM,IAAI,WAAW,yBAAyB,yCAAyC;AACzF,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -121,6 +121,136 @@ class ThreadTitles {
|
|
|
121
121
|
call(method, params) {
|
|
122
122
|
return this.rpc.request(method, params);
|
|
123
123
|
}
|
|
124
|
+
async startTemporary(source, model, threadSource, permissions) {
|
|
125
|
+
const { config } = await this.call("config/read", {
|
|
126
|
+
cwd: source.cwd,
|
|
127
|
+
includeLayers: false
|
|
128
|
+
});
|
|
129
|
+
const overrides = {
|
|
130
|
+
web_search: "disabled",
|
|
131
|
+
"cloud.skills.enabled": false,
|
|
132
|
+
"skills.include_instructions": false,
|
|
133
|
+
"tools.experimental_request_user_input.enabled": false,
|
|
134
|
+
"tools.update_plan.enabled": false,
|
|
135
|
+
mcp_servers: Object.fromEntries(
|
|
136
|
+
Object.keys(isRecord(config.mcp_servers) ? config.mcp_servers : {}).map((name) => [
|
|
137
|
+
name,
|
|
138
|
+
{ enabled: false }
|
|
139
|
+
])
|
|
140
|
+
)
|
|
141
|
+
};
|
|
142
|
+
for (const feature of [
|
|
143
|
+
"shell_tool",
|
|
144
|
+
"shell_snapshot",
|
|
145
|
+
"apps",
|
|
146
|
+
"plugins",
|
|
147
|
+
"hooks",
|
|
148
|
+
"multi_agent",
|
|
149
|
+
"goals",
|
|
150
|
+
"memories",
|
|
151
|
+
"browser_use",
|
|
152
|
+
"browser_use_external",
|
|
153
|
+
"computer_use",
|
|
154
|
+
"image_generation",
|
|
155
|
+
"code_mode",
|
|
156
|
+
"code_mode_only",
|
|
157
|
+
"context_management",
|
|
158
|
+
"current_time_reminder",
|
|
159
|
+
"deferred_executor",
|
|
160
|
+
"enable_fanout",
|
|
161
|
+
"multi_agent_v2",
|
|
162
|
+
"request_permissions_tool",
|
|
163
|
+
"standalone_web_search",
|
|
164
|
+
"token_budget",
|
|
165
|
+
"tool_suggest",
|
|
166
|
+
"unified_exec",
|
|
167
|
+
"view_image"
|
|
168
|
+
])
|
|
169
|
+
overrides[`features.${feature}`] = false;
|
|
170
|
+
if (!permissions) overrides.default_permissions = ":read-only";
|
|
171
|
+
const params = {
|
|
172
|
+
cwd: source.cwd,
|
|
173
|
+
model,
|
|
174
|
+
modelProvider: source.modelProvider,
|
|
175
|
+
ephemeral: true,
|
|
176
|
+
threadSource,
|
|
177
|
+
...permissions ? { permissions } : { sandbox: "read-only" },
|
|
178
|
+
runtimeWorkspaceRoots: [],
|
|
179
|
+
environments: [],
|
|
180
|
+
dynamicTools: [],
|
|
181
|
+
selectedCapabilityRoots: [],
|
|
182
|
+
config: overrides
|
|
183
|
+
};
|
|
184
|
+
return this.call("thread/start", params);
|
|
185
|
+
}
|
|
186
|
+
/** Explicit user-requested recap. Separate inference; no writes to the source thread. */
|
|
187
|
+
async recap(id, prompt) {
|
|
188
|
+
const key = `recap:${id}`;
|
|
189
|
+
if (this.closed || this.jobs.has(key))
|
|
190
|
+
throw new CodexError("RECAP_BUSY", "Recap is already running");
|
|
191
|
+
let finish;
|
|
192
|
+
const completed = new Promise((resolve) => {
|
|
193
|
+
finish = resolve;
|
|
194
|
+
});
|
|
195
|
+
const job = { cancelled: false, terminal: false, finish };
|
|
196
|
+
this.jobs.set(key, job);
|
|
197
|
+
this.armTimeout(job);
|
|
198
|
+
try {
|
|
199
|
+
const source = await this.call("thread/read", { threadId: id, includeTurns: false });
|
|
200
|
+
if (job.cancelled || source.thread.id !== id)
|
|
201
|
+
throw new CodexError("RECAP_FAILED", "Recap was interrupted");
|
|
202
|
+
const generated = await this.startTemporary(
|
|
203
|
+
source.thread,
|
|
204
|
+
source.thread.model ?? "",
|
|
205
|
+
"recap"
|
|
206
|
+
);
|
|
207
|
+
job.threadId = generated.thread.id;
|
|
208
|
+
this.internal.set(job.threadId, job);
|
|
209
|
+
if (job.cancelled || generated.sandbox.type !== "readOnly")
|
|
210
|
+
throw new CodexError("RECAP_FAILED", "Recap isolation could not be confirmed");
|
|
211
|
+
const { turn } = await this.call("turn/start", {
|
|
212
|
+
threadId: job.threadId,
|
|
213
|
+
input: [{ type: "text", text: prompt, text_elements: [] }],
|
|
214
|
+
outputSchema: {
|
|
215
|
+
type: "object",
|
|
216
|
+
properties: { summary: { type: "string" } },
|
|
217
|
+
required: ["summary"],
|
|
218
|
+
additionalProperties: false
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
job.turnId = turn.id;
|
|
222
|
+
if (turn.status !== "inProgress") {
|
|
223
|
+
job.terminal = true;
|
|
224
|
+
job.finish(turn);
|
|
225
|
+
}
|
|
226
|
+
const result = await completed;
|
|
227
|
+
if (job.cancelled || result?.status !== "completed")
|
|
228
|
+
throw new CodexError("RECAP_FAILED", "Recap did not complete");
|
|
229
|
+
const output = result.items.filter((item) => item.type === "agentMessage").at(-1)?.text ?? job.output;
|
|
230
|
+
let value;
|
|
231
|
+
try {
|
|
232
|
+
value = JSON.parse(output ?? "");
|
|
233
|
+
} catch {
|
|
234
|
+
throw new CodexError("RECAP_FAILED", "Recap returned an invalid response");
|
|
235
|
+
}
|
|
236
|
+
if (!isRecord(value) || typeof value.summary !== "string" || !value.summary.trim() || Buffer.byteLength(value.summary) > TITLE_RESPONSE_MAX_BYTES)
|
|
237
|
+
throw new CodexError("RECAP_FAILED", "Recap returned an invalid response");
|
|
238
|
+
return value.summary.trim();
|
|
239
|
+
} finally {
|
|
240
|
+
clearTimeout(job.timer);
|
|
241
|
+
this.jobs.delete(key);
|
|
242
|
+
if (job.threadId && !this.closed) {
|
|
243
|
+
if (job.turnId && !job.terminal)
|
|
244
|
+
await this.call("turn/interrupt", { threadId: job.threadId, turnId: job.turnId }).catch(
|
|
245
|
+
() => {
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
await this.call("thread/unsubscribe", { threadId: job.threadId }).catch(() => {
|
|
249
|
+
});
|
|
250
|
+
this.internal.set(job.threadId, void 0);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
124
254
|
async generate(id, text, source, job, completed) {
|
|
125
255
|
try {
|
|
126
256
|
const before = await this.call("thread/read", { threadId: id, includeTurns: false });
|
|
@@ -137,67 +267,12 @@ class ThreadTitles {
|
|
|
137
267
|
);
|
|
138
268
|
const profile = source.activePermissionProfile?.id;
|
|
139
269
|
const permissions = profile && !profile.startsWith(":") ? profile : void 0;
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
includeLayers: false
|
|
143
|
-
});
|
|
144
|
-
if (job.cancelled) return;
|
|
145
|
-
const overrides = {
|
|
146
|
-
web_search: "disabled",
|
|
147
|
-
"cloud.skills.enabled": false,
|
|
148
|
-
"skills.include_instructions": false,
|
|
149
|
-
"tools.experimental_request_user_input.enabled": false,
|
|
150
|
-
"tools.update_plan.enabled": false,
|
|
151
|
-
mcp_servers: Object.fromEntries(
|
|
152
|
-
Object.keys(isRecord(config.mcp_servers) ? config.mcp_servers : {}).map((name) => [
|
|
153
|
-
name,
|
|
154
|
-
{ enabled: false }
|
|
155
|
-
])
|
|
156
|
-
)
|
|
157
|
-
};
|
|
158
|
-
for (const feature of [
|
|
159
|
-
"shell_tool",
|
|
160
|
-
"shell_snapshot",
|
|
161
|
-
"apps",
|
|
162
|
-
"plugins",
|
|
163
|
-
"hooks",
|
|
164
|
-
"multi_agent",
|
|
165
|
-
"goals",
|
|
166
|
-
"memories",
|
|
167
|
-
"browser_use",
|
|
168
|
-
"browser_use_external",
|
|
169
|
-
"computer_use",
|
|
170
|
-
"image_generation",
|
|
171
|
-
"code_mode",
|
|
172
|
-
"code_mode_only",
|
|
173
|
-
"context_management",
|
|
174
|
-
"current_time_reminder",
|
|
175
|
-
"deferred_executor",
|
|
176
|
-
"enable_fanout",
|
|
177
|
-
"multi_agent_v2",
|
|
178
|
-
"request_permissions_tool",
|
|
179
|
-
"standalone_web_search",
|
|
180
|
-
"token_budget",
|
|
181
|
-
"tool_suggest",
|
|
182
|
-
"unified_exec",
|
|
183
|
-
"view_image"
|
|
184
|
-
])
|
|
185
|
-
overrides[`features.${feature}`] = false;
|
|
186
|
-
if (!permissions) overrides.default_permissions = ":read-only";
|
|
187
|
-
const params = {
|
|
188
|
-
cwd: before.thread.cwd,
|
|
270
|
+
const generated = await this.startTemporary(
|
|
271
|
+
before.thread,
|
|
189
272
|
model,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
...permissions ? { permissions } : { sandbox: "read-only" },
|
|
194
|
-
runtimeWorkspaceRoots: [],
|
|
195
|
-
environments: [],
|
|
196
|
-
dynamicTools: [],
|
|
197
|
-
selectedCapabilityRoots: [],
|
|
198
|
-
config: overrides
|
|
199
|
-
};
|
|
200
|
-
const generated = await this.call("thread/start", params);
|
|
273
|
+
"thread_title",
|
|
274
|
+
permissions
|
|
275
|
+
);
|
|
201
276
|
job.threadId = generated.thread.id;
|
|
202
277
|
this.internal.set(job.threadId, job);
|
|
203
278
|
if (job.cancelled) return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/codex/thread-titles.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ClientRequest } from './generated/ClientRequest.js';\nimport type { ServerNotification } from './generated/ServerNotification.js';\nimport type { ConfigReadResponse } from './generated/v2/ConfigReadResponse.js';\nimport type { ThreadReadResponse } from './generated/v2/ThreadReadResponse.js';\nimport type { ThreadStartResponse } from './generated/v2/ThreadStartResponse.js';\nimport type { TurnStartResponse } from './generated/v2/TurnStartResponse.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { JsonValue } from './generated/serde_json/JsonValue.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport {\n parseTitle,\n selectTitleModel,\n titlePrompt,\n titleOutputSchema,\n TITLE_MODEL,\n TITLE_RESPONSE_MAX_BYTES,\n} from './thread-title-policy.js';\nimport { CodexError, isRecord, type RpcNotification, type RpcTransport } from './transport.js';\n\n// These experimental fields are omitted by the stable protocol generator.\n// Their shapes match the verified CLI 0.164.0 app-server protocol.\ntype TitleSource = ThreadStartResponse & {\n activePermissionProfile?: { id: string } | null;\n};\ntype TemporaryThreadParams = ThreadStartParams & {\n permissions?: string;\n runtimeWorkspaceRoots: [];\n environments: [];\n dynamicTools: [];\n selectedCapabilityRoots: [];\n};\ntype Job = {\n cancelled: boolean;\n threadId?: string;\n turnId?: string;\n terminal: boolean;\n output?: string;\n timer?: NodeJS.Timeout;\n finish: (turn: Turn | null) => void;\n};\ntype Responses = {\n 'config/read': ConfigReadResponse;\n 'thread/read': ThreadReadResponse;\n 'thread/start': TitleSource;\n 'turn/start': TurnStartResponse;\n 'thread/name/set': unknown;\n 'thread/unsubscribe': unknown;\n 'turn/interrupt': unknown;\n};\n\n/** Optional naming work, scoped to one transport lifetime and never exposed as a user task. */\nexport class ThreadTitles {\n private readonly candidates = new Map<string, TitleSource>();\n private readonly jobs = new Map<string, Job>();\n private readonly internal = new Map<string, Job | undefined>();\n private readonly manualNames = new Set<string>();\n private readonly nameWrites = new Map<string, Promise<unknown>>();\n private closed = false;\n private hasChatgptAccount = false;\n private models: string[] = [];\n\n constructor(\n private readonly rpc: RpcTransport,\n private readonly timeoutMs = 30_000,\n ) {\n rpc.once('failure', () => {\n this.closed = true;\n this.candidates.clear();\n for (const job of this.jobs.values()) this.cancel(job);\n this.internal.clear();\n });\n }\n\n configure(hasChatgptAccount: boolean, models: string[]): void {\n this.hasChatgptAccount = hasChatgptAccount;\n this.models = models;\n }\n\n register(result: TitleSource): void {\n if (\n !this.closed &&\n !this.manualNames.has(result.thread.id) &&\n !result.thread.name &&\n !result.thread.ephemeral\n )\n this.candidates.set(result.thread.id, { ...result, thread: { ...result.thread, turns: [] } });\n else this.candidates.delete(result.thread.id);\n }\n\n async prepareManualName(id: string): Promise<void> {\n this.manualNames.add(id);\n this.candidates.delete(id);\n const job = this.jobs.get(id);\n if (job) this.cancel(job);\n // A timeout does not cancel the upstream write. Retain that failure until a new\n // transport lifetime, rather than let a late generated title overwrite a manual name.\n await this.nameWrites.get(id);\n }\n\n private start(id: string, text: string): void {\n const candidate = this.candidates.get(id);\n // Retry only on a later user-message event, never while another attempt is pending.\n if (!candidate || this.closed || !text.trim() || this.jobs.has(id) || this.nameWrites.has(id))\n return;\n let finish!: Job['finish'];\n const completed = new Promise<Turn | null>((resolve) => {\n finish = resolve;\n });\n const job: Job = { cancelled: false, terminal: false, finish };\n this.jobs.set(id, job);\n this.armTimeout(job);\n void this.generate(id, text, candidate, job, completed)\n .catch(() => {\n /* Keep the upstream preview; naming must never fail the user's task. */\n })\n .finally(() => {\n clearTimeout(job.timer);\n this.jobs.delete(id);\n });\n }\n\n /** Called before ordinary event mapping, including notifications preceding RPC receipts. */\n notification(message: RpcNotification): boolean {\n const event = message as ServerNotification;\n if (event.method === 'thread/started' && event.params.thread.ephemeral) {\n // The notification can arrive before OR after thread/start's response.\n if (!this.internal.has(event.params.thread.id))\n this.internal.set(event.params.thread.id, undefined);\n return true;\n }\n const params = message.params;\n if (!isRecord(params) || typeof params.threadId !== 'string') return false;\n const id = params.threadId;\n if (this.internal.has(id)) {\n const job = this.internal.get(id);\n if (job && event.method === 'item/completed' && event.params.item.type === 'agentMessage') {\n if (Buffer.byteLength(event.params.item.text) > TITLE_RESPONSE_MAX_BYTES) this.cancel(job);\n else job.output = event.params.item.text;\n }\n if (job && (event.method === 'turn/started' || event.method === 'turn/completed')) {\n job.turnId = event.params.turn.id;\n if (event.method === 'turn/completed') {\n job.terminal = true;\n job.finish(event.params.turn);\n }\n }\n if (job && event.method === 'error' && !event.params.willRetry) this.cancel(job);\n if (event.method === 'thread/closed') this.internal.delete(id);\n return true;\n }\n if (event.method === 'thread/name/updated') {\n const source = this.candidates.get(id);\n if (source) source.thread.name = event.params.threadName ?? null;\n if (event.params.threadName) this.candidates.delete(id);\n const job = this.jobs.get(id);\n if (job) this.cancel(job);\n }\n if (event.method === 'thread/closed') this.candidates.delete(id);\n if (event.method === 'item/completed' && event.params.item.type === 'userMessage') {\n const text = event.params.item.content\n .flatMap((input) => {\n if (input.type !== 'text') return [];\n // CLI removes its IDE context wrapper before constructing the title prompt.\n return input.text.split('## My request for Codex:').at(-1)!.trim();\n })\n .join(' ');\n this.start(id, text);\n }\n return false;\n }\n\n isInternal(threadId: unknown): boolean {\n return typeof threadId === 'string' && this.internal.has(threadId);\n }\n\n private cancel(job: Job): void {\n job.cancelled = true;\n job.finish(null);\n }\n\n private armTimeout(job: Job): void {\n clearTimeout(job.timer);\n job.timer = setTimeout(() => this.cancel(job), this.timeoutMs);\n job.timer.unref();\n }\n\n private call<M extends keyof Responses>(\n method: M,\n params: Extract<ClientRequest, { method: M }>['params'],\n ): Promise<Responses[M]> {\n return this.rpc.request<Responses[M]>(method, params);\n }\n\n private async generate(\n id: string,\n text: string,\n source: TitleSource,\n job: Job,\n completed: Promise<Turn | null>,\n ): Promise<void> {\n try {\n const before = await this.call('thread/read', { threadId: id, includeTurns: false });\n if (job.cancelled || before.thread.id !== id) return;\n if (before.thread.name) {\n this.candidates.delete(id);\n return;\n }\n const model = selectTitleModel(\n before.thread.model ?? source.model,\n before.thread.modelProvider,\n this.hasChatgptAccount,\n this.models,\n );\n const profile = source.activePermissionProfile?.id;\n const permissions = profile && !profile.startsWith(':') ? profile : undefined;\n // Config reads may redact values to empty strings. Override only enabled flags,\n // never round-trip the returned server definitions (timeouts/credentials/etc.).\n // The filesystem sandbox does not constrain MCP tools.\n const { config } = await this.call('config/read', {\n cwd: before.thread.cwd,\n includeLayers: false,\n });\n if (job.cancelled) return;\n const overrides: Record<string, JsonValue> = {\n web_search: 'disabled',\n 'cloud.skills.enabled': false,\n 'skills.include_instructions': false,\n 'tools.experimental_request_user_input.enabled': false,\n 'tools.update_plan.enabled': false,\n mcp_servers: Object.fromEntries(\n Object.keys(isRecord(config.mcp_servers) ? config.mcp_servers : {}).map((name) => [\n name,\n { enabled: false },\n ]),\n ) as JsonValue,\n };\n for (const feature of [\n 'shell_tool',\n 'shell_snapshot',\n 'apps',\n 'plugins',\n 'hooks',\n 'multi_agent',\n 'goals',\n 'memories',\n 'browser_use',\n 'browser_use_external',\n 'computer_use',\n 'image_generation',\n 'code_mode',\n 'code_mode_only',\n 'context_management',\n 'current_time_reminder',\n 'deferred_executor',\n 'enable_fanout',\n 'multi_agent_v2',\n 'request_permissions_tool',\n 'standalone_web_search',\n 'token_budget',\n 'tool_suggest',\n 'unified_exec',\n 'view_image',\n ])\n overrides[`features.${feature}`] = false;\n if (!permissions) overrides.default_permissions = ':read-only';\n const params: TemporaryThreadParams = {\n cwd: before.thread.cwd,\n model,\n modelProvider: before.thread.modelProvider,\n ephemeral: true,\n threadSource: 'thread_title',\n ...(permissions ? { permissions } : { sandbox: 'read-only' }),\n runtimeWorkspaceRoots: [],\n environments: [],\n dynamicTools: [],\n selectedCapabilityRoots: [],\n config: overrides,\n };\n const generated = await this.call('thread/start', params);\n job.threadId = generated.thread.id;\n this.internal.set(job.threadId, job);\n if (job.cancelled) return;\n if (\n permissions\n ? generated.activePermissionProfile?.id !== permissions\n : generated.sandbox.type !== 'readOnly'\n )\n return;\n this.armTimeout(job);\n const { turn } = await this.call('turn/start', {\n threadId: job.threadId,\n input: [\n {\n type: 'text',\n text: titlePrompt(text),\n text_elements: [],\n },\n ],\n ...(model === TITLE_MODEL ? { effort: 'low' } : {}),\n outputSchema: titleOutputSchema,\n });\n job.turnId = turn.id;\n if (turn.status !== 'inProgress') {\n job.terminal = true;\n job.finish(turn);\n }\n const result = await completed;\n clearTimeout(job.timer);\n if (job.cancelled || result?.status !== 'completed') return;\n const output =\n result.items.filter((item) => item.type === 'agentMessage').at(-1)?.text ?? job.output;\n const title = output ? parseTitle(output) : undefined;\n if (!title) return;\n // An explicit name always wins, including one set while inference was running.\n const latest = await this.call('thread/read', { threadId: id, includeTurns: false });\n if (job.cancelled || latest.thread.id !== id || latest.thread.name) return;\n const write = this.call('thread/name/set', { threadId: id, name: title });\n this.nameWrites.set(id, write);\n void write.then(\n () => this.nameWrites.delete(id),\n (error: unknown) => {\n if (error instanceof CodexError && !error.uncertain) this.nameWrites.delete(id);\n },\n );\n await write;\n this.candidates.delete(id);\n } finally {\n if (job.threadId && !this.closed) {\n if (job.turnId && !job.terminal)\n await this.call('turn/interrupt', { threadId: job.threadId, turnId: job.turnId }).catch(\n () => {},\n );\n await this.call('thread/unsubscribe', { threadId: job.threadId }).catch(() => {});\n // Retain the ID until thread/closed so late notifications cannot leak into the UI.\n if (this.internal.has(job.threadId)) this.internal.set(job.threadId, undefined);\n }\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { ClientRequest } from './generated/ClientRequest.js';\nimport type { ServerNotification } from './generated/ServerNotification.js';\nimport type { ConfigReadResponse } from './generated/v2/ConfigReadResponse.js';\nimport type { ThreadReadResponse } from './generated/v2/ThreadReadResponse.js';\nimport type { ThreadStartResponse } from './generated/v2/ThreadStartResponse.js';\nimport type { TurnStartResponse } from './generated/v2/TurnStartResponse.js';\nimport type { Turn } from './generated/v2/Turn.js';\nimport type { JsonValue } from './generated/serde_json/JsonValue.js';\nimport type { ThreadStartParams } from './generated/v2/ThreadStartParams.js';\nimport {\n parseTitle,\n selectTitleModel,\n titlePrompt,\n titleOutputSchema,\n TITLE_MODEL,\n TITLE_RESPONSE_MAX_BYTES,\n} from './thread-title-policy.js';\nimport { CodexError, isRecord, type RpcNotification, type RpcTransport } from './transport.js';\n\n// These experimental fields are omitted by the stable protocol generator.\n// Their shapes match the verified CLI 0.164.0 app-server protocol.\ntype TitleSource = ThreadStartResponse & {\n activePermissionProfile?: { id: string } | null;\n};\ntype TemporaryThreadParams = ThreadStartParams & {\n permissions?: string;\n runtimeWorkspaceRoots: [];\n environments: [];\n dynamicTools: [];\n selectedCapabilityRoots: [];\n};\ntype Job = {\n cancelled: boolean;\n threadId?: string;\n turnId?: string;\n terminal: boolean;\n output?: string;\n timer?: NodeJS.Timeout;\n finish: (turn: Turn | null) => void;\n};\ntype Responses = {\n 'config/read': ConfigReadResponse;\n 'thread/read': ThreadReadResponse;\n 'thread/start': TitleSource;\n 'turn/start': TurnStartResponse;\n 'thread/name/set': unknown;\n 'thread/unsubscribe': unknown;\n 'turn/interrupt': unknown;\n};\n\n/** Optional naming work, scoped to one transport lifetime and never exposed as a user task. */\nexport class ThreadTitles {\n private readonly candidates = new Map<string, TitleSource>();\n private readonly jobs = new Map<string, Job>();\n private readonly internal = new Map<string, Job | undefined>();\n private readonly manualNames = new Set<string>();\n private readonly nameWrites = new Map<string, Promise<unknown>>();\n private closed = false;\n private hasChatgptAccount = false;\n private models: string[] = [];\n\n constructor(\n private readonly rpc: RpcTransport,\n private readonly timeoutMs = 30_000,\n ) {\n rpc.once('failure', () => {\n this.closed = true;\n this.candidates.clear();\n for (const job of this.jobs.values()) this.cancel(job);\n this.internal.clear();\n });\n }\n\n configure(hasChatgptAccount: boolean, models: string[]): void {\n this.hasChatgptAccount = hasChatgptAccount;\n this.models = models;\n }\n\n register(result: TitleSource): void {\n if (\n !this.closed &&\n !this.manualNames.has(result.thread.id) &&\n !result.thread.name &&\n !result.thread.ephemeral\n )\n this.candidates.set(result.thread.id, { ...result, thread: { ...result.thread, turns: [] } });\n else this.candidates.delete(result.thread.id);\n }\n\n async prepareManualName(id: string): Promise<void> {\n this.manualNames.add(id);\n this.candidates.delete(id);\n const job = this.jobs.get(id);\n if (job) this.cancel(job);\n // A timeout does not cancel the upstream write. Retain that failure until a new\n // transport lifetime, rather than let a late generated title overwrite a manual name.\n await this.nameWrites.get(id);\n }\n\n private start(id: string, text: string): void {\n const candidate = this.candidates.get(id);\n // Retry only on a later user-message event, never while another attempt is pending.\n if (!candidate || this.closed || !text.trim() || this.jobs.has(id) || this.nameWrites.has(id))\n return;\n let finish!: Job['finish'];\n const completed = new Promise<Turn | null>((resolve) => {\n finish = resolve;\n });\n const job: Job = { cancelled: false, terminal: false, finish };\n this.jobs.set(id, job);\n this.armTimeout(job);\n void this.generate(id, text, candidate, job, completed)\n .catch(() => {\n /* Keep the upstream preview; naming must never fail the user's task. */\n })\n .finally(() => {\n clearTimeout(job.timer);\n this.jobs.delete(id);\n });\n }\n\n /** Called before ordinary event mapping, including notifications preceding RPC receipts. */\n notification(message: RpcNotification): boolean {\n const event = message as ServerNotification;\n if (event.method === 'thread/started' && event.params.thread.ephemeral) {\n // The notification can arrive before OR after thread/start's response.\n if (!this.internal.has(event.params.thread.id))\n this.internal.set(event.params.thread.id, undefined);\n return true;\n }\n const params = message.params;\n if (!isRecord(params) || typeof params.threadId !== 'string') return false;\n const id = params.threadId;\n if (this.internal.has(id)) {\n const job = this.internal.get(id);\n if (job && event.method === 'item/completed' && event.params.item.type === 'agentMessage') {\n if (Buffer.byteLength(event.params.item.text) > TITLE_RESPONSE_MAX_BYTES) this.cancel(job);\n else job.output = event.params.item.text;\n }\n if (job && (event.method === 'turn/started' || event.method === 'turn/completed')) {\n job.turnId = event.params.turn.id;\n if (event.method === 'turn/completed') {\n job.terminal = true;\n job.finish(event.params.turn);\n }\n }\n if (job && event.method === 'error' && !event.params.willRetry) this.cancel(job);\n if (event.method === 'thread/closed') this.internal.delete(id);\n return true;\n }\n if (event.method === 'thread/name/updated') {\n const source = this.candidates.get(id);\n if (source) source.thread.name = event.params.threadName ?? null;\n if (event.params.threadName) this.candidates.delete(id);\n const job = this.jobs.get(id);\n if (job) this.cancel(job);\n }\n if (event.method === 'thread/closed') this.candidates.delete(id);\n if (event.method === 'item/completed' && event.params.item.type === 'userMessage') {\n const text = event.params.item.content\n .flatMap((input) => {\n if (input.type !== 'text') return [];\n // CLI removes its IDE context wrapper before constructing the title prompt.\n return input.text.split('## My request for Codex:').at(-1)!.trim();\n })\n .join(' ');\n this.start(id, text);\n }\n return false;\n }\n\n isInternal(threadId: unknown): boolean {\n return typeof threadId === 'string' && this.internal.has(threadId);\n }\n\n private cancel(job: Job): void {\n job.cancelled = true;\n job.finish(null);\n }\n\n private armTimeout(job: Job): void {\n clearTimeout(job.timer);\n job.timer = setTimeout(() => this.cancel(job), this.timeoutMs);\n job.timer.unref();\n }\n\n private call<M extends keyof Responses>(\n method: M,\n params: Extract<ClientRequest, { method: M }>['params'],\n ): Promise<Responses[M]> {\n return this.rpc.request<Responses[M]>(method, params);\n }\n\n private async startTemporary(\n source: { cwd: string; modelProvider: string },\n model: string,\n threadSource: string,\n permissions?: string,\n ) {\n // Config reads may redact values to empty strings. Override only enabled flags,\n // never round-trip the returned server definitions (timeouts/credentials/etc.).\n // The filesystem sandbox does not constrain MCP tools.\n const { config } = await this.call('config/read', {\n cwd: source.cwd,\n includeLayers: false,\n });\n const overrides: Record<string, JsonValue> = {\n web_search: 'disabled',\n 'cloud.skills.enabled': false,\n 'skills.include_instructions': false,\n 'tools.experimental_request_user_input.enabled': false,\n 'tools.update_plan.enabled': false,\n mcp_servers: Object.fromEntries(\n Object.keys(isRecord(config.mcp_servers) ? config.mcp_servers : {}).map((name) => [\n name,\n { enabled: false },\n ]),\n ) as JsonValue,\n };\n for (const feature of [\n 'shell_tool',\n 'shell_snapshot',\n 'apps',\n 'plugins',\n 'hooks',\n 'multi_agent',\n 'goals',\n 'memories',\n 'browser_use',\n 'browser_use_external',\n 'computer_use',\n 'image_generation',\n 'code_mode',\n 'code_mode_only',\n 'context_management',\n 'current_time_reminder',\n 'deferred_executor',\n 'enable_fanout',\n 'multi_agent_v2',\n 'request_permissions_tool',\n 'standalone_web_search',\n 'token_budget',\n 'tool_suggest',\n 'unified_exec',\n 'view_image',\n ])\n overrides[`features.${feature}`] = false;\n if (!permissions) overrides.default_permissions = ':read-only';\n const params: TemporaryThreadParams = {\n cwd: source.cwd,\n model,\n modelProvider: source.modelProvider,\n ephemeral: true,\n threadSource,\n ...(permissions ? { permissions } : { sandbox: 'read-only' }),\n runtimeWorkspaceRoots: [],\n environments: [],\n dynamicTools: [],\n selectedCapabilityRoots: [],\n config: overrides,\n };\n return this.call('thread/start', params);\n }\n\n /** Explicit user-requested recap. Separate inference; no writes to the source thread. */\n async recap(id: string, prompt: string): Promise<string> {\n const key = `recap:${id}`;\n if (this.closed || this.jobs.has(key))\n throw new CodexError('RECAP_BUSY', 'Recap is already running');\n let finish!: Job['finish'];\n const completed = new Promise<Turn | null>((resolve) => {\n finish = resolve;\n });\n const job: Job = { cancelled: false, terminal: false, finish };\n this.jobs.set(key, job);\n this.armTimeout(job);\n try {\n const source = await this.call('thread/read', { threadId: id, includeTurns: false });\n if (job.cancelled || source.thread.id !== id)\n throw new CodexError('RECAP_FAILED', 'Recap was interrupted');\n const generated = await this.startTemporary(\n source.thread,\n source.thread.model ?? '',\n 'recap',\n );\n job.threadId = generated.thread.id;\n this.internal.set(job.threadId, job);\n if (job.cancelled || generated.sandbox.type !== 'readOnly')\n throw new CodexError('RECAP_FAILED', 'Recap isolation could not be confirmed');\n const { turn } = await this.call('turn/start', {\n threadId: job.threadId,\n input: [{ type: 'text', text: prompt, text_elements: [] }],\n outputSchema: {\n type: 'object',\n properties: { summary: { type: 'string' } },\n required: ['summary'],\n additionalProperties: false,\n },\n });\n job.turnId = turn.id;\n if (turn.status !== 'inProgress') {\n job.terminal = true;\n job.finish(turn);\n }\n const result = await completed;\n if (job.cancelled || result?.status !== 'completed')\n throw new CodexError('RECAP_FAILED', 'Recap did not complete');\n const output =\n result.items.filter((item) => item.type === 'agentMessage').at(-1)?.text ?? job.output;\n let value: unknown;\n try {\n value = JSON.parse(output ?? '');\n } catch {\n throw new CodexError('RECAP_FAILED', 'Recap returned an invalid response');\n }\n if (\n !isRecord(value) ||\n typeof value.summary !== 'string' ||\n !value.summary.trim() ||\n Buffer.byteLength(value.summary) > TITLE_RESPONSE_MAX_BYTES\n )\n throw new CodexError('RECAP_FAILED', 'Recap returned an invalid response');\n return value.summary.trim();\n } finally {\n clearTimeout(job.timer);\n this.jobs.delete(key);\n if (job.threadId && !this.closed) {\n if (job.turnId && !job.terminal)\n await this.call('turn/interrupt', { threadId: job.threadId, turnId: job.turnId }).catch(\n () => {},\n );\n await this.call('thread/unsubscribe', { threadId: job.threadId }).catch(() => {});\n this.internal.set(job.threadId, undefined);\n }\n }\n }\n\n private async generate(\n id: string,\n text: string,\n source: TitleSource,\n job: Job,\n completed: Promise<Turn | null>,\n ): Promise<void> {\n try {\n const before = await this.call('thread/read', { threadId: id, includeTurns: false });\n if (job.cancelled || before.thread.id !== id) return;\n if (before.thread.name) {\n this.candidates.delete(id);\n return;\n }\n const model = selectTitleModel(\n before.thread.model ?? source.model,\n before.thread.modelProvider,\n this.hasChatgptAccount,\n this.models,\n );\n const profile = source.activePermissionProfile?.id;\n const permissions = profile && !profile.startsWith(':') ? profile : undefined;\n const generated = await this.startTemporary(\n before.thread,\n model,\n 'thread_title',\n permissions,\n );\n job.threadId = generated.thread.id;\n this.internal.set(job.threadId, job);\n if (job.cancelled) return;\n if (\n permissions\n ? generated.activePermissionProfile?.id !== permissions\n : generated.sandbox.type !== 'readOnly'\n )\n return;\n this.armTimeout(job);\n const { turn } = await this.call('turn/start', {\n threadId: job.threadId,\n input: [\n {\n type: 'text',\n text: titlePrompt(text),\n text_elements: [],\n },\n ],\n ...(model === TITLE_MODEL ? { effort: 'low' } : {}),\n outputSchema: titleOutputSchema,\n });\n job.turnId = turn.id;\n if (turn.status !== 'inProgress') {\n job.terminal = true;\n job.finish(turn);\n }\n const result = await completed;\n clearTimeout(job.timer);\n if (job.cancelled || result?.status !== 'completed') return;\n const output =\n result.items.filter((item) => item.type === 'agentMessage').at(-1)?.text ?? job.output;\n const title = output ? parseTitle(output) : undefined;\n if (!title) return;\n // An explicit name always wins, including one set while inference was running.\n const latest = await this.call('thread/read', { threadId: id, includeTurns: false });\n if (job.cancelled || latest.thread.id !== id || latest.thread.name) return;\n const write = this.call('thread/name/set', { threadId: id, name: title });\n this.nameWrites.set(id, write);\n void write.then(\n () => this.nameWrites.delete(id),\n (error: unknown) => {\n if (error instanceof CodexError && !error.uncertain) this.nameWrites.delete(id);\n },\n );\n await write;\n this.candidates.delete(id);\n } finally {\n if (job.threadId && !this.closed) {\n if (job.turnId && !job.terminal)\n await this.call('turn/interrupt', { threadId: job.threadId, turnId: job.turnId }).catch(\n () => {},\n );\n await this.call('thread/unsubscribe', { threadId: job.threadId }).catch(() => {});\n // Retain the ID until thread/closed so late notifications cannot leak into the UI.\n if (this.internal.has(job.threadId)) this.internal.set(job.threadId, undefined);\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|